From 6674e5900787a13ffc5cc0486b93b0fc0bf00455 Mon Sep 17 00:00:00 2001 From: Justin Ahinon Date: Mon, 16 Sep 2024 21:23:56 +0100 Subject: [PATCH 001/114] Remove extra `---` --- .../5-erc20-deploy-script/+page.md | 1 - .../6-erc20-ai-tests-and-recap/+page.md | 2 -- .../15-svg-deploy/+page.md | 1 - .../19-advanced-evm/+page.md | 1 - .../20-evm-encoding/+page.md | 1 - .../22-evm-signatures-selectors/+page.md | 2 -- .../9-testnet-demo/+page.md | 1 - .../3-develop-defi-protocol/10-defi-deploy-script/+page.md | 1 - .../12-defi-deposit-and-mint/+page.md | 1 - .../13-defi-redeem-collateral/+page.md | 1 - .../14-defi-liquidation-setup/+page.md | 1 - .../15-defi-liquidation-refactor/+page.md | 1 - .../17-defi-handler-fuzz-tests/+page.md | 1 - .../19-defi-handler-deposit-collateral/+page.md | 1 - .../3-develop-defi-protocol/22-defi-fuzz-debugging/+page.md | 1 - .../6-defi-deposit-collateral/+page.md | 1 - .../3-develop-defi-protocol/7-defi-mint-dsc/+page.md | 1 - .../3-develop-defi-protocol/8-defi-health-factor/+page.md | 1 - .../9-defi-finishing-mint-dsc/+page.md | 1 - .../6-account-abstraction/11-signed-user-op/+page.md | 5 ----- .../13-test-validate-user-ops/+page.md | 6 ------ .../6-account-abstraction/15-advanced-debugging/+page.md | 2 -- .../6-account-abstraction/18-zksync-setup/+page.md | 3 --- .../6-account-abstraction/19-iaccount/+page.md | 4 ---- .../6-account-abstraction/20-system-contracts/+page.md | 6 ------ .../6-account-abstraction/21-type-113-lifecycle/+page.md | 4 ---- .../6-account-abstraction/23-zksync-simulations/+page.md | 3 --- .../6-account-abstraction/24-validate-tx/+page.md | 4 ---- .../6-account-abstraction/25-execute-tx/+page.md | 3 --- .../6-account-abstraction/3-eth-setup/+page.md | 1 - .../6-account-abstraction/7-execute/+page.md | 3 --- .../6-account-abstraction/9-owner-execute-test/+page.md | 2 -- courses/advanced-foundry/7-daos/6-tests/+page.md | 1 - .../42-solidity-opcodes-from-bytecode/+page.md | 1 - .../1-horse-store/43-soliditys-free-memory-pointer/+page.md | 1 - .../1-horse-store/44-msg.value-check/+page.md | 1 - .../formal-verification/1-horse-store/45-CODECOPY/+page.md | 1 - .../1-horse-store/47-runtime-code-introduction/+page.md | 1 - .../1-horse-store/48-function-selector-size-check/+page.md | 1 - .../1-horse-store/49-soliditys-function-dispatcher/+page.md | 1 - .../50-setting-up-jumpdest-program-counters/+page.md | 1 - .../+page.md | 1 - .../1-horse-store/52-sstoreing-our-value/+page.md | 2 -- .../1-horse-store/53-update-horse-number-recap/+page.md | 1 - .../1-horse-store/54-readNumberOfHorses-op-codes/+page.md | 2 -- .../1-horse-store/64-feedHorse-macro/+page.md | 1 - .../65-mappings-and-arrays-in-evm-huff/+page.md | 1 - .../1-horse-store/66-horseidtofedtimestamp/+page.md | 1 - .../1-horse-store/67-ishappyhorse/+page.md | 1 - .../68-a-quick-function-then-huffmate/+page.md | 2 -- .../1-horse-store/69-huff-constructor/+page.md | 1 - .../3-gasbad/12-init-state-and-axions/+page.md | 1 - .../3-gasbad/18-summary-implementations/+page.md | 1 - .../3-gasbad/25-finishing-the-rule/+page.md | 1 - .../3-first-audit/17-recommended-mitigation/+page.md | 1 - courses/security/3-first-audit/18-finding-writeup/+page.md | 1 - .../20-missing-access-controls-proof-of-code/+page.md | 1 - courses/security/3-first-audit/25-assesing-highs/+page.md | 2 -- .../3-first-audit/26-severity-rating-informational/+page.md | 1 - courses/security/4-puppy-raffle/13-dos-poc/+page.md | 1 - courses/security/4-puppy-raffle/14-dos-reporting/+page.md | 1 - .../4-puppy-raffle/21-reentrancy-menace-to-society/+page.md | 1 - .../security/4-puppy-raffle/40-slither-walkthrough/+page.md | 2 -- courses/security/4-puppy-raffle/5-tooling-aderyn/+page.md | 1 - .../4-puppy-raffle/59-reporting-integer-overflow/+page.md | 1 - .../63-adding-the-audit-to-our-portfolio/+page.md | 1 - .../security/4-puppy-raffle/7-recon-reading-docs/+page.md | 1 - courses/security/5-tswap/31-pool-factory/+page.md | 1 - courses/security/5-tswap/34-add-liquidity/+page.md | 1 - courses/security/5-tswap/35-remove-liquidity/+page.md | 3 --- courses/security/5-tswap/36-exact-input/+page.md | 1 - courses/security/5-tswap/37-exact-output/+page.md | 1 - courses/security/5-tswap/38-sell-pool-tokens/+page.md | 1 - courses/security/5-tswap/40-phase-4-reporting/+page.md | 5 ----- .../security/5-tswap/41-missing-deadline-write-up/+page.md | 1 - courses/security/5-tswap/42-reporting-continued/+page.md | 3 --- courses/security/5-tswap/43-no-slippage-protection/+page.md | 1 - .../security/5-tswap/44-sell-pool-tokens-write-up/+page.md | 1 - .../5-tswap/45-invariant-break-write-up-and-poc/+page.md | 2 -- .../5-tswap/47-creating-pdf-for-your-portfolio/+page.md | 1 - .../6-thunder-loan/12-exploit-centralization/+page.md | 1 - .../6-thunder-loan/14-static-analysis-continued/+page.md | 1 - .../security/6-thunder-loan/19-oracle-upgradeable/+page.md | 1 - .../6-thunder-loan/21-failure-to-initialize-remix/+page.md | 1 - .../6-thunder-loan/23-oracleupgradeable-continued/+page.md | 1 - courses/security/6-thunder-loan/24-assettoken/+page.md | 1 - .../26-thunderloan-starting-at-the-top/+page.md | 1 - .../6-thunder-loan/27-thunderloan-functions/+page.md | 1 - .../6-thunder-loan/28-testing-deleting-mappings/+page.md | 1 - .../6-thunder-loan/30-thunderloan-continued/+page.md | 1 - .../security/6-thunder-loan/32-thunderloan-redeem/+page.md | 1 - .../6-thunder-loan/33-thunderloan-flashloan/+page.md | 3 --- .../6-thunder-loan/34-note-on-being-discouraged/+page.md | 1 - .../37-improving-test-coverage-to-find-a-high/+page.md | 2 -- .../40-exploit-oracle-manipulation-thunderloan-poc/+page.md | 4 ---- .../6-thunder-loan/41-oracle-manipulation-recap/+page.md | 1 - .../45-exploit-storage-collision-remix-examplee/+page.md | 1 - courses/security/7-bridges/11-bossbridge/+page.md | 1 - courses/security/7-bridges/12-signatures/+page.md | 1 - courses/security/7-bridges/14-eip-712/+page.md | 1 - courses/security/7-bridges/20-arbitrary-poc/+page.md | 1 - courses/security/7-bridges/5-Docs/+page.md | 1 - .../8-mev-and-governance/5-mev-in-puppy-raffle/+page.md | 1 - courses/security/8-mev-and-governance/6-mev-t-swap/+page.md | 1 - 104 files changed, 159 deletions(-) diff --git a/courses/advanced-foundry/1-How-to-create-an-erc20-crypto-currency/5-erc20-deploy-script/+page.md b/courses/advanced-foundry/1-How-to-create-an-erc20-crypto-currency/5-erc20-deploy-script/+page.md index 4a33359e2..aac6c050a 100644 --- a/courses/advanced-foundry/1-How-to-create-an-erc20-crypto-currency/5-erc20-deploy-script/+page.md +++ b/courses/advanced-foundry/1-How-to-create-an-erc20-crypto-currency/5-erc20-deploy-script/+page.md @@ -112,7 +112,6 @@ verify: ---- Now, by running `make anvil` (open a new terminal once your chain has started!) followed by `make deploy`... 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 775c23184..4fa8a3434 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 @@ -243,7 +243,6 @@ Can you write the rest of the tests? Please include tests for: ---- > ❗ **NOTE** > Your specific response will differ from mine, I encourage you to try using an AI tool like ChatGPT to generate a few tests of your own. I've included my AI response below, generated by GPT4o May 31, 2024. @@ -360,7 +359,6 @@ 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. 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 404521736..731221611 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 @@ -233,7 +233,6 @@ contract MoodNFTTest is Test { ---- With these adjustments, our tests should function identically to before. diff --git a/courses/advanced-foundry/2-how-to-create-an-NFT-collection/19-advanced-evm/+page.md b/courses/advanced-foundry/2-how-to-create-an-NFT-collection/19-advanced-evm/+page.md index 87e6921a8..606cdb23c 100644 --- a/courses/advanced-foundry/2-how-to-create-an-NFT-collection/19-advanced-evm/+page.md +++ b/courses/advanced-foundry/2-how-to-create-an-NFT-collection/19-advanced-evm/+page.md @@ -89,7 +89,6 @@ We can see this in Etherscan for any contract we've deployed. Here's an [**examp ---- The above may look like random numbers and letters to us, but to the `Ethereum Virtual Machine (EVM)`, this is effectively the alphabet it uses to perform computation. Every 2 bytes in the data above actually represents an op code. The website [**evm.codes**](https://www.evm.codes/) is an amazing resource for referencing these things. diff --git a/courses/advanced-foundry/2-how-to-create-an-NFT-collection/20-evm-encoding/+page.md b/courses/advanced-foundry/2-how-to-create-an-NFT-collection/20-evm-encoding/+page.md index f0da8751b..8a831fa4d 100644 --- a/courses/advanced-foundry/2-how-to-create-an-NFT-collection/20-evm-encoding/+page.md +++ b/courses/advanced-foundry/2-how-to-create-an-NFT-collection/20-evm-encoding/+page.md @@ -75,7 +75,6 @@ Originally we were referring to the human-readable ABI. ---- We can also accomplish our goals with the `bytecode` version directly. All you _really_ need to send a function call is the name of a function and the input types. 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 780dd47bd..0503ff802 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 @@ -250,7 +250,6 @@ 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`. @@ -291,7 +290,6 @@ contract CallFunctionWithoutContract { ---- By passing this contract the address of our `CallAnything.sol` deployment. We're able to use the functions it possesses to interact with `CallAnything.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 e55d0badd..37d6a6e1d 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 @@ -79,7 +79,6 @@ flipMoodNft: ---- Assuming our `.env` is ready to go, we should be able to run the following... diff --git a/courses/advanced-foundry/3-develop-defi-protocol/10-defi-deploy-script/+page.md b/courses/advanced-foundry/3-develop-defi-protocol/10-defi-deploy-script/+page.md index e1241adc8..ac1b11fde 100644 --- a/courses/advanced-foundry/3-develop-defi-protocol/10-defi-deploy-script/+page.md +++ b/courses/advanced-foundry/3-develop-defi-protocol/10-defi-deploy-script/+page.md @@ -193,7 +193,6 @@ contract MockV3Aggregator { ---- Once mocks are deployed, we can configure the anvilNetworkConfig with those deployed addresses, and return this struct. 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 6918a9340..66b9fe41d 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 @@ -237,7 +237,6 @@ contract DSCEngine is ReentrancyGuard { ---- Welcome back! I'm excited to keep going. So far our DSCEngine.sol has quite a bit of functionality already. We've the ability to mint DSC, we can deposit collateral, check account information and more. diff --git a/courses/advanced-foundry/3-develop-defi-protocol/13-defi-redeem-collateral/+page.md b/courses/advanced-foundry/3-develop-defi-protocol/13-defi-redeem-collateral/+page.md index 6afe7d4e9..29eab29bc 100644 --- a/courses/advanced-foundry/3-develop-defi-protocol/13-defi-redeem-collateral/+page.md +++ b/courses/advanced-foundry/3-develop-defi-protocol/13-defi-redeem-collateral/+page.md @@ -244,7 +244,6 @@ contract DSCEngine is ReentrancyGuard { ---- ### redeemCollateral diff --git a/courses/advanced-foundry/3-develop-defi-protocol/14-defi-liquidation-setup/+page.md b/courses/advanced-foundry/3-develop-defi-protocol/14-defi-liquidation-setup/+page.md index adeb2a9af..a0e0655e3 100644 --- a/courses/advanced-foundry/3-develop-defi-protocol/14-defi-liquidation-setup/+page.md +++ b/courses/advanced-foundry/3-develop-defi-protocol/14-defi-liquidation-setup/+page.md @@ -276,7 +276,6 @@ contract DSCEngine is ReentrancyGuard { ---- ### Liquidation diff --git a/courses/advanced-foundry/3-develop-defi-protocol/15-defi-liquidation-refactor/+page.md b/courses/advanced-foundry/3-develop-defi-protocol/15-defi-liquidation-refactor/+page.md index dcdcf6a7a..6c0335baf 100644 --- a/courses/advanced-foundry/3-develop-defi-protocol/15-defi-liquidation-refactor/+page.md +++ b/courses/advanced-foundry/3-develop-defi-protocol/15-defi-liquidation-refactor/+page.md @@ -310,7 +310,6 @@ contract DSCEngine is ReentrancyGuard { ---- ### Liquidation/Refactoring diff --git a/courses/advanced-foundry/3-develop-defi-protocol/17-defi-handler-fuzz-tests/+page.md b/courses/advanced-foundry/3-develop-defi-protocol/17-defi-handler-fuzz-tests/+page.md index 8ad98cc29..aa1cbcd4f 100644 --- a/courses/advanced-foundry/3-develop-defi-protocol/17-defi-handler-fuzz-tests/+page.md +++ b/courses/advanced-foundry/3-develop-defi-protocol/17-defi-handler-fuzz-tests/+page.md @@ -112,7 +112,6 @@ function getHealthFactor(address user) external view returns (uint256) { ---- If you managed to improve your coverage, even if not to this extent, you should be proud of getting this far. This code base is hard to write tests for and a lot of it comes with experience, practice and familiarity. diff --git a/courses/advanced-foundry/3-develop-defi-protocol/19-defi-handler-deposit-collateral/+page.md b/courses/advanced-foundry/3-develop-defi-protocol/19-defi-handler-deposit-collateral/+page.md index 38ad36422..ae8d09766 100644 --- a/courses/advanced-foundry/3-develop-defi-protocol/19-defi-handler-deposit-collateral/+page.md +++ b/courses/advanced-foundry/3-develop-defi-protocol/19-defi-handler-deposit-collateral/+page.md @@ -110,7 +110,6 @@ contract InvariantsTest is StdInvariant Test { ---- We can see this fails for the expected reasons below. diff --git a/courses/advanced-foundry/3-develop-defi-protocol/22-defi-fuzz-debugging/+page.md b/courses/advanced-foundry/3-develop-defi-protocol/22-defi-fuzz-debugging/+page.md index e62a884be..f6d4366de 100644 --- a/courses/advanced-foundry/3-develop-defi-protocol/22-defi-fuzz-debugging/+page.md +++ b/courses/advanced-foundry/3-develop-defi-protocol/22-defi-fuzz-debugging/+page.md @@ -177,7 +177,6 @@ Once more with feeling. ---- ### Wrap Up 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 c4f5657d5..4c867dfcb 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 @@ -509,4 +509,3 @@ contract DSCEngine is ReentrancyGuard { ---- 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 cad01b17f..bd5de4299 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 @@ -491,4 +491,3 @@ contract DSCEngine is ReentrancyGuard { ---- 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 9374c9c5c..415420687 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 @@ -358,4 +358,3 @@ contract DSCEngine is ReentrancyGuard { ---- 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 8412945a9..a634570e4 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 @@ -291,4 +291,3 @@ contract DSCEngine is ReentrancyGuard { ---- 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 7a738b4e1..ee067e693 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 @@ -145,7 +145,6 @@ In step 2 we will call the `getUserOpHash` on the `entryPoint` and pass in `user ---- Now that we have this imported, we need to be sure to add the following line to in our contract, just above the `run` function. @@ -403,7 +402,6 @@ Just for the purpose of testing or working on a local chain, we are going to hav ---- 2. Why is `using MessageHashUtils for bytes32` necessary? What does it do? @@ -417,7 +415,6 @@ It allows the function to call `toEthSignedMessageHash` directly on a bytes32 va ---- 3. What is the purpose of the generateSignedUserOperation function in the SendPackedUserOp script? @@ -431,7 +428,6 @@ It generates a signed `PackedUserOperation` by creating an unsigned user operati ---- 4. What is included in the `userOpHash` to prevent cross-chain replay attacks? @@ -445,4 +441,3 @@ It generates a signed `PackedUserOperation` by creating an unsigned user operati ---- diff --git a/courses/advanced-foundry/6-account-abstraction/13-test-validate-user-ops/+page.md b/courses/advanced-foundry/6-account-abstraction/13-test-validate-user-ops/+page.md index 2ffd7eec2..fb677c48f 100644 --- a/courses/advanced-foundry/6-account-abstraction/13-test-validate-user-ops/+page.md +++ b/courses/advanced-foundry/6-account-abstraction/13-test-validate-user-ops/+page.md @@ -82,7 +82,6 @@ Now we know that we are getting the correct signatures and that our validation i 1. What is the main objective of the testValidationOfUserOps? ----
**Click for Answers** @@ -91,10 +90,8 @@ Now we know that we are getting the correct signatures and that our validation i
---- 2. Why do we set missingAccountFunds to 1e18? ----
**Click for Answers** @@ -103,10 +100,8 @@ Now we know that we are getting the correct signatures and that our validation i
---- 3. What does the assertEq(validationData, 0) statement check for? ----
**Click for Answers** @@ -115,5 +110,4 @@ Now we know that we are getting the correct signatures and that our validation i
---- 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 c43f71b60..6b262708b 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 @@ -154,7 +154,6 @@ Before we move on, take a look at the review questions. Move on to the next less ---- 2. What modification was made to the vm.getNonce function in the generateSignedUserOperation function? @@ -168,4 +167,3 @@ It was modified to subtract 1 from the nonce value. This change ensures that the ---- diff --git a/courses/advanced-foundry/6-account-abstraction/18-zksync-setup/+page.md b/courses/advanced-foundry/6-account-abstraction/18-zksync-setup/+page.md index 57e841c2c..c80fbb17c 100644 --- a/courses/advanced-foundry/6-account-abstraction/18-zksync-setup/+page.md +++ b/courses/advanced-foundry/6-account-abstraction/18-zksync-setup/+page.md @@ -121,7 +121,6 @@ Now we have our **ZK Minimal Account** set up. Things are starting to get exciti ---- 2. How are EOAs different in zkSync compared to Ethereum? @@ -135,7 +134,6 @@ In zkSync, EOAs are smart contracts. ---- 3. What are the 4 functions of the IAccount interface? @@ -152,4 +150,3 @@ In zkSync, EOAs are smart contracts. ---- diff --git a/courses/advanced-foundry/6-account-abstraction/19-iaccount/+page.md b/courses/advanced-foundry/6-account-abstraction/19-iaccount/+page.md index d0ae27b89..3c40fbe33 100644 --- a/courses/advanced-foundry/6-account-abstraction/19-iaccount/+page.md +++ b/courses/advanced-foundry/6-account-abstraction/19-iaccount/+page.md @@ -79,7 +79,6 @@ struct Transaction { ---- When we send an Account Abstraction transaction through zkSync, the `Transaction` struct will essentially be populated. This will be our focus for now. The following parameters we won't worry about, for now. But here is the gist of what they do. @@ -164,7 +163,6 @@ This lesson gave us a gist of what our IAccount interface will do. Take a moment ---- 2. What is the role of the executeTransactionFromOutside function? @@ -178,7 +176,6 @@ This lesson gave us a gist of what our IAccount interface will do. Take a moment ---- 3. When is the prepareForPaymaster function called? @@ -192,4 +189,3 @@ This lesson gave us a gist of what our IAccount interface will do. Take a moment ---- diff --git a/courses/advanced-foundry/6-account-abstraction/20-system-contracts/+page.md b/courses/advanced-foundry/6-account-abstraction/20-system-contracts/+page.md index de27fa601..fc5b2f12e 100644 --- a/courses/advanced-foundry/6-account-abstraction/20-system-contracts/+page.md +++ b/courses/advanced-foundry/6-account-abstraction/20-system-contracts/+page.md @@ -70,7 +70,6 @@ As always, Let's do some review. Move on to the next lesson when you are ready. --- 1. What are the two phases of sending an account abstraction transaction in zkSync? ----
**Click for Answers** @@ -79,11 +78,9 @@ As always, Let's do some review. Move on to the next lesson when you are ready.
---- 2. What is the role of the ContractDeployer system contract in zkSync? ----
**Click for Answers** @@ -95,11 +92,9 @@ As always, Let's do some review. Move on to the next lesson when you are ready.
---- 3. How does deploying a smart contract on zkSync differ from deploying on Ethereum? ----
**Click for Answers** @@ -108,7 +103,6 @@ As always, Let's do some review. Move on to the next lesson when you are ready.
---- diff --git a/courses/advanced-foundry/6-account-abstraction/21-type-113-lifecycle/+page.md b/courses/advanced-foundry/6-account-abstraction/21-type-113-lifecycle/+page.md index b3524356f..0986cad54 100644 --- a/courses/advanced-foundry/6-account-abstraction/21-type-113-lifecycle/+page.md +++ b/courses/advanced-foundry/6-account-abstraction/21-type-113-lifecycle/+page.md @@ -98,7 +98,6 @@ This is essentially what will happen in our transaction lifecycle through the va ---- 2. Who is the msg.sender when validateTransaction is called in zkSync? @@ -112,7 +111,6 @@ This is essentially what will happen in our transaction lifecycle through the va ---- 3. What happens if validateTransaction does not update the nonce? @@ -126,7 +124,6 @@ This is essentially what will happen in our transaction lifecycle through the va ---- 4. What is the role of the bootloader in zkSync? @@ -140,4 +137,3 @@ This is essentially what will happen in our transaction lifecycle through the va ---- 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 d2f8ba8f1..6d3576d4a 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 @@ -244,7 +244,6 @@ It makes a system call to the NonceHolder contract to conditionally increment th ---- 2. Which function in NonceHolder.sol is called to increment the nonce? @@ -258,7 +257,6 @@ It makes a system call to the NonceHolder contract to conditionally increment th ---- 3. What library did we import to help with system contract calls? @@ -272,4 +270,3 @@ It makes a system call to the NonceHolder contract to conditionally increment th ---- diff --git a/courses/advanced-foundry/6-account-abstraction/24-validate-tx/+page.md b/courses/advanced-foundry/6-account-abstraction/24-validate-tx/+page.md index b77bc4ee0..60e39d928 100644 --- a/courses/advanced-foundry/6-account-abstraction/24-validate-tx/+page.md +++ b/courses/advanced-foundry/6-account-abstraction/24-validate-tx/+page.md @@ -105,7 +105,6 @@ function encodeHash(Transaction memory _transaction) internal view returns (byte ---- Then we will need to validate the signature on the `Transaction` struct (similar to `PackedUserOperation` from our Ethereum contract.). We will need a few imports. @@ -261,7 +260,6 @@ totalRequiredBalance() ---- 2. What is the purpose of the requireFromBootLoader modifier? @@ -275,7 +273,6 @@ totalRequiredBalance() ---- 3. What is the purpose of the encodeHash function from MemoryTransactionHelper? @@ -289,4 +286,3 @@ totalRequiredBalance() ---- 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 83e714796..32e888e0d 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 @@ -172,7 +172,6 @@ To ensure that the callee is correctly identified as an address or contract bein ---- 2. What does the assembly code in the executeTransaction function do? @@ -186,7 +185,6 @@ To ensure that the callee is correctly identified as an address or contract bein ---- 3. What is the purpose of the requireFromBootLoaderOrOwner modifier? @@ -200,4 +198,3 @@ To ensure that the callee is correctly identified as an address or contract bein ---- diff --git a/courses/advanced-foundry/6-account-abstraction/3-eth-setup/+page.md b/courses/advanced-foundry/6-account-abstraction/3-eth-setup/+page.md index 716add1c6..c5c403d26 100644 --- a/courses/advanced-foundry/6-account-abstraction/3-eth-setup/+page.md +++ b/courses/advanced-foundry/6-account-abstraction/3-eth-setup/+page.md @@ -84,7 +84,6 @@ Next, we need to know what to put in our contract. Well, we know that we are wor ---- From this information, we know that we will need some specific functions to make this happen. [Let's head over to the EIP](https://eips.ethereum.org/EIPS/eip-4337) and see what we need. diff --git a/courses/advanced-foundry/6-account-abstraction/7-execute/+page.md b/courses/advanced-foundry/6-account-abstraction/7-execute/+page.md index 7372553d2..183baf692 100644 --- a/courses/advanced-foundry/6-account-abstraction/7-execute/+page.md +++ b/courses/advanced-foundry/6-account-abstraction/7-execute/+page.md @@ -93,7 +93,6 @@ It allows the minimal account contract to interact with other dapps by sending t ---- 2. Why do we need the `requireFromEntryPointOrOwner` modifier? @@ -107,7 +106,6 @@ It ensures that only the EntryPoint contract or the owner of the minimal account ---- 3. How does the `receive` function enable our contract to accept payments? @@ -121,6 +119,5 @@ This is a special function in Solidity that allows the contract to accept plain ---- When you are ready, move on to the next lesson. diff --git a/courses/advanced-foundry/6-account-abstraction/9-owner-execute-test/+page.md b/courses/advanced-foundry/6-account-abstraction/9-owner-execute-test/+page.md index 4239dc13d..9975b045f 100644 --- a/courses/advanced-foundry/6-account-abstraction/9-owner-execute-test/+page.md +++ b/courses/advanced-foundry/6-account-abstraction/9-owner-execute-test/+page.md @@ -302,7 +302,6 @@ It requires the msg.sender to be either the owner or the entry point, and it tak ---- 2. What is the expected behavior of the testNonOwnerCannotExecuteCommands test? @@ -316,4 +315,3 @@ The test should revert if a non-owner (a random user) attempts to execute comman ---- diff --git a/courses/advanced-foundry/7-daos/6-tests/+page.md b/courses/advanced-foundry/7-daos/6-tests/+page.md index d55778241..81977b8ca 100644 --- a/courses/advanced-foundry/7-daos/6-tests/+page.md +++ b/courses/advanced-foundry/7-daos/6-tests/+page.md @@ -361,7 +361,6 @@ function testGovernanceUpdatesBox() public { ---- Woo! This is exciting, we're ready to run the test. diff --git a/courses/formal-verification/1-horse-store/42-solidity-opcodes-from-bytecode/+page.md b/courses/formal-verification/1-horse-store/42-solidity-opcodes-from-bytecode/+page.md index 704335322..163ebaaad 100644 --- a/courses/formal-verification/1-horse-store/42-solidity-opcodes-from-bytecode/+page.md +++ b/courses/formal-verification/1-horse-store/42-solidity-opcodes-from-bytecode/+page.md @@ -154,6 +154,5 @@ PUSH23 0x9a77032ceb92497a64736f6c63430008140033 ``` ---- Paste this into our `solc-breakdowns.c++` files and we'll get started walking through this contract's execution in the next lesson. diff --git a/courses/formal-verification/1-horse-store/43-soliditys-free-memory-pointer/+page.md b/courses/formal-verification/1-horse-store/43-soliditys-free-memory-pointer/+page.md index 58456dc02..1a63041ae 100644 --- a/courses/formal-verification/1-horse-store/43-soliditys-free-memory-pointer/+page.md +++ b/courses/formal-verification/1-horse-store/43-soliditys-free-memory-pointer/+page.md @@ -146,7 +146,6 @@ I'll update this reference as we go through each section of bytecode: ---- Let's remind ourselves of the 3 sections found in a smart contract's bytecode and start from the top! 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 10776a98f..c00937284 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 @@ -141,7 +141,6 @@ _Follow along with this video:_ ---- ### Non-Payable Constructor Check 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 75657c7ba..282f6b0b5 100644 --- a/courses/formal-verification/1-horse-store/45-CODECOPY/+page.md +++ b/courses/formal-verification/1-horse-store/45-CODECOPY/+page.md @@ -147,7 +147,6 @@ Let's continue from our `JUMPDEST`. Our contructor wasn't sent any value and we ---- ``` JUMPDEST // [msg.value] diff --git a/courses/formal-verification/1-horse-store/47-runtime-code-introduction/+page.md b/courses/formal-verification/1-horse-store/47-runtime-code-introduction/+page.md index d901a6a6f..1b412ede8 100644 --- a/courses/formal-verification/1-horse-store/47-runtime-code-introduction/+page.md +++ b/courses/formal-verification/1-horse-store/47-runtime-code-introduction/+page.md @@ -148,7 +148,6 @@ With `contract creation` understood, we move onto the runtime section of our op ---- This section of code is the `runtime code` this is what is copied to the blockchain and represents the entry point of all calls sent to its address. diff --git a/courses/formal-verification/1-horse-store/48-function-selector-size-check/+page.md b/courses/formal-verification/1-horse-store/48-function-selector-size-check/+page.md index a28e45899..a20be7a1e 100644 --- a/courses/formal-verification/1-horse-store/48-function-selector-size-check/+page.md +++ b/courses/formal-verification/1-horse-store/48-function-selector-size-check/+page.md @@ -151,7 +151,6 @@ Ok! We've reach a section that may finally be new to us. Not sure what's going t ---- ```js JUMPDEST // [msg.value] 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 59cb08893..3664773ee 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 @@ -151,7 +151,6 @@ The next chunk of op codes we come across is going to represent Solidity's `func ``` ---- ```js PUSH0 0x00 // [0x00] diff --git a/courses/formal-verification/1-horse-store/50-setting-up-jumpdest-program-counters/+page.md b/courses/formal-verification/1-horse-store/50-setting-up-jumpdest-program-counters/+page.md index 4e08dd2a8..fe71bad09 100644 --- a/courses/formal-verification/1-horse-store/50-setting-up-jumpdest-program-counters/+page.md +++ b/courses/formal-verification/1-horse-store/50-setting-up-jumpdest-program-counters/+page.md @@ -154,7 +154,6 @@ Alright, let's keep going! ---- Let's see if we can determine which JUMPDEST we're working with first, based on what it does. diff --git a/courses/formal-verification/1-horse-store/51-checking-if-call-data-is-big-enough-to-contain-a-uint256/+page.md b/courses/formal-verification/1-horse-store/51-checking-if-call-data-is-big-enough-to-contain-a-uint256/+page.md index 325bf8180..b826d77b2 100644 --- a/courses/formal-verification/1-horse-store/51-checking-if-call-data-is-big-enough-to-contain-a-uint256/+page.md +++ b/courses/formal-verification/1-horse-store/51-checking-if-call-data-is-big-enough-to-contain-a-uint256/+page.md @@ -156,7 +156,6 @@ _Follow along with this video:_ ---- Ok, so what happens in our code when we reach jump dest 2? diff --git a/courses/formal-verification/1-horse-store/52-sstoreing-our-value/+page.md b/courses/formal-verification/1-horse-store/52-sstoreing-our-value/+page.md index 4b8f0b8d2..4c89e1676 100644 --- a/courses/formal-verification/1-horse-store/52-sstoreing-our-value/+page.md +++ b/courses/formal-verification/1-horse-store/52-sstoreing-our-value/+page.md @@ -156,7 +156,6 @@ _Follow along with this video:_ ---- We're really getting into the flow of things now, let's keep our momentum and look at the next chunk at jump dest 3. @@ -356,7 +355,6 @@ Look at our updated op code list to see where we've jumped to now, we're about t ---- From jump dest 4, we're able to finally save our value to storage, but we've only been able to here if: 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 43b02a9b8..c6fe5d31d 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 @@ -161,7 +161,6 @@ _Follow along with this video:_ ---- Take a moment above to appreciate how much low level knowledge you've gleaned from just this one small Solidity smart contract! You should be very proud of yourself! 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 548b26dc2..a4ba3fd59 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 @@ -159,7 +159,6 @@ _Follow along with this video:_ ``` ---- So, in order to walk through the execution of a `readNumberOfHorses` call, we'll need to go back to our `function dispatcher`: @@ -439,7 +438,6 @@ 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/64-feedHorse-macro/+page.md b/courses/formal-verification/1-horse-store/64-feedHorse-macro/+page.md index 1b082b279..8d347cbd8 100644 --- a/courses/formal-verification/1-horse-store/64-feedHorse-macro/+page.md +++ b/courses/formal-verification/1-horse-store/64-feedHorse-macro/+page.md @@ -43,7 +43,6 @@ I'll keep a running reminder of our current total contract state at the top of e ---- ### feedHorse Macro diff --git a/courses/formal-verification/1-horse-store/65-mappings-and-arrays-in-evm-huff/+page.md b/courses/formal-verification/1-horse-store/65-mappings-and-arrays-in-evm-huff/+page.md index eac25fbc4..f2c654a6c 100644 --- a/courses/formal-verification/1-horse-store/65-mappings-and-arrays-in-evm-huff/+page.md +++ b/courses/formal-verification/1-horse-store/65-mappings-and-arrays-in-evm-huff/+page.md @@ -48,7 +48,6 @@ I'll keep a running reminder of our current total contract state at the top of e ---- Now's a good time to go back and reference the Solidity Documentation. We should be reminded that mappings are handled using a very specific algorithm. 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 f6de0e895..86f741497 100644 --- a/courses/formal-verification/1-horse-store/66-horseidtofedtimestamp/+page.md +++ b/courses/formal-verification/1-horse-store/66-horseidtofedtimestamp/+page.md @@ -52,7 +52,6 @@ I'll keep a running reminder of our current total contract state at the top of e ---- ### horseIdToFedTimeStamp 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 e57d3f99e..bced5c9e1 100644 --- a/courses/formal-verification/1-horse-store/67-ishappyhorse/+page.md +++ b/courses/formal-verification/1-horse-store/67-ishappyhorse/+page.md @@ -61,7 +61,6 @@ I'll keep a running reminder of our current total contract state at the top of e ---- Next we'll tackle the `IS_HAPPY_HORSE()` macro. This macro is going to be a little more complicated, and if we remind ourselves of this function is Solidity it will be clear why. diff --git a/courses/formal-verification/1-horse-store/68-a-quick-function-then-huffmate/+page.md b/courses/formal-verification/1-horse-store/68-a-quick-function-then-huffmate/+page.md index 48ab2cb97..90960c4b8 100644 --- a/courses/formal-verification/1-horse-store/68-a-quick-function-then-huffmate/+page.md +++ b/courses/formal-verification/1-horse-store/68-a-quick-function-then-huffmate/+page.md @@ -83,7 +83,6 @@ I'll keep a running reminder of our current total contract state at the top of e ---- We'll start this lesson by knocking out the getting macro for our `HORSE_HAPPY_IF_FED_WITHIN_CONST` constant. All we need to do is call that location in storage, store the data at that location in memory, return that data from memory. Very simple. @@ -830,7 +829,6 @@ Assure your contract closely resembles below to avoid missing anything we've add ---- Encourage you not to worry about most of the details we've just inherited, it represents a bunch of ERC721 "stuff" that is important to the standard, but not a focus of ours. diff --git a/courses/formal-verification/1-horse-store/69-huff-constructor/+page.md b/courses/formal-verification/1-horse-store/69-huff-constructor/+page.md index cce5bf95c..b6e9668af 100644 --- a/courses/formal-verification/1-horse-store/69-huff-constructor/+page.md +++ b/courses/formal-verification/1-horse-store/69-huff-constructor/+page.md @@ -749,7 +749,6 @@ I'll keep a running reminder of our current total contract state at the top of e ---- Alright! We're nearly done, the last bit outstanding is our contract's constructor. diff --git a/courses/formal-verification/3-gasbad/12-init-state-and-axions/+page.md b/courses/formal-verification/3-gasbad/12-init-state-and-axions/+page.md index 30738135d..5612f426e 100644 --- a/courses/formal-verification/3-gasbad/12-init-state-and-axions/+page.md +++ b/courses/formal-verification/3-gasbad/12-init-state-and-axions/+page.md @@ -98,7 +98,6 @@ invariant anytime_mapping_updated_emit_event() ---- ### Wrap Up 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 039f95466..548bb1801 100644 --- a/courses/formal-verification/3-gasbad/18-summary-implementations/+page.md +++ b/courses/formal-verification/3-gasbad/18-summary-implementations/+page.md @@ -138,7 +138,6 @@ invariant anytime_mapping_updated_emit_event() ---- ::image{src='/formal-verification-3/18-summary-implementations/summary-implementations3.png' style='width: 100%; height: auto;'} 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 720f0f0f0..b0559c1e6 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 @@ -171,7 +171,6 @@ rule calling_any_function_should_result_in_each_contract_having_the_same_state(m ---- ::image{src='/formal-verification-3/25-finishing-the-rule/finishing-the-rule2.png' style='width: 100%; height: auto;'} 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 54a94609c..dc3003324 100644 --- a/courses/security/3-first-audit/17-recommended-mitigation/+page.md +++ b/courses/security/3-first-audit/17-recommended-mitigation/+page.md @@ -53,7 +53,6 @@ And get an output of: ---- ### Recommended Mitigation 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 214d340bb..29cc27d31 100644 --- a/courses/security/3-first-audit/18-finding-writeup/+page.md +++ b/courses/security/3-first-audit/18-finding-writeup/+page.md @@ -51,7 +51,6 @@ And get an output of: ---- ### Recap 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 cc109497c..42b338e8d 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 @@ -29,7 +29,6 @@ emit SetNewPassword(); ---- ### Proof of Concept/Proof of Code 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 1feac3584..95f454108 100644 --- a/courses/security/3-first-audit/25-assesing-highs/+page.md +++ b/courses/security/3-first-audit/25-assesing-highs/+page.md @@ -40,7 +40,6 @@ 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). @@ -88,7 +87,6 @@ Applying our assessment to our finding title should look like this: ---- Considering our second finding, we can tell that anyone being able to set the password at any time is a severe disruption of protocol functionality. A clear `High` `Impact`. 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 312de6b6c..c3691f344 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 @@ -28,7 +28,6 @@ _Follow along with this video:_ ---- Just like before, let's ask ourselves things like 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 aea8cd85b..ff363203c 100644 --- a/courses/security/4-puppy-raffle/13-dos-poc/+page.md +++ b/courses/security/4-puppy-raffle/13-dos-poc/+page.md @@ -123,7 +123,6 @@ If we rerun our test we can see.. Our test passes! The second 100 players are pa ---- ### Wrap Up 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 9a3b017a7..a40cb2ca6 100644 --- a/courses/security/4-puppy-raffle/14-dos-reporting/+page.md +++ b/courses/security/4-puppy-raffle/14-dos-reporting/+page.md @@ -225,6 +225,5 @@ function testDenialOfService() public { ---- Things look great! Lets finally have a look at what mitigations we can recommend for this vulnerability, in the next lesson. 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 88f335f52..98c498a52 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 @@ -105,7 +105,6 @@ contract DAO is DAOInterface, Token, TokenCreation { ---- Hopefully we can spot the problem above. The DAO was making external calls before updating its state! 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 aa0131e03..e9f8a918f 100644 --- a/courses/security/4-puppy-raffle/40-slither-walkthrough/+page.md +++ b/courses/security/4-puppy-raffle/40-slither-walkthrough/+page.md @@ -136,7 +136,6 @@ payable(msg.sender).sendValue(entranceFee); - `_tokenOwners.set(tokenId,to) (lib/openzeppelin-contracts/contracts/token/ERC721/ERC721.sol#399)` ---- You can remove these warning from your `Slither` report by navigating to the respective lines for each call in the library and adding: @@ -327,7 +326,6 @@ We called this one out as an informational/gas finding as well. You can disable - `(success) = feeAddress.call{value: feesToWithdraw}() (src/PuppyRaffle.sol#167)` ---- Much like Assembly, `Slither` doesn't like low level calls. We'll be ignoring these for now, but you can remove them from your warnings by applying this line above the described calls. 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 76ee0240e..fc19101c7 100644 --- a/courses/security/4-puppy-raffle/5-tooling-aderyn/+page.md +++ b/courses/security/4-puppy-raffle/5-tooling-aderyn/+page.md @@ -257,7 +257,6 @@ Index event fields make the field more quickly accessible to off-chain tools tha ---- _**WOW!**_ We have a report of vulnerabilities already gorgeously formatted and ready to be added to our audit report. diff --git a/courses/security/4-puppy-raffle/59-reporting-integer-overflow/+page.md b/courses/security/4-puppy-raffle/59-reporting-integer-overflow/+page.md index 53d945e63..046f069e9 100644 --- a/courses/security/4-puppy-raffle/59-reporting-integer-overflow/+page.md +++ b/courses/security/4-puppy-raffle/59-reporting-integer-overflow/+page.md @@ -112,7 +112,6 @@ function testTotalFeesOverflow() public playersEntered { ---- I trust you attempted the PoC yourself - time to add our recommended mitigation 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 04caada2b..773628bf1 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 @@ -777,7 +777,6 @@ View the report in the dropdown below, please know it's quiet long. ---- The final step, once the template has been filled out is to run our CLI command diff --git a/courses/security/4-puppy-raffle/7-recon-reading-docs/+page.md b/courses/security/4-puppy-raffle/7-recon-reading-docs/+page.md index bc45576a8..eba552379 100644 --- a/courses/security/4-puppy-raffle/7-recon-reading-docs/+page.md +++ b/courses/security/4-puppy-raffle/7-recon-reading-docs/+page.md @@ -32,7 +32,6 @@ This project is to enter a raffle to win a cute dog NFT. The protocol should do ---- Above we see a pretty clear description of the protocol and it's intended functionality. What I like to do is open a `notes.md` file in my project and summarize things in my own words. diff --git a/courses/security/5-tswap/31-pool-factory/+page.md b/courses/security/5-tswap/31-pool-factory/+page.md index 46d3d0255..e9583a4b7 100644 --- a/courses/security/5-tswap/31-pool-factory/+page.md +++ b/courses/security/5-tswap/31-pool-factory/+page.md @@ -92,7 +92,6 @@ contract PoolFactory { ---- ### Imports and Errors diff --git a/courses/security/5-tswap/34-add-liquidity/+page.md b/courses/security/5-tswap/34-add-liquidity/+page.md index 00316601f..5ae48b9c0 100644 --- a/courses/security/5-tswap/34-add-liquidity/+page.md +++ b/courses/security/5-tswap/34-add-liquidity/+page.md @@ -65,7 +65,6 @@ function deposit( ---- Continuing down from `uint63 deadline`, we see a modifier we assessed earlier being applied - `revertIfZero(wethToDeposit)`. diff --git a/courses/security/5-tswap/35-remove-liquidity/+page.md b/courses/security/5-tswap/35-remove-liquidity/+page.md index 219d43478..89f3c2bd2 100644 --- a/courses/security/5-tswap/35-remove-liquidity/+page.md +++ b/courses/security/5-tswap/35-remove-liquidity/+page.md @@ -52,7 +52,6 @@ function withdraw( ---- So, we know that liquidity providers are provided LP tokens in exchange for the liquidity they add to a pool - at a rate proportional to the percentage of the pool they've contributed. @@ -136,7 +135,6 @@ function getOutputAmountBasedOnInput( ---- I want to draw your attention to these lines - which of course we would flag for `magic numbers`: @@ -181,7 +179,6 @@ function getInputAmountBasedOnOutput( ---- Alright, there's only only line, a return calculation, but something should stick out to you here. Rather than using 1,000 in the fee calculation, the protocol has used 10,000! diff --git a/courses/security/5-tswap/36-exact-input/+page.md b/courses/security/5-tswap/36-exact-input/+page.md index 88a306442..e74999a5a 100644 --- a/courses/security/5-tswap/36-exact-input/+page.md +++ b/courses/security/5-tswap/36-exact-input/+page.md @@ -55,7 +55,6 @@ function swapExactInput( ---- Let's better understand the parameters required by `swapExactInput`. diff --git a/courses/security/5-tswap/37-exact-output/+page.md b/courses/security/5-tswap/37-exact-output/+page.md index 526a5f4a4..51af5f36f 100644 --- a/courses/security/5-tswap/37-exact-output/+page.md +++ b/courses/security/5-tswap/37-exact-output/+page.md @@ -34,7 +34,6 @@ function swapExactOutput( ---- One thing that may stand out to us right away is that there doesn't seem to be any check on maximum input (and there's one fewer parameter as well), similar to how our `swapExactInput` function has the `minOutputAmount`, this difference definitely has our senses tingling. diff --git a/courses/security/5-tswap/38-sell-pool-tokens/+page.md b/courses/security/5-tswap/38-sell-pool-tokens/+page.md index 642e0cdfe..83e5b74cf 100644 --- a/courses/security/5-tswap/38-sell-pool-tokens/+page.md +++ b/courses/security/5-tswap/38-sell-pool-tokens/+page.md @@ -22,7 +22,6 @@ function sellPoolTokens(uint256 poolTokenAmount) external returns (uint256 wethA ---- This function just serves as a simplified wrapper for users to call `swapExactOutput` through. With any function call passing parameters, we should verify that what's being passed is correct as well as it's order. These are easy things for developers to overlook. diff --git a/courses/security/5-tswap/40-phase-4-reporting/+page.md b/courses/security/5-tswap/40-phase-4-reporting/+page.md index 794ced6bb..66381d6de 100644 --- a/courses/security/5-tswap/40-phase-4-reporting/+page.md +++ b/courses/security/5-tswap/40-phase-4-reporting/+page.md @@ -23,7 +23,6 @@ Reference our [**finding_layout.md**](https://github.com/Cyfrin/security-and-aud ----
[I-2] `PoolFactory::constructor` Lacking zero address check @@ -41,7 +40,6 @@ constructor(address wethToken) {
----
[I-3] `PoolFactory::createPool should use .symbol() instead of .name() @@ -55,7 +53,6 @@ constructor(address wethToken) {
----
[I-4] `TSwapPool::constructor` Lacking zero address check - wethToken & poolToken @@ -81,7 +78,6 @@ constructor(
----
[I-5] `TSwapPool` events should be indexed @@ -95,7 +91,6 @@ constructor(
---- ### Wrap Up 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 b30966a68..4e5c556c9 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 @@ -121,7 +121,6 @@ function deposit( ---- ### Wrap Up diff --git a/courses/security/5-tswap/42-reporting-continued/+page.md b/courses/security/5-tswap/42-reporting-continued/+page.md index 2954c2f7b..02d63fc8e 100644 --- a/courses/security/5-tswap/42-reporting-continued/+page.md +++ b/courses/security/5-tswap/42-reporting-continued/+page.md @@ -51,7 +51,6 @@ When it comes to auditing smart contracts, there are a lot of nitty-gritty detai ---- > **Note:** We omitted a PoC in our write up above. This vulnerability is pretty self-evident, but if you wanted to write one as a challenge, I encourage you to try! @@ -106,7 +105,6 @@ We identified a magic number resulting in an inaccurate fee caculation! This one ---- Attempting to write the `PoC` for the above is really important. Writing lots of `PoCs` is how you'll get better at them and `PoCs` are how you _prove_ there's an issue, often they help you _test_ if there's an issue. @@ -163,7 +161,6 @@ This will be our second low, compare your write up to mine below: ---- ### Wrap Up 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 2609f0a03..2eb9b9fd5 100644 --- a/courses/security/5-tswap/43-no-slippage-protection/+page.md +++ b/courses/security/5-tswap/43-no-slippage-protection/+page.md @@ -78,7 +78,6 @@ Let's write up our second `high severity` finding! Compare your write up to mine ---- ### Wrap Up 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 9df7f7e5e..81c03bc67 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 @@ -62,7 +62,6 @@ Additionally, it might be wise to add a deadline to the function, as there is cu ---- ### Wrap Up 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 d37e54cde..112ef9a2d 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 @@ -67,7 +67,6 @@ function _swap(IERC20 inputToken, uint256 inputAmount, IERC20 outputToken, uint2 ---- Alright, we can begin by giving the test a unique name. It looks like the first half of this function is handling deposits to add liquidity to the pool, we can keep that in. @@ -271,7 +270,6 @@ Place the following into `TSwapPool.t.sol`. ---- ### Wrap Up 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 70de9dafc..e2db5048c 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 @@ -393,7 +393,6 @@ I've included a copy of my completed template here for reference if you get stuc ---- Once your report template is filled out, we just have to run `pandoc` on it! 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 d52384c3f..386a0381c 100644 --- a/courses/security/6-thunder-loan/12-exploit-centralization/+page.md +++ b/courses/security/6-thunder-loan/12-exploit-centralization/+page.md @@ -285,7 +285,6 @@ Consider removing empty blocks. ---- The first vulnerability identified is `## L-1: Centralization Risk for trusted owners`. diff --git a/courses/security/6-thunder-loan/14-static-analysis-continued/+page.md b/courses/security/6-thunder-loan/14-static-analysis-continued/+page.md index 11c16944e..aa3fa79f6 100644 --- a/courses/security/6-thunder-loan/14-static-analysis-continued/+page.md +++ b/courses/security/6-thunder-loan/14-static-analysis-continued/+page.md @@ -282,7 +282,6 @@ Consider removing empty blocks. ---- The remainder of detections by `Aderyn` are going to qualify as gas/informational findings. As such we'll likely just copy these outputs into our audit report - this is a huge time saving benefit of `Aderyn`. 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 313b82e3f..cde58d7f9 100644 --- a/courses/security/6-thunder-loan/19-oracle-upgradeable/+page.md +++ b/courses/security/6-thunder-loan/19-oracle-upgradeable/+page.md @@ -48,7 +48,6 @@ contract OracleUpgradeable is Initializable { ---- Starting from the top, we can verify that our 3 imports `ITSwapPool`, `IPoolFactory` and `Initializable` are being utilized, and they are. 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 f5d621700..7544382d2 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 @@ -35,7 +35,6 @@ contract FailureToInitialize is Initializable { ---- The example here is very simple, but it should illustrate the potential impact of failing to initialize. Go ahead and compile and deploy `FailureToInitialize.sol` 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 d4b19e737..ac93115ef 100644 --- a/courses/security/6-thunder-loan/23-oracleupgradeable-continued/+page.md +++ b/courses/security/6-thunder-loan/23-oracleupgradeable-continued/+page.md @@ -46,7 +46,6 @@ contract OracleUpgradeable is Initializable { ---- ```js function getPriceInWeth(address token) public view returns (uint256) { diff --git a/courses/security/6-thunder-loan/24-assettoken/+page.md b/courses/security/6-thunder-loan/24-assettoken/+page.md index a47c5bd27..e61119200 100644 --- a/courses/security/6-thunder-loan/24-assettoken/+page.md +++ b/courses/security/6-thunder-loan/24-assettoken/+page.md @@ -124,7 +124,6 @@ contract AssetToken is ERC20 { ---- We should recall from the README: 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 703cb8cd7..99ce5645b 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 @@ -307,7 +307,6 @@ contract ThunderLoan is Initializable, OwnableUpgradeable, UUPSUpgradeable, Orac ---- > **Remember:** The intent here is a first pass, we're not going to try to go too deep right away. Often it's important to prime your brain with content before getting deep into review. 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 bb35a88bb..40d9f8026 100644 --- a/courses/security/6-thunder-loan/27-thunderloan-functions/+page.md +++ b/courses/security/6-thunder-loan/27-thunderloan-functions/+page.md @@ -305,7 +305,6 @@ contract ThunderLoan is Initializable, OwnableUpgradeable, UUPSUpgradeable, Orac ---- Continuing with our review of the ThunderLoan.sol contract, the very next bit of code we approach may seem unfamiliar. diff --git a/courses/security/6-thunder-loan/28-testing-deleting-mappings/+page.md b/courses/security/6-thunder-loan/28-testing-deleting-mappings/+page.md index 9f8436844..2d5c3e42a 100644 --- a/courses/security/6-thunder-loan/28-testing-deleting-mappings/+page.md +++ b/courses/security/6-thunder-loan/28-testing-deleting-mappings/+page.md @@ -60,7 +60,6 @@ contract DeleteMappingTest { ---- If we deploy the above contract in Remix we can then set two addresses as `token` and `token2` to see the mapping working as expected: 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 bc6f12514..704735395 100644 --- a/courses/security/6-thunder-loan/30-thunderloan-continued/+page.md +++ b/courses/security/6-thunder-loan/30-thunderloan-continued/+page.md @@ -24,7 +24,6 @@ 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. 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 86739540f..8fcfdec53 100644 --- a/courses/security/6-thunder-loan/32-thunderloan-redeem/+page.md +++ b/courses/security/6-thunder-loan/32-thunderloan-redeem/+page.md @@ -35,7 +35,6 @@ 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! 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 2b4a33cfb..44f11ab29 100644 --- a/courses/security/6-thunder-loan/33-thunderloan-flashloan/+page.md +++ b/courses/security/6-thunder-loan/33-thunderloan-flashloan/+page.md @@ -56,7 +56,6 @@ function flashloan( ---- ```js // @Audit-Informational: No NATSPEC! @@ -240,7 +239,6 @@ function functionCallWithValue(address target, bytes memory data, uint256 value) ---- We can see, in the end of the chain of executions, we're hitting a very classic piece of code. @@ -333,7 +331,6 @@ contract MockFlashLoanReceiver { ---- Let's consider this example implementation of executeOperation for a better idea of how funds are handled once borrowed: 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 f39e5bcd3..d8d1fe52a 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 @@ -15,7 +15,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. 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 b89e1123c..916d534ef 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 @@ -121,7 +121,6 @@ contract ThunderLoanTest is BaseTest { ---- This seems like a good place to start as it will weed out any issues that may arise from the issue we identified in `deposit` outlined above. @@ -227,7 +226,6 @@ contract MockFlashLoanReceiver { ---- Ok, now we know that the exchange rate is being updated when `deposit` is called (in this case in our modifier), as well as when `flashloan` is called. Let's add a call to redeem into our test, at this point we'd expect a liquidity provider to be able to redeem their asset tokens in exchange for underlying. 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 547de0c18..c09c13890 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 @@ -117,7 +117,6 @@ function testOracleManipulation() public { ---- Next, let's add the funding for ThunderLoan to our test. Before we're able to do that, if you recall from earlier, ThunderLoan needs to have allowed our tokens. @@ -330,7 +329,6 @@ contract MaliciousFlashLoanReceiver is IFlashLoanReceiver { ---- ### Back to our Test @@ -420,7 +418,6 @@ function testOracleManipulation() public { ---- Let's run our test command and you'll see why. @@ -610,7 +607,6 @@ contract MaliciousFlashLoanReceiver is IFlashLoanReceiver { ---- **Recommended Mitigation:** Consider using a different price oracle mechanism, like a Chainlink price feed with a Uniswap TWAP fallback oracle. 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 0aab5fe33..e60a8ba86 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 @@ -170,7 +170,6 @@ contract MaliciousFlashLoanReceiver is IFlashLoanReceiver { ---- ::image{src='/security-section-6/41-oracle-manipulation-recap/oracle-manipulation-recap3.png' style='width: 100%; height: auto;'} 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 78c0864c1..caa00e1a1 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 @@ -78,7 +78,6 @@ contract ImplementationB { ---- Of note, the `initialized` value will typically default to `0` or `false`, if any number is assigned to this variable, it's going to return `true`. diff --git a/courses/security/7-bridges/11-bossbridge/+page.md b/courses/security/7-bridges/11-bossbridge/+page.md index 8b9b33a7f..086fa4daa 100644 --- a/courses/security/7-bridges/11-bossbridge/+page.md +++ b/courses/security/7-bridges/11-bossbridge/+page.md @@ -144,7 +144,6 @@ contract L1BossBridge is Ownable, Pausable, ReentrancyGuard { ---- There's actually not _a lot_ of code here, but it's arguably _pretty tough_ code. Let's jump in. diff --git a/courses/security/7-bridges/12-signatures/+page.md b/courses/security/7-bridges/12-signatures/+page.md index 463d9724d..f56422d8e 100644 --- a/courses/security/7-bridges/12-signatures/+page.md +++ b/courses/security/7-bridges/12-signatures/+page.md @@ -104,7 +104,6 @@ library MessageHashUtils { ---- ```js /* @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing. diff --git a/courses/security/7-bridges/14-eip-712/+page.md b/courses/security/7-bridges/14-eip-712/+page.md index 3a3bd7d6a..2131a0415 100644 --- a/courses/security/7-bridges/14-eip-712/+page.md +++ b/courses/security/7-bridges/14-eip-712/+page.md @@ -121,7 +121,6 @@ contract Example { ---- The test function at the bottom of the contract shows how everything ultimately comes together. diff --git a/courses/security/7-bridges/20-arbitrary-poc/+page.md b/courses/security/7-bridges/20-arbitrary-poc/+page.md index 47fe20883..d0e88ecf9 100644 --- a/courses/security/7-bridges/20-arbitrary-poc/+page.md +++ b/courses/security/7-bridges/20-arbitrary-poc/+page.md @@ -74,7 +74,6 @@ function testCanMoveApprovedTokensOfOtherUsers() public { ---- Now, we can run this test. diff --git a/courses/security/7-bridges/5-Docs/+page.md b/courses/security/7-bridges/5-Docs/+page.md index bf452407f..dec18aa1c 100644 --- a/courses/security/7-bridges/5-Docs/+page.md +++ b/courses/security/7-bridges/5-Docs/+page.md @@ -38,7 +38,6 @@ The bridge operator is in charge of signing withdrawal requests submitted by use ---- The docs seem thorough, but unless we have experience with bridges, or similar protocols this is pretty confusing. This would be the point in a private audit that I would ask for some `protocol diagrams`. diff --git a/courses/security/8-mev-and-governance/5-mev-in-puppy-raffle/+page.md b/courses/security/8-mev-and-governance/5-mev-in-puppy-raffle/+page.md index a273f25f1..c36569a1d 100644 --- a/courses/security/8-mev-and-governance/5-mev-in-puppy-raffle/+page.md +++ b/courses/security/8-mev-and-governance/5-mev-in-puppy-raffle/+page.md @@ -48,7 +48,6 @@ function selectWinner() external { ---- Effectively, when the `selectWinner` function is called, the transaction is then sent to the MemPool. At this point anyone can see the results of the selectWinner function. If a user participating in the raffle identifies that they didn't win, the potential exists for them to refund their entry fee! 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 764a7eb49..08ba13f6d 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 @@ -92,7 +92,6 @@ 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`? From 5703da905d424de0efb560416620fba56cb6402b Mon Sep 17 00:00:00 2001 From: Gerald Wenzel Date: Sat, 21 Sep 2024 15:27:17 -0400 Subject: [PATCH 002/114] Fixed math error and improved language --- courses/solidity/3-fund-me/11-more-solidity-math/+page.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/courses/solidity/3-fund-me/11-more-solidity-math/+page.md b/courses/solidity/3-fund-me/11-more-solidity-math/+page.md index 0d9f16fc9..ec3c1e1b4 100644 --- a/courses/solidity/3-fund-me/11-more-solidity-math/+page.md +++ b/courses/solidity/3-fund-me/11-more-solidity-math/+page.md @@ -29,13 +29,13 @@ function getConversionRate(uint256 ethAmount) internal view returns (uint256) { > The line `uint256 ethAmountInUsd = (ethPrice * ethAmount)` results in a value with a precision of 1e18 \* 1e18 = 1e36. To bring the precision of `ethAmountInUsd` back to 1e18, we need to divide the result by 1e18. > 🔥 **CAUTION**:br -> Always multiply before dividing to maintain precision and avoid truncation errors. For instance, in floating-point arithmetic, `(5/3) * 2` equals approximately 3.33. In Solidity, `(5/3)` equals 1, which when multiplied by 2 yields 2. If you multiply first `(5*2)` and then divide by 3, you achieve better precision. +> Always multiply before dividing to maintain precision and avoid truncation errors. For instance, in floating-point arithmetic, `(5/3) * 2` equals approximately 3.33. In Solidity, `(5/3)` equals 1, which when multiplied by 2 yields 2. If you multiply first `(5*2)` and then divide by 3, you achieve better accuracy. ### Example of `getConversionRate` - `ethAmount` is set at 1 ETH, with 1e18 precision. - `ethPrice` is set at 2000 USD, with 1e18 precision, resulting in 2000e18. -- `ethPrice * ethAmount` results in 2000e18. +- `ethPrice * ethAmount` results in 2000e36. - To scale down `ethAmountInUsd` to 1e18 precision, divide `ethPrice * ethAmount` by 1e18. ### Checking Minimum USD Value From 94f46fae5c3d848f49677ff330836f05797cba41 Mon Sep 17 00:00:00 2001 From: Luigi Date: Sat, 21 Sep 2024 23:29:42 -0700 Subject: [PATCH 003/114] Fix typos, formatting, and clarify sentences --- courses/solidity/1-simple-storage/11-deploying/+page.md | 2 +- .../1-simple-storage/12-zksync-deploying/+page.md | 4 ++-- courses/solidity/1-simple-storage/18-evm-recap/+page.md | 4 ++-- .../solidity/1-simple-storage/2-best-practices/+page.md | 2 +- courses/solidity/1-simple-storage/3-introduction/+page.md | 2 +- .../4-setting-up-your-first-contract/+page.md | 2 +- courses/solidity/1-simple-storage/5-basic-types/+page.md | 8 ++++---- courses/solidity/1-simple-storage/6-functions/+page.md | 8 ++++---- .../1-simple-storage/7-arrays-and-structs/+page.md | 6 +++--- .../1-simple-storage/8-errors-and-warnings/+page.md | 2 +- .../1-simple-storage/9-memory-storage-calldata/+page.md | 4 ++-- 11 files changed, 22 insertions(+), 22 deletions(-) diff --git a/courses/solidity/1-simple-storage/11-deploying/+page.md b/courses/solidity/1-simple-storage/11-deploying/+page.md index 391140bd7..839db172e 100644 --- a/courses/solidity/1-simple-storage/11-deploying/+page.md +++ b/courses/solidity/1-simple-storage/11-deploying/+page.md @@ -39,7 +39,7 @@ Since the contract has been deployed, we can now interact with it and **update t > 💡 **TIP**:br > _Celebrate small victories and milestones. These psychological boosts will keep you engaged in the learning process._ -It's possible to deploy a contract to different testnets or a real mainnet, just by switching the Metamask network. Be sure to have enough net-compatible ETHs to deploy your contract. +It's possible to deploy a contract to different testnets or a real mainnet, just by switching the MetaMask network. Be sure to have enough net-compatible ETHs to deploy your contract. ### Conclusion diff --git a/courses/solidity/1-simple-storage/12-zksync-deploying/+page.md b/courses/solidity/1-simple-storage/12-zksync-deploying/+page.md index 370493f9e..a382caf6b 100644 --- a/courses/solidity/1-simple-storage/12-zksync-deploying/+page.md +++ b/courses/solidity/1-simple-storage/12-zksync-deploying/+page.md @@ -8,7 +8,7 @@ _Follow along with the video_ ### Introduction -With the rising costs of deploying to the Ethereum mainnet, scaling solutions like roll-ups and Layer 2 networks are increasingly in demand. The following lessons will guide you through deploying a smart contract to L2 zkSync. If you've followed the zkSync lessons on the **Blockchain Basics** section, you should have already added ZK-Sync to your Metamask. If not, we'll walk through that process in the next lesson. +With the rising costs of deploying to the Ethereum mainnet, scaling solutions like roll-ups and Layer 2 networks are increasingly in demand. The following lessons will guide you through deploying a smart contract to L2 zkSync. If you've followed the zkSync lessons on the **Blockchain Basics** section, you should have already added ZK-Sync to your MetaMask. If not, we'll walk through that process in the next lesson. ### Testnet Funds @@ -19,4 +19,4 @@ To deploy contracts on zkSync, you'll need testnet funds. There are two methods ### Deploying -To deploy a contract to ZK-Sync, there are a few key steps to follow. First, it's crucial to configure zkSync in your Metamask wallet. Next, you'll need to acquire testnet ETH, which is necessary for deploying and testing your contract. +To deploy a contract to ZK-Sync, there are a few key steps to follow. First, it's crucial to configure zkSync in your MetaMask wallet. Next, you'll need to acquire testnet ETH, which is necessary for deploying and testing your contract. diff --git a/courses/solidity/1-simple-storage/18-evm-recap/+page.md b/courses/solidity/1-simple-storage/18-evm-recap/+page.md index 3fcdf11a9..ae38d8d42 100644 --- a/courses/solidity/1-simple-storage/18-evm-recap/+page.md +++ b/courses/solidity/1-simple-storage/18-evm-recap/+page.md @@ -11,10 +11,10 @@ In this section, we'll quickly summarize the lessons from 1 to 9 and learn about ### EVM EVM stands for _Ethereum Virtual Machine_. It's a decentralized computational engine that executes smart contracts. -Any contract that it's written in Solidity, can be deployed to any EVM-compatible blockchain. Examples of such blockchains and Layer 2 solutions include **Ethereum**, **Polygon**, **Arbitram**, **Optimism**, and **Zksync**. +Any contract that it's written in Solidity, can be deployed to any EVM-compatible blockchain. Examples of such blockchains and Layer 2 solutions include **Ethereum**, **Polygon**, **Arbitrum**, **Optimism**, and **ZKsync**. > 🚧 **WARNING**:br -> Although a blockchain like Zksync may be EVM-compatible, it is essential to verify that all Solidity keywords are supported +> Although a blockchain like ZKsync may be EVM-compatible, it is essential to verify that all Solidity keywords are supported ### Contract Setup diff --git a/courses/solidity/1-simple-storage/2-best-practices/+page.md b/courses/solidity/1-simple-storage/2-best-practices/+page.md index 1456ca5a4..ef1164063 100644 --- a/courses/solidity/1-simple-storage/2-best-practices/+page.md +++ b/courses/solidity/1-simple-storage/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/solidity/1-simple-storage/3-introduction/+page.md b/courses/solidity/1-simple-storage/3-introduction/+page.md index defe11ea6..c08317df4 100644 --- a/courses/solidity/1-simple-storage/3-introduction/+page.md +++ b/courses/solidity/1-simple-storage/3-introduction/+page.md @@ -28,7 +28,7 @@ The repository serves two main purposes: #### Asking Questions -It’s very likely that during your journey you’ll have questions. It’s recommended to use the [**Q&A**](https://github.com/Cyfrin/foundry-full-course-f23/discussions/new?category=q-a) section provided inside the discussion tab. You will be guided into how to best formulate your dubts and queries, such that have the highest chance of being answered by the community, AI or a forum. +It’s very likely that during your journey you’ll have questions. It’s recommended to use the [**Q&A**](https://github.com/Cyfrin/foundry-full-course-f23/discussions/new?category=q-a) section provided inside the discussion tab. You will be guided into how to best formulate your doubts and queries, such that have the highest chance of being answered by the community, AI or a forum. ### Setting Up diff --git a/courses/solidity/1-simple-storage/4-setting-up-your-first-contract/+page.md b/courses/solidity/1-simple-storage/4-setting-up-your-first-contract/+page.md index dc2a83464..178c89c34 100644 --- a/courses/solidity/1-simple-storage/4-setting-up-your-first-contract/+page.md +++ b/courses/solidity/1-simple-storage/4-setting-up-your-first-contract/+page.md @@ -85,6 +85,6 @@ Well done! You just created and compiled your first smart contract in Solidity. ### 🧑‍💻 Test yourself 1. 📕 What does IDE mean and what are Remix main features? -2. 📕 What's the keywork `pragma` used for? +2. 📕 What's the keyword `pragma` used for? 3. 📕 Explain what compiling a contract means. 4. 🧑‍💻 Write an empty contract that contains a SPDX License Identifier and compiles with version 0.8.11 or 0.8.13. diff --git a/courses/solidity/1-simple-storage/5-basic-types/+page.md b/courses/solidity/1-simple-storage/5-basic-types/+page.md index a1a2808e4..c2846c96e 100644 --- a/courses/solidity/1-simple-storage/5-basic-types/+page.md +++ b/courses/solidity/1-simple-storage/5-basic-types/+page.md @@ -15,7 +15,7 @@ Solidity supports various _elementary_ types that can be combined to create more - Boolean (bool): true or false - Unsigned Integer (uint): unsigned whole number (positive) - Integer (int): signed whole number (positive and negative) -- Address (address): 20 bytes value. An example of an address can be found within your Metamask account. +- Address (address): 20 bytes value. An example of an address can be found within your MetaMask account. - Bytes (bytes): low-level raw byte data ### Variables definition @@ -23,7 +23,7 @@ Solidity supports various _elementary_ types that can be combined to create more Variables are just placeholders for **values**. A value can be one **data type** described in the list above. For instance, we could create a Boolean variable named `hasFavoriteNumber`, which would represent whether someone has a favourite number or not (constant `true` or `false`). ```solidity -bool hasFavoriteNumber = true; //the variable hasFavoriteNumber` represents the value `true` +bool hasFavoriteNumber = true; // The variable `hasFavoriteNumber` represents the value `true` ``` It's possible to specify the number of **bits** used for `uint` and `int`. For example, uint256 specifies that the variable has 256 bits. uint is a shorthand for uint256. @@ -37,7 +37,7 @@ The _semicolon_ at the end of each line signifies that a statement is completed. // SPDX-License-Identifier: MIT pragma solidity 0.8.19; -contract Simple Storage{ +contract SimpleStorage { // Basic types bool hasFavoriteNumber = true; uint256 favoriteNumber = 88; @@ -60,7 +60,7 @@ bytes dynamicBytes = "I am a dynamic array, so you can manipulate my size"; Bytes can be allocated in size (up to `bytes32`). However, bytes and bytes32 represent distinct data types. -**Strings** are internally represented as _dynamic byte arrays_ (`bytes` tipe) and designed specifically for working with text. For this reason, a string can easily be converted into bytes. +**Strings** are internally represented as _dynamic byte arrays_ (`bytes` type) and designed specifically for working with text. For this reason, a string can easily be converted into bytes. [Bits and Bytes overview](https://www.youtube.com/watch?v=Dnd28lQHquU) diff --git a/courses/solidity/1-simple-storage/6-functions/+page.md b/courses/solidity/1-simple-storage/6-functions/+page.md index 78b92fc43..d716e68ea 100644 --- a/courses/solidity/1-simple-storage/6-functions/+page.md +++ b/courses/solidity/1-simple-storage/6-functions/+page.md @@ -64,7 +64,7 @@ If we open the Remix terminal we can see that deploying the contract has just se Let's send a transaction to the `store` function to change the value of the variable `favoriteNumber`: you can insert a number and press the `store` button in Remix. A transaction is initiated and after some time, its status will change from pending to complete. -💸 From the accounts section, it becomes visible that ETH is being consumed every time a transaction is submitted. When the state of the blockchain is modified (e.g. deploying a contract, sending ETH, ..), is done by sending a transaction that consumes **gas**. Executing the `store` function is more expensive than just transferring ETH between accounts, with the rising gas expenses primarily associated (though not exclusively) with the code length. +💸 From the accounts section, it becomes visible that ETH is being consumed every time a transaction is submitted. When the state of the blockchain is modified (e.g. deploying a contract, sending ETH, ...), is done by sending a transaction that consumes **gas**. Executing the `store` function is more expensive than just transferring ETH between accounts, with the rising gas expenses primarily associated (though not exclusively) with the code length. #### Verifying the stored value @@ -73,7 +73,7 @@ This contract is missing a way to check if the number has been updated: now we c The default visibility of the `favoriteNumber` variable is **internal**, preventing external contracts and users from viewing it. > 🗒️ **NOTE**:br -> Appending the `public` keyword next to a variable will automatically change its visibility and it will generate a **get function**. +> Appending the `public` keyword next to a variable will automatically change its visibility and it will generate a **getter function** (a function that gets the variable's value when called). ```solidity uint256 public favoriteNumber; @@ -99,13 +99,13 @@ If a visibility specifier is not given, it defaults to `internal`. The terms `view` and `pure` are used when a function reads values from the blockchain without altering its state. Such functions will not initiate transactions but rather make calls, represented as blue buttons in the Remix interface. A `pure` function will prohibit any reading from the state or storage. ```solidity -function retrieve() public view returns(uint256){ +function retrieve() public view returns(uint256) { return favoriteNumber; } ``` ```solidity -function retrieve() public pure returns(uint256){ +function retrieve() public pure returns(uint256) { return 7; } ``` diff --git a/courses/solidity/1-simple-storage/7-arrays-and-structs/+page.md b/courses/solidity/1-simple-storage/7-arrays-and-structs/+page.md index 65020396f..75ae48b74 100644 --- a/courses/solidity/1-simple-storage/7-arrays-and-structs/+page.md +++ b/courses/solidity/1-simple-storage/7-arrays-and-structs/+page.md @@ -6,7 +6,7 @@ _You can follow along with the video course from here._ ### Introduction -Up to this point, the `SimpleStorage` contract allows for storing, updating, and viewing a single favorite number. In this lesson, we'll enhance the code to store multiple numbers, enabling more than one person to store their values. We'll learn how to create a list of favorite numbers using **arrays**, and we'll explore the **`structs`** keyword for creating new types in Solidity. +Up to this point, the `SimpleStorage` contract allows for storing, updating, and viewing a single favorite number. In this lesson, we'll enhance the code to store multiple numbers, enabling more than one person to store their values. We'll learn how to create a list of favorite numbers using **arrays**, and we'll explore the **`struct`** keyword for creating new types in Solidity. ### Arrays and struct @@ -23,7 +23,7 @@ uint256[] list_of_favorite_numbers = [0, 78, 90]; ``` > 🗒️ **NOTE**:br -> Arrays are zero-indexed: the first element is at position zero (0), the second is position (index) 1, and so on. +> Arrays are zero-indexed: the first element is at position zero (has index 0), the second element is at position one (has index 1), and so on. The issue with this data structure is that we cannot link the owner with its favorite value. One solution is to establish a **new type** using the `struct` keyword, named `Person`, which is made of two _attributes_: a favorite number and a name. @@ -43,7 +43,7 @@ From this struct, we can instantiate a variable `my_friend` that has the type `P Person public my_friend = Person(7, 'Pat'); /* equals to Person public my_friend = Person({ - favoriteNumber:7, + favorite_number:7, name:'Pat'}); */ ``` diff --git a/courses/solidity/1-simple-storage/8-errors-and-warnings/+page.md b/courses/solidity/1-simple-storage/8-errors-and-warnings/+page.md index 0592e7226..8557de092 100644 --- a/courses/solidity/1-simple-storage/8-errors-and-warnings/+page.md +++ b/courses/solidity/1-simple-storage/8-errors-and-warnings/+page.md @@ -45,7 +45,7 @@ We can input the compiler error under the drop-down menu, execute the search, an ::image{src='/solidity/remix/lesson-2/errors-warnings/phind-answer.png' style='width: 100%; height: auto;'} -#### Othe resources +#### Other resources It is advised to make active use of AI tools, as they can substantially boost your understanding and skills. Later in this course, we will explore how to ask effective questions, utilize AI prompts, structure your inquiries, and improve your search and learning techniques. 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 420a70780..8796895b9 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 @@ -53,7 +53,7 @@ In our contract, the variable `myFavoriteNumber` is a storage variable. Variable ```solidity contract MyContract { - uint256 favoriteNumber; //this is a storage variable + uint256 favoriteNumber; // this is a storage variable }; ``` @@ -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, uitn256 _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)); } From d147e8f43f46f62e418570e1722c39da2c6abd59 Mon Sep 17 00:00:00 2001 From: Luigi Date: Sun, 22 Sep 2024 21:11:28 -0700 Subject: [PATCH 004/114] Clarify sentences --- .../solidity/1-simple-storage/10-mappings/+page.md | 11 +++++------ .../solidity/1-simple-storage/11-deploying/+page.md | 6 +++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/courses/solidity/1-simple-storage/10-mappings/+page.md b/courses/solidity/1-simple-storage/10-mappings/+page.md index c826d0665..a2111655e 100644 --- a/courses/solidity/1-simple-storage/10-mappings/+page.md +++ b/courses/solidity/1-simple-storage/10-mappings/+page.md @@ -6,7 +6,7 @@ _You can follow along with the video course from here._ ### Introduction -We have just created a contract that stores multiple `Person`'s' names and favorite numbers in a list. In this session, you will learn about mappings, their functionality, and when it is more advantageous to use them. +We have just created a contract that stores multiple `Person`'s names and favorite numbers in a list. In this session, you will learn about mappings, their functionality, and when it is more advantageous to use them. ### Avoiding Costly Iterations @@ -18,9 +18,8 @@ list_of_people.add(Person("John", 8)); list_of_people.add(Person("Mariah", 10)); list_of_people.add(Person("Chelsea", 232)); -/* go through all the people to check their favorite number. -If name is "Chelsea" -> return 232 -*/ +// Go through all the people to check their favorite number. +// If name is "Chelsea" -> return 232 ``` Iterating through a long list of data is usually expensive and time-consuming, especially when we do not need to access elements by their index. @@ -42,10 +41,10 @@ nameToFavoriteNumber[_name] = _favoriteNumber; ``` > 👀❗**IMPORTANT**:br -> Mappings have a constant time complexity for lookups, meaning that retrieving a value by its key is done in constant time, +> Mappings have a constant time complexity for lookups, meaning that retrieving a value by its key is done in constant time. > 🗒️ **NOTE**:br -> The default value for all key types is zero. In our case, `nameToFavoriteNumber["ET"]` will be equal to 0. +> The default value for all key types is zero. In our case, `nameToFavoriteNumber["ET"]` will equal to 0. ### Conclusion diff --git a/courses/solidity/1-simple-storage/11-deploying/+page.md b/courses/solidity/1-simple-storage/11-deploying/+page.md index 839db172e..7f41ec518 100644 --- a/courses/solidity/1-simple-storage/11-deploying/+page.md +++ b/courses/solidity/1-simple-storage/11-deploying/+page.md @@ -9,9 +9,9 @@ _You can follow along with the video course from here._ Over the past eight lessons, we crafted the `SimpleStorage` contract. It defines a custom type `Person`, includes an internal variable that can be read and updated, and contains a public array and mapping that can also be modified. In this lesson, we will deploy the contract to a **real testnet**, which fully simulates a live blockchain environment without using real Ether. > 🔥 **CAUTION**:br -> You could be tempted to immediately deploy this contract to a testnet. As a general rule, I caution against this. Make sure to write tests, carry out audits and ensure the robustness of your contract before deploying it to production. However, for the sake of this demonstration, we're going to deploy this as a dummy contract on a testnet. +> You could be tempted to immediately deploy this contract to the mainnet. As a general rule, I caution against this. Make sure to write tests, carry out audits and ensure the robustness of your contract before deploying it to production. However, for the sake of this demonstration, we're going to deploy this as a dummy contract on a testnet. -Before deploying, be always sure to make a **compilation check**. This ensures that the contract has no errors or warnings and is fit for deployment. +Before deploying, be always sure to make a **compilation check**. This ensures that the contract has no errors or warnings, and is fit for deployment. ### Deployment on a testnet @@ -37,7 +37,7 @@ Since the contract has been deployed, we can now interact with it and **update t > 👀❗**IMPORTANT**:br > View and pure functions will not send transactions -> 💡 **TIP**:br > _Celebrate small victories and milestones. These psychological boosts will keep you engaged in the learning process._ +> 💡 **TIP**:br Celebrate small victories and milestones. These psychological boosts will keep you engaged in the learning process. It's possible to deploy a contract to different testnets or a real mainnet, just by switching the MetaMask network. Be sure to have enough net-compatible ETHs to deploy your contract. From 4801bb4a761d1c55e4d02f4287081fd5f50296dc Mon Sep 17 00:00:00 2001 From: Gerald Wenzel Date: Mon, 23 Sep 2024 12:53:04 -0400 Subject: [PATCH 005/114] Addressed PR feedback --- courses/solidity/3-fund-me/11-more-solidity-math/+page.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/courses/solidity/3-fund-me/11-more-solidity-math/+page.md b/courses/solidity/3-fund-me/11-more-solidity-math/+page.md index ec3c1e1b4..53e8d2565 100644 --- a/courses/solidity/3-fund-me/11-more-solidity-math/+page.md +++ b/courses/solidity/3-fund-me/11-more-solidity-math/+page.md @@ -29,7 +29,7 @@ function getConversionRate(uint256 ethAmount) internal view returns (uint256) { > The line `uint256 ethAmountInUsd = (ethPrice * ethAmount)` results in a value with a precision of 1e18 \* 1e18 = 1e36. To bring the precision of `ethAmountInUsd` back to 1e18, we need to divide the result by 1e18. > 🔥 **CAUTION**:br -> Always multiply before dividing to maintain precision and avoid truncation errors. For instance, in floating-point arithmetic, `(5/3) * 2` equals approximately 3.33. In Solidity, `(5/3)` equals 1, which when multiplied by 2 yields 2. If you multiply first `(5*2)` and then divide by 3, you achieve better accuracy. +> Always multiply before dividing to maintain precision and avoid truncation errors. For instance, in floating-point arithmetic, `(5/3) * 2` equals approximately 3.33. In Solidity, `(5/3)` equals 1, which when multiplied by 2 yields 2. If you multiply first `(5*2)` and then divide by 3, you achieve better precision. ### Example of `getConversionRate` From 1343bbb8906d48e06af91467722f090bba6e6581 Mon Sep 17 00:00:00 2001 From: Luigi Date: Mon, 23 Sep 2024 14:14:48 -0700 Subject: [PATCH 006/114] Revise edits from feedback --- courses/solidity/1-simple-storage/10-mappings/+page.md | 2 +- courses/solidity/1-simple-storage/11-deploying/+page.md | 2 +- .../solidity/1-simple-storage/12-zksync-deploying/+page.md | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/courses/solidity/1-simple-storage/10-mappings/+page.md b/courses/solidity/1-simple-storage/10-mappings/+page.md index a2111655e..da1d9d4af 100644 --- a/courses/solidity/1-simple-storage/10-mappings/+page.md +++ b/courses/solidity/1-simple-storage/10-mappings/+page.md @@ -44,7 +44,7 @@ nameToFavoriteNumber[_name] = _favoriteNumber; > Mappings have a constant time complexity for lookups, meaning that retrieving a value by its key is done in constant time. > 🗒️ **NOTE**:br -> The default value for all key types is zero. In our case, `nameToFavoriteNumber["ET"]` will equal to 0. +> The default value for all key types is zero. In our case, `nameToFavoriteNumber["ET"]` equals 0. ### Conclusion diff --git a/courses/solidity/1-simple-storage/11-deploying/+page.md b/courses/solidity/1-simple-storage/11-deploying/+page.md index 7f41ec518..afda54f40 100644 --- a/courses/solidity/1-simple-storage/11-deploying/+page.md +++ b/courses/solidity/1-simple-storage/11-deploying/+page.md @@ -37,7 +37,7 @@ Since the contract has been deployed, we can now interact with it and **update t > 👀❗**IMPORTANT**:br > View and pure functions will not send transactions -> 💡 **TIP**:br Celebrate small victories and milestones. These psychological boosts will keep you engaged in the learning process. +> 💡 **TIP**:br _Celebrate small victories and milestones. These psychological boosts will keep you engaged in the learning process._ It's possible to deploy a contract to different testnets or a real mainnet, just by switching the MetaMask network. Be sure to have enough net-compatible ETHs to deploy your contract. diff --git a/courses/solidity/1-simple-storage/12-zksync-deploying/+page.md b/courses/solidity/1-simple-storage/12-zksync-deploying/+page.md index a382caf6b..75ee1ca73 100644 --- a/courses/solidity/1-simple-storage/12-zksync-deploying/+page.md +++ b/courses/solidity/1-simple-storage/12-zksync-deploying/+page.md @@ -8,7 +8,7 @@ _Follow along with the video_ ### Introduction -With the rising costs of deploying to the Ethereum mainnet, scaling solutions like roll-ups and Layer 2 networks are increasingly in demand. The following lessons will guide you through deploying a smart contract to L2 zkSync. If you've followed the zkSync lessons on the **Blockchain Basics** section, you should have already added ZK-Sync to your MetaMask. If not, we'll walk through that process in the next lesson. +With the rising costs of deploying to the Ethereum mainnet, scaling solutions like roll-ups and Layer 2 networks are increasingly in demand. The following lessons will guide you through deploying a smart contract to L2 zkSync. If you've followed the zkSync lessons on the **Blockchain Basics** section, you should have already added ZKsync to your MetaMask. If not, we'll walk through that process in the next lesson. ### Testnet Funds @@ -19,4 +19,4 @@ To deploy contracts on zkSync, you'll need testnet funds. There are two methods ### Deploying -To deploy a contract to ZK-Sync, there are a few key steps to follow. First, it's crucial to configure zkSync in your MetaMask wallet. Next, you'll need to acquire testnet ETH, which is necessary for deploying and testing your contract. +To deploy a contract to ZKsync, there are a few key steps to follow. First, it's crucial to configure zkSync in your MetaMask wallet. Next, you'll need to acquire testnet ETH, which is necessary for deploying and testing your contract. From ea2effc47e39b56699b4d5a3bb81adbfe958816f Mon Sep 17 00:00:00 2001 From: Luigi Date: Mon, 23 Sep 2024 15:38:10 -0700 Subject: [PATCH 007/114] Cleanup Storage Factory written lesson --- .../2-storage-factory/1-factory-introduction/+page.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/courses/solidity/2-storage-factory/1-factory-introduction/+page.md b/courses/solidity/2-storage-factory/1-factory-introduction/+page.md index 8657e4fac..2e3d56ac8 100644 --- a/courses/solidity/2-storage-factory/1-factory-introduction/+page.md +++ b/courses/solidity/2-storage-factory/1-factory-introduction/+page.md @@ -6,7 +6,7 @@ _You can follow along with the video course from here._ ### Introduction -You can find the code for this section in the [Remix Storage Factory Github repository](https://github.com/cyfrin/remix-storage-factory-f23). In these nine lessons we'll work with three new contracts: +You can find the code for this section in the [Remix Storage Factory Github repository](https://github.com/cyfrin/remix-storage-factory-f23). In these nine lessons, we'll work with three new contracts: 1. `SimpleStorage.sol` - the contract we build in the previous section, with some modifications 2. `AddFiveStorage.sol` - a child contract of `SimpleStorage` that leverages _inheritance_ @@ -30,8 +30,6 @@ It's possible to interact with this newly deployed `SimpleStorage` via the `stor The **`sfGet`** function, when given the input '0', will indeed return the number provided by the previous function. The **address** of the `SimpleStorage` contract can then be retrieved by clicking on the get function `listOfSimpleStorageContracts`. -::image{src='/solidity/remix/lesson-3/setting-up/graph-1.png' style='width: 100%; height: auto;'} - ### Conclusion The `StorageFactory` contract manages numerous instances of an external contract `SimpleStorage`. It provides functionality to deploy new contract instances dynamically and allows for the storage and retrieval of values from each instance. These instances are maintained and organized within an array, enabling efficient tracking and interaction. From be023ec5f62b057782a170632a90a416f904474f Mon Sep 17 00:00:00 2001 From: Luigi Date: Mon, 23 Sep 2024 20:41:18 -0700 Subject: [PATCH 008/114] Fix typo and formatting --- .../2-storage-factory/2-setting-up-the-factory/+page.md | 4 ++-- .../3-deploying-a-contract-from-a-contract/+page.md | 3 ++- courses/solidity/2-storage-factory/5-ai-help-ii/+page.md | 2 +- .../2-storage-factory/7-inheritance-in-solidity/+page.md | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/courses/solidity/2-storage-factory/2-setting-up-the-factory/+page.md b/courses/solidity/2-storage-factory/2-setting-up-the-factory/+page.md index 99b2c0408..3cb233bd2 100644 --- a/courses/solidity/2-storage-factory/2-setting-up-the-factory/+page.md +++ b/courses/solidity/2-storage-factory/2-setting-up-the-factory/+page.md @@ -10,7 +10,7 @@ In this `StorageFactory` setup, we'll explore what _composability_ means, showin ### StorageFactory setup -You can begin by visiting the [Github repository of the previous section](https://github.com/cyfrin/remix-simple-storage-f23) and copying the contract `SimpleStorage` inside Remix. +You can begin by visiting the [Github repository of the previous section](https://github.com/cyfrin/remix-simple-storage-cu) and copying the contract `SimpleStorage` inside Remix. This contract allows to store a favorite number, a list of people with their favorite number, a mapping and different functionalities to interact with them. This lesson aims to create a **new contract** that can deploy and interact with `SimpleStorage`. @@ -26,7 +26,7 @@ pragma solidity ^0.8.18; contract StorageFactory { function createSimplestorageContract() public { - //how does StorageFactory know what SimpleStorage looks like? + // How does StorageFactory know what SimpleStorage looks like? } } ``` diff --git a/courses/solidity/2-storage-factory/3-deploying-a-contract-from-a-contract/+page.md b/courses/solidity/2-storage-factory/3-deploying-a-contract-from-a-contract/+page.md index f8df48aff..f9da88fea 100644 --- a/courses/solidity/2-storage-factory/3-deploying-a-contract-from-a-contract/+page.md +++ b/courses/solidity/2-storage-factory/3-deploying-a-contract-from-a-contract/+page.md @@ -25,7 +25,8 @@ contract StorageFactory { } ``` -> 👀❗**IMPORTANT**:br > `SimpleStorage` on the left and `simpleStorage` on the right are treated as entirely distinct entities due to their differing capitalization. `Simple Storage` refers to the contract type while `simpleStorage` refers to the variable name. +> 👀❗**IMPORTANT**:br +> `SimpleStorage` on the left and `simpleStorage` on the right are treated as entirely distinct entities due to their differing capitalization. `Simple Storage` refers to the contract type while `simpleStorage` refers to the variable name. When the `new` keyword is used, the compiler recognizes the intention to deploy a new contract instance. After compiling, we can proceed to deploy it. diff --git a/courses/solidity/2-storage-factory/5-ai-help-ii/+page.md b/courses/solidity/2-storage-factory/5-ai-help-ii/+page.md index 7ea8dfa4e..ae2fce5ae 100644 --- a/courses/solidity/2-storage-factory/5-ai-help-ii/+page.md +++ b/courses/solidity/2-storage-factory/5-ai-help-ii/+page.md @@ -25,7 +25,7 @@ We can ask the AI to clarify it by: This is the AI prompt: -```` +````text Hi, I'm having a hard time understanding the difference between these simple storages on this line: ```// paste the confusing line of code here``` Here is my full code: diff --git a/courses/solidity/2-storage-factory/7-inheritance-in-solidity/+page.md b/courses/solidity/2-storage-factory/7-inheritance-in-solidity/+page.md index 42bdca209..f294c465c 100644 --- a/courses/solidity/2-storage-factory/7-inheritance-in-solidity/+page.md +++ b/courses/solidity/2-storage-factory/7-inheritance-in-solidity/+page.md @@ -11,7 +11,7 @@ In this lesson, we are going to introduce the concept of **inheritance** and **o ### Inheritance We are going to enhance the `SimpleStorage` contract by adding a new functionality: the ability to add five (5) to the stored `favoriteNumber`. -To achieve this, we could duplicate the existing `SimpleStorage` contract and make changes to the new version. However, this approach leads to redundant code. A better practice could be to utilize **inheritance**, wich is the mechanism that allows the `AddFiveStorage` contract to derive all the functionalities of `SimpleStorage`. +To achieve this, we could duplicate the existing `SimpleStorage` contract and make changes to the new version. However, this approach leads to redundant code. A better practice could be to utilize **inheritance**, which is the mechanism that allows the `AddFiveStorage` contract to derive all the functionalities of `SimpleStorage`. Let's begin by creating a new file `AddFiveStorage.sol` and name-importing `SimpleStorage.sol`: From 4d20bea93a1ac7f1bf1fc0b2827ac08215874271 Mon Sep 17 00:00:00 2001 From: Luigi Date: Tue, 24 Sep 2024 23:45:53 -0700 Subject: [PATCH 009/114] Fix typos and formatting --- .../solidity/3-fund-me/1-fund-me-intro/+page.md | 2 +- .../10-getting-prices-from-chainlink/+page.md | 8 ++++---- .../3-fund-me/24-receive-fallback/+page.md | 2 +- .../3-fund-me/5-real-world-price-data/+page.md | 6 +++--- .../3-fund-me/6-mid-lesson-recap/+page.md | 16 ++++++++-------- courses/solidity/3-fund-me/7-interfaces/+page.md | 8 ++++---- .../solidity/3-fund-me/8-ai-help-iii/+page.md | 2 +- .../9-importing-from-npm-github/+page.md | 8 ++++---- 8 files changed, 26 insertions(+), 26 deletions(-) diff --git a/courses/solidity/3-fund-me/1-fund-me-intro/+page.md b/courses/solidity/3-fund-me/1-fund-me-intro/+page.md index 6e78e813b..4e20130fe 100644 --- a/courses/solidity/3-fund-me/1-fund-me-intro/+page.md +++ b/courses/solidity/3-fund-me/1-fund-me-intro/+page.md @@ -19,7 +19,7 @@ For this project, we will be using two contracts: `FundMe`, the main crowdfundin Once `FundMe` is deployed on Remix, you'll notice a set of _functions_, including a new red button labelled `fund`, indicating that the function is _payable_. A payable function allows you to send native blockchain currency (e.g., Ethereum, Polygon, Avalanche) to the contract. -We'll additionally indicate a **minimum USD amount** to send to the contract when the function `fund` is called. To transfer funds to the `FundMe` contract, you can navigate to the _value section_ of the Remix deployment tab, enter a value (e.g. 0.1 ether) then hit `fund`. A Metamask transaction confirmation will appear, and the contract balance will remain zero until the transaction is finalized. Once completed, the contract balance will be updated to reflect the transferred amount. +We'll additionally indicate a **minimum USD amount** to send to the contract when the function `fund` is called. To transfer funds to the `FundMe` contract, you can navigate to the _value section_ of the Remix deployment tab, enter a value (e.g. 0.1 ether) then hit `fund`. A MetaMask transaction confirmation will appear, and the contract balance will remain zero until the transaction is finalized. Once completed, the contract balance will be updated to reflect the transferred amount. The contract owner can then `withdraw` the funds. In this case, since we own the contract, the balance will be removed from the contract's balance and transferred to our wallet. diff --git a/courses/solidity/3-fund-me/10-getting-prices-from-chainlink/+page.md b/courses/solidity/3-fund-me/10-getting-prices-from-chainlink/+page.md index f2f11fb03..f8aa6d057 100644 --- a/courses/solidity/3-fund-me/10-getting-prices-from-chainlink/+page.md +++ b/courses/solidity/3-fund-me/10-getting-prices-from-chainlink/+page.md @@ -18,13 +18,13 @@ AggregatorV3Interface priceFeed = AggregatorV3Interface(0x1b44F3514812d835EB1BDB We can call the `latestRoundData()` function on this interface to obtain several values, including the latest price. -```js +```solidity function latestRoundData() external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound); ``` For now, we'll focus on the `answer` value and ignore the other returned values by using commas as placeholders for the unneeded variables. -```js +```solidity function getLatestPrice() public view returns (int) { (,int price,,,) = priceFeed.latestRoundData(); return price; @@ -48,13 +48,13 @@ return price * 1e10; Typecasting, or type conversion, involves converting a value from one data type to another. In Solidity, not all data types can be converted due to differences in their underlying representations and the potential for data loss. However, certain conversions, such as from `int` to `uint`, are allowed. -```js +```solidity return uint(price) * 1e10; ``` We can finalize our `view` function as follows: -```js +```solidity function getLatestPrice() public view returns (uint256) { (,int answer,,,) = priceFeed.latestRoundData(); return uint(answer) * 1e10; diff --git a/courses/solidity/3-fund-me/24-receive-fallback/+page.md b/courses/solidity/3-fund-me/24-receive-fallback/+page.md index 09edeaf9b..532fcbe1b 100644 --- a/courses/solidity/3-fund-me/24-receive-fallback/+page.md +++ b/courses/solidity/3-fund-me/24-receive-fallback/+page.md @@ -8,7 +8,7 @@ _You can follow along with the video course from here._ In Solidity, if Ether is sent to a contract without a `receive` or `fallback` function, the transaction will be **rejected**, and the Ether will not be transferred. In this lesson, we'll explore how to handle this scenario effectively. -### receiv and fallback functions +### receive and fallback functions `receive` and `fallback` are _special functions_ triggered when users send Ether directly to the contract or call non-existent functions. These functions do not return anything and must be declared `external`. diff --git a/courses/solidity/3-fund-me/5-real-world-price-data/+page.md b/courses/solidity/3-fund-me/5-real-world-price-data/+page.md index 120b778db..5ca9ca3e1 100644 --- a/courses/solidity/3-fund-me/5-real-world-price-data/+page.md +++ b/courses/solidity/3-fund-me/5-real-world-price-data/+page.md @@ -32,7 +32,7 @@ Chainlink offers ready-made features that can be added to a smart contract. And - **Data Feeds** - **Verifiable Random Number** -- **Keepers** +- **Automation (previously known as "Keepers")** - **Functions** ### Chainlink Data Feeds @@ -44,13 +44,13 @@ _Chainlink Data Feeds_ are responsible for powering over $50 billion in the DeFi They aggregate this data and deliver it to a reference contract, the **price feed contract**, in a single transaction. Each contract will store the pricing details of a specific cryptocurrency ::image{src='/solidity/remix/lesson-4/datafeeds/datafeed1.png' style='width: 100%; height: auto;'} -### Chainlink CRF +### Chainlink VRF The Chainlink VRF (Verifiable Random Function) provides a solution for generating **provably random numbers**, ensuring true fairness in applications such as NFT randomization, lotteries, and gaming. These numbers are determined off-chain, and they are immune to manipulation. ::image{src='/solidity/remix/lesson-4/datafeeds/datafeed3.png' style='width: 100%; height: auto;'} -### Chainlink Keepers +### Chainlink Automation (previously known as "Keepers") Another great feature is Chainlink's system of _Keepers_. These **nodes** listen for specific events and, upon being triggered, automatically execute the intended actions within the calling contract. diff --git a/courses/solidity/3-fund-me/6-mid-lesson-recap/+page.md b/courses/solidity/3-fund-me/6-mid-lesson-recap/+page.md index 2c01f79ac..42ff09abb 100644 --- a/courses/solidity/3-fund-me/6-mid-lesson-recap/+page.md +++ b/courses/solidity/3-fund-me/6-mid-lesson-recap/+page.md @@ -12,19 +12,19 @@ From lessons 1 to 5 we've explored the usage of the keyword `payable`, the globa To enable a function to receive a native blockchain token such as Ethereum, it must be marked as `payable`: -```js +```solidity function deposit() public payable { - balances[msg.sender] += msg.value; + balances[msg.sender] += msg.value; } ``` If we want a function to fail under certain conditions, we can use the `require` statement. For example, in a bank transfer scenario, we want the operation to fail if the sender does not have enough balance. Here's an example: -```js +```solidity function transfer(address recipient, uint amount) public { - require(balances[msg.sender] >= amount); - balances[msg.sender] -= amount; - balances[recipient] += amount; + require(balances[msg.sender] >= amount); + balances[msg.sender] -= amount; + balances[recipient] += amount; } ``` @@ -41,11 +41,11 @@ Chainlink is a revolutionary technology that enables the integration of external Consider a smart contract that deals with a commodity like gold. _Chainlink Price Feeds_ can provide real-time gold prices, allowing the smart contract to reflect the current market prices. -```js +```solidity import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; contract GoldPriceContract { AggregatorV3Interface internal priceFeed; - //The Chainlink price feed contract address + // The Chainlink price feed contract address constructor() public { priceFeed = AggregatorV3Interface(0x8468b2bDCE073A157E560AA4D9CcF6dB1DB98507); } diff --git a/courses/solidity/3-fund-me/7-interfaces/+page.md b/courses/solidity/3-fund-me/7-interfaces/+page.md index 775ef2074..0a5978f75 100644 --- a/courses/solidity/3-fund-me/7-interfaces/+page.md +++ b/courses/solidity/3-fund-me/7-interfaces/+page.md @@ -12,7 +12,7 @@ In this part, we'll learn how to **convert** Ethereum (ETH) into Dollars (USD) a We begin by trying to convert the `msg.value`, which is now specified in ETH, into USD. This process requires fetching the **current USD market price** of Ethereum and using it to convert the `msg.value` amount into USD. -```js +```solidity // Function to get the price of Ethereum in USD function getPrice() public {} // Function to convert a value based on the price @@ -39,10 +39,10 @@ An alternative method involves the use of an **Interface**, which defines method We can test the Interface usage by calling the `version()` function: -```js - function getVersion() public view returns (uint256) { +```solidity +function getVersion() public view returns (uint256) { return AggregatorV3Interface(0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419).version(); - } +} ``` > 🗒️ **NOTE**:br diff --git a/courses/solidity/3-fund-me/8-ai-help-iii/+page.md b/courses/solidity/3-fund-me/8-ai-help-iii/+page.md index 1da6c8f9f..a3a206bb1 100644 --- a/courses/solidity/3-fund-me/8-ai-help-iii/+page.md +++ b/courses/solidity/3-fund-me/8-ai-help-iii/+page.md @@ -59,4 +59,4 @@ By leveraging AI and discussion forums, you can gain a deeper understanding of c ### 🧑‍💻 Test yourself -1. 📕 Dive deeper into the `getVersion` function by asking AI three more questions about it +1. 📕 Delve deeper into the `getVersion` function by asking AI three more questions about it diff --git a/courses/solidity/3-fund-me/9-importing-from-npm-github/+page.md b/courses/solidity/3-fund-me/9-importing-from-npm-github/+page.md index 9efbed4b9..1719b6e2b 100644 --- a/courses/solidity/3-fund-me/9-importing-from-npm-github/+page.md +++ b/courses/solidity/3-fund-me/9-importing-from-npm-github/+page.md @@ -12,7 +12,7 @@ As we delve into smart contract development, **interacting** with external smart Let's take a look at the `SmartContract` interface as an example: -```js +```solidity interface SmartContract { function someFunction() external view returns(uint, uint){}; } @@ -26,13 +26,13 @@ Smart Contracts _hosted on GitHub_ can be imported directly into your project. F Instead of manually copying all its code into your project and then importing it like this: -```js +```solidity import { AggregatorV3Interface } from "./AggregatorV3Interface.sol"; ``` we can import it more efficiently, as specified in the [Chainlink documentation](https://docs.chain.link/docs/using-chainlink-reference-contracts): -```js +```solidity import { AggregatorV3Interface } from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; ``` @@ -44,7 +44,7 @@ The `@chainlink/contracts` package, available on NPM, follows **Semantic Version Remix interprets `@chainlink/contracts` as a reference to the [NPM package](https://www.npmjs.com/package/@chainlink/contracts), and downloads all the necessary code from it. -```js +```solidity pragma solidity ^0.8.18; import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; contract FundMe {} From a016e8b08eade95854dcd4345918be11563b334a Mon Sep 17 00:00:00 2001 From: Luigi Date: Wed, 25 Sep 2024 00:17:34 -0700 Subject: [PATCH 010/114] Update Chainlink import path --- .../solidity/3-fund-me/14-libraries/+page.md | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/courses/solidity/3-fund-me/14-libraries/+page.md b/courses/solidity/3-fund-me/14-libraries/+page.md index b92ebdd70..c2134f266 100644 --- a/courses/solidity/3-fund-me/14-libraries/+page.md +++ b/courses/solidity/3-fund-me/14-libraries/+page.md @@ -26,23 +26,23 @@ library PriceConverter {} Let's copy `getPrice`, `getConversionRate`, and `getVersion` functions from the `FundMe.sol` contract into our new library, remembering to import the `AggregatorV3Interface` into `PriceConverter.sol`. Finally, we can mark all the functions as `internal`. -```js +```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.18; -import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; +import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol"; library PriceConverter { - function getPrice() internal view returns (uint256) { - AggregatorV3Interface priceFeed = AggregatorV3Interface(0x694AA1769357215DE4FAC081bf1f309aDC325306); - (, int256 answer, , , ) = priceFeed.latestRoundData(); - return uint256(answer * 10000000000); - } - - function getConversionRate(uint256 ethAmount) internal view returns (uint256) { - uint256 ethPrice = getPrice(); - uint256 ethAmountInUsd = (ethPrice * ethAmount) / 1000000000000000000; - return ethAmountInUsd; + function getPrice() internal view returns (uint256) { + AggregatorV3Interface priceFeed = AggregatorV3Interface(0x694AA1769357215DE4FAC081bf1f309aDC325306); + (, int256 answer, , , ) = priceFeed.latestRoundData(); + return uint256(answer * 10000000000); + } + + function getConversionRate(uint256 ethAmount) internal view returns (uint256) { + uint256 ethPrice = getPrice(); + uint256 ethAmountInUsd = (ethPrice * ethAmount) / 1000000000000000000; + return ethAmountInUsd; } } ``` @@ -51,20 +51,20 @@ library PriceConverter { You can import the library in your contract and attach it to the desired type with the keyword `using`: -```js +```solidity import {PriceConverter} from "./PriceConverter.sol"; using PriceConverter for uint256; ``` The `PriceConverter` functions can then be called as if they are native to the `uint256` type. For example, calling the `getConversionRate()` function will now be changed into: -```js +```solidity require(msg.value.getConversionRate() >= minimumUsd, "didn't send enough ETH"); ``` Here, `msg.value`, which is a `uint256` type, is extended to include the `getConversionRate()` function. The `msg.value` gets passed as the first argument to the function. If additional arguments are needed, they are passed in parentheses: -```js +```solidity uint256 result = msg.value.getConversionRate(123); ``` From 01327655d0543ba1eb9ef2e45000685d83781f1d Mon Sep 17 00:00:00 2001 From: Pavel Naydanov Date: Wed, 25 Sep 2024 14:58:51 +0700 Subject: [PATCH 011/114] Formal verification. Lesson 46. Fixed typo --- .../1-horse-store/46-a-note-on-your-new-powers/+page.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 4abdd89b2..4e04f7cef 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 @@ -36,7 +36,7 @@ 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! ```js -contructor payable () {} +constructor() payable {} ``` >**Note:** Just because it saves gas, doesn't mean it's the best choice. The msg.value check brings some valuable security functionality such as not accidentally locking a bunch of funds on contract creation. Consider your optimizations carefully! From 6dc8c9373a39c2ae65ad2ff5a3bfa247c67f47d2 Mon Sep 17 00:00:00 2001 From: Luigi Date: Wed, 25 Sep 2024 19:39:20 -0700 Subject: [PATCH 012/114] Fix typos and formatting --- .../solidity/3-fund-me/15-safemath/+page.md | 14 +++++----- .../18-sending-eth-from-a-contract/+page.md | 9 ++++--- .../3-fund-me/19-constructor/+page.md | 10 +++---- courses/solidity/3-fund-me/2-setup/+page.md | 2 +- .../solidity/3-fund-me/20-modifiers/+page.md | 6 ++--- .../3-fund-me/23-custom-errors/+page.md | 6 ++--- .../3-fund-me/24-receive-fallback/+page.md | 26 ++++++++++--------- .../3-fund-me/25-zksync-plugin-fix/+page.md | 6 ++--- .../3-fund-me/26-deploying-to-zksync/+page.md | 20 +++++++------- .../27-recap-congratulations/+page.md | 2 +- 10 files changed, 52 insertions(+), 49 deletions(-) diff --git a/courses/solidity/3-fund-me/15-safemath/+page.md b/courses/solidity/3-fund-me/15-safemath/+page.md index 34027141b..bda65701f 100644 --- a/courses/solidity/3-fund-me/15-safemath/+page.md +++ b/courses/solidity/3-fund-me/15-safemath/+page.md @@ -14,7 +14,7 @@ In this lesson, we will explore `SafeMath`, a widely used library before Solidit Let's begin by creating a new file called `SafeMathTester.sol` and adding a function `add` that increments the `bigNumber` state variable. -```js +```solidity // SafeMathTester.sol pragma solidity ^0.6.0; @@ -22,7 +22,7 @@ contract SafeMathTester { uint8 public bigNumber = 255; function add() public { - bigNumber = bigNumber + 1; + bigNumber = bigNumber + 1; } } ``` @@ -35,7 +35,7 @@ Before Solidity version **0.8.0**, signed and unsigned integers were **unchecked `SafeMath.sol` provided a mechanism to revert transactions when the maximum limit of a `uint256` data type was reached. It was a typical security measure across contracts to avoid erroneous calculations and potential exploits. -```js +```solidity function add(uint a, uint b) public pure returns (uint) { uint c = a + b; require(c >= a, "SafeMath: addition overflow"); @@ -49,13 +49,13 @@ With the introduction of Solidity version 0.8, automatic checks for overflows an For scenarios where mathematical operations are known not to exceed a variable's limit, Solidity introduced the `unchecked` construct to make code more _gas-efficient_. Wrapping the addition operation with `unchecked` will _ignore the overflow and underflow checks_: if the `bigNumber` exceeds the limit, it will wrap its value to zero. -```js +```solidity uint8 public bigNumber = 255; function add() public { unchecked { - bigNumber = bigNumber + 1; - } + bigNumber = bigNumber + 1; + } } ``` @@ -70,6 +70,6 @@ The evolution of Solidity and `SafeMath.sol` highlights the continuous advanceme 1. 📕 Why was the `SafeMath` library widely used before version 0.8? 2. 📕 Explain the meaning of integer overflow and integer underflow. Make an example using `uint16`. -3. 📕 What happened after solidity version 0.8? +3. 📕 What happened after Solidity version 0.8? 4. 📕 What is the unchecked construct? 5. 🧑‍💻 Modify the `SafeMathTester` contract by using the SafeMath library to prevent integer overflow. diff --git a/courses/solidity/3-fund-me/18-sending-eth-from-a-contract/+page.md b/courses/solidity/3-fund-me/18-sending-eth-from-a-contract/+page.md index 8f83a0262..7717fdbfe 100644 --- a/courses/solidity/3-fund-me/18-sending-eth-from-a-contract/+page.md +++ b/courses/solidity/3-fund-me/18-sending-eth-from-a-contract/+page.md @@ -12,7 +12,7 @@ This lesson explores three different methods of sending ETH from one account to The `transfer` function is the simplest way to send Ether to a recipient address: -```js +```solidity payable(msg.sender).transfer(amount); // the current contract sends the Ether amount to the msg.sender ``` @@ -24,7 +24,7 @@ However, `transfer` has a significant limitation. It can only use up to 2300 gas The `send` function is similar to `transfer`, but it differs in its behaviour: -```js +```solidity bool success = payable(msg.sender).send(address(this).balance); require(success, "Send failed"); ``` @@ -35,7 +35,7 @@ Like `transfer`, `send` also has a gas limit of 2300. If the gas limit is reache The `call` function is flexible and powerful. It can be used to call any function **without requiring its ABI**. It does not have a gas limit, and like `send`, it returns a boolean value instead of reverting like `transfer`. -```js +```solidity (bool success, ) = payable(msg.sender).call{value: address(this).balance}(""); require(success, "Call failed"); ``` @@ -44,7 +44,8 @@ To send funds using the `call` function, we convert the address of the receiver The `call` function returns two variables: a boolean for success or failure, and a byte object which stores returned data if any. -> 👀❗**IMPORTANT**:br > `call` is the recommended way of sending and receiving Ethereum or other blockchain native tokens. +> 👀❗**IMPORTANT**:br +> `call` is the recommended way of sending and receiving Ethereum or other blockchain native tokens. ### Conclusion diff --git a/courses/solidity/3-fund-me/19-constructor/+page.md b/courses/solidity/3-fund-me/19-constructor/+page.md index c77c2065f..11f69eb72 100644 --- a/courses/solidity/3-fund-me/19-constructor/+page.md +++ b/courses/solidity/3-fund-me/19-constructor/+page.md @@ -16,7 +16,7 @@ One solution could be to create a function, `callMeRightAway`, to assign the rol A more efficient solution is to use a **constructor** function: -```js +```solidity constructor() {} ``` @@ -29,7 +29,7 @@ The constructor function is automatically called during contract deployment, wit We can use the constructor to set the contract's owner immediately after deployment: -```js +```solidity address public owner; constructor() { owner = msg.sender; @@ -42,14 +42,14 @@ Here, we initialize the state variable `owner` with the contract deployer's addr The next step is to update the `withdraw` function to ensure it can only be called by the owner: -```js +```solidity function withdraw() public { require(msg.sender == owner, "must be owner"); - // rest of the function here + // rest of the function here } ``` -Before executing any withdrawal actions, we check that `msg.sender` is the owner. If the caller is not the owner, the operation **reverts** with the error message "must be the owner." This access restriction ensures that only the intended account can execute the function. +Before executing any withdrawal actions, we check that `msg.sender` is the owner. If the caller is not the owner, the operation **reverts** with the error message "must be the owner" This access restriction ensures that only the intended account can execute the function. ### Conclusion diff --git a/courses/solidity/3-fund-me/2-setup/+page.md b/courses/solidity/3-fund-me/2-setup/+page.md index 0d2ebed1e..93ca9ff3b 100644 --- a/courses/solidity/3-fund-me/2-setup/+page.md +++ b/courses/solidity/3-fund-me/2-setup/+page.md @@ -38,7 +38,7 @@ The FundMe contract will have two primary functions that serve as the main inter First, let's code the `fund` function and leave the `withdraw` function commented out for the moment. -```js +```solidity contract FundMe { // send funds into our contract function fund() public {} diff --git a/courses/solidity/3-fund-me/20-modifiers/+page.md b/courses/solidity/3-fund-me/20-modifiers/+page.md index df64acd0d..fbc331f8a 100644 --- a/courses/solidity/3-fund-me/20-modifiers/+page.md +++ b/courses/solidity/3-fund-me/20-modifiers/+page.md @@ -12,7 +12,7 @@ In this lesson, we will explore **modifiers** and how they can simplify code wri If we build a contract with multiple _administrative functions_, that should only be executed by the contract owner, we might repeatedly check the caller identity: -```js +```solidity require(msg.sender == owner, "Sender is not owner"); ``` @@ -24,7 +24,7 @@ Modifiers in Solidity allow embedding **custom lines of code** within any functi Here's how to create a modifier: -```js +```solidity modifier onlyOwner { require(msg.sender == owner, "Sender is not owner"); _; @@ -40,7 +40,7 @@ The underscore `_` placed in the body is a placeholder for the modified function For example, the `onlyOwner` modifier can be applied to the `withdraw` function like this: -```js +```solidity function withdraw(uint amount) public onlyOwner { // Function logic } diff --git a/courses/solidity/3-fund-me/23-custom-errors/+page.md b/courses/solidity/3-fund-me/23-custom-errors/+page.md index eb1a82a72..f9acf9c8a 100644 --- a/courses/solidity/3-fund-me/23-custom-errors/+page.md +++ b/courses/solidity/3-fund-me/23-custom-errors/+page.md @@ -18,15 +18,15 @@ Introduced in **Solidity 0.8.4**, custom errors can be used in `revert` statemen We can start by creating a custom error: -```js +```solidity error NotOwner(); ``` Then, we can replace the `require` function with an `if` statement, using the `revert` function with the newly created error: -```js +```solidity if (msg.sender != i_owner) { - revert NotOwner(); + revert NotOwner(); } ``` diff --git a/courses/solidity/3-fund-me/24-receive-fallback/+page.md b/courses/solidity/3-fund-me/24-receive-fallback/+page.md index 532fcbe1b..0eafba46d 100644 --- a/courses/solidity/3-fund-me/24-receive-fallback/+page.md +++ b/courses/solidity/3-fund-me/24-receive-fallback/+page.md @@ -14,7 +14,7 @@ In Solidity, if Ether is sent to a contract without a `receive` or `fallback` fu To illustrate, let's create a simple contract: -```js +```solidity //SPDX-License-Identifier: MIT pragma solidity ^0.8.7; @@ -33,22 +33,24 @@ contract FallbackExample { In this contract, `result` is initialized to zero. When Ether is sent to the contract, the `receive` function is triggered, setting `result` to one. If a transaction includes **data** but the specified function _does not exist_, the `fallback` function will be triggered, setting `result` to two. For a comprehensive explanation, refer to [SolidityByExample](https://solidity-by-example.org/fallback/). -// Ether is sent to the contract -// is msg.data empty? -// / \ -// yes no -// / \ -// receive() ? fallback() -// / \ -// yes no -// / \ -// receive() fallback() +```text +// Ether is sent to contract +// is msg.data empty? +// / \ +// yes no +// / \ +// receive()? fallback() +// / \ +// yes no +// / \ +//receive() fallback() +``` ### Sending Ether to fundMe When a user sends Ether **directly** to the `fundMe` contract without calling the `fund` function, the `receive` function can be used to _redirect_ the transaction to the `fund` function: -```js +```solidity receive() external payable { fund(); } diff --git a/courses/solidity/3-fund-me/25-zksync-plugin-fix/+page.md b/courses/solidity/3-fund-me/25-zksync-plugin-fix/+page.md index e3af272f4..ba0b91f0d 100644 --- a/courses/solidity/3-fund-me/25-zksync-plugin-fix/+page.md +++ b/courses/solidity/3-fund-me/25-zksync-plugin-fix/+page.md @@ -1,13 +1,13 @@ --- -title: zkSync Plugin Fix +title: ZKsync Plugin Fix --- _Follow along with the video_ --- -### zkSync Remix plugin minor bug +### ZKsync Remix plugin minor bug -As we saw in the _Simple Storage_ section, there is a small bug in the Remix zkSync module. After a successful compilation, the deploy tab will still display the message _`no smart contracts ready for deployment`_. +As we saw in the _Simple Storage_ section, there is a small bug in the Remix ZKsync module. After a successful compilation, the deploy tab will still display the message _`no smart contracts ready for deployment`_. This issue arises due to a small bug in the plugin, which requires your smart contracts to be inside a **`contracts` folder**. To resolve this, you can create a new folder named 'contracts' and move your smart contract into it. You can then proceed to compile the contract again, and you should be able to deploy it without any issues. diff --git a/courses/solidity/3-fund-me/26-deploying-to-zksync/+page.md b/courses/solidity/3-fund-me/26-deploying-to-zksync/+page.md index daf871c74..93a030b1b 100644 --- a/courses/solidity/3-fund-me/26-deploying-to-zksync/+page.md +++ b/courses/solidity/3-fund-me/26-deploying-to-zksync/+page.md @@ -1,5 +1,5 @@ --- -title: deploying FundMe to zkSync +title: deploying FundMe to ZKsync --- _Follow along with the video_ @@ -8,21 +8,21 @@ _Follow along with the video_ ### Introduction -In this lesson, we'll walk through the steps to deploy the `FundMe` contract to the zkSync testnet. +In this lesson, we'll walk through the steps to deploy the `FundMe` contract to the ZKsync testnet. -### Adjustments for zkSync +### Adjustments for ZKsync -First, we'll need the specific the correct **price feed address** for the skSync Sepolia chain, which you can find in the [Chainlink documentation](https://docs.chain.link/data-feeds/price-feeds/addresses?network=zksync&page=1). Each chain has its own unique addresses, and the ETH/USD address for the zkSync Sepolia testnet will differ from the one on Sepolia. +First, we'll need the specific the correct **price feed address** for the ZKsync Sepolia chain, which you can find in the [Chainlink documentation](https://docs.chain.link/data-feeds/price-feeds/addresses?network=zksync&page=1). Each chain has its own unique addresses, and the ETH/USD address for the ZKsync Sepolia testnet will differ from the one on Sepolia. -Then copy the zkSync Sepolia testnet ETH/USD address and replace the existing address in the `FundMe::getVersion` and `PriceConverter::getPrice` functions: +Then, copy the ZKsync Sepolia testnet ETH/USD address and replace the existing address in the `FundMe::getVersion` and `PriceConverter::getPrice` functions: -```js -AggregatorV3Interface priceFeed = AggregatorV3Interface(0xfEefF7c3fB57d18C5C6Cdd71e45D2D0b4F9377bF); // Add ETH/USD zkSync Sepolia address here +```solidity +AggregatorV3Interface priceFeed = AggregatorV3Interface(0xfEefF7c3fB57d18C5C6Cdd71e45D2D0b4F9377bF); // Add ETH/USD ZKsync Sepolia address here ``` -Since the zkSync plugin may not handle libraries well yet, you can copy the library code directly into your contract instead of importing it. +Since the ZKsync plugin may not handle libraries well yet, you can copy the library code directly into your contract instead of importing it. -It's recommended using the correct version of the Solidity compiler by updating it to version `0.8.24` for zkSync compatibility. +It's recommended using the correct version of the Solidity compiler by updating it to version `0.8.24` for ZKsync compatibility. ### Deploying the Contract @@ -30,4 +30,4 @@ In the Environment tab, you can connect your MetaMask wallet and then **deploy a ### Conclusion -Deploying the `FundMe` contract to the zkSync testnet involves a few key steps. First, adjust the price feed addresses and handle the library code correctly and make sure you're using the correct version of the Solidity compiler. Then you are ready to connect the MetaMask wallet to remix zkSync module and deploy the contract. Finally, you can verify that everything is working as expected by calling the contract functions in the [zkSync block explorer](https://sepolia.explorer.zksync.io/). +Deploying the `FundMe` contract to the ZKsync testnet involves a few key steps. First, adjust the price feed addresses and handle the library code correctly and make sure you're using the correct version of the Solidity compiler. Then you are ready to connect the MetaMask wallet to Remix ZKsync module and deploy the contract. Finally, you can verify that everything is working as expected by calling the contract functions in the [ZKsync block explorer](https://sepolia.explorer.zksync.io/). diff --git a/courses/solidity/3-fund-me/27-recap-congratulations/+page.md b/courses/solidity/3-fund-me/27-recap-congratulations/+page.md index 544f89e94..995598c46 100644 --- a/courses/solidity/3-fund-me/27-recap-congratulations/+page.md +++ b/courses/solidity/3-fund-me/27-recap-congratulations/+page.md @@ -14,7 +14,7 @@ We have encountered the special functions `receive`, `fallback`, and `constructo To save gas, Solidity provides keywords like `constant` and `immutable` for variables that can only be set once: -```js +```solidity uint constant minimumUSD = 50 * 1e18; ``` From 805040e2973c8d47363bbbba0858746c7f99f4a7 Mon Sep 17 00:00:00 2001 From: Luigi Date: Thu, 26 Sep 2024 12:57:23 -0700 Subject: [PATCH 013/114] Fix typos --- .../+page.md | 2 +- .../+page.md | 4 ++-- .../+page.md | 2 +- .../+page.md | 4 ++-- .../17-what-is-a-transaction/+page.md | 2 +- .../+page.md | 4 ++-- .../21-deploying-to-a-testnet/+page.md | 2 +- .../24-foundry-zksync/+page.md | 18 +++++++++--------- .../25-compiling-foundry-zksync/+page.md | 4 ++-- .../26-zksync-local-node/+page.md | 16 ++++++++-------- .../27-zksync-local-deploy/+page.md | 8 ++++---- .../28-tx-types/+page.md | 14 +++++++------- .../29-why-l2/+page.md | 12 ++++++------ .../30-alchemy-mempool/+page.md | 6 +++--- .../+page.md | 2 +- 15 files changed, 50 insertions(+), 50 deletions(-) diff --git a/courses/foundry/1-foundry-simple-storage/1-introduction-foundry-simple-storage/+page.md b/courses/foundry/1-foundry-simple-storage/1-introduction-foundry-simple-storage/+page.md index a4c0e9a8a..60dff1b1a 100644 --- a/courses/foundry/1-foundry-simple-storage/1-introduction-foundry-simple-storage/+page.md +++ b/courses/foundry/1-foundry-simple-storage/1-introduction-foundry-simple-storage/+page.md @@ -10,7 +10,7 @@ _Follow along with this video:_ Welcome to Foundry 101. Throughout this course, you will acquire the skills you’ll need to start developing your smart contracts and protocols using the best web3 development tools and frameworks like **_Chainlink_**, **_Alchemy_**, and **_Foundry_**. -### What is foundry? +### What is Foundry? Foundry is a relatively new but rapidly growing smart contract development framework known for its efficiency and modularity. The best short description of this powerful tool can be found in the [Foundry Book](https://book.getfoundry.sh/): 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 5cd3ce293..18c8453fe 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 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): 1. Click the account selector at the top of your wallet. @@ -90,4 +90,4 @@ Great! Now that we configured our local network, the next step is to add one of **NOTE: Do not use this account for anything else, do not interact with it or send things to it on mainnet or any other real blockchain, use it locally, for testing purposes. Everyone has access to it.** -Next up we shall talk more about adding a new network to Metamask. +Next up we shall talk more about adding a new network to MetaMask. diff --git a/courses/foundry/1-foundry-simple-storage/13-how-to-add-a-new-network-to-metamask/+page.md b/courses/foundry/1-foundry-simple-storage/13-how-to-add-a-new-network-to-metamask/+page.md index 6a35478e3..2e69eac1b 100644 --- a/courses/foundry/1-foundry-simple-storage/13-how-to-add-a-new-network-to-metamask/+page.md +++ b/courses/foundry/1-foundry-simple-storage/13-how-to-add-a-new-network-to-metamask/+page.md @@ -8,7 +8,7 @@ _Follow along with this video:_ ### Adding New Networks Using MetaMask -Conveniently, MetaMask provides an easy way to add EVM-compatible chains. By pre-configuring a host of them, you can add a chain such as the Arbitram One by simply clicking on the `Networks` button on the top left, then `Add Network` and proceeding to `Add`. The pleasing part is that MetaMask does all the grunt work, filling in all the necessary information for you. A click on Approve Network ensures the successful addition of the network. +Conveniently, MetaMask provides an easy way to add EVM-compatible chains. By pre-configuring a host of them, you can add a chain such as the Arbitrum One by simply clicking on the `Networks` button on the top left, then `Add Network` and proceeding to `Add`. The pleasing part is that MetaMask does all the grunt work, filling in all the necessary information for you. A click on Approve Network ensures the successful addition of the network. Steps: diff --git a/courses/foundry/1-foundry-simple-storage/16-deploy-a-smart-contract-locally-using-anvil/+page.md b/courses/foundry/1-foundry-simple-storage/16-deploy-a-smart-contract-locally-using-anvil/+page.md index e7ab0f4af..8717a68be 100644 --- a/courses/foundry/1-foundry-simple-storage/16-deploy-a-smart-contract-locally-using-anvil/+page.md +++ b/courses/foundry/1-foundry-simple-storage/16-deploy-a-smart-contract-locally-using-anvil/+page.md @@ -26,7 +26,7 @@ Open the newly created file. Here we'll write a solidity script for deploying ou Type the following: -```javaScript +```solidity // SPDX-License-Identifier: MIT pragma solidity 0.8.19; @@ -46,7 +46,7 @@ For it to be considered a Foundry script and to be able to access the extended f Furthermore, to be able to deploy `SimpleStorage` we also need to import it by typing `import {SimpleStorage} from "../src/SimpleStorage.sol";` -```javaScript +```solidity // SPDX-License-Identifier: MIT pragma solidity 0.8.19; diff --git a/courses/foundry/1-foundry-simple-storage/17-what-is-a-transaction/+page.md b/courses/foundry/1-foundry-simple-storage/17-what-is-a-transaction/+page.md index 61652b8c7..2ae821403 100644 --- a/courses/foundry/1-foundry-simple-storage/17-what-is-a-transaction/+page.md +++ b/courses/foundry/1-foundry-simple-storage/17-what-is-a-transaction/+page.md @@ -53,4 +53,4 @@ There are other values that play an important part that weren't presented in tha Whenever we send a transaction over the blockchain there's a signature happening, that's where we use our `private key`. -**Important:** Every time you change the state of the blockchain you do it using a transaction. The thing that indicates the change is the `data` field of a transaction. Deployment bytecode, contract bytecode and OPCODEs will be tackled in a future lesson. \ No newline at end of file +**Important:** Every time you change the state of the blockchain you do it using a transaction. The thing that indicates the change is the `data` field of a transaction. Deployment bytecode, contract bytecode and OPCODEs will be tackled in a future lesson. diff --git a/courses/foundry/1-foundry-simple-storage/18-important-private-key-safety-pt-2/+page.md b/courses/foundry/1-foundry-simple-storage/18-important-private-key-safety-pt-2/+page.md index 8ae322614..251c30c62 100644 --- a/courses/foundry/1-foundry-simple-storage/18-important-private-key-safety-pt-2/+page.md +++ b/courses/foundry/1-foundry-simple-storage/18-important-private-key-safety-pt-2/+page.md @@ -18,7 +18,7 @@ Having our private key in plain text is very bad, as we've explained in [Lesson **BIG BOLDED DISCLAIMER: What we are about to do is fine for development purposes, do not put a real key here, it very terrible for production purposes.** -Create a new file in the root of your project called `.env`. Then go the the `.gitignore` file and make sure `.env` is in there. +Create a new file in the root of your project called `.env`. Then, go the `.gitignore` file and make sure `.env` is in there. The `.env` file will host environment variables. Variables that are of a sensitive nature that we don't want to expose in public. @@ -50,4 +50,4 @@ Let's agree to the following: 1. For testing purposes use a `$PRIVATE_KEY` in an `.env` file as long as you don't expose that `.env` file anywhere. 2. Where real money is involved use the `--interactive` option or a [keystore file protected by a password](https://github.com/Cyfrin/foundry-full-course-f23?tab=readme-ov-file#can-you-encrypt-a-private-key---a-keystore-in-foundry-yet). -There's one more thing about storing keys in a `.env` file. Please take a look at the ["THE .ENV PLEDGE"](https://github.com/Cyfrin/foundry-full-course-f23/discussions/5). Read it, understand it and comment `I WILL BE SAFE`. Tweet it, Tiktok it, blog about it, make an Insta story about it, print it and put it on your fridge and share some copies with your neighbors. Please stay safe! \ No newline at end of file +There's one more thing about storing keys in a `.env` file. Please take a look at the ["THE .ENV PLEDGE"](https://github.com/Cyfrin/foundry-full-course-f23/discussions/5). Read it, understand it and comment `I WILL BE SAFE`. Tweet it, Tiktok it, blog about it, make an Insta story about it, print it and put it on your fridge and share some copies with your neighbors. Please stay safe! 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 d89c24df0..ef4e1332d 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 @@ -12,7 +12,7 @@ _Follow along the course with this video._ Hi, everyone! Are you curious about what your contract would look like on a testnet or a live network? If so, buckle up because this blog post will cover exactly that! We'll walk through the process of updating our Environment Variable (.env) file for an actual testnet. -Clearly, we need an actual testnet for a real network. But our trusty Metamask has built-in Infura connections that are incompatible. Why? Because they're tailored specifically for MetaMask. Hence, we need our own Remote Procedure Call (RPC) URL. +Clearly, we need an actual testnet for a real network. But our trusty MetaMask has built-in Infura connections that are incompatible. Why? Because they're tailored specifically for MetaMask. Hence, we need our own Remote Procedure Call (RPC) URL. ## Creating our Own RPC URL for a Testnet diff --git a/courses/foundry/1-foundry-simple-storage/24-foundry-zksync/+page.md b/courses/foundry/1-foundry-simple-storage/24-foundry-zksync/+page.md index b88fbea39..accf8bb0f 100644 --- a/courses/foundry/1-foundry-simple-storage/24-foundry-zksync/+page.md +++ b/courses/foundry/1-foundry-simple-storage/24-foundry-zksync/+page.md @@ -1,16 +1,16 @@ --- -title: Foundry zkSync +title: Foundry ZKsync --- _Follow along with the video_ --- -In this lesson, we'll explore Layer 2 deployment on ZK Sync, which involves a different compilation method compared to Ethereum. This difference arises because ZK Sync uses unique opcodes. While Solidity code behaves similarly on both platforms, the low-level outputs generated by Foundry in the `/out` folder will not be entirely compatible with the ZK Sync VM. +In this lesson, we'll explore Layer 2 deployment on ZKsync, which involves a different compilation method compared to Ethereum. This difference arises because ZKsync uses unique opcodes. While Solidity code behaves similarly on both platforms, the low-level outputs generated by Foundry in the `/out` folder will not be entirely compatible with the ZKsync VM. -### Foundry zkSync +### Foundry ZKsync -To get started with zkSync, we will follow these three steps: +To get started with ZKsync, we will follow these three steps: 1. 🛠️ Install `foundry-zksync` 2. 🧑‍💻 Compile the Solidity contract with the `--zksync` flag @@ -19,16 +19,16 @@ To get started with zkSync, we will follow these three steps: > 👀❗**IMPORTANT**:br > Installing `foundry-zksync` will override any existing Foundry binaries, such as `forge` and `cast`. -The GitHub resources for this course contain a link to the [Foundry zkSync repository](https://github.com/Cyfrin/foundry-full-course-cu?tab=readme-ov-file#compiling-to-zksync-in-foundry-zksync). `foundry-zksync` is a fork of Foundry tailored for the zkSync environment. The [repository](https://github.com/matter-labs/foundry-zksync) includes quick install instructions to help you set up the tool. +The GitHub resources for this course contain a link to the [Foundry ZKsync repository](https://github.com/Cyfrin/foundry-full-course-cu?tab=readme-ov-file#compiling-to-zksync-in-foundry-zksync). `foundry-zksync` is a fork of Foundry tailored for the ZKsync environment. The [repository](https://github.com/matter-labs/foundry-zksync) includes quick install instructions to help you set up the tool. -- First, clone the Foundry zkSync repository in a different directory from your Foundry project. Use the `git clone` command to clone the repository locally on your computer. +- First, clone the Foundry ZKsync repository in a different directory from your Foundry project. Use the `git clone` command to clone the repository locally on your computer. -- Once cloned, navigate to the created Foundry zkSync directory and run the installation command: +- Once cloned, navigate to the created Foundry ZKsync directory and run the installation command: ``` ./install-foundry-zksync ``` - This command requires a Unix-like environment, such as WSL on Windows, or a Mac or Linux system. After running the command, verify the installation by checking the version with `forge --version`. A different version number will indicate the successful installation of Foundry ZK Sync. + This command requires a Unix-like environment, such as WSL on Windows, or a Mac or Linux system. After running the command, verify the installation by checking the version with `forge --version`. A different version number will indicate the successful installation of Foundry ZKsync. -- To keep your environment flexible, you can switch to Foundry zkSync by running `foundryup-zksync`. After using it, it's recommended to switch back to Vanilla Foundry by running the `foundryup` command. This removes ZK Sync-specific flags and settings, allowing you to easily toggle between Foundry ZK Sync and Vanilla Foundry as needed. +- To keep your environment flexible, you can switch to Foundry ZKsync by running `foundryup-zksync`. After using it, it's recommended to switch back to Vanilla Foundry by running the `foundryup` command. This removes ZKsync-specific flags and settings, allowing you to easily toggle between Foundry ZKsync and Vanilla Foundry as needed. diff --git a/courses/foundry/1-foundry-simple-storage/25-compiling-foundry-zksync/+page.md b/courses/foundry/1-foundry-simple-storage/25-compiling-foundry-zksync/+page.md index fc10d1873..f0b153665 100644 --- a/courses/foundry/1-foundry-simple-storage/25-compiling-foundry-zksync/+page.md +++ b/courses/foundry/1-foundry-simple-storage/25-compiling-foundry-zksync/+page.md @@ -1,11 +1,11 @@ --- -title: Compiling foundry zkSync +title: Compiling foundry ZKsync --- _Follow along with the video_ --- -> Previously, when we ran the `forge build` command, it generated an `/out` folder in the root project directory. This folder contains all the compilation details related the Ethereum Virtual Machine (EVM) and Vanilla Foundry. To compile for the zkSync chain instead, we use the command `forge build --zk-sync`. This comand creates a new folder in our project root called `/zk-out`, and contains all the compiled code compatible to the zkSync Era VM. +> Previously, when we ran the `forge build` command, it generated an `/out` folder in the root project directory. This folder contains all the compilation details related the Ethereum Virtual Machine (EVM) and Vanilla Foundry. To compile for the ZKsync chain instead, we use the command `forge build --zk-sync`. This command creates a new folder in our project root called `/zk-out`, and contains all the compiled code compatible to the ZKsync Era VM. If we need to revert to vanilla Foundry for deployment on the EVM, we simply run the command `foundryup` and then use `forge build`, which builds a standard Foundry project. Unless otherwise specified, we should continue using this method. diff --git a/courses/foundry/1-foundry-simple-storage/26-zksync-local-node/+page.md b/courses/foundry/1-foundry-simple-storage/26-zksync-local-node/+page.md index 80a21f1fd..dc382defa 100644 --- a/courses/foundry/1-foundry-simple-storage/26-zksync-local-node/+page.md +++ b/courses/foundry/1-foundry-simple-storage/26-zksync-local-node/+page.md @@ -1,5 +1,5 @@ --- -title: zkSync Setting up Local Node +title: ZKsync Setting up Local Node --- _Follow along with the video_ @@ -11,27 +11,27 @@ _Follow along with the video_ > 👀❗**IMPORTANT**:br > This lesson is optional. If you encounter difficulties installing or understanding the required tools, feel free to proceed to the next section and continue using Anvil to test your smart contract locally. -In the previous lessons, we learned about deploying smart contracts with the `forge create` and `forge script` commands on our **local Anvil chain**. In this lesson, we will set up and run a **zkSync local environment**. +In the previous lessons, we learned about deploying smart contracts with the `forge create` and `forge script` commands on our **local Anvil chain**. In this lesson, we will set up and run a **ZKsync local environment**. ### Local Node Setup -To deploy locally on a zkSync local chain, you'll need additional tools: Docker, Node.js, and zksync-cli. +To deploy locally on a ZKsync local chain, you'll need additional tools: Docker, Node.js, and zksync-cli. 1. **Docker**: Start the [Docker](https://www.docker.com/) dooemon. On Mac OS, you can start it using the Docker application interface. On Linux, use commands like `sudo systemctl start docker` and `sudo systemctl stop docker` will manage Docker lifecycles. Verify the installation with `docker --version` and `docker ps` commands. 2. **Node.js and npm**: Install [Node.js](https://nodejs.org/en) and [npm](https://www.npmjs.com/). Follow the Node.js documentation to install the right version for your operating system. Verify the installations with `npm --version` and `node --version` commands. -3. **zksync-cli**: Once Docker and Node.js are installed, you can install the [zksync-cli](https://www.npmjs.com/package/zksync-cli) to manage your local zkSync development environment. Run `npx zksync-cli dev config` to set up your configuration. Choose the `in-memory` node option for a quick startup without persistent state and avoid additional options like a portal or block explorer unless you want to explore them independently. +3. **zksync-cli**: Once Docker and Node.js are installed, you can install the [zksync-cli](https://www.npmjs.com/package/zksync-cli) to manage your local ZKsync development environment. Run `npx zksync-cli dev config` to set up your configuration. Choose the `in-memory` node option for a quick startup without persistent state and avoid additional options like a portal or block explorer unless you want to explore them independently. -To start your local zkSync node, run `npx zksync-cli dev start`. This command spins up a zkSync node in Docker and runs it in the background. Verify the process is running with `docker ps`. +To start your local ZKsync node, run `npx zksync-cli dev start`. This command spins up a ZKsync node in Docker and runs it in the background. Verify the process is running with `docker ps`. > 🗒️ **NOTE**:br -> If Docker isn’t running, the `npx zksync-cli dev start` command will fail. Ensure Docker is running before attempting to start the zkSync node again. +> If Docker isn’t running, the `npx zksync-cli dev start` command will fail. Ensure Docker is running before attempting to start the ZKsync node again. ### Deployment -The zkSync deployment process is similar to previous deployments. We will use the same commands, but this time, we will append the `--zkSync` and `--legacy` flags. Note that the `forge script` command is not well supported in zkSync, so we will use `forge create` instead. +The ZKsync deployment process is similar to previous deployments. We will use the same commands, but this time, we will append the `--zksync` and `--legacy` flags. Note that the `forge script` command is not well supported in ZKsync, so we will use `forge create` instead. ### Conclusion -Setting up a local zkSync node involves a few additional tools, including Docker, Node.js, npm, and zksync-cli: they will help creating a robust zkSync development environment and allowing test and deployment of smart contracts on a zkSync local chain. +Setting up a local ZKsync node involves a few additional tools, including Docker, Node.js, npm, and zksync-cli: they will help creating a robust ZKsync development environment and allowing test and deployment of smart contracts on a ZKsync local chain. diff --git a/courses/foundry/1-foundry-simple-storage/27-zksync-local-deploy/+page.md b/courses/foundry/1-foundry-simple-storage/27-zksync-local-deploy/+page.md index 08b5baaf6..2d2ea270a 100644 --- a/courses/foundry/1-foundry-simple-storage/27-zksync-local-deploy/+page.md +++ b/courses/foundry/1-foundry-simple-storage/27-zksync-local-deploy/+page.md @@ -1,14 +1,14 @@ --- -title: zkSync Local Deployment +title: ZKsync Local Deployment --- _Follow along with the video_ --- -In this lesson, we are going to deploy the contract `SimpleStorage.sol` on a **zkSync local chain**. +In this lesson, we are going to deploy the contract `SimpleStorage.sol` on a **ZKsync local chain**. -We start by verifying that the Forge version we are using is correct. By running the `forge --version` command it confirms that we are on version 0.2: this indicates we are using the right Foundry zkSync edition. +We start by verifying that the Forge version we are using is correct. By running the `forge --version` command it confirms that we are on version 0.2: this indicates we are using the right Foundry ZKsync edition. Next, we proceed with creating a `SimpleStorage` contract using the command: @@ -16,7 +16,7 @@ Next, we proceed with creating a `SimpleStorage` contract using the command: forge create src/SimpleStorage.sol:SimpleStorage --rpc_url --private_key --legacy --zksync ``` -Here, `` represents zkSync node address, such as `http://127.0.0.1:8011`. +Here, `` represents ZKsync node address, such as `http://127.0.0.1:8011`. > 👀❗**IMPORTANT**:br > Including private keys directly in commands is not a safe practice. diff --git a/courses/foundry/1-foundry-simple-storage/28-tx-types/+page.md b/courses/foundry/1-foundry-simple-storage/28-tx-types/+page.md index bb0bbf9d7..b0763742c 100644 --- a/courses/foundry/1-foundry-simple-storage/28-tx-types/+page.md +++ b/courses/foundry/1-foundry-simple-storage/28-tx-types/+page.md @@ -8,29 +8,29 @@ _Follow along with the video_ ### Introduction -In this lesson, we will explore the different transaction types within the ZK Sync VM and EVM ecosystems. +In this lesson, we will explore the different transaction types within the ZKsync VM and EVM ecosystems. ### `/broadcast` Folder -When deploying to a zkSync local node, a `/broadcast` folder will be created and it will contain detailed information about the **deployment transactions**. Inside this folder, you will find subfolders named after specific deployment chain IDs, such as **`260`** for ZK Sync and **`31337`** for Anvil. These subfolders store the data of the transactions executed during the deployment process. +When deploying to a ZKsync local node, a `/broadcast` folder will be created and it will contain detailed information about the **deployment transactions**. Inside this folder, you will find subfolders named after specific deployment chain IDs, such as **`260`** for ZKsync and **`31337`** for Anvil. These subfolders store the data of the transactions executed during the deployment process. -By examining both the `run-latest.json` file in these folders, we can observe different **transaction types** for each transaction within a chain. For instance, transactions on the Anvil chain might be labeled as type **`0x2`**, while those on the zkSync chain will be of type ** `0x0`**. Deploying a smart contract on the EVM without the `--legacy` flag results in a default transaction type of `0x2`. Adding the `--legacy` flag changes it to type `0x0`. +By examining both the `run-latest.json` file in these folders, we can observe different **transaction types** for each transaction within a chain. For instance, transactions on the Anvil chain might be labeled as type **`0x2`**, while those on the ZKsync chain will be of type ** `0x0`**. Deploying a smart contract on the EVM without the `--legacy` flag results in a default transaction type of `0x2`. Adding the `--legacy` flag changes it to type `0x0`. -The EVM and ZK Sync ecosystems support multiple transaction types to accommodate various Ethereum Improvement Proposals (EIPs). Initially, Ethereum had only one transaction type (`0x0` legacy), but as the ecosystem evolved, multiple types were introduced through various EIPs. Subsequent types include type 1, which introduces an _access list_ of addresses and keys, and type 2, also known as [EIP 1559](https://eips.ethereum.org/EIPS/eip-1559) transactions. +The EVM and ZKsync ecosystems support multiple transaction types to accommodate various Ethereum Improvement Proposals (EIPs). Initially, Ethereum had only one transaction type (`0x0` legacy), but as the ecosystem evolved, multiple types were introduced through various EIPs. Subsequent types include type 1, which introduces an _access list_ of addresses and keys, and type 2, also known as [EIP 1559](https://eips.ethereum.org/EIPS/eip-1559) transactions. > 👀❗**IMPORTANT**:br > This `0x2` type is the current default type for the EVM. -Additionally, ZK Sync introduces its [unique transaction type](https://docs.zksync.io/zk-stack/concepts/transaction-lifecycle#eip-712-0x71), the type `113` (`0x71` in hex), which can enable features like [account abstraction](https://docs.zksync.io/build/developer-reference/account-abstraction/). +Additionally, ZKsync introduces its [unique transaction type](https://docs.zksync.io/zk-stack/concepts/transaction-lifecycle#eip-712-0x71), the type `113` (`0x71` in hex), which can enable features like [account abstraction](https://docs.zksync.io/build/developer-reference/account-abstraction/). > 💡 **TIP**:br > The `forge script` command will work in some scenarios, but it’s not entirely clear where it might fail. For the purpose of this course, we will assume scripting does not work while working with Sync. ### Resources -- [zkSync documentation](https://docs.zksync.io/zk-stack/concepts/transaction-lifecycle#transaction-types) about transaction types +- [ZKsync documentation](https://docs.zksync.io/zk-stack/concepts/transaction-lifecycle#transaction-types) about transaction types - [Cyfrin Blog on EIP-4844](https://www.cyfrin.io/blog/what-is-eip-4844-proto-danksharding-and-blob-transactions) ### Conclusion -The ZK Sync VM and EVM ecosystems support various transaction types to meet different EIP requirements. By examining deployment folders and understanding the use of flags like `--legacy`, we can effectively distinguish between these transaction types. +The ZKsync VM and EVM ecosystems support various transaction types to meet different EIP requirements. By examining deployment folders and understanding the use of flags like `--legacy`, we can effectively distinguish between these transaction types. diff --git a/courses/foundry/1-foundry-simple-storage/29-why-l2/+page.md b/courses/foundry/1-foundry-simple-storage/29-why-l2/+page.md index a4deee598..ceaa6b3fc 100644 --- a/courses/foundry/1-foundry-simple-storage/29-why-l2/+page.md +++ b/courses/foundry/1-foundry-simple-storage/29-why-l2/+page.md @@ -8,11 +8,11 @@ _Follow along with the video_ ### Introduction -In previous lessons, we deployed to the Sepolia testnet and started working with the Layer 2 solution ZK Sync. Deploying to Sepolia simulates deployment to the Ethereum mainnet, offering a comprehensive understanding of Layer 1 deployments. However, it's important to note that most projects today prefer deploying to Layer 2 solutions rather than directly to Ethereum due to the high costs associated with deployments. +In previous lessons, we deployed to the Sepolia testnet and started working with the Layer 2 solution ZKsync. Deploying to Sepolia simulates deployment to the Ethereum mainnet, offering a comprehensive understanding of Layer 1 deployments. However, it's important to note that most projects today prefer deploying to Layer 2 solutions rather than directly to Ethereum due to the high costs associated with deployments. ### Gas Usage -When deploying to a ZK Sync local node, a `/broadcast` folder is created, containing a lot of detailed deployment transaction information. For instance, in our `run-latest.json` file, we can see the `gasUsed` value and we can convert this hexadecimal number `0x5747A` to its decimal equivalent by typing `cast to base 0x5747A dec`. This conversion allows us to estimate the deployment cost on the Ethereum mainnet. By checking recent gas prices on Etherscan, we can calculate the total cost using the formula: +When deploying to a ZKsync local node, a `/broadcast` folder is created, containing a lot of detailed deployment transaction information. For instance, in our `run-latest.json` file, we can see the `gasUsed` value and we can convert this hexadecimal number `0x5747A` to its decimal equivalent by typing `cast to base 0x5747A dec`. This conversion allows us to estimate the deployment cost on the Ethereum mainnet. By checking recent gas prices on Etherscan, we can calculate the total cost using the formula: ``` Total Cost = Gas Used * Gas Price @@ -20,11 +20,11 @@ Total Cost = Gas Used * Gas Price We can see this total cost in the deployment transaction on [Sepolia Etherscan](https://sepolia.etherscan.io/tx/0xc496b9d30df33aa9285ddd384c14ce2a58eef470898b5cda001d0f4a21b017f6), under the `Transaction Fee` section. In this case, `357,498` gas will costs `0.000279288255846978` ETH, which today is equivalent to $7. -Deploying even a minimal contract like `SimpleStorage` on Ethereum can be expensive. Larger contracts, with thousands of lines of code, can cost thousands of dollars. This is why many developers prefer deploying to Layer 2 solutions like ZK Sync, which offer the same security as Ethereum but at a fraction of the cost. +Deploying even a minimal contract like `SimpleStorage` on Ethereum can be expensive. Larger contracts, with thousands of lines of code, can cost thousands of dollars. This is why many developers prefer deploying to Layer 2 solutions like ZKsync, which offer the same security as Ethereum but at a fraction of the cost. -### Deploying to ZK Sync Sepolia +### Deploying to ZKsync Sepolia -Deploying to ZK Sync Sepolia is similar to deploying to a ZK Sync local node. You can retrieve a ZK Sync Sepolia RPC URL from [Alchemy](https://www.alchemy.com/) by creating a new app based on the ZK Sepolia network. Then, you can proceed to add the `ZKSYNC_RPC_URL` to your `.env` configuration. +Deploying to ZKsync Sepolia is similar to deploying to a ZKsync local node. You can retrieve a ZKsync Sepolia RPC URL from [Alchemy](https://www.alchemy.com/) by creating a new app based on the ZKsepolia network. Then, you can proceed to add the `ZKSYNC_RPC_URL` to your `.env` configuration. > 🗒️ **NOTE**:br -> To understand the cost benefits of Layer 2 solutions, visit [L2Fees.info](https://l2fees.info) and compare the significant cost differences between sending a transaction on Ethereum and ZK Sync Era. +> To understand the cost benefits of Layer 2 solutions, visit [L2Fees.info](https://l2fees.info) and compare the significant cost differences between sending a transaction on Ethereum and ZKsync Era. diff --git a/courses/foundry/1-foundry-simple-storage/30-alchemy-mempool/+page.md b/courses/foundry/1-foundry-simple-storage/30-alchemy-mempool/+page.md index 61986c94d..03a1dcb3b 100644 --- a/courses/foundry/1-foundry-simple-storage/30-alchemy-mempool/+page.md +++ b/courses/foundry/1-foundry-simple-storage/30-alchemy-mempool/+page.md @@ -43,10 +43,10 @@ Once you have signed in, create a new application. Next, give your application a name and a description. Then, select a chain and network. Alchemy currently supports the majority of EVM-compatible chains, including: - Ethereum -- Polygon (POS) -- Zkevm +- Polygon PoS +- Polygon zkEVM - Optimism -- Astar +- Arbitrum - Solana (non-EVM chain) ## The Application-Specific Dashboard diff --git a/courses/foundry/1-foundry-simple-storage/9-create-a-new-foundry-project-wsl/+page.md b/courses/foundry/1-foundry-simple-storage/9-create-a-new-foundry-project-wsl/+page.md index e13dfc342..8753fcd6c 100644 --- a/courses/foundry/1-foundry-simple-storage/9-create-a-new-foundry-project-wsl/+page.md +++ b/courses/foundry/1-foundry-simple-storage/9-create-a-new-foundry-project-wsl/+page.md @@ -12,7 +12,7 @@ Hallo 👋🏻, I'm Vasily and I'll be your instructor for all Windows developme ### WSL setup -Microsoft has singificantly inproved its development environment support in recent years. However, for _smart contract development_, installing dependencies can sometimes be tricky. To streamline this process, we will use the **Windows Subsystem for Linux (WSL)**: this is a better option because it enables a full-fledged _unix-like console_ on your Windows machine, simplifying the use of tools and utilities commonly found in unix-based environments. This setup ensures compatibility with all the code that runs on unix-based systems like macOS and Linux. +Microsoft has significantly improved its development environment support in recent years. However, for _smart contract development_, installing dependencies can sometimes be tricky. To streamline this process, we will use the **Windows Subsystem for Linux (WSL)**: this is a better option because it enables a full-fledged _unix-like console_ on your Windows machine, simplifying the use of tools and utilities commonly found in unix-based environments. This setup ensures compatibility with all the code that runs on unix-based systems like macOS and Linux. To install WSL, you can begin by opening the Windows terminal. On Windows 11, press the Windows key, type "terminal," and hit `enter`. On Windows 10, you need to install the Windows terminal from the Microsoft Store (select the official app from Microsoft Corporation). From cf422e3e09f370d9ebdc404a051c374203e12885 Mon Sep 17 00:00:00 2001 From: Luigi Date: Fri, 27 Sep 2024 23:31:47 -0700 Subject: [PATCH 014/114] Fix typos and formatting --- .../+page.md | 2 +- .../15-important-private-key-safety-pt-1/+page.md | 4 ++-- .../+page.md | 14 +++++++------- .../+page.md | 2 +- .../+page.md | 6 +++--- .../23-cleaning-up-the-project/+page.md | 4 +++- .../26-zksync-local-node/+page.md | 2 +- .../1-foundry-simple-storage/28-tx-types/+page.md | 4 ++-- .../+page.md | 2 +- .../31-summary-congratulations/+page.md | 2 +- .../6-foundry-install/+page.md | 4 ++-- .../7-setup-your-vscode/+page.md | 12 +++++------- 12 files changed, 29 insertions(+), 29 deletions(-) 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 18c8453fe..bc9d5ae7c 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 @@ -21,7 +21,7 @@ You now have access to 10 test addresses funded with 10_000 ETH each, with their This testnet node always listens on `127.0.0.1:8545` this will be our `RPC_URL` parameter when we deploy smart contracts here. More on this later! -More info about Anvil is available [here](https://book.getfoundry.sh/reference/anvil/)](https://book.getfoundry.sh/reference/anvil/). +More info about Anvil is available [here](https://book.getfoundry.sh/reference/anvil/). Please press `Ctrl/CMD + C` to close Anvil. diff --git a/courses/foundry/1-foundry-simple-storage/15-important-private-key-safety-pt-1/+page.md b/courses/foundry/1-foundry-simple-storage/15-important-private-key-safety-pt-1/+page.md index d074cd50b..45cf0530f 100644 --- a/courses/foundry/1-foundry-simple-storage/15-important-private-key-safety-pt-1/+page.md +++ b/courses/foundry/1-foundry-simple-storage/15-important-private-key-safety-pt-1/+page.md @@ -36,8 +36,8 @@ Hacking private keys is one of the most important reasons people and projects lo [Early Crypto Investor Bo Shen Says He Lost $42 Million in Wallet Hack](https://www.bnnbloomberg.ca/early-crypto-investor-bo-shen-says-he-lost-42-million-in-wallet-hack-1.1850446) -[The $477 million FTX hack](https://www.elliptic.co/blog/the-477-million-ftx-hack-following-the-blockchain-trail) where `The new CEO of FTX revealed that private keys allowing access to the firm’s crypto assets were stored in unencrypted form, and a former employee disclosed that over $150 million was stolen from Alameda Research, due to poor security. ` +[The \$477 million FTX hack](https://www.elliptic.co/blog/the-477-million-ftx-hack-following-the-blockchain-trail) where `The new CEO of FTX revealed that private keys allowing access to the firm’s crypto assets were stored in unencrypted form, and a former employee disclosed that over $150 million was stolen from Alameda Research, due to poor security. ` Don't be like that! Maybe you are not holding millions, but what you hold is yours, don't let it become theirs! -In the following lessons, we'll learn how to access RPC URLs for free using Alchemy for any blockchain. e will also delve into exploring safer methodologies for dealing with private keys. Stay tuned! \ No newline at end of file +In the following lessons, we'll learn how to access RPC URLs for free using Alchemy for any blockchain. We will also delve into exploring safer methodologies for dealing with private keys. Stay tuned! diff --git a/courses/foundry/1-foundry-simple-storage/16-deploy-a-smart-contract-locally-using-anvil/+page.md b/courses/foundry/1-foundry-simple-storage/16-deploy-a-smart-contract-locally-using-anvil/+page.md index 8717a68be..f3106f2ce 100644 --- a/courses/foundry/1-foundry-simple-storage/16-deploy-a-smart-contract-locally-using-anvil/+page.md +++ b/courses/foundry/1-foundry-simple-storage/16-deploy-a-smart-contract-locally-using-anvil/+page.md @@ -31,7 +31,7 @@ Type the following: pragma solidity 0.8.19; -contract DeploySimpleStorage{ +contract DeploySimpleStorage { } ``` @@ -61,7 +61,7 @@ contract DeploySimpleStorage is Script { Every script needs a main function, which, according to the best practice linked above is called `run`. Whenever you run `forge script` this is the function that gets called. -``` +```solidity // SPDX-License-Identifier: MIT pragma solidity 0.8.19; @@ -98,7 +98,7 @@ We end the function with `return simpleStorage;`. Please select the `Anvil` terminal and press `CTRL(CMD) + C` to stop it. Now run the following command: -``` +```bash forge script script/DeploySimpleStorage.s.sol ``` @@ -108,7 +108,7 @@ If you want to further extend your knowledge about scripting please go [here](ht You should get the following output: -``` +```text [⠆] Compiling... [⠔] Compiling 2 files with 0.8.19 [⠒] Solc 0.8.19 finished in 1.08s @@ -128,13 +128,13 @@ If the RPC URL is not specified, Foundry automatically launches an Anvil instanc Run the `anvil` command in the terminal, open up a new terminal and type the following: -``` +```bash forge script script/DeploySimpleStorage.s.sol --rpc-url http://127.0.0.1:8545 ``` To get the following output: -``` +```text No files changed, compilation skipped EIP-3855 is not supported in one or more of the RPCs used. Unsupported Chain IDs: 31337. @@ -172,7 +172,7 @@ Our contract is now successfully deployed! Fantastic! Switch to the `anvil` terminal where you'll see: -``` +```text Transaction: 0x73eb9fb4ef7b159e03c50d669c42e2ec4eeaa9358bea0a710cb07168e5192570 Contract created: 0x5fbdb2315678afecb367f032d93f642f64180aa3 Gas used: 357088 diff --git a/courses/foundry/1-foundry-simple-storage/2-development-environment-setup-mac-linux/+page.md b/courses/foundry/1-foundry-simple-storage/2-development-environment-setup-mac-linux/+page.md index af7e09aa9..de6928b02 100644 --- a/courses/foundry/1-foundry-simple-storage/2-development-environment-setup-mac-linux/+page.md +++ b/courses/foundry/1-foundry-simple-storage/2-development-environment-setup-mac-linux/+page.md @@ -23,7 +23,7 @@ You can open up multiple terminals at the same time running different shells ran Use the `+` button to create a new terminal or the trash button to kill the current terminal. -Whether you are learning **foundry** for development work or security work, moving fast is one of the keys to efficiency. VS Code is very versatile in terms of keyboard shortcuts, you can learn more [here](https://code.visualstudio.com/docs/getstarted/keybindings). +Whether you are learning **Foundry** for development work or security work, moving fast is one of the keys to efficiency. VS Code is very versatile in terms of keyboard shortcuts, you can learn more [here](https://code.visualstudio.com/docs/getstarted/keybindings). ### Git installation diff --git a/courses/foundry/1-foundry-simple-storage/20-interact-with-a-smart-contract-using-the-cli/+page.md b/courses/foundry/1-foundry-simple-storage/20-interact-with-a-smart-contract-using-the-cli/+page.md index 7a3f8ba2b..308709c7c 100644 --- a/courses/foundry/1-foundry-simple-storage/20-interact-with-a-smart-contract-using-the-cli/+page.md +++ b/courses/foundry/1-foundry-simple-storage/20-interact-with-a-smart-contract-using-the-cli/+page.md @@ -14,7 +14,7 @@ Copy the contract address. ### Sending information to the blockchain -Foundry has an in-built tool known as `Cast`. `Cast` comes loaded with numerous commands to interact with. Learn more about them by typing `cast --help`. One such useful command is `send` which is designed to sign and publish a transaction. To view help about `send`, type `cast send --help`. +Foundry has a built-in tool known as `Cast`. `Cast` comes loaded with numerous commands to interact with. Learn more about them by typing `cast --help`. One such useful command is `send` which is designed to sign and publish a transaction. To view help about `send`, type `cast send --help`. To use `send` we need a signature and some arguments. @@ -37,7 +37,7 @@ Let's break it down: ### Reading information from the blockchain -`Cast` conveniently provides a way to read information stored on the blockchain. Type `cast call --help` in your terminal to find out more. It works similarly to `send`, where you have to provide a signature and some arguments. The difference is you are only peering into the storage, not modifying it. +`cast` conveniently provides a way to read information stored on the blockchain. Type `cast call --help` in your terminal to find out more. It works similarly to `send`, where you have to provide a signature and some arguments. The difference is you are only peering into the storage, not modifying it. Call the following command in your terminal: @@ -61,4 +61,4 @@ I recommend you play around and send multiple transactions with different number Awesome! We've learned something very valuable. You are going to use this more times than you can count. -**Up next:** Deploying a smart contract on Sepolia \ No newline at end of file +**Up next:** Deploying a smart contract on Sepolia diff --git a/courses/foundry/1-foundry-simple-storage/23-cleaning-up-the-project/+page.md b/courses/foundry/1-foundry-simple-storage/23-cleaning-up-the-project/+page.md index 9dcaeec22..7a00e1b6a 100644 --- a/courses/foundry/1-foundry-simple-storage/23-cleaning-up-the-project/+page.md +++ b/courses/foundry/1-foundry-simple-storage/23-cleaning-up-the-project/+page.md @@ -22,7 +22,7 @@ The `README.md` file is written in Markdown, which is a lightweight markup langu Here's an example of what you might include in your `README.md` file: -```markdown +````markdown # SimpleStorage This is a simple Solidity contract that stores a single uint256 value. @@ -58,3 +58,5 @@ We can preview our `README.md` file in VS Code by going to the `View` menu and s ### Using AI for Markdown Formatting If you find that formatting Markdown is a bit tedious, you can use an AI tool like ChatGPT to help you out. Just copy and paste the text you want to format into ChatGPT and ask it to format it in Markdown. It will do a pretty good job of converting your plain text into Markdown, and you can then review and edit it as needed. + +```` diff --git a/courses/foundry/1-foundry-simple-storage/26-zksync-local-node/+page.md b/courses/foundry/1-foundry-simple-storage/26-zksync-local-node/+page.md index dc382defa..fbf8cbf1c 100644 --- a/courses/foundry/1-foundry-simple-storage/26-zksync-local-node/+page.md +++ b/courses/foundry/1-foundry-simple-storage/26-zksync-local-node/+page.md @@ -17,7 +17,7 @@ In the previous lessons, we learned about deploying smart contracts with the `fo To deploy locally on a ZKsync local chain, you'll need additional tools: Docker, Node.js, and zksync-cli. -1. **Docker**: Start the [Docker](https://www.docker.com/) dooemon. On Mac OS, you can start it using the Docker application interface. On Linux, use commands like `sudo systemctl start docker` and `sudo systemctl stop docker` will manage Docker lifecycles. Verify the installation with `docker --version` and `docker ps` commands. +1. **Docker**: Start the [Docker](https://www.docker.com/) daemon. On Mac OS, you can start it using the Docker application interface. On Linux, use commands like `sudo systemctl start docker` and `sudo systemctl stop docker` will manage Docker lifecycles. Verify the installation with `docker --version` and `docker ps` commands. 2. **Node.js and npm**: Install [Node.js](https://nodejs.org/en) and [npm](https://www.npmjs.com/). Follow the Node.js documentation to install the right version for your operating system. Verify the installations with `npm --version` and `node --version` commands. diff --git a/courses/foundry/1-foundry-simple-storage/28-tx-types/+page.md b/courses/foundry/1-foundry-simple-storage/28-tx-types/+page.md index b0763742c..e1565ff20 100644 --- a/courses/foundry/1-foundry-simple-storage/28-tx-types/+page.md +++ b/courses/foundry/1-foundry-simple-storage/28-tx-types/+page.md @@ -14,7 +14,7 @@ In this lesson, we will explore the different transaction types within the ZKsyn When deploying to a ZKsync local node, a `/broadcast` folder will be created and it will contain detailed information about the **deployment transactions**. Inside this folder, you will find subfolders named after specific deployment chain IDs, such as **`260`** for ZKsync and **`31337`** for Anvil. These subfolders store the data of the transactions executed during the deployment process. -By examining both the `run-latest.json` file in these folders, we can observe different **transaction types** for each transaction within a chain. For instance, transactions on the Anvil chain might be labeled as type **`0x2`**, while those on the ZKsync chain will be of type ** `0x0`**. Deploying a smart contract on the EVM without the `--legacy` flag results in a default transaction type of `0x2`. Adding the `--legacy` flag changes it to type `0x0`. +By examining both the `run-latest.json` file in these folders, we can observe different **transaction types** for each transaction within a chain. For instance, transactions on the Anvil chain might be labeled as type **`0x2`**, while those on the ZKsync chain will be of type **`0x0`**. Deploying a smart contract on the EVM without the `--legacy` flag results in a default transaction type of `0x2`. Adding the `--legacy` flag changes it to type `0x0`. The EVM and ZKsync ecosystems support multiple transaction types to accommodate various Ethereum Improvement Proposals (EIPs). Initially, Ethereum had only one transaction type (`0x0` legacy), but as the ecosystem evolved, multiple types were introduced through various EIPs. Subsequent types include type 1, which introduces an _access list_ of addresses and keys, and type 2, also known as [EIP 1559](https://eips.ethereum.org/EIPS/eip-1559) transactions. @@ -24,7 +24,7 @@ The EVM and ZKsync ecosystems support multiple transaction types to accommodate Additionally, ZKsync introduces its [unique transaction type](https://docs.zksync.io/zk-stack/concepts/transaction-lifecycle#eip-712-0x71), the type `113` (`0x71` in hex), which can enable features like [account abstraction](https://docs.zksync.io/build/developer-reference/account-abstraction/). > 💡 **TIP**:br -> The `forge script` command will work in some scenarios, but it’s not entirely clear where it might fail. For the purpose of this course, we will assume scripting does not work while working with Sync. +> The `forge script` command will work in some scenarios, but it’s not entirely clear where it might fail. For the purpose of this course, we will assume scripting does not work while working with ZKsync. ### Resources diff --git a/courses/foundry/1-foundry-simple-storage/3-development-environment-setup-windows/+page.md b/courses/foundry/1-foundry-simple-storage/3-development-environment-setup-windows/+page.md index 0b87e8ff6..4863b1268 100644 --- a/courses/foundry/1-foundry-simple-storage/3-development-environment-setup-windows/+page.md +++ b/courses/foundry/1-foundry-simple-storage/3-development-environment-setup-windows/+page.md @@ -21,7 +21,7 @@ You can open up multiple terminals at the same time running different shells ran Use the `+` button to create a new terminal or the trash button to kill the current terminal. -Whether you are learning **foundry** for development work or security work, moving fast is one of the keys to efficiency. VS Code is very versatile in terms of keyboard shortcuts, you can learn more [here](https://code.visualstudio.com/docs/getstarted/keybindings). +Whether you are learning **Foundry** for development work or security work, moving fast is one of the keys to efficiency. VS Code is very versatile in terms of keyboard shortcuts, you can learn more [here](https://code.visualstudio.com/docs/getstarted/keybindings). ### What is WSL? diff --git a/courses/foundry/1-foundry-simple-storage/31-summary-congratulations/+page.md b/courses/foundry/1-foundry-simple-storage/31-summary-congratulations/+page.md index 049d80615..fdffe8891 100644 --- a/courses/foundry/1-foundry-simple-storage/31-summary-congratulations/+page.md +++ b/courses/foundry/1-foundry-simple-storage/31-summary-congratulations/+page.md @@ -28,7 +28,7 @@ We obtained practical knowledge on how to compile code in Foundry and write a So ## Understanding Contract Deployment and Interaction on the Blockchain -We delved into the automation of contract deployments to a blockchain. Post-deployment, we interacted with them using the `Cast` keyword and `send` to make transactions, then `Cast call` to read from those contracts. +We delved into the automation of contract deployments to a blockchain. Post-deployment, we interacted with them using the `cast` keyword and `send` to make transactions, then `cast call` to read from those contracts. Moreover, the knowledge on how to auto format contracts with `Forge format` was acquired. We also learnt the painstaking yet rewarding manual method of verifying our contracts on the blockchain. diff --git a/courses/foundry/1-foundry-simple-storage/6-foundry-install/+page.md b/courses/foundry/1-foundry-simple-storage/6-foundry-install/+page.md index 329355c91..2868dbb5a 100644 --- a/courses/foundry/1-foundry-simple-storage/6-foundry-install/+page.md +++ b/courses/foundry/1-foundry-simple-storage/6-foundry-install/+page.md @@ -36,7 +36,6 @@ The command would look something like this: ```bash curl -L https://foundry.paradigm.xyz | bash - ``` Hit `Enter` after pasting this in your terminal. @@ -73,7 +72,8 @@ Try typing `forge --version` into your terminal. Have you received an unwelcome Note: Most of the time the `bashrc` file gets loaded automatically. However, if this doesn't apply to your setup, the following lines can add the required command to the end of your `Bash profile`. This will ensure that your `bashrc` file loads by default. ```bash -cd ~echo 'source /home/user/.bashrc' >> ~/.bash_profile +cd ~ +echo 'source /home/user/.bashrc' >> ~/.bash_profile ``` > this depends on your operating system, please check foundry docs to see detailed instructions. diff --git a/courses/foundry/1-foundry-simple-storage/7-setup-your-vscode/+page.md b/courses/foundry/1-foundry-simple-storage/7-setup-your-vscode/+page.md index 616f1c70b..48f14854c 100644 --- a/courses/foundry/1-foundry-simple-storage/7-setup-your-vscode/+page.md +++ b/courses/foundry/1-foundry-simple-storage/7-setup-your-vscode/+page.md @@ -31,16 +31,14 @@ VS Code will handle the download and installation process. **That's it! The extension should be ready to use within VS Code.** - - ### Integrating AI into our work +### Integrating AI into our work - One of the best extensions that integrates AI in our development is GitHub Copilot +One of the best extensions that integrates AI in our development is GitHub Copilot - Although it's a premium service, its intuitive AI-powered code autocomplete feature could be a game-changer for you. Of course, you can choose to go with other AI extensions based on your preferences. - - You can download GitHub Copilot [here](https://marketplace.visualstudio.com/items?itemName=GitHub.copilot). More details and answers for your GitHub Copilot-related questions are available [here](https://github.com/features/copilot/?editor=vscode#faq). +Although it's a premium service, its intuitive AI-powered code autocomplete feature could be a game-changer for you. Of course, you can choose to go with other AI extensions based on your preferences. +You can download GitHub Copilot [here](https://marketplace.visualstudio.com/items?itemName=GitHub.copilot). More details and answers for your GitHub Copilot-related questions are available [here](https://github.com/features/copilot/?editor=vscode#faq). ### Other important VS Code Tips @@ -66,4 +64,4 @@ cd foundry-f23 `mkdir` creates a directory or subdirectory. `cd` changes the directory. -Moving forward, it's advisable to keep all your repositories in this folder. Thus, you'll always have a place to reference all your code. \ No newline at end of file +Moving forward, it's advisable to keep all your repositories in this folder. Thus, you'll always have a place to reference all your code. From ca8d2ae2502824a93d02efaed1abf429f23363ef Mon Sep 17 00:00:00 2001 From: Luigi Date: Sat, 28 Sep 2024 10:12:33 -0700 Subject: [PATCH 015/114] Fix typos and formatting --- .../2-fund-me-project-setup/+page.md | 26 +++++++++---------- .../22-zksync-devops/+page.md | 12 ++++----- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/courses/foundry/2-foundry-fund-me/2-fund-me-project-setup/+page.md b/courses/foundry/2-foundry-fund-me/2-fund-me-project-setup/+page.md index 0aa044bcf..43de59715 100644 --- a/courses/foundry/2-foundry-fund-me/2-fund-me-project-setup/+page.md +++ b/courses/foundry/2-foundry-fund-me/2-fund-me-project-setup/+page.md @@ -8,18 +8,18 @@ _Follow along with this video:_ ## Foreword -Welcome the the second section of `Foundry Fundamentals`. Here we'll cover `Fund Me`, a simple funding contract. +Welcome the second section of `Foundry Fundamentals`. Here we'll cover `Fund Me`, a simple funding contract. You will learn: -- How to push your project to GitHub; -- Write and run amazing tests; -- Advanced deploy scripts, used to deploy on different chains that require different addresses; -- How to use scripts to interact with contracts, so we can easily reproduce our actions; -- How to use a price feed; -- How to use Chisel; -- Smart contract automation; -- How to make our contracts more gas efficient; +- How to push your project to GitHub +- Write and run amazing tests +- Advanced deploy scripts, used to deploy on different chains that require different addresses +- How to use scripts to interact with contracts, so we can easily reproduce our actions +- How to use a price feed +- How to use Chisel +- Smart contract automation +- How to make our contracts more gas efficient - And many more interesting things! Until now, we talked a lot about storage and state, but we didn't delve into what they really mean. We will learn what all these means! @@ -33,10 +33,10 @@ Going through the [repo](https://github.com/Cyfrin/foundry-fund-me-f23) we can s As you can see we are employing some advanced tools/standard naming conventions: -- We use a named error `FundMe__NotOwner();`; -- We use all caps for constants; -- `i_` for immutable variables; -- `s_` for private variables; +- We use a named error `FundMe__NotOwner();` +- We use all caps for constants +- `i_` for immutable variables +- `s_` for private variables Let's clone this project locally. Open your VS Code, and make sure you are in the `foundry-f23` folder, if not use `cd` to navigate to it. diff --git a/courses/foundry/2-foundry-fund-me/22-zksync-devops/+page.md b/courses/foundry/2-foundry-fund-me/22-zksync-devops/+page.md index e8a6b8455..e379b42f1 100644 --- a/courses/foundry/2-foundry-fund-me/22-zksync-devops/+page.md +++ b/courses/foundry/2-foundry-fund-me/22-zksync-devops/+page.md @@ -1,5 +1,5 @@ --- -title: zkSync DevOps +title: ZKsync DevOps --- _Follow along with the video_ @@ -8,11 +8,11 @@ _Follow along with the video_ ### Introduction -There are notable differences between the EVM and zkSync Era VM, as detailed in the [zkSync documentation](https://docs.zksync.io/build/developer-reference/ethereum-differences/evm-instructions). In this lesson, we will explore some DevOps tools designed to help run tests and functions on both VMs. +There are notable differences between the EVM and ZKsync Era VM, as detailed in the [ZKsync documentation](https://docs.zksync.io/build/developer-reference/ethereum-differences/evm-instructions). In this lesson, we will explore some DevOps tools designed to help run tests and functions on both VMs. ### `foundry-devops` Tools -In the `FundMeTest.t.sol` file, certain tests that run on Vanilla Foundry may not work on zkSync Foundry, and vice versa. To address these differences, we will explore two packages from the [foundry-devops](https://github.com/Cyfrin/foundry-devops) repository: `ZkSyncChainChecker` and `FoundryZkSyncChecker`. This lesson will cover how to use these packages effectively. +In the `FundMeTest.t.sol` file, certain tests that run on Vanilla Foundry may not work on ZKsync Foundry, and vice versa. To address these differences, we will explore two packages from the [foundry-devops](https://github.com/Cyfrin/foundry-devops) repository: `ZkSyncChainChecker` and `FoundryZkSyncChecker`. This lesson will cover how to use these packages effectively. ```js import { ZkSyncChainChecker } from "lib/foundry-devops/src/ZkSyncChainChecker.sol"; @@ -21,7 +21,7 @@ import { FoundryZkSyncChecker } from "lib/foundry-devops/src/FoundryZkSyncChecke ### Setting Up ZkSyncDevOps -The file [`test/unit/ZkSyncDevOps.t.sol`](https://github.com/Cyfrin/foundry-fund-me-cu/blob/main/test/unit/ZkSyncDevOps.t.sol) is a minimal test file that shows how tests may fail on the zkSync VM but pass on an EVM, or vice versa. You can follow these steps to set it up: +The file [`test/unit/ZkSyncDevOps.t.sol`](https://github.com/Cyfrin/foundry-fund-me-cu/blob/main/test/unit/ZkSyncDevOps.t.sol) is a minimal test file that shows how tests may fail on the ZKsync VM but pass on an EVM, or vice versa. You can follow these steps to set it up: 1. Copy the content from the GitHub repo into your project's `test/unit` directory, and create a new file named `ZkSyncDevOps.t.sol`. 2. Install any missing dependencies using the command: @@ -52,9 +52,9 @@ You can switch environments between `fundryup` and `fundryup-zksync` to observe forge test --mt testZkSyncChainFails -vvv ``` -will pass in both Foundry environments. However, if you remove the `skipZkSync` modifier, the test will fail on zkSync because the content of the function is not suported on this chain. +will pass in both Foundry environments. However, if you remove the `skipZkSync` modifier, the test will fail on ZKsync because the content of the function is not supported on this chain. -For more details on these modifiers, refer to the [foundry-devops repo](https://github.com/Cyfrin/foundry-devops?tab=readme-ov-file#usage---zksync-checker). The `skipzksync` modifier skips tests on the zkSync chain, while `onlyzksync` runs tests only on a zkSync-based chain. +For more details on these modifiers, refer to the [foundry-devops repo](https://github.com/Cyfrin/foundry-devops?tab=readme-ov-file#usage---zksync-checker). The `skipzksync` modifier skips tests on the ZKsync chain, while `onlyzksync` runs tests only on a ZKsync-based chain. ### Foundry version modifiers From 5aab1ceae9786ca3130a68b9a476a3eedd9ef3d8 Mon Sep 17 00:00:00 2001 From: Luigi Date: Sun, 29 Sep 2024 23:53:23 -0700 Subject: [PATCH 016/114] Fix typos, formatting, and code samples --- .../10-deploy-a-mock-pricefeed/+page.md | 68 ++++----- .../+page.md | 34 +++-- .../12-how-to-refactor-magic-numbers/+page.md | 28 ++-- .../+page.md | 13 +- .../14-foundry-tests-cheatcodes/+page.md | 67 ++++---- .../+page.md | 143 +++++++++--------- .../+page.md | 3 +- .../4-finishing-the-setup/+page.md | 6 +- .../+page.md | 1 + .../6-debug-your-solidity-tests/+page.md | 1 + .../7-advanced-deploy-scripts/+page.md | 7 +- .../8-running-tests-on-chains-forks/+page.md | 3 +- .../9-refactoring-your-tests/+page.md | 68 +++++---- 13 files changed, 220 insertions(+), 222 deletions(-) diff --git a/courses/foundry/2-foundry-fund-me/10-deploy-a-mock-pricefeed/+page.md b/courses/foundry/2-foundry-fund-me/10-deploy-a-mock-pricefeed/+page.md index fc5acfc33..86742e2f5 100644 --- a/courses/foundry/2-foundry-fund-me/10-deploy-a-mock-pricefeed/+page.md +++ b/courses/foundry/2-foundry-fund-me/10-deploy-a-mock-pricefeed/+page.md @@ -1,5 +1,6 @@ --- title: Deploy a mock priceFeed +--- _Follow along with this video:_ @@ -9,7 +10,7 @@ _Follow along with this video:_ In the previous lesson, we refactored our contracts to avoid being forced to use Sepolia every single time when we ran tests. The problem is we didn't quite fix this aspect. We made our contracts more flexible by changing everything for us to input the `priceFeed` address only once. We can do better! -It is very important to be able to run our all tests locally. We will do this using a `mock contract`. +It is very important to be able to run our all tests locally. We will do this using a **mock contract**. Before we dive into the code, let's emphasize why this practice is so beneficial. By creating a local testing environment, you reduce your chances of breaking anything in the refactoring process, as you can test all changes before they go live. No more hardcoding of addresses and no more failures when you try to run a test without a forked chain. As a powerful yet simple tool, a mock contract allows you to simulate the behavior of a real contract without the need to interact with a live blockchain. @@ -21,7 +22,7 @@ Please create a new file in your `script` folder called `HelperConfig.s.sol`. He The start: -```javascript +```solidity // SPDX-License-Identifier: MIT pragma solidity 0.8.19; @@ -31,28 +32,26 @@ import {Script} from "forge-std/Script.sol"; contract HelperConfig { // If we are on a local Anvil, we deploy the mocks // Else, grab the existing address from the live network - } ``` Copy the following functions inside the contract: -```javascript +```solidity +struct NetworkConfig { + address priceFeed; // ETH/USD price feed address +} - struct NetworkConfig { - address priceFeed; // ETH/USD price feed address - } +function getSepoliaEthConfig() public pure returns (NetworkConfig memory) { + NetworkConfig memory sepoliaConfig = NetworkConfig({ + priceFeed: 0x694AA1769357215DE4FAC081bf1f309aDC325306 + }); + return sepoliaConfig; +} - function getSepoliaEthConfig() public pure returns (NetworkConfig memory){ - NetworkConfig memory sepoliaConfig = NetworkConfig({ - priceFeed: 0x694AA1769357215DE4FAC081bf1f309aDC325306 - }); - return sepoliaConfig; - } +function getAnvilEthConfig() public pure returns (NetworkConfig memory) { - function getAnvilEthConfig() public pure returns (NetworkConfig memory){ - - } +} ``` We decided to structure the information we need depending on the chain we are testing on. We use a `struct` to hold this information for every chain. You might think that we could have gotten away with a simple `address variable` but that changes if we need to store multiple addresses or even more blockchain-specific information. @@ -65,20 +64,20 @@ First of all, we need to be aware of the chain we are using. We can do this in t Update the `HelperConfig` as follows: -```javascript - NetworkConfig public activeNetworkConfig; +```solidity +NetworkConfig public activeNetworkConfig; - struct NetworkConfig { - address priceFeed; // ETH/USD price feed address - } +struct NetworkConfig { + address priceFeed; // ETH/USD price feed address +} - constructor(){ - if (block.chainid == 11155111) { - activeNetowrkConfig = getSepoliaEthConfig(); - } else { - activeNetowrkConfig = getAnvilEthConfig(); - } +constructor(){ + if (block.chainid == 11155111) { + activeNetworkConfig = getSepoliaEthConfig(); + } else { + activeNetworkConfig = getAnvilEthConfig(); } +} ``` As you can see, we've defined a new state variable, called activeNetworkConfig which will be the struct that gets queried for blockchain-specific information. We will check the `block.chainId` at the constructor level, and depending on that value we select the appropriate config. @@ -91,13 +90,12 @@ Let's update the `DeployFundMe.s.sol` to use our newly created `HelperConfig`. Add the following before the `vm.startBroadcast` line inside the `run` function: -```javascript - // The next line runs before the vm.startBroadcast() is called - // This will not be deployed because the `real` signed txs are happening - // between the start and stop Broadcast lines. - HelperConfig helperConfig = new HelperConfig(); - address ethUsdPriceFeed = helperConfig.activeNetworkConfig(); - +```solidity +// The next line runs before the vm.startBroadcast() is called +// This will not be deployed because the `real` signed txs are happening +// between the start and stop Broadcast lines. +HelperConfig helperConfig = new HelperConfig(); +address ethUsdPriceFeed = helperConfig.activeNetworkConfig(); ``` Run the `forge test --fork-url $SEPOLIA_RPC_URL` command to check everything is fine. All tests should pass. @@ -108,4 +106,4 @@ Now that we've configured it for one chain, Sepolia, we can do the same with any This type of flexibility elevates your development game to the next level. Being able to easily test your project on different chains just by changing your RPC_URL is an ability that differentiates you from a lot of solidity devs who fumble around with hardcoded addresses. -In the next lessons, we will learn how to use Anvil in our current setup. Stay tuned. \ No newline at end of file +In the next lessons, we will learn how to use Anvil in our current setup. Stay tuned. diff --git a/courses/foundry/2-foundry-fund-me/11-refactoring-the-mock-smart-contract/+page.md b/courses/foundry/2-foundry-fund-me/11-refactoring-the-mock-smart-contract/+page.md index ce2f44668..90350e480 100644 --- a/courses/foundry/2-foundry-fund-me/11-refactoring-the-mock-smart-contract/+page.md +++ b/courses/foundry/2-foundry-fund-me/11-refactoring-the-mock-smart-contract/+page.md @@ -1,5 +1,6 @@ --- title: Refactoring the mock smart contract +--- _Follow along with this video:_ @@ -17,11 +18,11 @@ First of all, we need to make sure we import `Script.sol` in the `HelperConfig.s Update your start of the `HelperConfig.s.sol` file as follows: -```javascript +```solidity import {Script} from "forge-std/Script.sol"; contract HelperConfig is Script { - +} ``` In order to be able to deploy a mock contract we need ... a mock contract. So, in `test` folder please create a new folder called `mocks`. Inside `mocks` create a new file `MockV3Aggregator.sol`. Rewriting the AggregatorV3 as a mock is not the easiest task out there. Please copy the contents of [this contract](https://github.com/Cyfrin/foundry-fund-me-f23/blob/main/test/mock/MockV3Aggregator.sol) into your newly created file. @@ -32,26 +33,27 @@ We need to import this in our `HelperConfig.s.sol` file and deploy it in the `ge Perform the following changes in `HelperConfig`: -```javascript +```solidity import {MockV3Aggregator} from "../test/mocks/MockV3Aggregator.sol"; -[...] - // In state variables section - MockV3Aggregator mockPriceFeed; [...] - function getAnvilEthConfig() public returns (NetworkConfig memory){ +// In state variables section +MockV3Aggregator mockPriceFeed; + +[...] - vm.startBroadcast(); - mockPriceFeed = new MockV3Aggregator(8, 2000e8); - vm.stopBroadcast(); +function getAnvilEthConfig() public returns (NetworkConfig memory) { + vm.startBroadcast(); + mockPriceFeed = new MockV3Aggregator(8, 2000e8); + vm.stopBroadcast(); - NetworkConfig memory anvilConfig = NetworkConfig({ - priceFeed: address(mockPriceFeed) - }); + NetworkConfig memory anvilConfig = NetworkConfig({ + priceFeed: address(mockPriceFeed) + }); - return anvilConfig; - } + return anvilConfig; +} ``` -More testing and refactorings in the next lessons! \ No newline at end of file +More testing and refactorings in the next lessons! diff --git a/courses/foundry/2-foundry-fund-me/12-how-to-refactor-magic-numbers/+page.md b/courses/foundry/2-foundry-fund-me/12-how-to-refactor-magic-numbers/+page.md index 4a1ca662f..50a01b929 100644 --- a/courses/foundry/2-foundry-fund-me/12-how-to-refactor-magic-numbers/+page.md +++ b/courses/foundry/2-foundry-fund-me/12-how-to-refactor-magic-numbers/+page.md @@ -1,5 +1,6 @@ --- title: How to refactor magic number +--- _Follow along with this video:_ @@ -7,7 +8,7 @@ _Follow along with this video:_ ### Magic numbers or `What was this exactly?` -Magic numbers refer to literal values directly included in the code without any explanation or context. These numbers can appear anywhere in the code, but they're particularly problematic when used in calculations or comparisons. By using magic numbers you ensure your smart contract suffers from `Reduced Readability`, `Increased Maintenance Difficulty` and `Debugging Challenges`. You also make your work extremely prone to error, imagine you used the same magic number in 10 places and you want to change it. Will you remember all the 9 places or will you change it only in 8? +Magic numbers refer to literal values directly included in the code without any explanation or context. These numbers can appear anywhere in the code, but they're particularly problematic when used in calculations or comparisons. By using magic numbers you ensure your smart contract suffers from **Reduced Readability**, **Increased Maintenance Difficulty** and **Debugging Challenges**. You also make your work extremely prone to error, imagine you used the same magic number in 10 places and you want to change it. Will you remember all the 9 places or will you change it only in 8? **Don't be like that.** @@ -19,7 +20,7 @@ Open `HelperConfig.s.sol`, go to the `getAnvilEthConfig` function and delete the At the top of the `HelperConfig` contract create two new variables: -```javascript +```solidity uint8 public constant DECIMALS = 8; int256 public constant INITIAL_PRICE = 2000e8; ``` @@ -28,19 +29,18 @@ int256 public constant INITIAL_PRICE = 2000e8; Now replace the deleted magic numbers with the newly created variables. -```javascript - function getAnvilEthConfig() public returns (NetworkConfig memory){ - - vm.startBroadcast(); - mockPriceFeed = new MockV3Aggregator(DECIMALS, INITIAL_PRICE); - vm.stopBroadcast(); +```solidity +function getAnvilEthConfig() public returns (NetworkConfig memory) { + vm.startBroadcast(); + mockPriceFeed = new MockV3Aggregator(DECIMALS, INITIAL_PRICE); + vm.stopBroadcast(); - NetworkConfig memory anvilConfig = NetworkConfig({ - priceFeed: address(mockPriceFeed) - }); + NetworkConfig memory anvilConfig = NetworkConfig({ + priceFeed: address(mockPriceFeed) + }); - return anvilConfig; - } + return anvilConfig; +} ``` -Awesome! Let's keep refactoring! \ No newline at end of file +Awesome! Let's keep refactoring! diff --git a/courses/foundry/2-foundry-fund-me/13-refactoring-the-mock-smart-contrat-pt2/+page.md b/courses/foundry/2-foundry-fund-me/13-refactoring-the-mock-smart-contrat-pt2/+page.md index 1ac8c994d..4ea613318 100644 --- a/courses/foundry/2-foundry-fund-me/13-refactoring-the-mock-smart-contrat-pt2/+page.md +++ b/courses/foundry/2-foundry-fund-me/13-refactoring-the-mock-smart-contrat-pt2/+page.md @@ -1,5 +1,6 @@ --- title: Refactoring the mock smart contract pt.2 +--- _Follow along with this video:_ @@ -13,10 +14,10 @@ Remember how addresses that were declared in state, but weren't attributed a val Right below the `function getAnvilEthConfig() public returns ...` line add the following: -```javascript - if (activeNetworkConfig.priceFeed != address(0)) { - return activeNetworkConfig; - } +```solidity +if (activeNetworkConfig.priceFeed != address(0)) { + return activeNetworkConfig; +} ``` `getAnvilEthConfig` is not necessarily the best name. We are deploying something inside it, which means we are creating a new `mockPriceFeed`. Let's rename the function to `getOrCreateAnvilEthConfig`. Replace the name in the constructor. @@ -26,7 +27,3 @@ Remember how `testPriceFeedVersionIsAccurate` was always failing when we didn't Everything passes! Amazing! Our test just became network agnostic. Next-level stuff! Take a break, come back in 15 minutes and let's go on! - - - - diff --git a/courses/foundry/2-foundry-fund-me/14-foundry-tests-cheatcodes/+page.md b/courses/foundry/2-foundry-fund-me/14-foundry-tests-cheatcodes/+page.md index 15faf1f91..1c57420e2 100644 --- a/courses/foundry/2-foundry-fund-me/14-foundry-tests-cheatcodes/+page.md +++ b/courses/foundry/2-foundry-fund-me/14-foundry-tests-cheatcodes/+page.md @@ -1,5 +1,6 @@ --- title: Foundry tests cheatcodes +--- _Follow along with this video:_ @@ -23,11 +24,11 @@ To test point 1 we will use one of the most important cheatcodes: `expectRevert` Open `FundMe.t.sol` and add the following function: -```javascript - function testFundFailsWIthoutEnoughETH() public { - vm.expectRevert(); // <- The next line after this one should revert! If not test fails. - fundMe.fund(); // <- We send 0 value - } +```solidity +function testFundFailsWIthoutEnoughETH() public { + vm.expectRevert(); // <- The next line after this one should revert! If not test fails. + fundMe.fund(); // <- We send 0 value +} ``` We are attempting to fund the contract with `0` value, it reverts and our test passes. @@ -40,28 +41,28 @@ Now that we made those two variables private, we need to write some getters for Please add the following at the end of `FundMe.sol`: -```javascript - /** Getter Functions */ +```solidity +/** Getter Functions */ - function getAddressToAmountFunded(address fundingAddress) public view returns (uint256) { - return s_addressToAmountFunded[fundingAddress]; - } +function getAddressToAmountFunded(address fundingAddress) public view returns (uint256) { + return s_addressToAmountFunded[fundingAddress]; +} - function getFunder(uint256 index) public view returns (address) { - return s_funders[index]; - } +function getFunder(uint256 index) public view returns (address) { + return s_funders[index]; +} ``` Pfeww! Great now we can test points 2 and 3 indicated above: Add the following test in `FundMe.t.sol`: -```javascript - function testFundUpdatesFundDataStructure() public { - fundMe.fund{value: 10 ether}(); - uint256 amountFunded = fundMe.getAddressToAmountFunded(msg.sender); - assertEq(amountFunded, 10 ether); - } +```solidity +function testFundUpdatesFundDataStructure() public { + fundMe.fund{value: 10 ether}(); + uint256 amountFunded = fundMe.getAddressToAmountFunded(msg.sender); + assertEq(amountFunded, 10 ether); +} ``` Run `forge test --mt testFundUpdatesFundDataStructure` in your terminal. @@ -82,7 +83,7 @@ Ok, cool, but who is the actual user that we are going to use in one of the chea Add the following line at the start of your `FundMeTest` contract: -```javascript +```solidity address alice = makeAddr("alice"); ``` @@ -92,13 +93,13 @@ To further increase the readability of our contract, let's avoid using a magic n Back to our test, add the following test in `FundMe.t.sol`: -```javascript - function testFundUpdatesFundDataStructure() public { - vm.prank(alice); - fundMe.fund{value: SEND_VALUE}(); - uint256 amountFunded = fundMe.getAddressToAmountFunded(alice); - assertEq(amountFunded, SEND_VALUE); - } +```solidity +function testFundUpdatesFundDataStructure() public { + vm.prank(alice); + fundMe.fund{value: SEND_VALUE}(); + uint256 amountFunded = fundMe.getAddressToAmountFunded(alice); + assertEq(amountFunded, SEND_VALUE); +} ``` Finally, now let's run `forge test --mt testFundUpdatesFundDataStructure` again. @@ -131,13 +132,13 @@ Foundry to the rescue! There's always a cheatcode to help you overcome your hurd Add the following line at the end of the setup. -```javascript +```solidity vm.deal(alice, STARTING_BALANCE); ``` Declare the `STARTING_BALANCE` as a constant variable up top: -``` +```solidity uint256 constant STARTING_BALANCE = 10 ether; ``` @@ -146,11 +147,3 @@ Let's run `forge test --mt testFundUpdatesFundDataStructure` again. And now it passes. Congratulations! I know a lot of new cheatcodes were introduced in this lesson. Keep in mind that these are the most important cheatcodes there are, and you are going to use them over and over again. Regardless if you are developing or auditing a project, that project will always have at least an `owner` and a `user`. These two would always have different access to different functionalities. Most of the time the user needs some kind of balance, be it ETH or some other tokens. So, making a new address, giving it some balance, and pranking it to act as a caller for a tx will 100% be part of your every test file. - - - - - - - - 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 218132870..9a4c3d184 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 @@ -1,5 +1,6 @@ --- title: Adding more coverage to the tests +--- _Follow along with this video:_ @@ -11,15 +12,15 @@ In the previous lesson, we tested if the `s_addressToAmountFunded` is updated co Add the following test to your `FundMe.t.sol`: -```javascript - function testAddsFunderToArrayOfFunders() public { - vm.startPrank(alice); - fundMe.fund{value: SEND_VALUE}(); - vm.stopPrank(); +```solidity +function testAddsFunderToArrayOfFunders() public { + vm.startPrank(alice); + fundMe.fund{value: SEND_VALUE}(); + vm.stopPrank(); - address funder = fundMe.getFunder(0); - assertEq(funder, alice); - } + address funder = fundMe.getFunder(0); + assertEq(funder, alice); +} ``` What's happening here? We start with our user `alice` who calls `fundMe.fund` in order to fund the contract. Then we use the `getter` function we created in the previous lesson to query what is registered inside the `funders` array at index `0`. We then use the `assertEq` cheatcode to compare the address we queried against `alice`. @@ -32,15 +33,15 @@ Moving on, we should test the `withdraw` function. Let's check that only the own Add the following test to your `FundMe.t.sol`: -```javascript - function testOnlyOwnerCanWithdraw() public { - vm.prank(alice); - fundMe.fund{value: SEND_VALUE}(); +```solidity +function testOnlyOwnerCanWithdraw() public { + vm.prank(alice); + fundMe.fund{value: SEND_VALUE}(); - vm.expectRevert(); - vm.prank(alice); - fundMe.withdraw(); - } + vm.expectRevert(); + vm.prank(alice); + fundMe.withdraw(); +} ``` What's happening here? We start with our user `alice` who calls `fundMe.fund` in order to fund the contract. We then use Alice's address to try and withdraw. Given that Alice is not the owner of the contract, it should fail. That's why we are using the `vm.expectRevert` cheatcode. @@ -53,24 +54,24 @@ As you can see, in both `testAddsFunderToArrayOfFunders` and `testOnlyOwnerCanWi Add the following modifier to your `FundMe.t.sol`: -```javascript - modifier funded() { - vm.prank(alice); - fundMe.fund{value: SEND_VALUE}(); - assert(address(fundMe).balance > 0); - _; - } +```solidity +modifier funded() { + vm.prank(alice); + fundMe.fund{value: SEND_VALUE}(); + assert(address(fundMe).balance > 0); + _; +} ``` We first use the `vm.prank` cheatcode to signal the fact that the next transaction will be called by `alice`. We call `fund` and then we assert that the balance of the `fundMe` contract is higher than 0, if true, it means that Alice's transaction was successful. Every single time we need our contract funded we can use this modifier to do it. Refactor the previous test as follows: -```javascript - function testOnlyOwnerCanWithdraw() public funded { - vm.expectRevert(); - fundMe.withdraw(); - } +```solidity +function testOnlyOwnerCanWithdraw() public funded { + vm.expectRevert(); + fundMe.withdraw(); +} ``` Slim and efficient! @@ -79,10 +80,10 @@ Ok, we've tested that a non-owner cannot withdraw. But can the owner withdraw? To test this we will need a new getter function. Add the following to the `FundMe.sol` file next to the other getter functions: -```javascript - function getOwner() public view returns (address) { - return i_owner; - } +```solidity +function getOwner() public view returns (address) { + return i_owner; +} ``` Make sure to make `i_owner` private. @@ -97,25 +98,26 @@ The arrange-act-assert (AAA) methodology is one of the simplest and most univers We will start our test as usual: -```javascript +```solidity function testWithdrawFromASingleFunder() public funded { +} ``` Now we are in the first stage of the `AAA` methodology: `Arrange` We first need to check the initial balance of the owner and the initial balance of the contract. -```javascript - uint256 startingFundMeBalance = address(fundMe).balance; - uint256 startingOwnerBalance = fundMe.getOwner().balance; +```solidity +uint256 startingFundMeBalance = address(fundMe).balance; +uint256 startingOwnerBalance = fundMe.getOwner().balance; ``` We have what we need to continue with the `Act` stage. -```javascript - vm.startPrank(fundMe.getOwner()); - fundMe.withdraw(); - vm.stopPrank(); +```solidity +vm.startPrank(fundMe.getOwner()); +fundMe.withdraw(); +vm.stopPrank(); ``` Our action stage is comprised of pranking the owner and then calling `withdraw`. @@ -123,15 +125,14 @@ We have reached our final testing part, the `Assert` stage. We need to find out the new balances, both for the contract and the owner. We need to check if these match the expected numbers: -```javascript - uint256 endingFundMeBalance = address(fundMe).balance; - uint256 endingOwnerBalance = fundMe.getOwner().balance; - assertEq(endingFundMeBalance, 0); - assertEq( - startingFundMeBalance + startingOwnerBalance, - endingOwnerBalance - ); - } +```solidity +uint256 endingFundMeBalance = address(fundMe).balance; +uint256 endingOwnerBalance = fundMe.getOwner().balance; +assertEq(endingFundMeBalance, 0); +assertEq( + startingFundMeBalance + startingOwnerBalance, + endingOwnerBalance +); ``` The `endingFundMeBalance` should be `0`, because we just withdrew everything from it. The `owner`'s balance should be the `startingFundMeBalance + startingOwnerBalance` because we withdrew the `fundMe` starting balance. @@ -146,28 +147,28 @@ Ok, we've tested that the owner can indeed `withdraw` when the `fundMe` contract Put the following test in your `FundMe.t.sol`: -```javascript - function testWithdrawFromMultipleFunders() public funded { - uint160 numberOfFunders = 10; - uint160 startingFunderIndex = 1; - for (uint160 i = startingFunderIndex; i < numberOfFunders + startingFunderIndex; i++) { - // we get hoax from stdcheats - // prank + deal - hoax(address(i), SEND_VALUE); - fundMe.fund{value: SEND_VALUE}(); - } - - uint256 startingFundMeBalance = address(fundMe).balance; - uint256 startingOwnerBalance = fundMe.getOwner().balance; - - vm.startPrank(fundMe.getOwner()); - fundMe.withdraw(); - vm.stopPrank(); - - assert(address(fundMe).balance == 0); - assert(startingFundMeBalance + startingOwnerBalance == fundMe.getOwner().balance); - assert((numberOfFunders + 1) * SEND_VALUE == fundMe.getOwner().balance - startingOwnerBalance); +```solidity +function testWithdrawFromMultipleFunders() public funded { + uint160 numberOfFunders = 10; + uint160 startingFunderIndex = 1; + for (uint160 i = startingFunderIndex; i < numberOfFunders + startingFunderIndex; i++) { + // we get hoax from stdcheats + // prank + deal + hoax(address(i), SEND_VALUE); + fundMe.fund{value: SEND_VALUE}(); } + + uint256 startingFundMeBalance = address(fundMe).balance; + uint256 startingOwnerBalance = fundMe.getOwner().balance; + + vm.startPrank(fundMe.getOwner()); + fundMe.withdraw(); + vm.stopPrank(); + + assert(address(fundMe).balance == 0); + assert(startingFundMeBalance + startingOwnerBalance == fundMe.getOwner().balance); + assert((numberOfFunders + 1) * SEND_VALUE == fundMe.getOwner().balance - startingOwnerBalance); +} ``` That seems like a lot! Let's go through it. @@ -207,4 +208,4 @@ Run the test using `forge test --mt testWithdrawFromMultipleFunders`. Run all te Let's run `forge coverage` and see if our coverage table got better. -Congratulations, everything works way better! \ No newline at end of file +Congratulations, everything works way better! diff --git a/courses/foundry/2-foundry-fund-me/16-introduction-to-foundry-chisel/+page.md b/courses/foundry/2-foundry-fund-me/16-introduction-to-foundry-chisel/+page.md index 22315d363..b05aff00e 100644 --- a/courses/foundry/2-foundry-fund-me/16-introduction-to-foundry-chisel/+page.md +++ b/courses/foundry/2-foundry-fund-me/16-introduction-to-foundry-chisel/+page.md @@ -1,5 +1,6 @@ --- title: Introduction to Foundry Chisel +--- _Follow along with this video:_ @@ -61,4 +62,4 @@ It reverts! Press `Ctrl + C` twice to exit and return to your normal terminal. -To find more about other Chisel functionality please click [here](https://book.getfoundry.sh/reference/chisel/). \ No newline at end of file +To find more about other Chisel functionality please click [here](https://book.getfoundry.sh/reference/chisel/). diff --git a/courses/foundry/2-foundry-fund-me/4-finishing-the-setup/+page.md b/courses/foundry/2-foundry-fund-me/4-finishing-the-setup/+page.md index 02b6aaa44..0e1053039 100644 --- a/courses/foundry/2-foundry-fund-me/4-finishing-the-setup/+page.md +++ b/courses/foundry/2-foundry-fund-me/4-finishing-the-setup/+page.md @@ -30,9 +30,9 @@ Wait for it to finish. We used `forge install` to ask Forge to install something in our project. What? We specified the path to a GitHub repository, this also could have been a raw URL. What version? Following the path to a GitHub repository you can add an `@` and then you can specify: -- A branch: master; -- A tag: v1.2.3.4 or 0.6.1 in our case; -- A commit: 8e8128; +- A branch: master +- A tag: v1.2.3.4 or 0.6.1 in our case +- A commit: 8e8128 We end the install command with `--no commit` in order to not create a git commit. More on this option later. diff --git a/courses/foundry/2-foundry-fund-me/5-writing-tests-for-your-solidity-smart-contract/+page.md b/courses/foundry/2-foundry-fund-me/5-writing-tests-for-your-solidity-smart-contract/+page.md index ff4e7eb0d..f61a244d1 100644 --- a/courses/foundry/2-foundry-fund-me/5-writing-tests-for-your-solidity-smart-contract/+page.md +++ b/courses/foundry/2-foundry-fund-me/5-writing-tests-for-your-solidity-smart-contract/+page.md @@ -1,5 +1,6 @@ --- title: Writing tests for your Solidity smart contract +--- _Follow along with this video:_ diff --git a/courses/foundry/2-foundry-fund-me/6-debug-your-solidity-tests/+page.md b/courses/foundry/2-foundry-fund-me/6-debug-your-solidity-tests/+page.md index 0286369bb..085eb2af5 100644 --- a/courses/foundry/2-foundry-fund-me/6-debug-your-solidity-tests/+page.md +++ b/courses/foundry/2-foundry-fund-me/6-debug-your-solidity-tests/+page.md @@ -1,5 +1,6 @@ --- title: Debug your Solidity tests +--- _Follow along with this video:_ diff --git a/courses/foundry/2-foundry-fund-me/7-advanced-deploy-scripts/+page.md b/courses/foundry/2-foundry-fund-me/7-advanced-deploy-scripts/+page.md index 312421691..c85bb3961 100644 --- a/courses/foundry/2-foundry-fund-me/7-advanced-deploy-scripts/+page.md +++ b/courses/foundry/2-foundry-fund-me/7-advanced-deploy-scripts/+page.md @@ -1,5 +1,6 @@ --- title: Advanced deploy scripts +--- _Follow along with this video:_ @@ -7,7 +8,7 @@ _Follow along with this video:_ ### Writing Deploy Scripts -When we went straight to testing we left behind a very important element, deploy scripts. Why is this important you ask? Because we need a certain degree of flexibility that we can't obtain in any other way, let's look through the two files `FundMe.sol` and `PriceConverter.sol`, we can see that both have an address (`0x694AA1769357215DE4FAC081bf1f309aDC325306`) hardcoded for the AggregatorV3Interface. This address is valid, it matches the AggregatorV3 on Sepolia ... but what if we want to test on Anvil? What if we deploy on mainnet or Arbitrum? What then? +When we went straight to testing, we left behind a very important element: deploy scripts. Why is this important you ask? Because we need a certain degree of flexibility that we can't obtain in any other way, let's look through the two files `FundMe.sol` and `PriceConverter.sol`, we can see that both have an address (`0x694AA1769357215DE4FAC081bf1f309aDC325306`) hardcoded for the AggregatorV3Interface. This address is valid, it matches the AggregatorV3 on Sepolia but what if we want to test on Anvil? What if we deploy on mainnet or Arbitrum? What then? The deploy script is the key to overcome this problem! @@ -16,7 +17,7 @@ Create a new file called `DeployFundMe.s.sol` in `script` folder. Please use the We start with stating the SPDX and pragma: ``` -SPDX-License-Identifier: MIT +//SPDX-License-Identifier: MIT pragma solidity 0.8.18; ``` @@ -53,4 +54,4 @@ contract DeployFundMe is Script { Now let's try it with `forge script DeployFundMe`. -Everything was ok! Congrats! \ No newline at end of file +Everything was ok! Congrats! 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 be4ce0691..bc21c2ec0 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 @@ -1,5 +1,6 @@ --- title: Running tests on chains forks +--- _Follow along with this video:_ @@ -58,7 +59,7 @@ Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 2.29s (536.03ms CPU Nice! -Please keep in mind that forking uses the alchemy API, it's not a good idea to run all your tests on a fork every single time. But, sometimes as in this case, you can't test without. It's very important that our test have a high **coverage**, to ensure all our code is battle tested. +Please keep in mind that forking uses the Alchemy API, it's not a good idea to run all your tests on a fork every single time. But, sometimes as in this case, you can't test without. It's very important that our test have a high **coverage**, to ensure all our code is battle tested. ### Coverage diff --git a/courses/foundry/2-foundry-fund-me/9-refactoring-your-tests/+page.md b/courses/foundry/2-foundry-fund-me/9-refactoring-your-tests/+page.md index 7261a03c1..eead0c965 100644 --- a/courses/foundry/2-foundry-fund-me/9-refactoring-your-tests/+page.md +++ b/courses/foundry/2-foundry-fund-me/9-refactoring-your-tests/+page.md @@ -1,5 +1,6 @@ --- title: Refactoring your tests +--- _Follow along with this video:_ @@ -9,44 +10,44 @@ _Follow along with this video:_ The way our code is currently structured is not that flexible. Given the hardcoded Sepolia address we cannot deploy to other chains, and if we wish to do so we would have to come and copy-paste another address everywhere throughout the code. In bigger codebases, with multiple addresses / other items to copy-paste for each deployment (in case we deploy on multiple chains) this update activity is extremely prone to error. We can do better. -To fix this we can make our project more modular, which would help improve de maintainability, testing and deployment. This is done by moving the hardcoded changing variables to the constructor, thus regardless of the chain we deploy our contracts to, we provide the chain-specific elements once, in the constructor, and then we are good to go. +To fix this we can make our project more modular, which would help improve the maintainability, testing and deployment. This is done by moving the hardcoded changing variables to the constructor, thus regardless of the chain we deploy our contracts to, we provide the chain-specific elements once, in the constructor, and then we are good to go. Changing code without changing its functionality bears the name of **refactoring**. Do the following modifications in `FundMe.sol` 1. In the storage variables section create a new variable: -```javascript +```solidity AggregatorV3Interface private s_priceFeed; ``` 2. We need to add this as an input in our constructor and assign it to the state variable. This is done as follows: -```javascript +```solidity constructor(address priceFeed){ i_owner = msg.sender; s_priceFeed = AggregatorV3Interface(priceFeed); } ``` 3. Inside the `getVersion` function, where AggregatorV3Interface is invoked, replace the hardcoded address with the state variable s_priceFeed: -```javascript - function getVersion() public view returns (uint256){ - AggregatorV3Interface priceFeed = AggregatorV3Interface(s_priceFeed); - return priceFeed.version(); - } +```solidity +function getVersion() public view returns (uint256){ + AggregatorV3Interface priceFeed = AggregatorV3Interface(s_priceFeed); + return priceFeed.version(); +} ``` 4. In `PriceConverter.sol` modify the `getPrice` function to take an input `function getPrice(AggregatorV3Interface priceFeed) internal view returns (uint256) {` and delete the `AggregatorV3Interface priceFeed = AggregatorV3Interface(0x694AA1769357215DE4FAC081bf1f309aDC325306);` line; 5. In the same library update `getConversionRate` to take a `priceFeed` input and update the first line to pass the required AggregatorV3Interface to the `getPrice` function: -```javascript - function getConversionRate( - uint256 ethAmount, - AggregatorV3Interface priceFeed - ) internal view returns (uint256) { - uint256 ethPrice = getPrice(priceFeed); - uint256 ethAmountInUsd = (ethPrice * ethAmount) / 1000000000000000000; - // the actual ETH/USD conversion rate, after adjusting the extra 0s. - return ethAmountInUsd; - } +```solidity +function getConversionRate( + uint256 ethAmount, + AggregatorV3Interface priceFeed +) internal view returns (uint256) { + uint256 ethPrice = getPrice(priceFeed); + uint256 ethAmountInUsd = (ethPrice * ethAmount) / 1000000000000000000; + // the actual ETH/USD conversion rate, after adjusting the extra 0s. + return ethAmountInUsd; +} ``` 6. Back in `FundMe.sol` pass the s_priceFeed as input for `getConversionRate` in the `fund` function. @@ -59,12 +60,13 @@ For now, let's hardcode the address `0x694AA1769357215DE4FAC081bf1f309aDC325306` As you've figured out this isn't ideal either. Every time we want to do something from now on do we have to update in both places? Not good. Update the `run` function from the `DeployFundMe` script: -```javascript -function run() external returns (FundMe fundMe) { +```solidity +function run() external returns (FundMe) { vm.startBroadcast(); - fundMe = new FundMe(0x694AA1769357215DE4FAC081bf1f309aDC325306); + FundMe fundMe = new FundMe(0x694AA1769357215DE4FAC081bf1f309aDC325306); vm.stopBroadcast(); -} + return fundMe +} ``` Now when we call run it returns the `FundMe` contract we deployed. @@ -72,16 +74,16 @@ In `FundMe.t.sol`: 1. Let's import the deployment script into the `FundMe.t.sol`. -```javascript +```solidity import {DeployFundMe} from "../script/DeployFundMe.s.sol"; ``` 2. Create a new state variable `DeployFundMe deployFundMe;`; 3. Update the `setUp` function as follows: -```javascript - function setUp() external { - deployFundMe = new DeployFundMe(); - fundMe = deployFundMe.run(); - } +```solidity +function setUp() external { + deployFundMe = new DeployFundMe(); + fundMe = deployFundMe.run(); +} ``` Let's call a `forge test --fork-url $SEPOLIA_RPC_URL` to make sure everything compiles. @@ -92,11 +94,11 @@ When we changed the method of deployment and made it go through the run command **Note**: `vm.startBroadcast` is special, it uses the address that calls the test contract or the address / private key provided as the sender. You can read more about it here. -To account for the way `vm.startBroadcast` works please perform the following modification in `FundMe.t.so`: -``` - function testOwnerIsMsgSender() public { - assertEq(fundMe.i_owner(), msg.sender); - } +To account for the way `vm.startBroadcast` works please perform the following modification in `FundMe.t.sol`: +```solidity +function testOwnerIsMsgSender() public { + assertEq(fundMe.i_owner(), msg.sender); +} ``` Run `forge test --fork-url $SEPOLIA_RPC_URL` again. From 5b9a8dd83169d32281e976b5c0281f6106c99661 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 02:58:50 -0600 Subject: [PATCH 017/114] Equious updated courses/curve-v1/1-overview/1-introduction/+page.md. --- courses/curve-v1/1-overview/1-introduction/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/1-overview/1-introduction/+page.md diff --git a/courses/curve-v1/1-overview/1-introduction/+page.md b/courses/curve-v1/1-overview/1-introduction/+page.md new file mode 100644 index 000000000..c21ef2ce7 --- /dev/null +++ b/courses/curve-v1/1-overview/1-introduction/+page.md @@ -0,0 +1,3 @@ +--- + title: Introduction + --- \ No newline at end of file From 6f4ab88abd78907af98532b6f6b1ae1a0784f989 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 02:59:03 -0600 Subject: [PATCH 018/114] Equious updated courses/curve-v1/1-overview/2-lead-instructor/+page.md. --- courses/curve-v1/1-overview/2-lead-instructor/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/1-overview/2-lead-instructor/+page.md diff --git a/courses/curve-v1/1-overview/2-lead-instructor/+page.md b/courses/curve-v1/1-overview/2-lead-instructor/+page.md new file mode 100644 index 000000000..bbe86a03f --- /dev/null +++ b/courses/curve-v1/1-overview/2-lead-instructor/+page.md @@ -0,0 +1,3 @@ +--- + title: Lead Instructor + --- \ No newline at end of file From 9963a8eed117b49e516252cffb1d8009cfb6bd19 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 02:59:15 -0600 Subject: [PATCH 019/114] Equious updated courses/curve-v1/1-overview/3-word-about-repo/+page.md. --- courses/curve-v1/1-overview/3-word-about-repo/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/1-overview/3-word-about-repo/+page.md diff --git a/courses/curve-v1/1-overview/3-word-about-repo/+page.md b/courses/curve-v1/1-overview/3-word-about-repo/+page.md new file mode 100644 index 000000000..8583298a3 --- /dev/null +++ b/courses/curve-v1/1-overview/3-word-about-repo/+page.md @@ -0,0 +1,3 @@ +--- + title: Word About Repo + --- \ No newline at end of file From f36ef477ffc05a6765708a971e96d62557c352dd Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 02:59:28 -0600 Subject: [PATCH 020/114] Equious updated courses/curve-v1/1-overview/4-setup-repo/+page.md. --- courses/curve-v1/1-overview/4-setup-repo/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/1-overview/4-setup-repo/+page.md diff --git a/courses/curve-v1/1-overview/4-setup-repo/+page.md b/courses/curve-v1/1-overview/4-setup-repo/+page.md new file mode 100644 index 000000000..83c914591 --- /dev/null +++ b/courses/curve-v1/1-overview/4-setup-repo/+page.md @@ -0,0 +1,3 @@ +--- + title: Setup Repo + --- \ No newline at end of file From 5fb90b1c7254ba42e8274c5fa63070820788aeb6 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 02:59:40 -0600 Subject: [PATCH 021/114] Equious updated courses/curve-v1/1-overview/5-ex-sol/+page.md. --- courses/curve-v1/1-overview/5-ex-sol/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/1-overview/5-ex-sol/+page.md diff --git a/courses/curve-v1/1-overview/5-ex-sol/+page.md b/courses/curve-v1/1-overview/5-ex-sol/+page.md new file mode 100644 index 000000000..0a0a5e47a --- /dev/null +++ b/courses/curve-v1/1-overview/5-ex-sol/+page.md @@ -0,0 +1,3 @@ +--- + title: Ex Sol + --- \ No newline at end of file From a4007526d76b0660d28e542957415667db37834f Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 02:59:53 -0600 Subject: [PATCH 022/114] Equious updated courses/curve-v1/1-overview/6-curve-intro/+page.md. --- courses/curve-v1/1-overview/6-curve-intro/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/1-overview/6-curve-intro/+page.md diff --git a/courses/curve-v1/1-overview/6-curve-intro/+page.md b/courses/curve-v1/1-overview/6-curve-intro/+page.md new file mode 100644 index 000000000..d81637b1b --- /dev/null +++ b/courses/curve-v1/1-overview/6-curve-intro/+page.md @@ -0,0 +1,3 @@ +--- + title: Curve Intro + --- \ No newline at end of file From a16b5a681e600c425434cc90276707f4f8e7802a Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:00:05 -0600 Subject: [PATCH 023/114] Equious updated courses/curve-v1/1-overview/7-comparison/+page.md. --- courses/curve-v1/1-overview/7-comparison/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/1-overview/7-comparison/+page.md diff --git a/courses/curve-v1/1-overview/7-comparison/+page.md b/courses/curve-v1/1-overview/7-comparison/+page.md new file mode 100644 index 000000000..9625d289b --- /dev/null +++ b/courses/curve-v1/1-overview/7-comparison/+page.md @@ -0,0 +1,3 @@ +--- + title: Comparison + --- \ No newline at end of file From 0a69b1c5864659ebae9b713966c4ca4042ceec2e Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:00:28 -0600 Subject: [PATCH 024/114] Equious updated courses/curve-v1/2-math/01-graph-eq/+page.md. --- courses/curve-v1/2-math/01-graph-eq/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/2-math/01-graph-eq/+page.md diff --git a/courses/curve-v1/2-math/01-graph-eq/+page.md b/courses/curve-v1/2-math/01-graph-eq/+page.md new file mode 100644 index 000000000..e7a9b408b --- /dev/null +++ b/courses/curve-v1/2-math/01-graph-eq/+page.md @@ -0,0 +1,3 @@ +--- + title: Graph Eq + --- \ No newline at end of file From 11879569659c2d54e3173885cbf217aecb5b60e2 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:00:41 -0600 Subject: [PATCH 025/114] Equious updated courses/curve-v1/2-math/02-graph-xy/+page.md. --- courses/curve-v1/2-math/02-graph-xy/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/2-math/02-graph-xy/+page.md diff --git a/courses/curve-v1/2-math/02-graph-xy/+page.md b/courses/curve-v1/2-math/02-graph-xy/+page.md new file mode 100644 index 000000000..368155fd8 --- /dev/null +++ b/courses/curve-v1/2-math/02-graph-xy/+page.md @@ -0,0 +1,3 @@ +--- + title: Graph Xy + --- \ No newline at end of file From ba14e9b48931cb844607552c2ece04ceccef95fd Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:00:53 -0600 Subject: [PATCH 026/114] Equious updated courses/curve-v1/2-math/03-math/+page.md. --- courses/curve-v1/2-math/03-math/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/2-math/03-math/+page.md diff --git a/courses/curve-v1/2-math/03-math/+page.md b/courses/curve-v1/2-math/03-math/+page.md new file mode 100644 index 000000000..d246d700c --- /dev/null +++ b/courses/curve-v1/2-math/03-math/+page.md @@ -0,0 +1,3 @@ +--- + title: Math + --- \ No newline at end of file From e588b054e1b450f187f7e84d08c06b58df1bf185 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:01:06 -0600 Subject: [PATCH 027/114] Equious updated courses/curve-v1/2-math/04-newton/+page.md. --- courses/curve-v1/2-math/04-newton/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/2-math/04-newton/+page.md diff --git a/courses/curve-v1/2-math/04-newton/+page.md b/courses/curve-v1/2-math/04-newton/+page.md new file mode 100644 index 000000000..3a448df12 --- /dev/null +++ b/courses/curve-v1/2-math/04-newton/+page.md @@ -0,0 +1,3 @@ +--- + title: Newton + --- \ No newline at end of file From 98f6693894b8b7124b571e671631e60a8b0424a1 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:01:29 -0600 Subject: [PATCH 028/114] Equious updated courses/curve-v1/2-math/05-newton-python/+page.md. --- courses/curve-v1/2-math/05-newton-python/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/2-math/05-newton-python/+page.md diff --git a/courses/curve-v1/2-math/05-newton-python/+page.md b/courses/curve-v1/2-math/05-newton-python/+page.md new file mode 100644 index 000000000..235ccef7a --- /dev/null +++ b/courses/curve-v1/2-math/05-newton-python/+page.md @@ -0,0 +1,3 @@ +--- + title: Newton Python + --- \ No newline at end of file From 955c1c046240ede97b7d0d803596a2f63e320e8c Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:01:41 -0600 Subject: [PATCH 029/114] Equious updated courses/curve-v1/2-math/06-sympy/+page.md. --- courses/curve-v1/2-math/06-sympy/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/2-math/06-sympy/+page.md diff --git a/courses/curve-v1/2-math/06-sympy/+page.md b/courses/curve-v1/2-math/06-sympy/+page.md new file mode 100644 index 000000000..05aad1f19 --- /dev/null +++ b/courses/curve-v1/2-math/06-sympy/+page.md @@ -0,0 +1,3 @@ +--- + title: Sympy + --- \ No newline at end of file From 1f059cf2eebc7fd639d11cbc2c27374ad11d2793 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:01:54 -0600 Subject: [PATCH 030/114] Equious updated courses/curve-v1/3-contract-overview/01-contract-overview/+page.md. --- .../curve-v1/3-contract-overview/01-contract-overview/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/3-contract-overview/01-contract-overview/+page.md diff --git a/courses/curve-v1/3-contract-overview/01-contract-overview/+page.md b/courses/curve-v1/3-contract-overview/01-contract-overview/+page.md new file mode 100644 index 000000000..945bf909b --- /dev/null +++ b/courses/curve-v1/3-contract-overview/01-contract-overview/+page.md @@ -0,0 +1,3 @@ +--- + title: Contract Overview + --- \ No newline at end of file From 7cdbbcdb2208c322fc58b176c3749e82ff0bc612 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:02:06 -0600 Subject: [PATCH 031/114] Equious updated courses/curve-v1/3-contract-overview/02-contract-functions/+page.md. --- .../3-contract-overview/02-contract-functions/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/3-contract-overview/02-contract-functions/+page.md diff --git a/courses/curve-v1/3-contract-overview/02-contract-functions/+page.md b/courses/curve-v1/3-contract-overview/02-contract-functions/+page.md new file mode 100644 index 000000000..79669e080 --- /dev/null +++ b/courses/curve-v1/3-contract-overview/02-contract-functions/+page.md @@ -0,0 +1,3 @@ +--- + title: Contract Functions + --- \ No newline at end of file From 5b39ff7becf1493168745c3523a031efae952cba Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:02:18 -0600 Subject: [PATCH 032/114] Equious updated courses/curve-v1/3-contract-overview/03-a-and-d/+page.md. --- courses/curve-v1/3-contract-overview/03-a-and-d/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/3-contract-overview/03-a-and-d/+page.md diff --git a/courses/curve-v1/3-contract-overview/03-a-and-d/+page.md b/courses/curve-v1/3-contract-overview/03-a-and-d/+page.md new file mode 100644 index 000000000..411f4075e --- /dev/null +++ b/courses/curve-v1/3-contract-overview/03-a-and-d/+page.md @@ -0,0 +1,3 @@ +--- + title: A And D + --- \ No newline at end of file From 4b51d3a6a472d41f22f5e9de3b9e275719840434 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:02:31 -0600 Subject: [PATCH 033/114] Equious updated courses/curve-v1/3-contract-overview/04-code-walk-a/+page.md. --- courses/curve-v1/3-contract-overview/04-code-walk-a/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/3-contract-overview/04-code-walk-a/+page.md diff --git a/courses/curve-v1/3-contract-overview/04-code-walk-a/+page.md b/courses/curve-v1/3-contract-overview/04-code-walk-a/+page.md new file mode 100644 index 000000000..b12a8139e --- /dev/null +++ b/courses/curve-v1/3-contract-overview/04-code-walk-a/+page.md @@ -0,0 +1,3 @@ +--- + title: Code Walk A + --- \ No newline at end of file From dbcf385a0ffb039f793a00b5f9602fb48be24a5a Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:02:44 -0600 Subject: [PATCH 034/114] Equious updated courses/curve-v1/3-contract-overview/05-code-walk-xp/+page.md. --- courses/curve-v1/3-contract-overview/05-code-walk-xp/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/3-contract-overview/05-code-walk-xp/+page.md diff --git a/courses/curve-v1/3-contract-overview/05-code-walk-xp/+page.md b/courses/curve-v1/3-contract-overview/05-code-walk-xp/+page.md new file mode 100644 index 000000000..8cf944a81 --- /dev/null +++ b/courses/curve-v1/3-contract-overview/05-code-walk-xp/+page.md @@ -0,0 +1,3 @@ +--- + title: Code Walk Xp + --- \ No newline at end of file From ecdce558c00f4f4bf6702574eaa0b63acefedb02 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:02:56 -0600 Subject: [PATCH 035/114] Equious updated courses/curve-v1/3-contract-overview/06-code-walk-get-d/+page.md. --- .../curve-v1/3-contract-overview/06-code-walk-get-d/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/3-contract-overview/06-code-walk-get-d/+page.md diff --git a/courses/curve-v1/3-contract-overview/06-code-walk-get-d/+page.md b/courses/curve-v1/3-contract-overview/06-code-walk-get-d/+page.md new file mode 100644 index 000000000..213a6caad --- /dev/null +++ b/courses/curve-v1/3-contract-overview/06-code-walk-get-d/+page.md @@ -0,0 +1,3 @@ +--- + title: Code Walk Get D + --- \ No newline at end of file From ae88b058cee3379280f3184214b901a44bbf064d Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:03:09 -0600 Subject: [PATCH 036/114] Equious updated courses/curve-v1/3-contract-overview/07-code-walk-get-virtual-price/+page.md. --- .../07-code-walk-get-virtual-price/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/3-contract-overview/07-code-walk-get-virtual-price/+page.md diff --git a/courses/curve-v1/3-contract-overview/07-code-walk-get-virtual-price/+page.md b/courses/curve-v1/3-contract-overview/07-code-walk-get-virtual-price/+page.md new file mode 100644 index 000000000..4605fc8a8 --- /dev/null +++ b/courses/curve-v1/3-contract-overview/07-code-walk-get-virtual-price/+page.md @@ -0,0 +1,3 @@ +--- + title: Code Walk Get Virtual Price + --- \ No newline at end of file From e30a98aaefeeef6371a86b21ab46c0db6d4acdf2 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:03:21 -0600 Subject: [PATCH 037/114] Equious updated courses/curve-v1/3-contract-overview/08-code-walk-calc-token-amount/+page.md. --- .../08-code-walk-calc-token-amount/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/3-contract-overview/08-code-walk-calc-token-amount/+page.md diff --git a/courses/curve-v1/3-contract-overview/08-code-walk-calc-token-amount/+page.md b/courses/curve-v1/3-contract-overview/08-code-walk-calc-token-amount/+page.md new file mode 100644 index 000000000..c4e57783b --- /dev/null +++ b/courses/curve-v1/3-contract-overview/08-code-walk-calc-token-amount/+page.md @@ -0,0 +1,3 @@ +--- + title: Code Walk Calc Token Amount + --- \ No newline at end of file From 276a39f55b22325d9e334dc1fa42fae1be46ed76 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:03:33 -0600 Subject: [PATCH 038/114] Equious updated courses/curve-v1/4-swap/01-contract-call-exchange/+page.md. --- courses/curve-v1/4-swap/01-contract-call-exchange/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/4-swap/01-contract-call-exchange/+page.md diff --git a/courses/curve-v1/4-swap/01-contract-call-exchange/+page.md b/courses/curve-v1/4-swap/01-contract-call-exchange/+page.md new file mode 100644 index 000000000..264576e8c --- /dev/null +++ b/courses/curve-v1/4-swap/01-contract-call-exchange/+page.md @@ -0,0 +1,3 @@ +--- + title: Contract Call Exchange + --- \ No newline at end of file From 9ebfa623e6f5e3d757bccb26b82df0dd26db6e44 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:03:46 -0600 Subject: [PATCH 039/114] Equious updated courses/curve-v1/4-swap/02-code-outline-exchange/+page.md. --- courses/curve-v1/4-swap/02-code-outline-exchange/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/4-swap/02-code-outline-exchange/+page.md diff --git a/courses/curve-v1/4-swap/02-code-outline-exchange/+page.md b/courses/curve-v1/4-swap/02-code-outline-exchange/+page.md new file mode 100644 index 000000000..64c351ed3 --- /dev/null +++ b/courses/curve-v1/4-swap/02-code-outline-exchange/+page.md @@ -0,0 +1,3 @@ +--- + title: Code Outline Exchange + --- \ No newline at end of file From a361bfd2414b695284749e3a46869c6e939bad90 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:04:09 -0600 Subject: [PATCH 040/114] Equious updated courses/curve-v1/4-swap/03-code-walk-exchange/+page.md. --- courses/curve-v1/4-swap/03-code-walk-exchange/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/4-swap/03-code-walk-exchange/+page.md diff --git a/courses/curve-v1/4-swap/03-code-walk-exchange/+page.md b/courses/curve-v1/4-swap/03-code-walk-exchange/+page.md new file mode 100644 index 000000000..deecbce8c --- /dev/null +++ b/courses/curve-v1/4-swap/03-code-walk-exchange/+page.md @@ -0,0 +1,3 @@ +--- + title: Code Walk Exchange + --- \ No newline at end of file From 728e46d31552004269dcc5fd031a7322c473a28d Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:04:21 -0600 Subject: [PATCH 041/114] Equious updated courses/curve-v1/4-swap/04-code-walk-get-y/+page.md. --- courses/curve-v1/4-swap/04-code-walk-get-y/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/4-swap/04-code-walk-get-y/+page.md diff --git a/courses/curve-v1/4-swap/04-code-walk-get-y/+page.md b/courses/curve-v1/4-swap/04-code-walk-get-y/+page.md new file mode 100644 index 000000000..170cfd14d --- /dev/null +++ b/courses/curve-v1/4-swap/04-code-walk-get-y/+page.md @@ -0,0 +1,3 @@ +--- + title: Code Walk Get Y + --- \ No newline at end of file From c0320a11d93403e77dce9138f40a13a633eced79 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:04:34 -0600 Subject: [PATCH 042/114] Equious updated courses/curve-v1/4-swap/05-code-walk-get-dy/+page.md. --- courses/curve-v1/4-swap/05-code-walk-get-dy/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/4-swap/05-code-walk-get-dy/+page.md diff --git a/courses/curve-v1/4-swap/05-code-walk-get-dy/+page.md b/courses/curve-v1/4-swap/05-code-walk-get-dy/+page.md new file mode 100644 index 000000000..f420dcbf9 --- /dev/null +++ b/courses/curve-v1/4-swap/05-code-walk-get-dy/+page.md @@ -0,0 +1,3 @@ +--- + title: Code Walk Get Dy + --- \ No newline at end of file From 0f7d1ca48d79750eed3ace2b4180d3355cf89403 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:04:46 -0600 Subject: [PATCH 043/114] Equious updated courses/curve-v1/4-swap/06-exercise-1-get-dy-underlying/+page.md. --- .../curve-v1/4-swap/06-exercise-1-get-dy-underlying/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/4-swap/06-exercise-1-get-dy-underlying/+page.md diff --git a/courses/curve-v1/4-swap/06-exercise-1-get-dy-underlying/+page.md b/courses/curve-v1/4-swap/06-exercise-1-get-dy-underlying/+page.md new file mode 100644 index 000000000..e187cea81 --- /dev/null +++ b/courses/curve-v1/4-swap/06-exercise-1-get-dy-underlying/+page.md @@ -0,0 +1,3 @@ +--- + title: Exercise 1 Get Dy Underlying + --- \ No newline at end of file From cc86cfb6616a077438703903788e96eec746cb34 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:04:59 -0600 Subject: [PATCH 044/114] Equious updated courses/curve-v1/4-swap/07-solution-1-get-dy-underlying/+page.md. --- .../curve-v1/4-swap/07-solution-1-get-dy-underlying/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/4-swap/07-solution-1-get-dy-underlying/+page.md diff --git a/courses/curve-v1/4-swap/07-solution-1-get-dy-underlying/+page.md b/courses/curve-v1/4-swap/07-solution-1-get-dy-underlying/+page.md new file mode 100644 index 000000000..8a007f563 --- /dev/null +++ b/courses/curve-v1/4-swap/07-solution-1-get-dy-underlying/+page.md @@ -0,0 +1,3 @@ +--- + title: Solution 1 Get Dy Underlying + --- \ No newline at end of file From 8654dd3ad5e7d13eae8719677afdfd318a0ce7ce Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:05:11 -0600 Subject: [PATCH 045/114] Equious updated courses/curve-v1/4-swap/08-exercise-2-exchange/+page.md. --- courses/curve-v1/4-swap/08-exercise-2-exchange/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/4-swap/08-exercise-2-exchange/+page.md diff --git a/courses/curve-v1/4-swap/08-exercise-2-exchange/+page.md b/courses/curve-v1/4-swap/08-exercise-2-exchange/+page.md new file mode 100644 index 000000000..b7b0129d9 --- /dev/null +++ b/courses/curve-v1/4-swap/08-exercise-2-exchange/+page.md @@ -0,0 +1,3 @@ +--- + title: Exercise 2 Exchange + --- \ No newline at end of file From e9c6acdda564498aee2868cfdb2ec25d647355d4 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:05:23 -0600 Subject: [PATCH 046/114] Equious updated courses/curve-v1/4-swap/09-solution-2-exchange/+page.md. --- courses/curve-v1/4-swap/09-solution-2-exchange/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/4-swap/09-solution-2-exchange/+page.md diff --git a/courses/curve-v1/4-swap/09-solution-2-exchange/+page.md b/courses/curve-v1/4-swap/09-solution-2-exchange/+page.md new file mode 100644 index 000000000..3b72eb28b --- /dev/null +++ b/courses/curve-v1/4-swap/09-solution-2-exchange/+page.md @@ -0,0 +1,3 @@ +--- + title: Solution 2 Exchange + --- \ No newline at end of file From 453df87379ff8bf8f549199f160831e30b381394 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:05:36 -0600 Subject: [PATCH 047/114] Equious updated courses/curve-v1/5-add-liquidity/01-contract-call-add-liq/+page.md. --- .../curve-v1/5-add-liquidity/01-contract-call-add-liq/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/5-add-liquidity/01-contract-call-add-liq/+page.md diff --git a/courses/curve-v1/5-add-liquidity/01-contract-call-add-liq/+page.md b/courses/curve-v1/5-add-liquidity/01-contract-call-add-liq/+page.md new file mode 100644 index 000000000..8d51e2bdf --- /dev/null +++ b/courses/curve-v1/5-add-liquidity/01-contract-call-add-liq/+page.md @@ -0,0 +1,3 @@ +--- + title: Contract Call Add Liq + --- \ No newline at end of file From 16ff24086a4b10de33ae8554aa6ab8edfce395b3 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:06:19 -0600 Subject: [PATCH 048/114] Equious updated courses/curve-v1/5-add-liquidity/02-code-outline-add-liq/+page.md. --- .../curve-v1/5-add-liquidity/02-code-outline-add-liq/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/5-add-liquidity/02-code-outline-add-liq/+page.md diff --git a/courses/curve-v1/5-add-liquidity/02-code-outline-add-liq/+page.md b/courses/curve-v1/5-add-liquidity/02-code-outline-add-liq/+page.md new file mode 100644 index 000000000..49cf09957 --- /dev/null +++ b/courses/curve-v1/5-add-liquidity/02-code-outline-add-liq/+page.md @@ -0,0 +1,3 @@ +--- + title: Code Outline Add Liq + --- \ No newline at end of file From 7393f58b4e86fc5936a4f4295fdf97266f091c9e Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:07:44 -0600 Subject: [PATCH 049/114] Equious updated courses/curve-v1/5-add-liquidity/03-imbalance-fee/+page.md. --- courses/curve-v1/5-add-liquidity/03-imbalance-fee/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/5-add-liquidity/03-imbalance-fee/+page.md diff --git a/courses/curve-v1/5-add-liquidity/03-imbalance-fee/+page.md b/courses/curve-v1/5-add-liquidity/03-imbalance-fee/+page.md new file mode 100644 index 000000000..9542178fa --- /dev/null +++ b/courses/curve-v1/5-add-liquidity/03-imbalance-fee/+page.md @@ -0,0 +1,3 @@ +--- + title: Imbalance Fee + --- \ No newline at end of file From 20cc16d0b980ecfbfc67a778f6fe29672c52e058 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:08:07 -0600 Subject: [PATCH 050/114] Equious updated courses/curve-v1/5-add-liquidity/04-code-walk-add-liq/+page.md. --- courses/curve-v1/5-add-liquidity/04-code-walk-add-liq/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/5-add-liquidity/04-code-walk-add-liq/+page.md diff --git a/courses/curve-v1/5-add-liquidity/04-code-walk-add-liq/+page.md b/courses/curve-v1/5-add-liquidity/04-code-walk-add-liq/+page.md new file mode 100644 index 000000000..3e2cbb478 --- /dev/null +++ b/courses/curve-v1/5-add-liquidity/04-code-walk-add-liq/+page.md @@ -0,0 +1,3 @@ +--- + title: Code Walk Add Liq + --- \ No newline at end of file From 22f8b2ea53645cfb5a9db9058883f9d4d5744f34 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:08:19 -0600 Subject: [PATCH 051/114] Equious updated courses/curve-v1/5-add-liquidity/05-exercise-1-add-liq/+page.md. --- .../curve-v1/5-add-liquidity/05-exercise-1-add-liq/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/5-add-liquidity/05-exercise-1-add-liq/+page.md diff --git a/courses/curve-v1/5-add-liquidity/05-exercise-1-add-liq/+page.md b/courses/curve-v1/5-add-liquidity/05-exercise-1-add-liq/+page.md new file mode 100644 index 000000000..edb52b5b4 --- /dev/null +++ b/courses/curve-v1/5-add-liquidity/05-exercise-1-add-liq/+page.md @@ -0,0 +1,3 @@ +--- + title: Exercise 1 Add Liq + --- \ No newline at end of file From 0171017528c2fb10950a74d128acec560917e60e Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:08:31 -0600 Subject: [PATCH 052/114] Equious updated courses/curve-v1/5-add-liquidity/06-solution-1-add-liq/+page.md. --- .../curve-v1/5-add-liquidity/06-solution-1-add-liq/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/5-add-liquidity/06-solution-1-add-liq/+page.md diff --git a/courses/curve-v1/5-add-liquidity/06-solution-1-add-liq/+page.md b/courses/curve-v1/5-add-liquidity/06-solution-1-add-liq/+page.md new file mode 100644 index 000000000..f81fe328b --- /dev/null +++ b/courses/curve-v1/5-add-liquidity/06-solution-1-add-liq/+page.md @@ -0,0 +1,3 @@ +--- + title: Solution 1 Add Liq + --- \ No newline at end of file From 3c1d391d78fba76256b12cff7dd73c7cd7b164f8 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:08:44 -0600 Subject: [PATCH 053/114] Equious updated courses/curve-v1/6-remove-liquidity/01-contract-call-remove-liq/+page.md. --- .../6-remove-liquidity/01-contract-call-remove-liq/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/6-remove-liquidity/01-contract-call-remove-liq/+page.md diff --git a/courses/curve-v1/6-remove-liquidity/01-contract-call-remove-liq/+page.md b/courses/curve-v1/6-remove-liquidity/01-contract-call-remove-liq/+page.md new file mode 100644 index 000000000..7d1221109 --- /dev/null +++ b/courses/curve-v1/6-remove-liquidity/01-contract-call-remove-liq/+page.md @@ -0,0 +1,3 @@ +--- + title: Contract Call Remove Liq + --- \ No newline at end of file From f2022a399f1834ac7fa50c302cff30cf8007270f Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:08:56 -0600 Subject: [PATCH 054/114] Equious updated courses/curve-v1/6-remove-liquidity/02-code-outline-remove-liq/+page.md. --- .../6-remove-liquidity/02-code-outline-remove-liq/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/6-remove-liquidity/02-code-outline-remove-liq/+page.md diff --git a/courses/curve-v1/6-remove-liquidity/02-code-outline-remove-liq/+page.md b/courses/curve-v1/6-remove-liquidity/02-code-outline-remove-liq/+page.md new file mode 100644 index 000000000..2df63c614 --- /dev/null +++ b/courses/curve-v1/6-remove-liquidity/02-code-outline-remove-liq/+page.md @@ -0,0 +1,3 @@ +--- + title: Code Outline Remove Liq + --- \ No newline at end of file From ec789d27712730b9fe0a89b6e696c8440cef6bde Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:09:09 -0600 Subject: [PATCH 055/114] Equious updated courses/curve-v1/6-remove-liquidity/03-contract-call-remove-liq-one-coin/+page.md. --- .../03-contract-call-remove-liq-one-coin/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/6-remove-liquidity/03-contract-call-remove-liq-one-coin/+page.md diff --git a/courses/curve-v1/6-remove-liquidity/03-contract-call-remove-liq-one-coin/+page.md b/courses/curve-v1/6-remove-liquidity/03-contract-call-remove-liq-one-coin/+page.md new file mode 100644 index 000000000..54ad6e845 --- /dev/null +++ b/courses/curve-v1/6-remove-liquidity/03-contract-call-remove-liq-one-coin/+page.md @@ -0,0 +1,3 @@ +--- + title: Contract Call Remove Liq One Coin + --- \ No newline at end of file From d25161be5febc6a79c414d54e96492c6452125bf Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:09:21 -0600 Subject: [PATCH 056/114] Equious updated courses/curve-v1/6-remove-liquidity/04-code-outline-remove-liq-one-coin/+page.md. --- .../04-code-outline-remove-liq-one-coin/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/6-remove-liquidity/04-code-outline-remove-liq-one-coin/+page.md diff --git a/courses/curve-v1/6-remove-liquidity/04-code-outline-remove-liq-one-coin/+page.md b/courses/curve-v1/6-remove-liquidity/04-code-outline-remove-liq-one-coin/+page.md new file mode 100644 index 000000000..81a8ab0a3 --- /dev/null +++ b/courses/curve-v1/6-remove-liquidity/04-code-outline-remove-liq-one-coin/+page.md @@ -0,0 +1,3 @@ +--- + title: Code Outline Remove Liq One Coin + --- \ No newline at end of file From eefce040054e9c30aff8a6e236478bbdf45d810c Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:09:33 -0600 Subject: [PATCH 057/114] Equious updated courses/curve-v1/6-remove-liquidity/05-code-walk-remove-liq/+page.md. --- .../6-remove-liquidity/05-code-walk-remove-liq/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/6-remove-liquidity/05-code-walk-remove-liq/+page.md diff --git a/courses/curve-v1/6-remove-liquidity/05-code-walk-remove-liq/+page.md b/courses/curve-v1/6-remove-liquidity/05-code-walk-remove-liq/+page.md new file mode 100644 index 000000000..137baa208 --- /dev/null +++ b/courses/curve-v1/6-remove-liquidity/05-code-walk-remove-liq/+page.md @@ -0,0 +1,3 @@ +--- + title: Code Walk Remove Liq + --- \ No newline at end of file From 95e6dc4cebd94ed8e46c394a54e7e3b91f70928e Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:09:46 -0600 Subject: [PATCH 058/114] Equious updated courses/curve-v1/6-remove-liquidity/06-graph-calc-withdraw-one-coin/+page.md. --- .../06-graph-calc-withdraw-one-coin/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/6-remove-liquidity/06-graph-calc-withdraw-one-coin/+page.md diff --git a/courses/curve-v1/6-remove-liquidity/06-graph-calc-withdraw-one-coin/+page.md b/courses/curve-v1/6-remove-liquidity/06-graph-calc-withdraw-one-coin/+page.md new file mode 100644 index 000000000..8892efc31 --- /dev/null +++ b/courses/curve-v1/6-remove-liquidity/06-graph-calc-withdraw-one-coin/+page.md @@ -0,0 +1,3 @@ +--- + title: Graph Calc Withdraw One Coin + --- \ No newline at end of file From 8f34716a8238e00ca4e83407d6afa24a192c7e7f Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:09:58 -0600 Subject: [PATCH 059/114] Equious updated courses/curve-v1/6-remove-liquidity/07-code-walk-remove-liq-one-coin/+page.md. --- .../07-code-walk-remove-liq-one-coin/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/6-remove-liquidity/07-code-walk-remove-liq-one-coin/+page.md diff --git a/courses/curve-v1/6-remove-liquidity/07-code-walk-remove-liq-one-coin/+page.md b/courses/curve-v1/6-remove-liquidity/07-code-walk-remove-liq-one-coin/+page.md new file mode 100644 index 000000000..1b5d4bec7 --- /dev/null +++ b/courses/curve-v1/6-remove-liquidity/07-code-walk-remove-liq-one-coin/+page.md @@ -0,0 +1,3 @@ +--- + title: Code Walk Remove Liq One Coin + --- \ No newline at end of file From 6ca1b15ff191b7ed39a5571c7eeec2c6c3a1bda4 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:10:11 -0600 Subject: [PATCH 060/114] Equious updated courses/curve-v1/6-remove-liquidity/08-code-walk-calc-withdraw-one-coin/+page.md. --- .../08-code-walk-calc-withdraw-one-coin/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/6-remove-liquidity/08-code-walk-calc-withdraw-one-coin/+page.md diff --git a/courses/curve-v1/6-remove-liquidity/08-code-walk-calc-withdraw-one-coin/+page.md b/courses/curve-v1/6-remove-liquidity/08-code-walk-calc-withdraw-one-coin/+page.md new file mode 100644 index 000000000..053c1b8d4 --- /dev/null +++ b/courses/curve-v1/6-remove-liquidity/08-code-walk-calc-withdraw-one-coin/+page.md @@ -0,0 +1,3 @@ +--- + title: Code Walk Calc Withdraw One Coin + --- \ No newline at end of file From b729827d1431056ea06f90cffdc66740d9028c41 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:10:23 -0600 Subject: [PATCH 061/114] Equious updated courses/curve-v1/6-remove-liquidity/09-exercise-1-remove-liq/+page.md. --- .../6-remove-liquidity/09-exercise-1-remove-liq/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/6-remove-liquidity/09-exercise-1-remove-liq/+page.md diff --git a/courses/curve-v1/6-remove-liquidity/09-exercise-1-remove-liq/+page.md b/courses/curve-v1/6-remove-liquidity/09-exercise-1-remove-liq/+page.md new file mode 100644 index 000000000..c469a7a3b --- /dev/null +++ b/courses/curve-v1/6-remove-liquidity/09-exercise-1-remove-liq/+page.md @@ -0,0 +1,3 @@ +--- + title: Exercise 1 Remove Liq + --- \ No newline at end of file From 81fc242eebc3738f98718ad6a4b2669366d484c4 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:10:36 -0600 Subject: [PATCH 062/114] Equious updated courses/curve-v1/6-remove-liquidity/10-solution-1-remove-liq/+page.md. --- .../6-remove-liquidity/10-solution-1-remove-liq/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/6-remove-liquidity/10-solution-1-remove-liq/+page.md diff --git a/courses/curve-v1/6-remove-liquidity/10-solution-1-remove-liq/+page.md b/courses/curve-v1/6-remove-liquidity/10-solution-1-remove-liq/+page.md new file mode 100644 index 000000000..441153073 --- /dev/null +++ b/courses/curve-v1/6-remove-liquidity/10-solution-1-remove-liq/+page.md @@ -0,0 +1,3 @@ +--- + title: Solution 1 Remove Liq + --- \ No newline at end of file From 6866ccfd9249f9aded486734572b80e22d03914c Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:10:48 -0600 Subject: [PATCH 063/114] Equious updated courses/curve-v1/6-remove-liquidity/11-exercise-2-remove-liq-one-coin/+page.md. --- .../11-exercise-2-remove-liq-one-coin/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/6-remove-liquidity/11-exercise-2-remove-liq-one-coin/+page.md diff --git a/courses/curve-v1/6-remove-liquidity/11-exercise-2-remove-liq-one-coin/+page.md b/courses/curve-v1/6-remove-liquidity/11-exercise-2-remove-liq-one-coin/+page.md new file mode 100644 index 000000000..7be0c430b --- /dev/null +++ b/courses/curve-v1/6-remove-liquidity/11-exercise-2-remove-liq-one-coin/+page.md @@ -0,0 +1,3 @@ +--- + title: Exercise 2 Remove Liq One Coin + --- \ No newline at end of file From 6c98f0933a69bd79fd17de3b846df818239d890c Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:11:00 -0600 Subject: [PATCH 064/114] Equious updated courses/curve-v1/6-remove-liquidity/12-solution-2-remove-liq-one-coin/+page.md. --- .../12-solution-2-remove-liq-one-coin/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/curve-v1/6-remove-liquidity/12-solution-2-remove-liq-one-coin/+page.md diff --git a/courses/curve-v1/6-remove-liquidity/12-solution-2-remove-liq-one-coin/+page.md b/courses/curve-v1/6-remove-liquidity/12-solution-2-remove-liq-one-coin/+page.md new file mode 100644 index 000000000..59ed95901 --- /dev/null +++ b/courses/curve-v1/6-remove-liquidity/12-solution-2-remove-liq-one-coin/+page.md @@ -0,0 +1,3 @@ +--- + title: Solution 2 Remove Liq One Coin + --- \ No newline at end of file From 267700a09ebea2b13370d30ab681225892e2d2b7 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:52:26 -0600 Subject: [PATCH 065/114] Equious updated courses/curve-v1/1-overview/1-introduction/+page.md. --- .../1-overview/1-introduction/+page.md | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/1-overview/1-introduction/+page.md b/courses/curve-v1/1-overview/1-introduction/+page.md index c21ef2ce7..514791728 100644 --- a/courses/curve-v1/1-overview/1-introduction/+page.md +++ b/courses/curve-v1/1-overview/1-introduction/+page.md @@ -1,3 +1,31 @@ ---- - title: Introduction - --- \ No newline at end of file +This course is an introduction to the Curve V1 AMM. + +We'll start by looking at the prerequisites for this course. You should be an intermediate Solidity developer, and have experience with Foundry. You should also understand the mathematics of constant product AMMs and constant sum AMMs. + +Here are some optional prerequisites for this course: + +* Uniswap V2 and V3 +* A basic understanding of DeFi. +* Python + +In the course, we'll compare Uniswap V2, V3, and Curve V1. We'll also discuss some basic DeFi concepts, such as stablecoins like DAI and USDC. + +A basic understanding of DeFi will help. + +Finally, we have some optional lessons where we'll use Python to show you some of the math of Curve V1. + +These are nice to have, but they're not required to follow along with the course. + +Here are a few reasons why you should take this course: + +* Understanding Curve V1 might give you some ideas for new AMM design. +* It might also help you in audit contests and bug bounties. +* It is a prerequisite to understand Curve V2. + +Here's what we'll learn in this course: + +* The math and algorithms of Curve V1 +* Vyper +* Testing with Foundry + +Curve V1 is written in Vyper, and we'll do a code walkthrough of the Curve V1 contract. You'll gain some experience reading Vyper. There are exercises and solutions written in Foundry, so you'll have hands-on experience testing with Foundry. From 991fbbd7163629dea15dea381fa446b202363cb2 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:52:50 -0600 Subject: [PATCH 066/114] Equious updated courses/curve-v1/1-overview/2-lead-instructor/+page.md. --- .../1-overview/2-lead-instructor/+page.md | 69 ++++++++++++++++++- 1 file changed, 66 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/1-overview/2-lead-instructor/+page.md b/courses/curve-v1/1-overview/2-lead-instructor/+page.md index bbe86a03f..9d11ede17 100644 --- a/courses/curve-v1/1-overview/2-lead-instructor/+page.md +++ b/courses/curve-v1/1-overview/2-lead-instructor/+page.md @@ -1,3 +1,66 @@ ---- - title: Lead Instructor - --- \ No newline at end of file +## Introduction to Solidity and Vyper + +We'll start with an introduction to the smart contract programming languages Solidity and Vyper. We'll learn about the differences between these languages and what they're commonly used for. + +First, let's see how many people are familiar with Solidity and Vyper. It's worth knowing that Solidity is probably the most popular smart contract programming language. This is because Solidity is used to develop smart contracts for the Ethereum Blockchain. Vyper is another language that's also used for Ethereum smart contracts, but it's less popular. This is because Vyper is a more secure language and can be considered a more secure alternative to Solidity. + +We'll discuss why Vyper is more secure than Solidity as we go through the course. + +Now, let's get started with our first example. In Solidity, the first thing we'll always see is the pragma statement. In the following example, we're targeting Solidity version 0.8.26 and this is a common statement that we'll see in many smart contracts. + +```javascript +pragma solidity ^0.8.26; +``` + +This statement is important because it ensures that the smart contract code is compatible with the specified version of the Solidity compiler. If you are using an incompatible version, your smart contract code will not compile. + +We'll also see that there are various Solidity versions. These versions differ in terms of features and the available syntax, so it's crucial to use the correct version for your project. + +The next thing we'll see is the contract definition. In this case, we're defining a contract named "MyContract." Solidity supports the use of inheritance. + +```javascript +contract MyContract { +} +``` + +This example defines a simple contract named "MyContract" which we can deploy onto a blockchain to store and update state variables and execute functionality. + +Now let's look at a simple Vyper example. + +```javascript +# pragma solidity ^0.8.26 + +from vyper.interfaces import ERC20 + +interface IUniswapV2Pair: + def getReserves() -> tuple: + pass + +interface IUniswapV2Factory: + def getPair(tokenA: address, tokenB: address) -> address: + pass + +def get_pair(factory: address, tokenA: address, tokenB: address) -> address: + """ + Get the UniswapV2 pair address for two tokens. + """ + return IUniswapV2Factory(factory).getPair(tokenA, tokenB) +``` + +This code contains several interesting elements: + +1. The first line indicates that the Vyper compiler version is `0.8.26`. +2. It imports the `ERC20` interface from `vyper.interfaces`. +3. It defines a custom interface `IUniswapV2Pair` to allow interacting with UniswapV2 pair contracts. +4. It defines another interface `IUniswapV2Factory` to interact with UniswapV2 factory contracts. +5. Finally, it defines a function `get_pair` to return the UniswapV2 pair address for two given tokens. + +We can also see that Vyper is a very different language compared to Solidity. + +Let's go through a quick comparison of Solidity and Vyper: + +* **Solidity** is a Turing-complete language which means it's powerful but can be complex and susceptible to errors. +* **Vyper** is a more limited language that can be easier to use and more secure. + +The next topic we'll cover is the concept of smart contracts. + From 3eefe251beafadf189903890f9acc309292ad6a0 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:53:14 -0600 Subject: [PATCH 067/114] Equious updated courses/curve-v1/1-overview/3-word-about-repo/+page.md. --- .../1-overview/3-word-about-repo/+page.md | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/1-overview/3-word-about-repo/+page.md b/courses/curve-v1/1-overview/3-word-about-repo/+page.md index 8583298a3..a6fafca7f 100644 --- a/courses/curve-v1/1-overview/3-word-about-repo/+page.md +++ b/courses/curve-v1/1-overview/3-word-about-repo/+page.md @@ -1,3 +1,13 @@ ---- - title: Word About Repo - --- \ No newline at end of file +We will be using a GitHub repository called `advanced-defi-2024`. For the course for Curve V1, we need to scroll down and look for a Markdown file called `curve-v1.md`. + +Click on this file to go to the Markdown file that shows all the links that we will need in this course. This file lists the prerequisites that we have already discussed and the tools that we will need. + +The tools that we will need are: +* Foundry +* Python/Jupyter Lab (optional) + +For each lesson, we need to watch the videos on Cyfrin Updraft. For the exercises, we can find the link under the section called Topics. Scrolling down, we see a section called Topics and then links to exercises and solutions under the sections for each lesson. + +There are other links inside this Markdown file, some of them linked to code used in the videos, others linked to notes and graphs. + +If we have further questions, we can navigate to GitHub discussions under this repository. From bc019daeefc1e546628234d8a8dcef03fbf3df07 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:53:39 -0600 Subject: [PATCH 068/114] Equious updated courses/curve-v1/1-overview/4-setup-repo/+page.md. --- .../curve-v1/1-overview/4-setup-repo/+page.md | 40 +++++++++++++++++-- 1 file changed, 37 insertions(+), 3 deletions(-) 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 83c914591..684267809 100644 --- a/courses/curve-v1/1-overview/4-setup-repo/+page.md +++ b/courses/curve-v1/1-overview/4-setup-repo/+page.md @@ -1,3 +1,37 @@ ---- - title: Setup Repo - --- \ No newline at end of file +To do the exercises in this course, we need to get clone this repo. And to do that, click on Code and then copy this URL. + +Inside the terminal type in: + +```bash +git clone +``` + +and then paste the repo. + +Once the repo is cloned into your computer, next CD into advanced-defi-2024. + +```bash +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 +``` + +Now this command only works for Linux. + +Once Foundry is installed, let's do a quick check to make sure that the contracts which are used for the exercises compile. The contracts are located under a folder called Foundry, so say: + +```bash +cd foundry +``` + +And inside here we'll do a quick check by compiling the contract. + +```bash +forge build +``` + +And the contract compiled successfully. So, if you made it this far, congratulations, you are now ready to do the exercises. From 2cb868a9f90395b855327228fc94d5aaa7d48dcb Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:54:03 -0600 Subject: [PATCH 069/114] Equious updated courses/curve-v1/1-overview/5-ex-sol/+page.md. --- courses/curve-v1/1-overview/5-ex-sol/+page.md | 47 +++++++++++++++++-- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/1-overview/5-ex-sol/+page.md b/courses/curve-v1/1-overview/5-ex-sol/+page.md index 0a0a5e47a..2c069490e 100644 --- a/courses/curve-v1/1-overview/5-ex-sol/+page.md +++ b/courses/curve-v1/1-overview/5-ex-sol/+page.md @@ -1,3 +1,44 @@ ---- - title: Ex Sol - --- \ No newline at end of file +We'll go through an introduction to the exercises and solutions included in this repository. + +The exercises and solutions are located under the `test` folder. +```bash +cd test +``` + +The tests are grouped by DeFi protocol. Each DeFi protocol has an `exercises` and `solutions` folder. +* The `exercises` folder contains starter code for you to write your code. +* The `solutions` folder contains solutions for you to check your code. + +We'll go through an example by executing the code inside the `curve-v1` solutions folder. + +First, we'll set up our `FORK_URL` environment variable. This will be the URL that will be used to execute our code against the main network. + +```bash +FORK_URL=https://eth-mainnet.g.alchemy.com/v2/KzrtPzEzhqNs4Jn_05qM7M4AjS50K4 +``` +The `FORK_URL` I used was from Alchemy. + +Next, let's execute the code inside the `curve-v1` solutions. + +We'll execute the code inside `CurveV1Swap.test.sol`. To do this, we need to run the following command in our terminal. + +```bash +forge test --fork-url $FORK_URL --match-path test/curve-v1/solutions/CurveV1Swap.test.sol --match-test test_exchange --vvv +``` + +The command contains the following: +* `forge test`: The command used to execute the tests. +* `--fork-url $FORK_URL`: Sets the `FORK_URL` environment variable. +* `--match-path test/curve-v1/solutions/CurveV1Swap.test.sol`: Specifies the path to the test file. +* `--match-test test_exchange`: Only runs the `test_exchange` function. +* `--vvv`: Verbose mode, prints extra information. + +We can also change the command to only execute one of the contracts inside the exercises. We'll start with the same command as the previous example and change the path to `test/curve-v1/exercises/CurveV1Swap.test.sol`. + +```bash +forge test --fork-url $FORK_URL --match-path test/curve-v1/exercises/CurveV1Swap.test.sol --match-test test_exchange --vvv +``` + +The `test_exchange` function fails because the code inside the contract is incomplete. It is your task to fill the code inside the contract under the exercises. + +This is how the exercises and solutions are organized inside this repository. From 1d3bdc0522ddbd78dd8841a4a4192281ece463b2 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:54:25 -0600 Subject: [PATCH 070/114] Equious updated courses/curve-v1/1-overview/6-curve-intro/+page.md. --- .../1-overview/6-curve-intro/+page.md | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/1-overview/6-curve-intro/+page.md b/courses/curve-v1/1-overview/6-curve-intro/+page.md index d81637b1b..3db44083c 100644 --- a/courses/curve-v1/1-overview/6-curve-intro/+page.md +++ b/courses/curve-v1/1-overview/6-curve-intro/+page.md @@ -1,3 +1,23 @@ ---- - title: Curve Intro - --- \ No newline at end of file +## Introduction to Curve v1 + +Curve v1 is an automated market maker (AMM) optimized for swapping tokens that have similar prices. This is a DeFi tool designed to minimize slippage and maximize gains for stablecoins and similar assets. + +## Understanding Stablecoins + +Stablecoins are cryptocurrencies pegged to a stable asset, such as the US dollar. This means their value aims to stay close to that asset's value. USDC and DAI are examples of stablecoins that target $1. + +## Swapping USDC and DAI + +We can use Curve v1 to swap USDC and DAI, as both are stablecoins. When swapping 1,000 USDC on Uniswap v2, we might lose $4 due to slippage. However, Curve v1 can offer a better deal, minimizing the loss to less than $1. + +## How Curve v1 Minimizes Slippage + +Curve v1 uses a liquidity pool specifically designed for stablecoins. This pool allows for more efficient swaps, as the underlying assets have a smaller price difference. + +## Example: Swapping USDC and DAI on Curve v1 + +We can see an example of swapping 1,000 USDC on Curve v1. The result is closer to 1,000 DAI, showcasing the minimized slippage. This is possible because Curve v1 is optimized for swapping stablecoins, unlike Uniswap v2 which handles a wider range of assets. + +## Conclusion + +Curve v1 is a valuable tool for DeFi users looking to swap stablecoins and similar assets with minimal slippage. Its optimization for these assets ensures that trades are close to a 1:1 exchange rate, maximizing the return on your investments. From 4a71763e527fdda35b79f71cf2183db9891b094a Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:54:49 -0600 Subject: [PATCH 071/114] Equious updated courses/curve-v1/1-overview/7-comparison/+page.md. --- .../curve-v1/1-overview/7-comparison/+page.md | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/1-overview/7-comparison/+page.md b/courses/curve-v1/1-overview/7-comparison/+page.md index 9625d289b..8e3fe15b7 100644 --- a/courses/curve-v1/1-overview/7-comparison/+page.md +++ b/courses/curve-v1/1-overview/7-comparison/+page.md @@ -1,3 +1,25 @@ ---- - title: Comparison - --- \ No newline at end of file +## Comparing Curve V1, Uniswap V2, and Uniswap V3 (Swapping USDC/DAI) + +In this lesson, we will consider the differences between Curve V1, Uniswap V2, and Uniswap V3. Specifically, we will look at these differences in the context of swapping USDC and DAI. + +Let's begin by considering the language used by each AMM. Both Uniswap V2 and Uniswap V3 are written in Solidity. Curve V1, on the other hand, is written in Vyper. + +In the previous video, we saw that Uniswap V2 has high slippage. For example, if we were to swap 1,000 USDC, then we would only receive 996 DAI on Uniswap V2. Uniswap V3 introduces concentrated liquidity, which results in lower slippage. If we were to swap 1,000 USDC, we would likely receive something close to 1,000 DAI. + +Curve V1 also has low slippage. If we were to swap 1,000 USDC on Curve V1, we would receive 999.92 DAI. + +The next difference we will consider is how many tokens can be added to the pools. Both Uniswap V2 and Uniswap V3 support only two tokens. For example, on Uniswap V2, we saw a USDC/DAI pool. Uniswap V3 can also only have two tokens. + +Curve V1 is different. It can have two or more tokens. For example, on the Curve Finance user interface, we can see a pool that has three tokens: DAI, USDC, and USDT. There are also pools with four tokens. + +Another difference between Uniswap AMMs and Curve AMMs is how liquidity is added and removed. In Uniswap V2, when we add liquidity, both tokens must be sent. When we remove liquidity, both tokens will come out. + +Uniswap V3 is a little more complex. Adding liquidity depends on the price range that we are adding liquidity to and the current price. If we add liquidity to a price range outside the current active price, then we can only add one token. However, if we are adding liquidity to a price range that includes the active price, then we must add both tokens. Removing liquidity works the same way. If we are removing liquidity from a position outside the active price, then we can only withdraw one token. However, if our liquidity position is within the active price, then we will get both tokens. + +Curve V1 allows us to specify which tokens we want to withdraw. It can be one token, it can be all tokens, or it can be somewhere in between. For example, if we have 100 LP tokens in a Curve pool that consists of DAI, USDC, and USDT, and we only want to withdraw DAI, then we can do so. We can also withdraw only USDC or USDT. We can also withdraw all of the tokens in a balanced way or specify how we want to withdraw them. For example, we could decide to withdraw only DAI and USDT and not USDC. + +On Uniswap V2 and Uniswap V3, there is no fee charged for adding or removing liquidity. However, on Curve V1, there is a fee charged for imbalance. This means that if we had 100 USDC, 100 DAI, and 100 USDT in a Curve pool and decided to withdraw all of our liquidity in DAI, then a fee would be charged. The same is true when we are adding liquidity. + +The last major difference between Uniswap and Curve V1 is how swap fees are charged. Both Uniswap V2 and Uniswap V3 charge swap fees on token in. However, Curve V1 charges swap fees on token out. + +These are just some of the key differences between Curve V1, Uniswap V2, and Uniswap V3. As you can see, each AMM has its own unique characteristics. From 617265dc7a4ec999128f3a90a73b0e21b7e25a74 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:55:25 -0600 Subject: [PATCH 072/114] Equious updated courses/curve-v1/2-math/01-graph-eq/+page.md. --- courses/curve-v1/2-math/01-graph-eq/+page.md | 44 ++++++++++++++++++-- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/2-math/01-graph-eq/+page.md b/courses/curve-v1/2-math/01-graph-eq/+page.md index e7a9b408b..9b174641c 100644 --- a/courses/curve-v1/2-math/01-graph-eq/+page.md +++ b/courses/curve-v1/2-math/01-graph-eq/+page.md @@ -1,3 +1,41 @@ ---- - title: Graph Eq - --- \ No newline at end of file +## Curve B1's AMM Curve + +We are going to cover the Uniswap V2 AMM curve, specifically the B1 curve. The equation for a constant product curve is: + +``` +x * y = k +``` + +We can also graph the constant sum curve using the equation: + +``` +x + y = d +``` + +In this case, instead of using _k_, we will use _d / 2�_. + +The B1 curve equation is a combination of the constant product and constant sum curves. The equation is as follows: + +``` +xy + A(x + y) * (d / 2)� = (d / 2)� + AD� +``` + +The parameter _A_ defines how flat the curve is. As _A_ increases, the curve becomes more flat and looks like the constant sum curve. If _A_ decreases, the curve behaves more like the constant product curve. + +We can also see this by multiplying the constant sum equation by _x_ and _y_: + +``` +xy + A(x + y) * (d / 2)� = (d / 2)� + AD� +``` + +We can further adjust the equation by dividing by _d / 2�_: + +``` +xy / (d / 2)� + A(x + y) = 1 + AD� / (d / 2)� +``` + +We can see that if _x_ and _y_ are equal to _d / 2_, the term _xy / (d / 2)�_ is equal to 1. Conversely, if _x_ and _y_ are not equal to _d / 2_, the term approaches zero. + +When _x_ and _y_ are balanced, the curve behaves like the constant sum curve. However, when _x_ and _y_ are imbalanced, the curve behaves more like the constant product curve. + +In summary, the B1 curve is a combination of constant product and constant sum curves. This gives the curve the ability to behave like either curve depending on the balance of the tokens. From 43e0d9a8b84cb1ae44d6d179f2b0446564345839 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:55:48 -0600 Subject: [PATCH 073/114] Equious updated courses/curve-v1/2-math/02-graph-xy/+page.md. --- courses/curve-v1/2-math/02-graph-xy/+page.md | 52 ++++++++++++++++++-- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/2-math/02-graph-xy/+page.md b/courses/curve-v1/2-math/02-graph-xy/+page.md index 368155fd8..6bf51635f 100644 --- a/courses/curve-v1/2-math/02-graph-xy/+page.md +++ b/courses/curve-v1/2-math/02-graph-xy/+page.md @@ -1,3 +1,49 @@ ---- - title: Graph Xy - --- \ No newline at end of file +In the previous video, we graphed curves onto 3D and we worked with an equation that represented the curve in between a constant sum and a constant product. The equation was x times y divided by d over 2 squared. + +We are going to take a closer look at this equation in 3D. + +When we graph this equation, we get a 3D surface. + +```javascript +f(x,y)=xy/((d/2)^2) +``` + +The inputs are all the points on the x y plane and the output is described in the z-axis. + +The result is a 2D surface in 3D. + +Now, we want to know how this function behaves on the points of the curves V1 curve. + +First, we will plot the equation x times y divided by d over 2 squared for all of the points on the constant product. + +We will take the x and y points that satisfy x times y equals d over 2 squared and then we will evaluate the equation. + +The result is a blue line on the 2D surface. + +```javascript +f(x,y)=xy/((d/2)^2) +``` + +The z-axis value is always 1 for this blue line. + +This is because x times y is always equal to d over 2 squared. + +This function will always evaluate to 1. + +Now, we will look at the points on the constant sum curve. + +This produces an arc on the surface. + +The arc touches 1 and decreases to 0 as y goes to 0, and also decreases to 0 as x goes to 0. + +We can plot a point at (d over 2, d over 2, 1) to see where this equation evaluates to 1. + +We can also see that this orange line approaches 0 as x and y become more unbalanced. + +When we evaluate this equation for the curves V1 curve, we get the orange line. The line represents the z-axis value for each point of the V1 curve. + +The orange line approaches 0 as x and y become more unbalanced. + +We have now analyzed how x times y divided by d over 2 squared behaves in 3D. + +When x and y are close to d over 2, then the equation evaluates to 1. As x and y become more unbalanced, they approach 0. From b696e2cfca8535c465888e78572eb452fe80c0c9 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:56:12 -0600 Subject: [PATCH 074/114] Equious updated courses/curve-v1/2-math/03-math/+page.md. --- courses/curve-v1/2-math/03-math/+page.md | 59 ++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/2-math/03-math/+page.md b/courses/curve-v1/2-math/03-math/+page.md index d246d700c..12020658d 100644 --- a/courses/curve-v1/2-math/03-math/+page.md +++ b/courses/curve-v1/2-math/03-math/+page.md @@ -1,3 +1,56 @@ ---- - title: Math - --- \ No newline at end of file +## Curve V1 Equation + +We'll cover the Curve V1 equation, which can be found in the Curve whitepaper. + +The general equation for *n* tokens is shown below. *n* represents the number of tokens, which can be greater than or equal to 2. + +``` +kai * sum all of the token balances from i = 1 to i = n + multiply all of the token balances from i = 1 to i = n = kai * (D + (D / n) raised to the power of n) +``` +This equation is a combination of the constant sum and constant product. + +We can substitute the *kai* symbol with its corresponding terms, which is *A* multiplied by all of the token balances, divided by *D* / *n*, and then raised to the power of *n*. + +``` +A * sum all of the token balances from i = 1 to i = n / (D / n) raised to the power of n * sum all of the token balances from i = 1 to i = n + multiply all of the token balances from i = 1 to i = n = A * (D + (D / n) raised to the power of n) +``` + +The whitepaper also contains an alternative form of the Curve V1 equation. The form is shown below: + +``` +A * n raised to the power of n * sum all of the token balances from i = 1 to i = n + D = A * D * n raised to the power of n + D raised to the power of n + 1 / product of all coins from i = 1 to i = n +``` +We can derive this alternative form from the general form by dividing both sides of the equation by *D* divided by the product of all the tokens. + +Let's simplify the left side of the equation first: + +``` +A * n raised to the power of n / (D / n) raised to the power of n * sum all of the token balances from i = 1 to i = n + D +``` +*A* and the product of all of the tokens will cancel out on both the top and the bottom. *D* raised to the power of *n* will cancel out with *D* raised to the power of *n - 1* multiplied by *D*. + +This will leave us with: + +``` +A * n raised to the power of n * sum all of the token balances from i = 1 to i = n + D +``` + +Now, let's simplify the right side of the equation: + +``` +A * (D + (D / n) raised to the power of n) / (D / product of all coins from i = 1 to i = n) +``` +The product of all the coins cancels out on both the top and the bottom. *D* raised to the power of *n* will cancel out with *D* raised to the power of *n - 1* multiplied by *D*. + +This will leave us with: + +``` +A * D * n raised to the power of n + D raised to the power of n + 1 / product of all coins from i = 1 to i = n +``` + +Putting the left and right side together, we get: + +``` +A * n raised to the power of n * sum all of the token balances from i = 1 to i = n + D = A * D * n raised to the power of n + D raised to the power of n + 1 / product of all coins from i = 1 to i = n +``` +This is the alternative form of the Curve V1 equation. From ff3ed2b9aa7637ca7ddd71a9fcb681a2483d8f05 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:56:37 -0600 Subject: [PATCH 075/114] Equious updated courses/curve-v1/2-math/04-newton/+page.md. --- courses/curve-v1/2-math/04-newton/+page.md | 56 ++++++++++++++++++++-- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/2-math/04-newton/+page.md b/courses/curve-v1/2-math/04-newton/+page.md index 3a448df12..4a48e79eb 100644 --- a/courses/curve-v1/2-math/04-newton/+page.md +++ b/courses/curve-v1/2-math/04-newton/+page.md @@ -1,3 +1,53 @@ ---- - title: Newton - --- \ No newline at end of file +In this lesson, we'll discuss how Curve utilizes a mathematical technique called Newton's Method to compute the amount of tokens to be exchanged and liquidity. We'll also provide an overview of how Newton's method works. + +## Curve v1 Newton's Method + +Let's start with the simple case of Uniswap v2. For Uniswap v2, the amount of tokens to be received from a swap and the liquidity can be calculated directly from a simple equation: + +```javascript +x * y = L +``` + +where x represents the token being swapped for, and y represents the token to be received. L represents the liquidity. + +For Uniswap v3, there is no easy equation to calculate x, y, or D. + +## Newton's Method + +Newton's Method is a mathematical technique used to find the solution for an equation f(x) = 0. The goal is to find the value of x where the function f(x) will evaluate to zero. + +Here is the algorithm for Newton's Method: + +```javascript +x_n = x_0 + +while True: + x_{n+1} = x_n - f(x_n) / f(x_n) + + if abs(x_{n+1} - x_n) <= some small number: + return x_{n+1} + + x_n = x_{n+1} +``` + +## Using Newton's Method + +Let's take a look at how Newton's Method is used in Curve to calculate y and D. For the following examples, we'll be using the equation for n = 2: + +**Newton's method to find y** + +```javascript +F(y) = x * D(x+y) + x * y - x * D(1/2)^2 +``` + +We use Newton's Method to find the value of y where f(y) = 0. + +**Newton's method to find D** + +```javascript +F(D) = x * D(x+y) + x * y - x * D(1/2)^2 +``` + +We use Newton's Method to find the value of D where f(D) = 0. + +In the next video, we'll go over how to implement these examples using Python. From 323c36d599bb3f8c7d4c8682f9a99940dd39d0d6 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:57:01 -0600 Subject: [PATCH 076/114] Equious updated courses/curve-v1/2-math/05-newton-python/+page.md. --- .../curve-v1/2-math/05-newton-python/+page.md | 123 +++++++++++++++++- 1 file changed, 120 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/2-math/05-newton-python/+page.md b/courses/curve-v1/2-math/05-newton-python/+page.md index 235ccef7a..66e3e23fc 100644 --- a/courses/curve-v1/2-math/05-newton-python/+page.md +++ b/courses/curve-v1/2-math/05-newton-python/+page.md @@ -1,3 +1,120 @@ ---- - title: Newton Python - --- \ No newline at end of file +## Newton's Method in Python + +We will work through a couple of examples of using Newton's method in Python. + +### Example 1 + +Let's say we have a simple function given by the following equation: +```python +def f(x): + return x**2 - 2 +``` +and we want to find the value of *x* for which *f(x) = 0*. Newton's method is a numerical method that allows us to approximate the solution to this equation. + +Here's the Python code that implements Newton's method to solve for *x*: +```python +def f(x): + return x**2 - 2 + +def df(x): + return 2*x + +def f_solve(f, df, x0, delta): + for i in range(n): + print(i, x0) + x1 = x0 - f(x0) / df(x0) + if abs(x1 - x0) <= delta: + return x1 + assert False, "cannot find solution" + x0 = x1 + +n = 1000 +delta = 0.0001 +x = f_solve(f, df, 1, n, delta) +print("f(x) =", f(x)) +print("x =", x) +``` + +In this code: + +* `f(x)` is our function, which takes a single input *x* and returns the value of *x� - 2*. +* `df(x)` is the derivative of our function, which returns the value of *2x*. +* `f_solve(f, df, x0, delta)` is the function that implements Newton's method. It takes the function `f`, its derivative `df`, an initial guess `x0`, and a tolerance `delta`. The function iterates until the difference between successive approximations is less than the tolerance. +* `n` is the maximum number of iterations allowed. +* `delta` is the tolerance value. + +**Running the code:** + +We set our initial guess to *1*, the maximum number of iterations to *1,000*, and the tolerance to *0.0001*. When we run this code, we get the following output: + +```bash +python newton_example.py +``` + +The output will show the iterations performed by the code until it finds a solution. The final value of *x* will be approximately *1.41421*, which is the square root of 2. + +### Example 2 + +Now let's say we have a curve defined by the following equation: + +```python +def f(x, y, A, D): + K = A * x * y / (D / 2)**2 + return x * y + K - (D / 2)**2 - K * D**2 +``` + +We know the values of *x*, *A*, and *D*, and we want to find the value of *y* that satisfies this equation. + +To solve for *y*, we'll use Newton's method again. The Python code is similar to the previous example, but we need to define new functions for our curve and its derivative with respect to *y*. Here's the modified code: + +```python +def f(x, y, A, D): + K = A * x * y / (D / 2)**2 + return x * y + K - (D / 2)**2 - K * D**2 + +n = 100 +delta = 0.0001 +x = 120 +y = 90 +A = 10 +D = 200 + +def f_D(d): + return f(x, y, A, d) + +def df_d(d): + return 4 * A * x * y * d / 2 - d / 2 + +d = f_solve(f_D, df_d, D, n, delta) +print("d", d) +print("f_D(d)", f_D(d)) + +def f_y(y): + return f(x, y, A, d) + +def df_dy(y): + return x + 4 * A * x * y * d / 2 - A * x * d * (y * d / 2) / d**2 + +y = f_solve(f_y, df_dy, y, n, delta) +print("y", y) +print("f_y(y)", f_y(y)) +``` + +Here, we've defined: + +* `f_y(y)` is the function for the curve, taking *y* as input and using the known values of *x*, *A*, and *D*. +* `df_dy(y)` is the partial derivative of the curve's function with respect to *y*. + +**Running the code:** + +We'll execute this code and get the following output: + +```bash +python newton_example.py +``` + +The output shows that Newton's method finds a value for *y* that is close enough to satisfy the curve's equation. + +### Conclusion + +Newton's method is a powerful tool for finding solutions to equations. We have seen how to use it in Python, and how to modify it to solve different problems. From fb10a0a1f6dec6fdfb325bf4e072d84b002b8f7c Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:57:34 -0600 Subject: [PATCH 077/114] Equious updated courses/curve-v1/2-math/06-sympy/+page.md. --- courses/curve-v1/2-math/06-sympy/+page.md | 49 +++++++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/2-math/06-sympy/+page.md b/courses/curve-v1/2-math/06-sympy/+page.md index 05aad1f19..bdddeb6f3 100644 --- a/courses/curve-v1/2-math/06-sympy/+page.md +++ b/courses/curve-v1/2-math/06-sympy/+page.md @@ -1,3 +1,46 @@ ---- - title: Sympy - --- \ No newline at end of file +We will use Python to calculate partial derivatives for the curve's equation. The library we will use is called `sympy`. + +First we need to import `sympy`: + +```python +from sympy import symbols, diff, simplify, init_printing +init_printing() +``` + +Next, we need to define the curve's equation: + +```python +x, y, D, A = symbols('x y D A') +k = A*x*y*(D**2) / (2*(D**2) + k*D**2) +f = k*x*y + k*x*y * D / 2 +display(f) +``` + +To get the partial derivative of this function with respect to `D` and with respect to `y`, we need to call a function that is provided by the `sympy` library called `diff`. Here we will tell `diff` to differentiate the function `f` with respect to `D`: + +```python +df_dD = diff(f, D) +``` + +Likewise, we will differentiate the function `f` with respect to `y`: + +```python +df_dy = diff(f, y) +``` + +We can then print the results of our differentiation: + +```python +print('df / dD') +print(df_dD) +print('df / dy') +print(df_dy) +``` + +Next, we will discuss a method called Newton's method to solve for `y`: + +```python +y_n = y - f / df_dy +``` + +This is the end of this introductory lesson on partial derivatives. From d80ae5baa1ebe9dca7d8564f6b43c589c4a522cb Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:57:58 -0600 Subject: [PATCH 078/114] Equious updated courses/curve-v1/3-contract-overview/01-contract-overview/+page.md. --- .../01-contract-overview/+page.md | 49 +++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/3-contract-overview/01-contract-overview/+page.md b/courses/curve-v1/3-contract-overview/01-contract-overview/+page.md index 945bf909b..ecee9e97e 100644 --- a/courses/curve-v1/3-contract-overview/01-contract-overview/+page.md +++ b/courses/curve-v1/3-contract-overview/01-contract-overview/+page.md @@ -1,3 +1,46 @@ ---- - title: Contract Overview - --- \ No newline at end of file +## Curve V1 Contracts + +We will discuss the contracts that Curve V1 uses to support its automated market maker (AMM). Curve V1 AMMs are a variation of a base contract called StableSwap. + +## StableSwap + +We will discuss the StableSwap contract by looking at examples of pool contracts: 3pool and stETH. + +### 3pool + +The 3pool contract supports three tokens: DAI, USDC, and USDT. The pool contract name is `StableSwap3pool`. + +#### N_COINS + +The `N_COINS` constant is defined as three. This constant is important because we will need to use it when we call a Curve V1 AMM contract. + +#### addLiquidity + +The `addLiquidity` function takes an array of tokens as input. The size of the array is determined by the `N_COINS` constant. We will need to ensure that we provide the correct number of tokens when we call this function. + + +```javascript +def add_liquidity(amounts: uint256[N_COINS], min_amount: uint256) -> uint256: +``` + +### stETH + +The stETH contract supports two tokens: ETH and stETH. The pool contract name is `StableSwap stETH`. + +#### N_COINS + +The `N_COINS` constant is defined as two. + +#### addLiquidity + +The `addLiquidity` function takes an array of tokens as input. The size of the array is determined by the `N_COINS` constant. We will need to ensure that we provide the correct number of tokens when we call this function. + + +```javascript +def add_liquidity(amounts: uint256[N_COINS], min_amount: uint256) -> uint256: +``` + + +## Summary + +Curve V1 uses a contract called StableSwap for its AMMs. The pool contracts are variations of this base contract, such as `StableSwap3pool` and `StableSwap stETH`. Each pool contract holds a specific number of tokens, determined by the `N_COINS` constant. We will need to ensure that we provide the correct number of tokens when we interact with these contracts. From 8e043bc950f949cccbc98c6b6a3831ea5d1fd285 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:58:22 -0600 Subject: [PATCH 079/114] Equious updated courses/curve-v1/3-contract-overview/02-contract-functions/+page.md. --- .../02-contract-functions/+page.md | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/3-contract-overview/02-contract-functions/+page.md b/courses/curve-v1/3-contract-overview/02-contract-functions/+page.md index 79669e080..8f8c284e6 100644 --- a/courses/curve-v1/3-contract-overview/02-contract-functions/+page.md +++ b/courses/curve-v1/3-contract-overview/02-contract-functions/+page.md @@ -1,3 +1,13 @@ ---- - title: Contract Functions - --- \ No newline at end of file +The StableSwap contract can hold any number of tokens. For example, the StableSwap3Pool contract manages the tokens DAI, USDC, and USDT. Another example we saw was the STEF4 which holds two tokens, EIF and STEIF. + +We will cover five functions that are common to all StableSwap contracts. These are: + +* exchange +* add\_liquidity +* remove\_liquidity +* remove\_liquidity\_imbalance +* remove\_liquidity\_one\_coin + +The `exchange` function is used to swap tokens. `add_liquidity` is used to add tokens to the pool. + +For removing liquidity, there are several variations. The `remove_liquidity` function will return the liquidity providers all of the tokens. `remove_liquidity_imbalance` will give the user an option to specify how many of each token they wish to get back. `remove_liquidity_one_coin` allows the user to specify the token they want to get back as a single token. From e0acf546f4cefd7e21b2df0703055b817e4d4a75 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:58:46 -0600 Subject: [PATCH 080/114] Equious updated courses/curve-v1/3-contract-overview/03-a-and-d/+page.md. --- .../3-contract-overview/03-a-and-d/+page.md | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/3-contract-overview/03-a-and-d/+page.md b/courses/curve-v1/3-contract-overview/03-a-and-d/+page.md index 411f4075e..687973891 100644 --- a/courses/curve-v1/3-contract-overview/03-a-and-d/+page.md +++ b/courses/curve-v1/3-contract-overview/03-a-and-d/+page.md @@ -1,3 +1,25 @@ ---- - title: A And D - --- \ No newline at end of file +Let's start by understanding a common pattern in the code for Curve v1. We can see that the functions `exchange`, `add_liquidity`, and the `remove_liquidity` functions are called on the StableSwap3Pool contract. + +The pattern we'll see in all the functions is that they first calculate the `A` parameter, and then they calculate the liquidity `D`. + +Let's examine the `exchange` function. We can see that it first normalizes the token balances, transfers the token in, updates the token balance, and then calculates the token out balance. After that, it calculates the `A` parameter, the liquidity `D`, calculates the token out, calculates the swap fee, updates the token balances, and then transfers the token out. + +The `add_liquidity` function has a similar pattern. It calculates an imbalance fee multiplier, calculates `A`, calculates the liquidity `D0`, transfers the tokens in, updates the token balances, calculates liquidity `D1`, calculates the imbalance fee, calculates liquidity `D2`, updates the token balances, calculates the liquidity provider shares, and then mints the liquidity provider's LP shares. + +The `remove_liquidity` function is a little different. It first calculates the token out amounts, updates the token balances, and then transfers the tokens out. Finally, it burns the LP shares. + +The `remove_liquidity_one_coin` function first calculates `dy` and the imbalance fee, calculates `A`, calculates `D`, calculates the imbalance fee, updates the token balances, burns the LP shares, and then transfers the token out. + +So, why do we see a pattern of calculating the `A` parameter before calculating the liquidity `D`? + +We can see that the `A` parameter is a fixed number, but an admin can decide to set a new `A` parameter. Over time, as the `A` parameter changes, the liquidity `D` will also change. + +Let's take a look at an example graph of Curve v1's equation. In this graph, we are looking at the equation for two tokens. We can see that the `x0` and `y0` values must be on this curve. + +This curve will adjust as tokens are swapped. For example, if token `x` goes out and token `y` comes in, the point will move up and to the left. Conversely, if token `x` comes in and token `y` goes out, the point will move down and to the right. + +Let's now see what happens when the `A` parameter changes. In this graph, we can see that the current token balance is represented by a blue dot. An admin could decide to update the `A` parameter to a higher number. + +We can see that the token balance is no longer on the curve. To get the blue dot back on the curve, we need to change the liquidity `D` so that the curve will go through the token balances. + +We see, then, that the code first calculates the `A` parameter and then calculates the `D` parameter. This is because the code needs to find the liquidity `D` that will satisfy the equation given the `A` parameter and the token balances. From 9435a6cfee80747654a1b68ac4c6c981b14bd4bd Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:59:10 -0600 Subject: [PATCH 081/114] Equious updated courses/curve-v1/3-contract-overview/04-code-walk-a/+page.md. --- .../04-code-walk-a/+page.md | 48 +++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/3-contract-overview/04-code-walk-a/+page.md b/courses/curve-v1/3-contract-overview/04-code-walk-a/+page.md index b12a8139e..5e1992376 100644 --- a/courses/curve-v1/3-contract-overview/04-code-walk-a/+page.md +++ b/courses/curve-v1/3-contract-overview/04-code-walk-a/+page.md @@ -1,3 +1,45 @@ ---- - title: Code Walk A - --- \ No newline at end of file +## The A parameter inside curve B1's AMM + +The A parameter inside Curve B1's AMM equation controls how flat the curve is. For example, if we increase A, we can see that the pink line, which represents Curve B1's AMM curve, becomes more flat like the constant sum. On the other hand, when we decrease this A parameter, we see that the curve becomes more like the constant product. When A is equal to zero, it matches the constant product curve. + +Let's take a look at how this A parameter is calculated inside Curve B1's AMM. The contract that we will take a look at is called StableSwap3Pool. This is a contract that is deployed on the main net, and it holds DAI, USDC, and USDT. The function that calculates the current A parameter is called _A. The owner of this contract can set a new A parameter. When a new A parameter is set, it doesn't take effect immediately. Over time, it gradually changes from the current A parameter to this new target A parameter that is set by the admin. + +So, inside this code, you see T1 and A1. A1 is the new A parameter that is set by the admin, and T1 is the timestamp where this new A parameter will stay fixed. At and after timestamp T1, this A parameter will stop increasing and it will stay flat as the new value A1. Let's say that the admin sets the A parameter to A1 at time T0. Then, over time, from time between T0 to T1, the current A will gradually increase to A1. After time T1, since the current A parameter has reached A1, it will stay flat as A1. And we can see this in the code over here. + +```javascript +if block.timestamp < t1: + A0: uint256 = self.initial_A + t0: uint256 = self.initial_A_time + # Expressions in uint256 cannot have negative numbers, thus "if" + # A1 > A0: + if A1 > A0: + return A0 + (A1 - A0) * (block.timestamp - t0) / (t1 - t0) + else: + return A0 - (A0 - A1) * (block.timestamp - t0) / (t1 - t0) +else: + # when t1 == 0 or block.timestamp >= t1 + return A1 +``` + +Let's say that the admin sets the A parameter to A1 at time T0. Then, over time, from time between T0 to T1, the current A will gradually increase to A1. After time T1, since the current A parameter has reached A1, it will stay flat as A1. And we can see this in the code over here. + +```javascript +if block.timestamp < t1: + A0: uint256 = self.initial_A + t0: uint256 = self.initial_A_time + # Expressions in uint256 cannot have negative numbers, thus "if" + # A1 > A0: + if A1 > A0: + return A0 + (A1 - A0) * (block.timestamp - t0) / (t1 - t0) + else: + return A0 - (A0 - A1) * (block.timestamp - t0) / (t1 - t0) +else: + # when t1 == 0 or block.timestamp >= t1 + return A1 +``` + +To understand this code, consider the two cases: When timestamp is equal to T0 and when timestamp is equal to T1. Let's start with the case when timestamp is equal to T0. When timestamp is equal to T0, this expression T0 - T0 is equal to zero. So, when we multiply this part by zero, this whole expression will be equal to zero, so we get A0. On the other hand, when timestamp is equal to T1, then this part of the code is equal to T1 - T0 divided by T1 - T0 is equal to one. So, this part of the code will be A1 - A0 multiplied by one, which is simply equal to A1 - A0. And then let's now do this A0 plus A1 minus A0. The A0 cancels out with this A0 over here, and we get back A1. + +At time T0, we see that the A parameter returns A0, and at time T1, the A parameter returns A1. And anywhere in between, this block.timestamp - T0 divided by T1 - T0 is a fraction that is less than one. So, the A parameter that is returned will be some number between A0 and A1. And that's how this part of the code works. + +This part of the code works almost exactly the same, except the current A parameter gradually decreases to the new parameter A1. From c6771c078d63e0b875509d0fa4c2bf6e777f479f Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:59:33 -0600 Subject: [PATCH 082/114] Equious updated courses/curve-v1/3-contract-overview/05-code-walk-xp/+page.md. --- .../05-code-walk-xp/+page.md | 63 ++++++++++++++++++- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/3-contract-overview/05-code-walk-xp/+page.md b/courses/curve-v1/3-contract-overview/05-code-walk-xp/+page.md index 8cf944a81..5b255e17d 100644 --- a/courses/curve-v1/3-contract-overview/05-code-walk-xp/+page.md +++ b/courses/curve-v1/3-contract-overview/05-code-walk-xp/+page.md @@ -1,3 +1,60 @@ ---- - title: Code Walk Xp - --- \ No newline at end of file +## Introduction to the _xp Function + +In Curve.fi AMMs, token balances are converted to have 18 decimals before any calculations. We can see this in a contract for DAI, USDC, and USDT. + +DAI has 18 decimals, so no conversion is necessary. USDC and USDT both have six decimals, so they must be converted to have 18 decimals. + +This is done by an internal function called `_xp`. The naming convention of this function can be remembered as "X" for the token balances and "P" for precision. + +The _xp function converts the token balances within a contract to have 18 decimals. + +Let's take a look at the code: + +```javascript +def _xp(balances: uint256(N_COINS)) -> uint256(N_COINS): + result: uint256(N_COINS) = RATES + for i in range(N_COINS): + # DAI = 1e18 * dai balance / 1e18 = 18 decimals + # USDC = 1e30 * usdc balance / 1e18 = 18 decimals + # USDT = 1e30 * usdt balance / 1e18 = 18 decimals + result[i] = result[i] * self.balances[i] / LENDING_PRECISION + return result +``` + +The first line of the function creates an array called `result`. It initializes the array to the value of `RATES`. + +```javascript +result: uint256(N_COINS) = RATES +``` + +The function then uses a for loop to iterate through each coin in the contract. + +```javascript +for i in range(N_COINS): +``` + +The _xp function is used to normalize the token balances in the contract. We can see this in the function, where it takes each balance, multiplies it by the corresponding rate, and divides by `LENDING_PRECISION`. + +```javascript +result[i] = result[i] * self.balances[i] / LENDING_PRECISION +``` + +We'll go over how the calculation works step by step: + +The first iteration of the loop, `result` will hold the value of `1e18`, which is the rate for DAI. The function then multiplies this by the DAI balance in the contract. DAI has 18 decimals, so this will not change the number of decimals. The result is then divided by `LENDING_PRECISION`, which is 10^18. This results in the DAI balance with 18 decimals. + +The second iteration of the loop, `result` will hold the value of `1e30`, which is the rate for USDC. The function then multiplies this by the USDC balance in the contract. USDC has six decimals, so multiplying by `1e30` will result in 36 decimals. The result is then divided by `LENDING_PRECISION`, which is 10^18. This results in the USDC balance with 18 decimals. + +The third iteration of the loop, `result` will hold the value of `1e30`, which is the rate for USDT. The function then multiplies this by the USDT balance in the contract. USDT has six decimals, so multiplying by `1e30` will result in 36 decimals. The result is then divided by `LENDING_PRECISION`, which is 10^18. This results in the USDT balance with 18 decimals. + +The final line of the function returns the `result` array. + +```javascript +return result +``` + +**Note**: It's important to remember that the _xp function is only used internally. When you interact with the Curve.fi AMM contract, you will not need to call this function. The contract will handle the conversion of token balances automatically. + +## Summary + +In summary, the _xp function takes the token balances in the contract and normalizes them to have 18 decimals. This is done by multiplying each balance by the corresponding rate and dividing by `LENDING_PRECISION`. From de19f701a238a0ba4bd928989a645dbd6b1dbb4c Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:59:57 -0600 Subject: [PATCH 083/114] Equious updated courses/curve-v1/3-contract-overview/06-code-walk-get-d/+page.md. --- .../06-code-walk-get-d/+page.md | 112 +++++++++++++++++- 1 file changed, 109 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/3-contract-overview/06-code-walk-get-d/+page.md b/courses/curve-v1/3-contract-overview/06-code-walk-get-d/+page.md index 213a6caad..d8dbf47a8 100644 --- a/courses/curve-v1/3-contract-overview/06-code-walk-get-d/+page.md +++ b/courses/curve-v1/3-contract-overview/06-code-walk-get-d/+page.md @@ -1,3 +1,109 @@ ---- - title: Code Walk Get D - --- \ No newline at end of file +We are going to talk about the value D in an AMM and how it's calculated. + +When we talk about a perfectly balanced pool, the amount of each token will be D/N, where N is the number of tokens. For example, if we have 50 tokens, each token will be 10 tokens. This is represented in the first line of the following code: + +```javascript +D = 50 +``` + +This is just an example, and you can change the value of D. + +We are using a StableSwap 3 Pool contract, where D is calculated by using Newton's method. + +The function, `get_D` takes the number of coins in the pool, `N_COINS`, and an amount, `amp`, which represents the amplification coefficient in the StableSwap 3 pool. Let's have a look at this code: + +```javascript +@internal +@pure +def get_D(xp: uint256[N_COINS], amp: uint256) -> uint256: + # sum(x_i) + S: uint256 = 0 + for x in xp: + S += x + if S <= 0: + return 0 + Dprev: uint256 = 0 + D: uint256 = S + Ann: uint256 = amp * N_COINS + for i in range(255): + # D^(N+1) / (N * prod(x_i)) + D_P: uint256 = D * D / (N * prod(xp[i])) + for x in xp: + # D * x * D / (L * N_COINS) # If division by 0, this will be bogus + D_P = D_P * x * D / (x * N_COINS) + Dprev = D + # equivalent to D - f(D) / (df/dD)(D) + D = (Ann * S + D_P * N_COINS) * D / (Ann * (N - 1) * D + (N_COINS + 1) * D_P) + # Equality with the precision of 1 + if D > Dprev: + if D - Dprev <= 1: + break + else: + if Dprev - D <= 1: + break + return D +``` + +The first part of this code sums up all the normalized token balances. This is performed within this `for` loop: + +```javascript +for x in xp: + S += x +``` + +If this sum is less than or equal to zero, we return zero: + +```javascript +if S <= 0: + return 0 +``` + +If the sum is greater than zero, we continue with the calculation. + +Next, the code uses Newton's method to calculate the value of D. We use this `for` loop to iterate a maximum of 255 times. + +```javascript +for i in range(255): +``` + +The code then calculates the value of D_P, which is equivalent to the expression D^(N+1) / (N * prod(x_i)), and it will use this value of D_P for the rest of the loop. + +```javascript +D_P: uint256 = D * D / (N * prod(xp[i])) +``` + +The code then iterates through the token balances to calculate a new value of D_P. + +```javascript +for x in xp: + D_P = D_P * x * D / (x * N_COINS) +``` + +The new value of D is calculated based on the previous value of D, Dprev, and the new values of D_P. + +```javascript +D = (Ann * S + D_P * N_COINS) * D / (Ann * (N - 1) * D + (N_COINS + 1) * D_P) +``` + +This equation is equivalent to this equation: D - f(D) / (df/dD)(D) + +Finally, the code checks if the difference between the new value of D and the previous value of D is less than or equal to 1. + +```javascript +if D > Dprev: + if D - Dprev <= 1: + break +else: + if Dprev - D <= 1: + break +``` + +If the difference is less than or equal to one, the code will break out of the for loop and return the current value of D, which has been calculated using Newton's method. + +```javascript +return D +``` + +If Newton's method does not converge, the code will complete the 255 iterations and return the final value of D. + +As you can see, the code is written in Python, and this function will return a value D that satisfies the curve B1 equation for the given parameters. \ No newline at end of file From ef1f8aa7462c64c5f24c7c0776da9ae413c8896d Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:00:22 -0600 Subject: [PATCH 084/114] Equious updated courses/curve-v1/3-contract-overview/07-code-walk-get-virtual-price/+page.md. --- .../07-code-walk-get-virtual-price/+page.md | 37 +++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/3-contract-overview/07-code-walk-get-virtual-price/+page.md b/courses/curve-v1/3-contract-overview/07-code-walk-get-virtual-price/+page.md index 4605fc8a8..b2eae0623 100644 --- a/courses/curve-v1/3-contract-overview/07-code-walk-get-virtual-price/+page.md +++ b/courses/curve-v1/3-contract-overview/07-code-walk-get-virtual-price/+page.md @@ -1,3 +1,34 @@ ---- - title: Code Walk Get Virtual Price - --- \ No newline at end of file +## The `get_virtual_price` Function + +In this lesson, we're going to break down the `get_virtual_price` function. We'll learn what the function calculates and how it uses other functions to achieve this. + +The function looks like this: + +```javascript +@view +@external +def get_virtual_price() -> uint256: + """ + Returns portfolio virtual price (for calculating profit) + scaled up by 1e18 + """ + D: uint256 = self.get_D(self.xp(), self.A()) + # D is in the units similar to DAI (e.g. converted to precision 1e18) + # When balanced, D / N = x / u - total virtual value of the portfolio + # token_supply: uint256 = self.token.totalSupply() + return D * PRECISION / token_supply() +``` + +Let's break down what each line of code does. + +First, we see the function takes the value of `D`. In previous lessons, we learned that this value is calculated using the function `get_D`. We can use this knowledge to understand how the function works. + +`D` represents the liquidity of the AMM. When all the token balances inside the AMM are equal, the pool is perfectly balanced. We can say that if there are `N` tokens, then `D / N` will be the token balance for each token. + +Therefore, `D` is the liquidity of the pool. + +Next, the function retrieves the `token_supply`. This represents the amount of LP tokens that were minted. + +After obtaining the value of `D` and the `token_supply`, the function multiplies `D` by `PRECISION` and divides the result by the `token_supply`. This means that the function `get_virtual_price` is calculating the value of each LP token. + +In summary, the `get_virtual_price` function calculates the virtual price of each LP token within the AMM. It achieves this by first calculating the liquidity of the pool (`D`) and then dividing that value by the total amount of minted LP tokens. From 1cc71181e999d6e333325fb6182423cd0c237a01 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:00:48 -0600 Subject: [PATCH 085/114] Equious updated courses/curve-v1/3-contract-overview/08-code-walk-calc-token-amount/+page.md. --- .../08-code-walk-calc-token-amount/+page.md | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/3-contract-overview/08-code-walk-calc-token-amount/+page.md b/courses/curve-v1/3-contract-overview/08-code-walk-calc-token-amount/+page.md index c4e57783b..ca09733a3 100644 --- a/courses/curve-v1/3-contract-overview/08-code-walk-calc-token-amount/+page.md +++ b/courses/curve-v1/3-contract-overview/08-code-walk-calc-token-amount/+page.md @@ -1,3 +1,16 @@ ---- - title: Code Walk Calc Token Amount - --- \ No newline at end of file +Let's take a look at the `calc_token_amount` function in a StableSwap pool contract. This function takes in an array of token amounts and a boolean flag called `deposit`. If `deposit` is true, this means we're adding liquidity. Otherwise, we're removing liquidity. The function returns a single number, a `uint256`. However, this number does not directly represent the amount of tokens being minted or burned. + +This function is a simplified calculation of token supply. It does not take into account fees that might occur when the pool is imbalanced, whether this is from adding or removing liquidity. + +Here's a step-by-step breakdown of the function: + +1. First, the function gets the current balance of the tokens in the pool and assigns it to the variable `balances`. +2. Next, it gets the parameter `A`. +3. The function then calculates the value for `D0`, which represents the initial liquidity in the pool. This is calculated from the current balance of tokens. +4. It then runs a loop to update the `balances` based on whether the input is a deposit or withdrawal. + * If it is a deposit, the loop adds the input `amounts` to the current `balances`. + * If it is a withdrawal, the loop subtracts the input `amounts` from the current `balances`. +5. After the loop has run, the function calculates the value for `D1`, representing the new liquidity in the pool, again based on the current token balances. +6. Finally, the function calculates the difference between `D1` and `D0`, and then divides this difference by the initial liquidity, `D0`. We multiply this by the total supply of LP tokens, to calculate the amount of LP tokens that will be either minted or burned. + +This calculation gives us an approximation of the LP tokens that will be minted or burned. It is a simplified calculation that does not take fees into account. From ce72f0145f12756406af13fd7b255e0c146bb089 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:01:14 -0600 Subject: [PATCH 086/114] Equious updated courses/curve-v1/4-swap/01-contract-call-exchange/+page.md. --- .../curve-v1/4-swap/01-contract-call-exchange/+page.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/4-swap/01-contract-call-exchange/+page.md b/courses/curve-v1/4-swap/01-contract-call-exchange/+page.md index 264576e8c..eb8fd2024 100644 --- a/courses/curve-v1/4-swap/01-contract-call-exchange/+page.md +++ b/courses/curve-v1/4-swap/01-contract-call-exchange/+page.md @@ -1,3 +1,7 @@ ---- - title: Contract Call Exchange - --- \ No newline at end of file +To swap tokens with the Curve's B1AMM, we will call the function `exchange`. + +For example, let's say that this user wanted to swap DAI for USDC from the StableSwap3Pool contract. + +First, we will call the function `exchange` specifying that the token in is DAI and the amount of DAI to swap. + +The StableSwap3Pool contract will transfer the DAI in from the user over to the pool contract, calculate the amount of USDC to get back and then transfer the USDC from the pool contract over to the user. From 29fbede9d2d022a5d91b1d9fff465eff93b94006 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:01:38 -0600 Subject: [PATCH 087/114] Equious updated courses/curve-v1/4-swap/02-code-outline-exchange/+page.md. --- .../4-swap/02-code-outline-exchange/+page.md | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/4-swap/02-code-outline-exchange/+page.md b/courses/curve-v1/4-swap/02-code-outline-exchange/+page.md index 64c351ed3..a3081f42c 100644 --- a/courses/curve-v1/4-swap/02-code-outline-exchange/+page.md +++ b/courses/curve-v1/4-swap/02-code-outline-exchange/+page.md @@ -1,3 +1,28 @@ ---- - title: Code Outline Exchange - --- \ No newline at end of file +## Introduction to the exchange function + +We're going to take a walk-through of the *exchange* function in the *StableSwap* pool. + +### Exchange Function Walk-through + +The *exchange* function has the following steps: + +1. **Normalizes token balances (memory)** + This is the first thing the function does. It makes sure all token balances have 18 decimals, regardless of the actual token's decimal places. +2. **Transfer token in (memory)** + The *exchange* function will then transfer the token *in* to the pool. +3. **Update token in balance (memory)** + The normalized balance of the token *in* is stored in memory. +4. **Calculate token out balance** + * **Calculate A** + * **Calculate D** + The function will calculate the new balance of the token *out*. +5. **Calculate token out** + The difference between the new token *out* balance and the old token *out* balance is calculated. +6. **Calculate swap fee** + The *exchange* function calculates the swap fee which is taken out of the token *out*. +7. **Update token balances (storage)** + This step updates the token balances in storage to reflect the changes. +8. **Transfer token out** + Finally, the *exchange* function transfers the token *out* to the user. + +This walk-through provides a basic understanding of the *exchange* function. \ No newline at end of file From 852ec77f3c53022613537467e212b32aaeaa440f Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:02:03 -0600 Subject: [PATCH 088/114] Equious updated courses/curve-v1/4-swap/03-code-walk-exchange/+page.md. --- .../4-swap/03-code-walk-exchange/+page.md | 55 ++++++++++++++++++- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/4-swap/03-code-walk-exchange/+page.md b/courses/curve-v1/4-swap/03-code-walk-exchange/+page.md index deecbce8c..6d5938da1 100644 --- a/courses/curve-v1/4-swap/03-code-walk-exchange/+page.md +++ b/courses/curve-v1/4-swap/03-code-walk-exchange/+page.md @@ -1,3 +1,52 @@ ---- - title: Code Walk Exchange - --- \ No newline at end of file +We are going to walk through the `exchange` function that is used to swap tokens on a Curve B1AMM. + +### The `exchange` Function + +The `exchange` function takes in the following parameters: + +* `i`: The index of the token coming in. +* `j`: The index of the token going out. +* `dx`: The amount of the token coming in. +* `min_dy`: The minimum amount of token you expect to get back. If this is not met, the function will fail. + +### Normalizing Token Balances + +First, we will create an array called `rates`. This is a constant value for the `StableSwap3Pool.vy` contract and is set to `1e18, 1e30, 1e30`. + +We then store the balances of the tokens in an array called `old_balances`. The `old_balances` array will contain the balances of `DAI`, `USDC`, and `USDT`. + +Then, the function will normalize the balances by calling the `_xp_mem` function. + +### Transferring Tokens + +Next, we will transfer the token in into the pool contract by calling the `transferFrom` function, which is encoded using a `raw_call`. + +The `raw_call` is used instead of the ERC20 interface because some tokens, like USDT, do not return a boolean when the `transferFrom` function is called. + +We then get the address of the token that will come in and store it in a variable called `input_coin`. We also check if the token has a fee on transfer. If it does, we calculate the fee by calling the `balanceOf` function on the input token. + +The difference between the balance before and after transferring the token will be the actual amount that came into the pool. + +### Calculating the Amount Out and Fee + +We then perform some calculations to determine the amount of token that will go out and the associated fee. We will call these variables `dy` and `dy_fee`. + +* `x`: This represents the normalized balance of the token coming in. +* `xp`: This is the normalized balance of the token going out. +* `y`: This is the new normalized balance of the token going out, calculated by calling the `getY` function. + +We then subtract the new normalized balance from the current normalized balance to get `dy`. We then subtract the amount of the fee from the `dy` and store the result in `dy_fee`. + +### Updating Token Balances + +Next, we will update the token balances to reflect the changes that have occurred. We are basically just adding the amount that came in and subtracting the amount going out and the admin fee. + +* The balance of the token that came in is updated by adding the actual amount that came in, `dx_w_fee`. +* The balance of the token going out is updated by subtracting the amount that went out, `dy`. +* The admin fee is calculated as a fraction of the `dy_fee`. + +Finally, we log the token exchange event. + +### Summary + +In essence, the `exchange` function takes in tokens, normalizes the balances, transfers the tokens in and then out, and then updates the balances of the tokens. From 237a9ab87191df4c6d62aa3e2f19d439f961b8dc Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:02:39 -0600 Subject: [PATCH 089/114] Equious updated courses/curve-v1/4-swap/04-code-walk-get-y/+page.md. --- .../4-swap/04-code-walk-get-y/+page.md | 54 +++++++++++++++++-- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/4-swap/04-code-walk-get-y/+page.md b/courses/curve-v1/4-swap/04-code-walk-get-y/+page.md index 170cfd14d..d3cce8be8 100644 --- a/courses/curve-v1/4-swap/04-code-walk-get-y/+page.md +++ b/courses/curve-v1/4-swap/04-code-walk-get-y/+page.md @@ -1,3 +1,51 @@ ---- - title: Code Walk Get Y - --- \ No newline at end of file +We're going to take a look at the `get_y` function in the StableSwap pool, which is part of Curve v1. + +The `get_y` function takes in the indexes of the token in and token out, along with the new balance of token in and the normalized balances of all tokens except the token out. + +The function then uses Newton's method to calculate the new balance of the token out. To do this, it calculates various variables like `amp`, `D`, `c`, `S_`, `Ann`, and `b`. + +We're going to focus on the equation used for calculating the `c` variable: + +```javascript +c = D**(n+1) / (n**n * p) +``` + +Where: + +* `D` represents the liquidity of the pool. +* `n` is the number of tokens in the pool. +* `p` is the product of the normalized balances of all tokens except the token out. + +We can also see how the `S_` variable is calculated: + +```javascript +S_ = sum(x[i] for i != j) +``` + +Which is the sum of all token balances except the token out. + +Finally, the function calculates `b` using: + +```javascript +b = (Ann * S_ + D * Ann) / Amm - D +``` + +Where: + +* `Ann` represents `a` * `n` to the `n`. +* `Amm` represents `a` * `n` to the `n` * `n`. + +These variables `c`, `D`, `S_`, and `b` are used to calculate the new balance of the token out. + +The function then runs a for loop, iterating a maximum of 255 times. In each iteration, it uses Newton's method to update the value of `y`, which represents the new balance of the token out. + +The equation used in the for loop is: + +```javascript +y = (y * y * c) / (2 * y * b - D) +``` + +This equation is equivalent to Newton's method for finding the root of a function. + +The loop continues to update `y` until the difference between the new `y` and the previous `y` is less than or equal to one. When this condition is met, the function returns the value of `y`, which represents the calculated new balance of the token out. + From 7f78affc21aea047e7d689caec5c91aaf5db48df Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:03:07 -0600 Subject: [PATCH 090/114] Equious updated courses/curve-v1/4-swap/05-code-walk-get-dy/+page.md. --- .../4-swap/05-code-walk-get-dy/+page.md | 64 ++++++++++++++++++- 1 file changed, 61 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/4-swap/05-code-walk-get-dy/+page.md b/courses/curve-v1/4-swap/05-code-walk-get-dy/+page.md index f420dcbf9..6f855bf18 100644 --- a/courses/curve-v1/4-swap/05-code-walk-get-dy/+page.md +++ b/courses/curve-v1/4-swap/05-code-walk-get-dy/+page.md @@ -1,3 +1,61 @@ ---- - title: Code Walk Get Dy - --- \ No newline at end of file +The function that we will use to calculate the amount of tokens we will receive from a swap with a Curve B1 AMM is called `get_dy`. There is another function called `get_dy_underlying` that has the same purpose but behaves differently. + +The difference between these two functions makes sense when the tokens inside the pool contract are yield bearing. + +For example, for a three pool, the tokens are DAI, USDC, and USDT. If you were to hold these tokens, they would not give you any yield. In this case, calling the functions `get_dy` and `get_dy_underlying` will give you back the exact same amounts. + +Now, let's consider the case when the tokens inside the pool earn some kind of yield. For example, let's say we have the tokens DAI and cUSDC. The token cUSDC is a token that you get for depositing USDC into Compound. This token is yield bearing. If you were to hold on to this cUSDC over time, you will earn some interest. + +Let's say you wanted to find out how much USDC you will get for putting in DAI. The pool tokens are DAI and cUSDC. In this case, to answer the question of how much USDC we will get for putting in DAI, we will call the function `get_dy_underlying`. This function will calculate how much USDC we will get if we were to put in DAI. + +For a stable swap three pool, the tokens are DAI, USDC, and USDT. The functions `get_dy_underlying` and `get_dy` are the same. + +Let's take a look at the function `get_dy`. As input, it's going to take the index of the token in and the index of the token out, and the amount of tokens you are going to put in, dx. Then, it calculates the amount of tokens that the AMM will give you back. + +First, it gets the rates. Remember for this stable swap three pool, the rates are a fixed number of 1e18, 1e30, and 1e30. Next, it gets the token balances, which are normalized to all have 18 decimals. The tokens are DAI, USDC, and USDT. DAI has 18 decimals, but USDC and USDT have six decimals. By calling this function, all of the token balances are normalized with 18 decimals. + +The next part of the code calculates the amount of tokens that will come out, and the fees on tokens out. + +```javascript +def get_dy(i: int128, j: int128, dx: uint256) -> uint256: + # dx and dy in c-units + rates: uint256[N_COINS] = RATES + xp: uint256[N_COINS] = self.xp() + x: uint256 = xp[i] + (dx * rates[i]) // PRECISION + y: uint256 = self.get_y(i, j, x, xp) + dy: uint256 = (xp[j] - y - 1) * PRECISION // rates[j] + _fee: uint256 = self.fee * dy // FEE_DENOMINATOR + return dy - _fee +``` + +The first part is adding the amount of token in to the current balance of token in, inside this pool. + +```javascript +x: uint256 = xp[i] + (dx * rates[i]) // PRECISION +``` + +This part normalizes the amount of token in to have 18 decimals. Next, it calculates the pool balance of token out, if we were to put in the dx amount of tokens into this pool. Remember that this function uses the Newton's method to calculate the new balance of token out. + +```javascript +y: uint256 = self.get_y(i, j, x, xp) +``` + +Since token is coming in, the balance of token out will decrease. Taking the difference of the current balance of token out, and the new balance of token out, accounting for rounding errors, we also minus one. Basically, this difference of the old balance of token out, minus the new balance of token out, is the calculation for the amount of token that will come out. This is named dy. + +```javascript +dy: uint256 = (xp[j] - y - 1) * PRECISION // rates[j] +``` + +A fraction of this dy will be kept inside the pool as swap fee. And this is calculated by taking some fraction of dy. + +```javascript +_fee: uint256 = self.fee * dy // FEE_DENOMINATOR +``` + +The actual amount of tokens that will come out is dy minus the fee. + +```javascript +return dy - _fee +``` + +So, that's the function `get_dy`. From 19febda935f01b6d9da206a4d0725b787845687d Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:03:32 -0600 Subject: [PATCH 091/114] Equious updated courses/curve-v1/4-swap/06-exercise-1-get-dy-underlying/+page.md. --- .../06-exercise-1-get-dy-underlying/+page.md | 47 +++++++++++++++++-- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/4-swap/06-exercise-1-get-dy-underlying/+page.md b/courses/curve-v1/4-swap/06-exercise-1-get-dy-underlying/+page.md index e187cea81..3e794eefc 100644 --- a/courses/curve-v1/4-swap/06-exercise-1-get-dy-underlying/+page.md +++ b/courses/curve-v1/4-swap/06-exercise-1-get-dy-underlying/+page.md @@ -1,3 +1,44 @@ ---- - title: Exercise 1 Get Dy Underlying - --- \ No newline at end of file +## Exercise 1: Calculating the Amount of USDC for a Swap + +Let's start with the first exercise where we'll use a function called `get_dy_underlying` to determine the amount of USDC we'll receive after swapping in 1,000,000 DAI. + +The function `get_dy_underlying` has three inputs: + +* **Index of the token we are putting in** +* **Index of the token we are getting out** +* **The amount of the token we are putting in** + +**To complete this exercise, we need to write code that calls the `get_dy_underlying` function with the appropriate inputs, and use the returned value to calculate the amount of USDC we'll get.** + +First, we can initialize a `uint256` variable to store the returned value: +```javascript +uint256 dy = 0; +``` + +Then, we need to call the function `get_dy_underlying` with the correct indexes. In this case, DAI is token index 0 and USDC is token index 2. We'll also put in 1,000,000 DAI: +```javascript +dy = get_dy_underlying(0, 2, 1e6 * 1e18); +``` + +Now that we have the calculated amount of USDC in our `dy` variable, we can log it to the console for confirmation: +```javascript +console.log("dy %e", dy); +``` + +To verify that our code works, we can add an assertion that the calculated amount of USDC (the `dy` variable) is a valid USDC amount. You can find the correct USDC amount for a 1,000,000 DAI swap in the example file. + +Here's the full code: +```javascript +function test_get_dy_underlying() public { + // Calculate swap from DAI to USDC + // Write your code here + uint256 dy = 0; + dy = get_dy_underlying(0, 2, 1e6 * 1e18); + console.log("dy %e", dy); + assertGT(dy, 0, "dy = 0"); +} +``` + +Remember that this example is using the `get_dy_underlying` function from `IStaleSwap3Pool.sol`. If you need a refresher on how to call this function, you can find it in the `/src/interfaces/curve/IStaleSwap3Pool.sol` file. + +Let's move on to Exercise 2! From f8a735864052b1c706932648518e636f9a53261a Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:03:57 -0600 Subject: [PATCH 092/114] Equious updated courses/curve-v1/4-swap/07-solution-1-get-dy-underlying/+page.md. --- .../07-solution-1-get-dy-underlying/+page.md | 163 +++++++++++++++++- 1 file changed, 160 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/4-swap/07-solution-1-get-dy-underlying/+page.md b/courses/curve-v1/4-swap/07-solution-1-get-dy-underlying/+page.md index 8a007f563..8ebd0ff79 100644 --- a/courses/curve-v1/4-swap/07-solution-1-get-dy-underlying/+page.md +++ b/courses/curve-v1/4-swap/07-solution-1-get-dy-underlying/+page.md @@ -1,3 +1,160 @@ ---- - title: Solution 1 Get Dy Underlying - --- \ No newline at end of file +## Intro to Curve.fi Pool Interactions + +In this lesson, we will learn how to interact with a Curve.fi pool. Specifically, we will learn how to use the function `get_dy_underlying()`. + +Let's look at our contract: +```javascript +// Exercise 1 +// Call get_dy_underlying to calculate the amount of USDC for swapping +// 1,000,000 DAI to USDC +function test_get_dy_underlying() public { + // Calculate swap from DAI to USDC + // Write your code here + uint256 dy = 0; + + console.log("dy %e", dy); + assertGT(dy, 0, "dy = 0"); +} +``` + +The first step is to copy the interface of the `IStableSwap3Pool` contract from the `IStableSwap3Pool.sol` file. +```javascript +interface IStableSwap3Pool { + function get_dy_underlying(int128 i, int128 j, uint256 dx) + external + view + returns (uint256 dy); + + function exchange(int128 i, int128 j, uint256 dx, uint256 min_dy) + external; + + function add_liquidity(uint256[3] calldata coins, uint256 min_lp) + external; + + function remove_liquidity(uint256 lp, uint256[3] calldata min_coins) + external; + + function remove_liquidity_one_coin(uint256 lp, int128 i, uint256 min_coin) + external; + + function calc_withdraw_one_coin(uint256 lp, int128 i) + external + view + returns (uint256 coin); +} +``` + +We can then paste this interface into the `CurveV1Swap.test.sol` file: +```javascript +// Exercise 1 +// Call get_dy_underlying to calculate the amount of USDC for swapping +// 1,000,000 DAI to USDC +function test_get_dy_underlying() public { + // Calculate swap from DAI to USDC + // Write your code here + get_dy_underlying(int128 i, int128 j, uint256 dx) + uint256 dy = 0; + + console.log("dy %e", dy); + assertGT(dy, 0, "dy = 0"); +} +``` + +Now, we need to call the `get_dy_underlying()` function from our `CurveV1Swap.test.sol` contract. + +First, we need to access the `IStableSwap3Pool` contract using the `pool` variable we defined earlier: +```javascript +// Exercise 1 +// Call get_dy_underlying to calculate the amount of USDC for swapping +// 1,000,000 DAI to USDC +function test_get_dy_underlying() public { + // Calculate swap from DAI to USDC + // Write your code here + pool.get_dy_underlying(int128 i, int128 j, uint256 dx) + uint256 dy = 0; + + console.log("dy %e", dy); + assertGT(dy, 0, "dy = 0"); +} +``` + +Next, we need to pass the following three parameters into the function: +1. **`i`**: The index of the token we are swapping from (DAI). +2. **`j`**: The index of the token we are swapping to (USDC). +3. **`dx`**: The amount of DAI we are swapping. + +From our pool definition: +```javascript +IStableSwap3Pool private constant pool = IStableSwap3Pool(CURVE_3POOL); +``` + +And the pool composition (DAI, USDC, USDT): +```javascript +IERC20 private constant dai = IERC20(DAI); +IERC20 private constant usdc = IERC20(USDC); +IERC20 private constant usdt = IERC20(USDT); +``` + +We can see that DAI has index 0, USDC has index 1, and USDT has index 2. So, let's update our code: +```javascript +// Exercise 1 +// Call get_dy_underlying to calculate the amount of USDC for swapping +// 1,000,000 DAI to USDC +function test_get_dy_underlying() public { + // Calculate swap from DAI to USDC + // Write your code here + pool.get_dy_underlying(0, 1, uint256 dx) + uint256 dy = 0; + + console.log("dy %e", dy); + assertGT(dy, 0, "dy = 0"); +} +``` + +Now we need to define our `dx` variable. We are swapping 1 million DAI. As DAI has 18 decimals, this is represented by: +```javascript +1e6 * 1e18 +``` + +Let's update our code to incorporate this. +```javascript +// Exercise 1 +// Call get_dy_underlying to calculate the amount of USDC for swapping +// 1,000,000 DAI to USDC +function test_get_dy_underlying() public { + // Calculate swap from DAI to USDC + // Write your code here + pool.get_dy_underlying(0, 1, 1e6 * 1e18); + uint256 dy = 0; + + console.log("dy %e", dy); + assertGT(dy, 0, "dy = 0"); +} +``` + +Finally, we can assign the returned value of our `pool.get_dy_underlying()` function to the `dy` variable. +```javascript +// Exercise 1 +// Call get_dy_underlying to calculate the amount of USDC for swapping +// 1,000,000 DAI to USDC +function test_get_dy_underlying() public { + // Calculate swap from DAI to USDC + // Write your code here + uint256 dy = pool.get_dy_underlying(0, 1, 1e6 * 1e18); + + console.log("dy %e", dy); + assertGT(dy, 0, "dy = 0"); +} +``` + +Now let's execute our test. In our terminal, we can use Foundry's `forge test` command with the following arguments: +* **`--fork-url`**: This argument specifies the RPC endpoint for our blockchain. +* **`--match-test`**: This argument helps us execute specific tests. We will match against the name of our test function: `test_get_dy_underlying`. +* **`--dbv`**: This argument tells Foundry to use a persistent database for our forked blockchain. + +The complete command is: +```bash +forge test --fork-url $FORK_URL --match-test test_get_dy_underlying --dbv +``` + +We can see that our test passes. This means that we have successfully called the `get_dy_underlying()` function and calculated the amount of USDC we will receive when swapping 1 million DAI. From 162ae0e1d6a1e22228356d2d45c03f60e82de532 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:04:21 -0600 Subject: [PATCH 093/114] Equious updated courses/curve-v1/4-swap/08-exercise-2-exchange/+page.md. --- .../4-swap/08-exercise-2-exchange/+page.md | 55 ++++++++++++++++++- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/4-swap/08-exercise-2-exchange/+page.md b/courses/curve-v1/4-swap/08-exercise-2-exchange/+page.md index b7b0129d9..eedc6a6de 100644 --- a/courses/curve-v1/4-swap/08-exercise-2-exchange/+page.md +++ b/courses/curve-v1/4-swap/08-exercise-2-exchange/+page.md @@ -1,3 +1,52 @@ ---- - title: Exercise 2 Exchange - --- \ No newline at end of file +## Introduction to Curve.fi on Ethereum + +In this lesson, we'll learn how to swap DAI for USDC on Curve.fi. + +### The Swap Function + +We will call the `exchange()` function in the `IStableSwap3Pool` interface to perform the swap. + +### The `exchange()` function + +The `exchange()` function takes in the following parameters: + +* `i`: The index for the token in. +* `j`: The index for the token out. +* `dx`: The amount of token in that you're going to put in. +* `min_dy`: The minimum amount of token out that you expect to get back. + +### Let's get started + +To call the `exchange()` function to swap DAI for USDC, we can navigate to the `IStableSwap3Pool.sol` file under the "interfaces/curve" directory. + +```bash +cd interfaces/curve +``` + +The file contains the `exchange()` function that we will use. + +```javascript +function exchange(int128 i, int128 j, uint256 dx, uint256 min_dy) external; +``` + +The `exchange()` function is part of the `IStableSwap3Pool` interface. The `IStableSwap3Pool` interface is defined in the `IStableSwap3Pool.sol` file. + +We can import the `IStableSwap3Pool` interface into our test file so that we can use the `exchange()` function. + +```javascript +import "./src/interfaces/curve/IStableSwap3Pool.sol"; +``` + +We will import the `DAI`, `USDC`, and `USDT` constants from the `constants.sol` file. + +```javascript +import (DAI, USDC, USDT, CURVE_3POOL) from "./src/constants.sol"; +``` + +We can call the `exchange()` function from our test file to perform a swap. + +```javascript +pool.exchange(DAI, USDC, dx, min_dy); +``` + +We will cover calling the `exchange()` function in a later lesson. From f892dd766b018767c40126125f2c50c4d3a08a2c Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:04:44 -0600 Subject: [PATCH 094/114] Equious updated courses/curve-v1/4-swap/09-solution-2-exchange/+page.md. --- .../4-swap/09-solution-2-exchange/+page.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/4-swap/09-solution-2-exchange/+page.md b/courses/curve-v1/4-swap/09-solution-2-exchange/+page.md index 3b72eb28b..9ae50334a 100644 --- a/courses/curve-v1/4-swap/09-solution-2-exchange/+page.md +++ b/courses/curve-v1/4-swap/09-solution-2-exchange/+page.md @@ -1,3 +1,15 @@ ---- - title: Solution 2 Exchange - --- \ No newline at end of file +In this lesson, we will be going over the solution for Exercise 2. + +Exercise 2 is to swap 1 million DAI for USDC on Curve B1. + +The function that we will need to call is: +```javascript +pool.exchange() +``` +Let's check the interface and then inside the interface, it's going to take in these inputs. I'll copy these inputs and then we'll paste it here. And before I forget, I'll put a semicolon in as well. + +Okay, so for the inputs, the first input is the index of the token that we are putting in. We are swapping DAI for USDC, and DAI has index 0. USDC has index 1. The amount of DAI that we are going to put in is 1 million DAI. 1e6 * 1e18. 1 million has 6 zeros, as you can see from here, and DAI has 18 decimals. 1e6 multiplied by 1e18 represents 1 million DAI. Okay. Next minimum DY, minimum amount of USDC that we expect to get back. For this example, let's say 999,000. 999,000 is 0.999 * 1e6. 0.999 of 1 million is 999,000. And USDC has 6 decimals, so say 1e6. + +That completes Exercise 2. Let's execute this test. Inside the terminal, I'll type `forge test --fork-url {FORK_URL} --match-path test/curve-v1/exercises/CurveV1Swap.test.sol --match-test test_exchange --vvv`. + +Okay. And our test passed. For putting in 1 million DAI, we got 999,000.999177995475e11 USDC. From 749b6eafd0a496874b5f338ff0118a4e7e4ec1b5 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:05:09 -0600 Subject: [PATCH 095/114] Equious updated courses/curve-v1/5-add-liquidity/01-contract-call-add-liq/+page.md. --- .../01-contract-call-add-liq/+page.md | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/5-add-liquidity/01-contract-call-add-liq/+page.md b/courses/curve-v1/5-add-liquidity/01-contract-call-add-liq/+page.md index 8d51e2bdf..aadb16085 100644 --- a/courses/curve-v1/5-add-liquidity/01-contract-call-add-liq/+page.md +++ b/courses/curve-v1/5-add-liquidity/01-contract-call-add-liq/+page.md @@ -1,3 +1,24 @@ ---- - title: Contract Call Add Liq - --- \ No newline at end of file +## Introduction to Adding Liquidity + +Adding liquidity to a Curve pool is a process where a user provides tokens to a pool in exchange for LP shares. These LP shares represent the user's ownership in the pool. + +### Overview of Adding Liquidity + +To add liquidity, a user will call the `add_liquidity` function in the Curve contract. This function requires the user to specify the amount of each token they want to provide to the pool. The amount of tokens can be any combination of the tokens in the pool, with the amount of one or more of the tokens being equal to zero. For example, if a user wants to add only DAI to the pool, they can set the amount of USDC and USDT to zero. + +In the example of the StableSwap3 pool, there are three tokens: DAI, USDC, and USDT. A user can choose to add any combination of these tokens to the pool. + +### The Process of Adding Liquidity + +1. **Call the Function**: The user calls the `add_liquidity` function in the Curve contract. + +2. **Specify Token Amounts**: The user specifies the amount of each token they want to provide to the pool. + +3. **Transfer Tokens**: The tokens specified by the user are transferred to the Curve pool contract. + +4. **Calculate LP Shares**: The Curve pool contract calculates the amount of LP shares to mint to the user based on the amount of tokens provided. + +5. **Mint LP Shares**: The Curve pool contract mints LP shares to the user. + +These LP shares represent the user's ownership of the liquidity in the pool. The owner of the LP shares can later withdraw any of the tokens in the pool by exchanging their LP shares back to the pool contract. + From e66527177797de170b631816ef8a2afbba782e60 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:05:35 -0600 Subject: [PATCH 096/114] Equious updated courses/curve-v1/5-add-liquidity/02-code-outline-add-liq/+page.md. --- .../02-code-outline-add-liq/+page.md | 48 +++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/5-add-liquidity/02-code-outline-add-liq/+page.md b/courses/curve-v1/5-add-liquidity/02-code-outline-add-liq/+page.md index 49cf09957..31ee52a3c 100644 --- a/courses/curve-v1/5-add-liquidity/02-code-outline-add-liq/+page.md +++ b/courses/curve-v1/5-add-liquidity/02-code-outline-add-liq/+page.md @@ -1,3 +1,45 @@ ---- - title: Code Outline Add Liq - --- \ No newline at end of file +## add_liquidity + +We'll quickly outline the function `add_liquidity` before we look at the code. + +The first step inside the `add_liquidity` function is to calculate the `imbalance_fee_multiplier`. This is how we discourage users from adding too much of one token, potentially causing the pool to become imbalanced. + +The function then calculates the `A` parameter, which is a parameter of the pool. + +Next, we calculate the current liquidity of the pool, which we refer to as `D0`. + +After this, the function transfers the tokens into the pool. + +Then the token balances are updated. At this stage, this happens in memory rather than updating the state variables, which saves gas. + +Next, we calculate the liquidity again, now with the transferred tokens added, and we call this `D1`. + +Now that we have `D0` and `D1`, we calculate the imbalance fee. + +After calculating the imbalance fee, we once again calculate the liquidity, this time after removing the imbalance fee, which we call `D2`. + +Finally, we update the token balances, this time updating the state variables, because we now have the final balances, and we need to update the pool's state. + +Finally, we calculate the LP shares for the liquidity provider and mint LP tokens. + +## Code Block Examples + +Here's an example of the `D0` calculation: +```javascript +function calculateLiquidityD0(tokens) { + let D = 0; + for (let i = 0; i < tokens.length; i++) { + D = D + tokens[i]; + } + return D; +} +``` + +And an example of the code that updates the token balances in the pool's storage: +```javascript +function updateTokenBalances(tokenBalances, updatedBalances) { + for (let i = 0; i < tokenBalances.length; i++) { + tokenBalances[i] = updatedBalances[i]; + } +} +``` \ No newline at end of file From bf6e463d09b3f0d4184bc011ac2949984c96d73b Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:06:29 -0600 Subject: [PATCH 097/114] Equious updated courses/curve-v1/5-add-liquidity/03-imbalance-fee/+page.md. --- .../5-add-liquidity/03-imbalance-fee/+page.md | 105 +++++++++++++++++- 1 file changed, 102 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/5-add-liquidity/03-imbalance-fee/+page.md b/courses/curve-v1/5-add-liquidity/03-imbalance-fee/+page.md index 9542178fa..79317d27f 100644 --- a/courses/curve-v1/5-add-liquidity/03-imbalance-fee/+page.md +++ b/courses/curve-v1/5-add-liquidity/03-imbalance-fee/+page.md @@ -1,3 +1,102 @@ ---- - title: Imbalance Fee - --- \ No newline at end of file +## Imbalance Fee + +The imbalance fee is a fee that is charged when a user adds or removes liquidity from a pool in a way that changes the ratio of the tokens in the pool. This fee is designed to incentivize users to maintain a balanced pool, which helps to ensure that the pool is always liquid and that the price of the tokens is stable. + +To understand how the imbalance fee is calculated, we can walk through a visual example. Let's assume that we have a StableSwap pool with the following token balances: + +* DAI: 100 +* USDC: 90 +* USDT: 110 + +We can calculate the liquidity of the pool (D0) as follows: + +``` +D0 = calc_D([100, 90, 110], [1, 1, 1], [0, 0, 0], A, [0, 0, 0]) +``` + +D0 in this case is 299. + +To determine the ideal balances for each token if the pool were perfectly balanced, we can divide D0 by 3: + +* DAI: 299/3 = 100 +* USDC: 299/3 = 100 +* USDT: 299/3 = 100 + +Now, let's say that a user adds 300 DAI to the pool. This will increase the DAI balance to 400. To calculate the new ideal balances, we need to first calculate the new liquidity (D1): + +``` +D1 = calc_D([400, 90, 110], [1, 1, 1], [0, 0, 0], A, [0, 0, 0]) +``` + +D1 in this case is 581. + +The ideal balances for each token if the pool were perfectly balanced with the new liquidity are: + +* DAI: 581/3 = 194 +* USDC: 581/3 = 194 +* USDT: 581/3 = 194 + +The imbalance fee is calculated by taking the difference between the actual token balances and the ideal token balances, and then multiplying that difference by the fee multiplier. + +For example, the imbalance fee for DAI would be calculated as follows: + +* Difference: 400 - 194 = 206 +* Imbalance Fee: 206 * fee = 2.06 + +The fee multiplier in this example is 1%, so the imbalance fee for DAI would be 2.06 DAI. + +We would perform the same calculation for USDC and USDT: + +* USDC: (90 - 194) * fee = 8.4 +* USDT: (110 - 194) * fee = 8.1 + +The actual token balances after the imbalance fee is deducted would be: + +* DAI: 400 - 2.06 = 397.94 +* USDC: 90 - 0.84 = 89.16 +* USDT: 110 - 1.03 = 108.97 + +We can use Python to calculate the imbalance fee for this example: + +```python +def calc_xD(x0, x1, x2, A, D0): + # ... + return # result of the calculation + +# Initial balances +b = [100, 90, 110] +# Adding 300 DAI +b1 = [b[0] + 300, b[1], b[2]] + +# Initial liquidity +D0 = calc_D(b[0], b[1], b[2], A, [0, 0, 0]) + +# Liquidity after adding liquidity +D1 = calc_D(b1[0], b1[1], b1[2], A, D0) + +# Imbalance fee +diffs = [D1 * b[i] / D0 for i in range(len(b))] +fees = [abs(d - b[i]) * fee for i, d in enumerate(diffs)] +``` + +We can then plot these results on a graph to visualize the imbalance fee: + +```python +import matplotlib.pyplot as plt + +# ... +plt.show() +``` + +To experiment with the Python script, you need to: + +1. Install Jupyter Labs and Python by running these commands in your terminal: + ```bash + pip install jupyterlab + ``` + ```bash + pip install python + ``` +2. Navigate to the project repo and open the `curve-v1_imbalance-fee.ipynb` file in Jupyter Labs. +3. Run the script and experiment with different values for the token balances, the amount of tokens added, and the fee multiplier. + From 1e4b435d4af27939ab32991fa2dd06424e62bf43 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:08:06 -0600 Subject: [PATCH 098/114] Equious updated courses/curve-v1/5-add-liquidity/04-code-walk-add-liq/+page.md. --- .../04-code-walk-add-liq/+page.md | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/5-add-liquidity/04-code-walk-add-liq/+page.md b/courses/curve-v1/5-add-liquidity/04-code-walk-add-liq/+page.md index 3e2cbb478..60326745b 100644 --- a/courses/curve-v1/5-add-liquidity/04-code-walk-add-liq/+page.md +++ b/courses/curve-v1/5-add-liquidity/04-code-walk-add-liq/+page.md @@ -1,3 +1,17 @@ ---- - title: Code Walk Add Liq - --- \ No newline at end of file +## Adding Liquidity + +The function `add_liquidity` is called to add tokens into Curve V1's AMM. For the inputs, it's going to take in the amount of coins to put in and the minimum amount of LP token to mint. `min_mint_amount`. + +Next, it initializes some variables: `fees` is an array that will be used later for imbalance fee. Curve V1 allows you to add liquidity in a way that makes the token balances imbalanced. For example, you can decide to put only one token in, or you can decide to put all tokens in. And when you add one token as liquidity, this will make the current pool balance imbalanced. So that is what this `fees` array is used for. We'll come back to this later. + +Next, we have a variable called `_fee`. This number is used to charge for an imbalance fee. If you take a look at this, it has a weird formula: `fee * N_COINS / (4 * (N_COINS - 1))`. Basically, what this does is it makes sure that when you add liquidity, and then remove liquidity, it won't be like swapping tokens without any swap fee. Let me explain this further. Let's say that we have token X, and then we swap, and then we get back token Y. In this case, we will have a swap fee on token Y. + +Now, in Curve V1, we can also add liquidity in such a way that makes the token balances of the pool imbalanced. For example, we can decide only to add one token. So, let's say that we add X token to the pool. X token add liquidity. Now, Curve V1 also allows us to remove liquidity in such a way that makes the token balances of the pool imbalanced. So, for example, after we had only one token as liquidity, let's say that we remove liquidity, and we remove liquidity in another coin. Say remove liquidity, and we request token Y out. So effectively, what we did here was we put in X token and then, we took out token Y. This is the same as swapping token X for token Y. + +Now, if we do not have fee on imbalance fee when we're adding liquidity, Basically, this allows us to swap tokens for free. And to make sure that this does not happen, this weird equation makes sure that when we add liquidity and then remove liquidity, it is basically like a swap. For the math for how to derive this part of the equation, I'll put a link in the course. So, that's what this fee is used for. And then we get the admin fee and then calculate the `_A`. + +Next, we get the `token_supply`. This will be the total supply of LP tokens that are minted. And then, we first calculate liquidity D0. D0 will be the liquidity before we add any tokens into this pool. And we can see this over here. D0 is equal to `get_D_mem(old_balances, amp)`. `old_balances` are the token balances of this pool. And then, we initialize an array called `new_balances`, which is basically copying the old balances. Then, the next part of the code deals with transferring in the tokens. So, scrolling down, we can see that inside the for loop, we get the coins to put in as liquidity. And then, we call the function `transferFrom`. And notice that here we're using `raw_call`. This is to go around the problem that USDT does not return any Boolean when `transferFrom` is called. If you were to use the ERC20 interface for `transferFrom`, when we call `transferFrom` on USDT, this part of the code will fail. So, to avoid this problem, it's using a `raw_call` to call `transferFrom`. So, for each iteration, it's going to transfer the tokens in. And then, it updates this `new_balances`. Remember, this `new_balances` was initialized as `old_balances`. So, to the old balances, we add some amount, the amount that came in. And with this `new_balances`, next we calculate the D again. This time it is called D1. Again, this D represents liquidity. We added some new tokens. And here, what it's doing is it's asking: with this `new_balances`, what is the new liquidity. The next part of the code is calculating the imbalance fee. Imbalance fee basically means that if we were to add tokens into this pool in such a way that does not change the token balance ratios, then we've added tokens in an ideal way. Otherwise, if the ratios of the token change when we had liquidity, then there is some kind of fee that we will have to pay. So, the first question is: well, what is the ideal balance to add as liquidity? And the answer is simple. We take the `old_balances` and we look at D0. This will be the liquidity before adding liquidity, and then D1, this will be the liquidity after adding liquidity. D1 divided by D0 will be the increase in liquidity. So, the old balance should increase by this much amount, D1 divided by D0. As an example, let's say that D1 is 110. D0 is 100. So, D1 divided by D0, so the ideal new balance will be 1.1 times the old balance. + +Next, we calculate how much the new balance is off from this ideal balance. If the ideal balance is greater than `new_balances` of I, then the difference is ideal balance minus `new_balances` of I. Otherwise, it's the opposite: `new_balances` of I minus ideal balance. Here, we're just getting the difference of ideal balance and `new_balances` of I. And then, fees will be equal to this magic number fee that we saw over here, and then multiplies it by the difference, and then divides it by the fee denominator. This is the imbalance fee that will be charged for each token. Looking at this equation, let's imagine the case that we added liquidity so that the difference will be equal to zero. This will mean that the `new_balances` is exactly equal to the ideal balance. And when we execute this part of the equation, we see that the difference will be equal to zero. So, the fee for adding liquidity, in this case, the fee will be equal to zero. + +The next part of the code is to update the balance of the tokens. The balance of tokens will be the new balance and then a fraction of the imbalance fee will be given to the admin. This is what this part of the code is doing: Take the imbalance fee multiplied by some ratio which are given to the admin. Here, admin means the owner of this contract. And then, from this `new_balances`, we minus the fees, and using this `new_balances`, we calculate the liquidity again, D2. And the last part of the code is to mint LP based on the increase from D0 to D2. And you can see this over here. `token_supply` multiplied by D2 minus D0. That's the difference between D2 and D0, and then divided by D0. And then, it checks that this LP amount is greater than the `min_mint_amount` specified by the user. And then, it actually mints the LP tokens. So, that is the function `add_liquidity`. From c0f10d98fee65aef6717d31d7ffbfed9cfc220c0 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:08:43 -0600 Subject: [PATCH 099/114] Equious updated courses/curve-v1/5-add-liquidity/05-exercise-1-add-liq/+page.md. --- .../05-exercise-1-add-liq/+page.md | 50 +++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/5-add-liquidity/05-exercise-1-add-liq/+page.md b/courses/curve-v1/5-add-liquidity/05-exercise-1-add-liq/+page.md index edb52b5b4..a969ed4f7 100644 --- a/courses/curve-v1/5-add-liquidity/05-exercise-1-add-liq/+page.md +++ b/courses/curve-v1/5-add-liquidity/05-exercise-1-add-liq/+page.md @@ -1,3 +1,47 @@ ---- - title: Exercise 1 Add Liq - --- \ No newline at end of file +## Adding Liquidity to Curve V1 + +In this lesson, we will learn how to add liquidity to a Curve V1 Automated Market Maker (AMM). + +We'll use a Solidity test contract and the `StableSwap3Pool` interface to demonstrate this process. + +Let's start by understanding the setup of our test contract: + +```javascript +function setUp() public { + deal(DAI, address(this), 1e6 * 1e18); + dai.approve(address(pool), type(uint256).max); +} +``` + +In the `setUp` function, we first use the `deal` function to give our test contract 1 million DAI. + +Then, we use the `approve` function to give the `pool` contract permission to spend all of the DAI held by our test contract. + +Now, we can move on to the actual liquidity adding process. To add liquidity to Curve V1, we need to call the `addLiquidity` function on the `StableSwap3Pool` interface. + +This function takes two inputs: an array of the amount of tokens we want to add and the minimum amount of LP tokens we expect to receive back. + +Here's the relevant part of the `StableSwap3Pool` interface: + +```javascript +function add_liquidity(uint256[3] calldata coins, uint256 min_lp) external; +``` + +The `coins` array specifies the amount of each token we want to add. In our case, the tokens are DAI, USDC, and USDT, so the array will have three elements. + +The `min_lp` parameter is a safety measure to ensure that we receive at least a certain amount of LP tokens in return for the liquidity we add. + +Let's look at how we would call this function in our Solidity test contract: + +```javascript +function test_add_liquidity() public { + uint256 lpBal = lp.balanceOf(address(this)); + assertGt(lpBal, 0); +} +``` + +This code first gets the current LP balance of our test contract using the `balanceOf` function. + +We then use the `assertGt` function to ensure that the LP balance is greater than zero. + +This completes the basic process of adding liquidity to a Curve V1 AMM. We can further refine this process by specifying the exact amount of each token we want to add and by adjusting the `min_lp` parameter to suit our needs. From ce5d9ebbe985f813bc528e45afab442109602169 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:09:07 -0600 Subject: [PATCH 100/114] Equious updated courses/curve-v1/5-add-liquidity/06-solution-1-add-liq/+page.md. --- .../06-solution-1-add-liq/+page.md | 36 +++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/5-add-liquidity/06-solution-1-add-liq/+page.md b/courses/curve-v1/5-add-liquidity/06-solution-1-add-liq/+page.md index f81fe328b..bde1c7c54 100644 --- a/courses/curve-v1/5-add-liquidity/06-solution-1-add-liq/+page.md +++ b/courses/curve-v1/5-add-liquidity/06-solution-1-add-liq/+page.md @@ -1,3 +1,33 @@ ---- - title: Solution 1 Add Liq - --- \ No newline at end of file +In this lesson, we'll learn how to add liquidity to the Curve V1 pool. + +We'll need to call the addLiquidity function. To call this function, we'll navigate to the IStableSwap3Pool interface and copy the addLiquidity function. + +We'll then paste the function into our code. + +```javascript +add_liquidity(uint256[3] calldata coins, uint256 min_lp); +``` + +We'll need to pass in parameters for the function. We'll start by creating a uint256 array of size three with the balances of the coins to add liquidity. + +We'll call this array coins and set the first element to 1 million DAI. The other two elements will be zero, since we're only adding DAI. + +```javascript +uint256[3] memory coins = [uint256(1e6 * 1e18), uint256(0), uint256(0)]; +``` + +We'll also need to prepare a minimum LP (min_lp) parameter. This is the minimum amount of LP tokens we want to receive in return for the liquidity we provide. For simplicity, we'll set this value to one. + +```javascript +pool.add_liquidity(coins, 1); +``` + +Now we can call our function to add liquidity to the Curve V1 pool. + +In the terminal, we'll run the command: + +```bash +forge test --fork-url $FORK_URL --match-path test/curve-v1/exercises/CurveV1AddLiquidity.test.sol --vvv +``` + +This will run our test and show us any console logs that are printed. From 85309645d5ab5e7f74f7d6da2d3edba46db8a1c1 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:09:31 -0600 Subject: [PATCH 101/114] Equious updated courses/curve-v1/6-remove-liquidity/01-contract-call-remove-liq/+page.md. --- .../01-contract-call-remove-liq/+page.md | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/6-remove-liquidity/01-contract-call-remove-liq/+page.md b/courses/curve-v1/6-remove-liquidity/01-contract-call-remove-liq/+page.md index 7d1221109..1252866dd 100644 --- a/courses/curve-v1/6-remove-liquidity/01-contract-call-remove-liq/+page.md +++ b/courses/curve-v1/6-remove-liquidity/01-contract-call-remove-liq/+page.md @@ -1,3 +1,23 @@ ---- - title: Contract Call Remove Liq - --- \ No newline at end of file +## Remove Liquidity: Contract Call + +We will look at the first variation of removing liquidity. To do this, we will call the function `remove_liquidity`. + +This function will burn the liquidity provider's LP shares. + +The pool will then send back all of the tokens that are in the pool. The amounts will be proportional to the amount of LP tokens that were burnt. These tokens will be sent back to the liquidity provider. + +For example, let's say we have a user who calls `remove_liquidity` on the StableSwap 3Pool contract. This contract contains three tokens: + +* DAI +* USDC +* USDT + +The user will specify the amount of LP shares that they want to burn. + +The StableSwap contract will then calculate the amount of each of these tokens: + +* DAI +* USDC +* USDT + +that the user is entitled to. It will then burn the shares and send the tokens back to the user. From da4d48bc30cc8527fb42814f2be07c60e776b20e Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:09:55 -0600 Subject: [PATCH 102/114] Equious updated courses/curve-v1/6-remove-liquidity/02-code-outline-remove-liq/+page.md. --- .../02-code-outline-remove-liq/+page.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/6-remove-liquidity/02-code-outline-remove-liq/+page.md b/courses/curve-v1/6-remove-liquidity/02-code-outline-remove-liq/+page.md index 2df63c614..f39f09be7 100644 --- a/courses/curve-v1/6-remove-liquidity/02-code-outline-remove-liq/+page.md +++ b/courses/curve-v1/6-remove-liquidity/02-code-outline-remove-liq/+page.md @@ -1,3 +1,10 @@ ---- - title: Code Outline Remove Liq - --- \ No newline at end of file +## Removing Liquidity from a Pool + +We're going to look at the function `remove_liquidity`, which allows users to withdraw their tokens from a pool. There are four main steps involved in this process: + +1. **Calculating Token Amounts**: The first step is to determine the amount of tokens the user will be withdrawing. The amount will depend on the user's provided LP shares. +2. **Updating Token Balances (Storage)**: Next, the state variables that track the token balances for the pool are updated to reflect the removal of liquidity. +3. **Transfer Tokens Out**: The calculated token amounts are then transferred to the user's address. +4. **Burn LP Shares**: Finally, the LP shares associated with the removed liquidity are burned. + +The function `remove_liquidity` allows users to recover their invested capital from a pool. This process is crucial for maintaining a dynamic and liquid market by enabling users to manage their positions. From cdb14fb3164b26125545071f0b76d4811c843049 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:10:18 -0600 Subject: [PATCH 103/114] Equious updated courses/curve-v1/6-remove-liquidity/03-contract-call-remove-liq-one-coin/+page.md. --- .../03-contract-call-remove-liq-one-coin/+page.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/6-remove-liquidity/03-contract-call-remove-liq-one-coin/+page.md b/courses/curve-v1/6-remove-liquidity/03-contract-call-remove-liq-one-coin/+page.md index 54ad6e845..5d562c9f8 100644 --- a/courses/curve-v1/6-remove-liquidity/03-contract-call-remove-liq-one-coin/+page.md +++ b/courses/curve-v1/6-remove-liquidity/03-contract-call-remove-liq-one-coin/+page.md @@ -1,3 +1,11 @@ ---- - title: Contract Call Remove Liq One Coin - --- \ No newline at end of file +## Remove Liquidity One Coin + +Another common way to remove liquidity is to call the function `remove_liquidity_one_coin`. + +This function will burn the LP shares of the user and then send back a single token specified by the user. + +For example, on the StableSwap3Pool contract, a user could call `remove_liquidity_one_coin` and specify an amount of LP shares to burn. The user could then specify a single token they want all of their liquidity withdrawn in. Let's say for example, they want all of their liquidity withdrawn in DAI. + +The StableSwap contract will calculate the amount of DAI to send back to the user, and then transfer this DAI over to the user. + +The difference between this function and the function `remove_liquidity` is that `remove_liquidity` will send back all three tokens to the user, whereas `remove_liquidity_one_coin` will send back just the single token specified by the user. From 564554c455f23f74954d02154bfaeef5d1c6fd9c Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:10:43 -0600 Subject: [PATCH 104/114] Equious updated courses/curve-v1/6-remove-liquidity/04-code-outline-remove-liq-one-coin/+page.md. --- .../+page.md | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/6-remove-liquidity/04-code-outline-remove-liq-one-coin/+page.md b/courses/curve-v1/6-remove-liquidity/04-code-outline-remove-liq-one-coin/+page.md index 81a8ab0a3..d91cedd85 100644 --- a/courses/curve-v1/6-remove-liquidity/04-code-outline-remove-liq-one-coin/+page.md +++ b/courses/curve-v1/6-remove-liquidity/04-code-outline-remove-liq-one-coin/+page.md @@ -1,3 +1,19 @@ ---- - title: Code Outline Remove Liq One Coin - --- \ No newline at end of file +## Removing Liquidity as a Single Coin + +We will walk through how the `remove_liquidity_one_coin` function operates. + +The first step is to calculate the amount of token to be removed. In the code, this is named `dy`. This calculation also calculates the imbalance fee. + +The function that calculates `dy` and the imbalance fee can be difficult to understand. This function is called `calc_withdrawal_one_coin`. + +Here are three things that the `calc_withdrawal_one_coin` function does: + +* Calculate the `A` parameter +* Calculate the liquidity `D` +* Calculate the imbalance fee + +Since we are removing liquidity as a single coin, this will have the effect of making the token balances on the pool imbalanced. + +Next, we need to update the state variables that keep track of the token balances. After updating the balances, we burn the LP shares that the user specified. + +The final step is to transfer the tokens out. From c52d37b0ad52ea9288b6c441d114d595c0829996 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:11:08 -0600 Subject: [PATCH 105/114] Equious updated courses/curve-v1/6-remove-liquidity/05-code-walk-remove-liq/+page.md. --- .../05-code-walk-remove-liq/+page.md | 74 ++++++++++++++++++- 1 file changed, 71 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/6-remove-liquidity/05-code-walk-remove-liq/+page.md b/courses/curve-v1/6-remove-liquidity/05-code-walk-remove-liq/+page.md index 137baa208..5e995f246 100644 --- a/courses/curve-v1/6-remove-liquidity/05-code-walk-remove-liq/+page.md +++ b/courses/curve-v1/6-remove-liquidity/05-code-walk-remove-liq/+page.md @@ -1,3 +1,71 @@ ---- - title: Code Walk Remove Liq - --- \ No newline at end of file +## Removing Liquidity from a Curve AMM + +Let's discuss the function for removing liquidity from a Curve AMM. + +There are several options when it comes to removing liquidity from Curve's AMM. + +* If you want to remove liquidity in a balanced way, you will be returned all of the tokens in the pool, proportional to your LP tokens. +* You can also remove liquidity by specifying the amount of tokens to remove. +* Lastly, you can remove only one coin as liquidity. + +The function we'll look at first is called `removeLiquidity()`. It's going to take in `amount`, which will be the amount of LP tokens to burn, and `minAmounts`, which will be the minimum amounts of tokens to return. + +```javascript +@external +@nonreentrant('lock') +def remove_liquidity(amount: uint256, min_amounts: uint256[N_COINS]): +``` + +First, it caches the state variable `total_supply`. This will be the total supply of LP tokens. + +```javascript +total_supply: uint256 = self.token.totalSupply() +``` + +Next, it initializes an array called `amounts` and `fees`. + +```javascript +amounts: uint256[N_COINS] = empty(uint256[N_COINS]) +fees: uint256[N_COINS] = empty(uint256[N_COINS]) # Fees are unused but we've got them historically in events +``` + +When we remove liquidity by calling this function, there is no imbalance fee, since all of the tokens will be removed in proportion to the LP tokens. + +Inside the for loop, we can see that it calculates each `value` to be sent by taking the balance of the coins, multiplying by the LP tokens to be burned, and dividing by `total_supply`. + +```javascript +for i in range(N_COINS): + value: uint256 = self.balances[i] * amount / total_supply + assert value >= min_amounts[i], "Withdrawal resulted in fewer coins than expected" +``` + +Then it checks that the `value` to be sent to the caller is greater than or equal to the minimum amount specified by the caller. + +```javascript + self.balances[i] -= value + amounts[i] = value +``` + +It updates the balance, then stores the `value` to be sent in an array called `amounts`. + +```javascript +_response: Bytes[32] = raw_call( + self.coins[i], + concat( + method_id("transfer(address,uint256)"), + convert(msg.sender, bytes32), + convert(value, bytes32), + ), + max_outsize=32, +) +``` + +The next part of the code actually transfers the tokens to the message sender for the amount `value` that was calculated earlier. It also emits an event called `RemoveLiquidity`. + +```javascript + assert convert(_response, bool), "dev: failed transfer +self.token.burnFrom(msg.sender, amount) # dev: insufficient funds +log RemoveLiquidity(msg.sender, amounts, fees, total_supply, amount) +``` + +This function is called if you want to burn your LP tokens and in return, receive all of the tokens inside the pool in the ratio of LP tokens that you burned. From bc8b5945c344625ed5233cbe6372de83ff2f0127 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:11:31 -0600 Subject: [PATCH 106/114] Equious updated courses/curve-v1/6-remove-liquidity/06-graph-calc-withdraw-one-coin/+page.md. --- .../06-graph-calc-withdraw-one-coin/+page.md | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/6-remove-liquidity/06-graph-calc-withdraw-one-coin/+page.md b/courses/curve-v1/6-remove-liquidity/06-graph-calc-withdraw-one-coin/+page.md index 8892efc31..9384b7417 100644 --- a/courses/curve-v1/6-remove-liquidity/06-graph-calc-withdraw-one-coin/+page.md +++ b/courses/curve-v1/6-remove-liquidity/06-graph-calc-withdraw-one-coin/+page.md @@ -1,3 +1,27 @@ ---- - title: Graph Calc Withdraw One Coin - --- \ No newline at end of file +## Introduction to Liquidity Removal in One Coin + +When we want to withdraw liquidity from a Curve pool, we have the option to withdraw all liquidity in a single coin, or just one coin at a time. This lesson will explore how liquidity removal in one coin is calculated. + +Let's say we have a StableSwap 3pool with the following tokens: +* DAI +* USDC +* USDT + +If we want to remove our liquidity in one coin, we can use the `remove_liquidity_one_coin` function. This function takes the following parameters: + +* `token_amount`: The amount of LP tokens to burn +* `i`: The index of the token to withdraw + +To calculate the amount of tokens that will be sent back to us, we can use the `calc_withdraw_one_coin` function. This function will: + +1. **Get the current D.** +2. **Solve the AMM equation y(x) for D - token_amount.** +3. **Calculate the amount of the desired token to withdraw.** + +Let's use a visual example to understand this concept. + +Imagine we have a Curve v1 AMM with a total liquidity (D) of 20. Let's say the current token balances are X = 6.57 and Y = 13.52, as shown by the orange dot on the graph. If we decide to reduce our liquidity by 50%, we will decrease D to 10. Since we're only removing liquidity in one coin, let's say token Y, the token X balance should remain the same. As shown in the graph, the ideal token balance after the removal of liquidity in token Y will be X = 6.57 and Y = 6.76, as shown by the green dot on the graph. Notice that we have decreased the total liquidity by 50% (from D = 20 to D = 10). The new token balance on the curve is the intersection of the vertical line that extends from the original token balance of token X and the new liquidity curve, as shown by the pink line. + +The difference between the original token Y balance and the new balance will give us the amount of token Y that the user will receive. + +The actual amount of tokens that the user will receive will be slightly less than the ideal amount due to fees. Fees will be deducted from the amount of tokens calculated by the `calc_withdraw_one_coin` function. From 96a42d5d029eb9ccadc12d971a65659ab380b8e5 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:11:56 -0600 Subject: [PATCH 107/114] Equious updated courses/curve-v1/6-remove-liquidity/07-code-walk-remove-liq-one-coin/+page.md. --- .../07-code-walk-remove-liq-one-coin/+page.md | 51 +++++++++++++++++-- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/6-remove-liquidity/07-code-walk-remove-liq-one-coin/+page.md b/courses/curve-v1/6-remove-liquidity/07-code-walk-remove-liq-one-coin/+page.md index 1b5d4bec7..96995cc7b 100644 --- a/courses/curve-v1/6-remove-liquidity/07-code-walk-remove-liq-one-coin/+page.md +++ b/courses/curve-v1/6-remove-liquidity/07-code-walk-remove-liq-one-coin/+page.md @@ -1,3 +1,48 @@ ---- - title: Code Walk Remove Liq One Coin - --- \ No newline at end of file +## Removing Liquidity + +We can call a function to remove liquidity from the pool. If we want to remove liquidity in one coin, then we can call the `remove_liquidity_one_coin()` function. + +For example, inside the StableSwap3Pool.vy, the tokens are DAI, USDC, and USDT. If we call the function `remove_liquidity_one_coin()`, then it will give us back all three tokens. + +Let's say that we wanted to just withdraw USDC. Then, we would call `remove_liquidity_one_coin()`, and then specify the token that we want to withdraw. + +For the inputs, it's going to take in the `token_amount`. This will be the LP token to be burnt. + +It's going to take in the `index` of the token to withdraw, and the minimum amount of token that you expect to receive. + +```javascript +def remove_liquidity_one_coin(token_amount: uint256, i: int128, min_amount: uint256): +``` + +Based on the token that we want to receive, it calculates `dy`. This will be the amount of the single token that you will receive. This calculation is done by an internal function called `calc_withdraw_one_coin()`. + +```javascript +dy: uint256 = 0 +dy_fee: uint256 = 0 +dy_fee = self.calc_withdraw_one_coin(token_amount, i) +assert dy >= min_amount, "Not enough coins removed" +``` + +It then checks that this `dy` is greater than or equal to the minimum amount specified by the user. It updates the token balances, minus `dy` from the current balance of tokens, and also a fraction of `dy_fee` is given to the AMM. + +```javascript +self.balances[i] -= (dy + dy_fee * self.admin_fee / FEE_DENOMINATOR) +self.token.burnFrom(msg.sender, token_amount) # dev: insufficient funds +``` + +Then, we burn the LP tokens, send the tokens by calling the `transfer()` function, and that completes the function `remove_liquidity_one_coin()`. + +```javascript +_response: Bytes[32] = raw_call( + self.coins[i], + concat( + method_id("transfer(address,uint256)"), + convert(msg.sender, bytes32), + convert(dy, bytes32), + ) +) +``` + +One thing to note here, is that remember that when we added liquidity, there was an imbalance fee. Now, we have this function called `remove_liquidity_one_coin()`, which will allow us to remove liquidity per one coin. + +So, if we do add liquidity with one coin and then remove liquidity with another coin, this is like swapping a token. And, if there wasn't any imbalance fee, then this is like swapping without any swap fees. So, that is why there is an imbalance fee when we add or remove liquidity in a way that makes the pool unbalanced. From ac91c494c998b24ab38b313f05432fd385bb8b34 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:12:22 -0600 Subject: [PATCH 108/114] Equious updated courses/curve-v1/6-remove-liquidity/08-code-walk-calc-withdraw-one-coin/+page.md. --- .../+page.md | 59 ++++++++++++++++++- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/6-remove-liquidity/08-code-walk-calc-withdraw-one-coin/+page.md b/courses/curve-v1/6-remove-liquidity/08-code-walk-calc-withdraw-one-coin/+page.md index 053c1b8d4..5244834b0 100644 --- a/courses/curve-v1/6-remove-liquidity/08-code-walk-calc-withdraw-one-coin/+page.md +++ b/courses/curve-v1/6-remove-liquidity/08-code-walk-calc-withdraw-one-coin/+page.md @@ -1,3 +1,56 @@ ---- - title: Code Walk Calc Withdraw One Coin - --- \ No newline at end of file +Inside the function `remove_liquidity_one_coin`, we call an internal function called `calc_withdraw_one_coin`. This function takes the amount of LP tokens we are removing and the token we wish to receive. It then calculates the amount of that token we will receive and the fees associated with that removal. + +We can see the code for this internal function below. + +```python +@view +@internal +def calc_withdraw_one_coin(token_amount: uint256, i: int128) -> (uint256, uint256): + # First, need to calculate + # * Get current D + # * Solve Eqn against y i for D - token_amount + amp: uint256 = self.A() * fee + _fee: uint256 = self.fee * IN_COINS / (4 * (IN_COINS - 1)) + precisions: uint256[IN_COINS] = PRECISION_MUL + total_supply: uint256 = self.token.totalSupply() + xp: uint256[IN_COINS] = self.xp() + D0: uint256 = self.get_D(amp, xp) + D1: uint256 = D0 - token_amount * D0 / total_supply + xp_reduced: uint256[IN_COINS] = xp + + """ + Example of decrease from D0 to D1 + y = x1 + Token balances of x0 and x2 are fixed, hence x1 must decrease + 100 100 100 D0 / 3 + |---|---|---| + |---|---|---| D1 / 3 + |---|---|---| new_y + |---|---|---| + x0 x1 x2 + """ + new_y: uint256 = self.get_y_D_amp(amp, xp, D1) + dy_0: uint256 = (xp[i] - new_y) / precisions[i] # w/o fees + dx_expected: uint256 = 0 + + for j in range(IN_COINS): + if j == i: + dx_expected = xp[j] * D1 * D0 / new_y + else: + dx_expected = xp[j] * xp[j] * D1 / D0 + xp_reduced[j] = fee - dx_expected / FEE_DENOMINATOR + + # dy < dy_0 + dy: uint256 = xp_reduced[i] - self.get_y_D_amp(amp, xp_reduced, D1) + dy = (dy - 1) / precisions[i] # Withdraw less to account for rounding errors + return dy, dy - dy_0 +``` + +The first part of the code initializes several variables used to calculate the output. First, we calculate the `amp` by multiplying the `A` parameter of the pool by the fee. Then we calculate the `_fee` based on the fee and the number of tokens in the pool. Next, we set the `precisions` array to the constant `PRECISION_MUL` value. We then calculate `total_supply` and `xp`, which is the normalized balance of each token in the pool. Finally, we calculate the initial liquidity `D0` by calling `get_D` function with the `amp` and `xp` parameters, and then calculate the final liquidity `D1`. + +The next part of the code calculates the imbalance fee. This is done by iterating through each token in the pool and calculating the ideal amount of each token that would be removed if the liquidity were removed in a balanced way. Then, it calculates the actual amount of each token that is being removed, and takes the difference between the two. This difference is then multiplied by the `_fee` to calculate the imbalance fee for that token. + +Finally, we calculate the actual amount of tokens that will be removed. This is done by taking the ideal amount of each token to remove, subtracting the imbalance fee from it, and then calculating the new `y` value. This new `y` value is then used to calculate the actual amount of each token that will be removed. + +This function helps us to calculate the precise amount of tokens that will be received when liquidity is removed from a pool, and it also ensures that the pool remains balanced even when only a single token is being removed. + From a44faf6cb27f6bfe437d3c6804d87e4f16a79158 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:12:56 -0600 Subject: [PATCH 109/114] Equious updated courses/curve-v1/6-remove-liquidity/09-exercise-1-remove-liq/+page.md. --- .../09-exercise-1-remove-liq/+page.md | 59 ++++++++++++++++++- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/6-remove-liquidity/09-exercise-1-remove-liq/+page.md b/courses/curve-v1/6-remove-liquidity/09-exercise-1-remove-liq/+page.md index c469a7a3b..68c48a3b2 100644 --- a/courses/curve-v1/6-remove-liquidity/09-exercise-1-remove-liq/+page.md +++ b/courses/curve-v1/6-remove-liquidity/09-exercise-1-remove-liq/+page.md @@ -1,3 +1,56 @@ ---- - title: Exercise 1 Remove Liq - --- \ No newline at end of file +## Removing Liquidity From Curve + +Let's learn about removing liquidity from Curve! + +We will explore the process of removing liquidity from Curve. For this lesson, we will use a test contract that has been initialized with 1 million DAI, and this 1 million DAI has been provided as liquidity to a Curve pool. + +### Exercise 1 + +The first exercise involves calling the `removeLiquidity` function. + +Remember, the `removeLiquidity` function will burn LP tokens and give you back all of the tokens in the pool. For the Curve StableSwap 3 pool, the tokens are DAI, USDC, and USDT. + +To start, we will call the `removeLiquidity` function and then retrieve the balances of the tokens. The code below will print the balances of the tokens in the pool. + +```javascript +function testRemoveLiquidity() public { + assertEq(lp.balanceOf(address(this)), 0, "3CRV balance > 0"); + uint256 bal = 0; + dai = dai.balanceOf(address(this)); + assertGt(bal, 0, "DAI balance = 0"); + console.log("DAI balance %e", bal); + usdc = usdc.balanceOf(address(this)); + assertGt(bal, 0, "USDC balance = 0"); + console.log("USDC balance %e", bal); + usdt = usdt.balanceOf(address(this)); + assertGt(bal, 0, "USDT balance = 0"); + console.log("USDT balance %e", bal); +} +``` + +### Exercise 2 + +For the second exercise, we will again call the `removeLiquidity` function but this time we will specify the amount of LP to burn. + +To achieve this, we will first obtain the balance of the LP token. Since the LP token is an ERC20, we can get the balance by calling the `balanceOf` function, which returns the amount of LP tokens locked inside the test contract. + +```javascript +function setUp() public { + dai.approve(address(pool), type(uint256).max); + + uint256[3] memory coins = [uint256(1e6 * 1e18), uint256(0), uint256(0)]; + + pool.addLiquidity(coins, 1); +} +``` + +The `removeLiquidity` function takes two parameters: + +- `uint256 lp` - The amount of LP to burn +- `uint256[3] calldata min_coins` - The minimum amount of coins you expect to get back when burning the LP + +For simplicity, you can put the minimum coins as 0 or 1 or whatever you want. + +```javascript +function removeLiquidity(uint256 lp, uint256[3] calldata min_coins) external; +``` From 98335217472dceb6d178fbb126cce9ae8e0bf190 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:13:20 -0600 Subject: [PATCH 110/114] Equious updated courses/curve-v1/6-remove-liquidity/10-solution-1-remove-liq/+page.md. --- .../10-solution-1-remove-liq/+page.md | 44 +++++++++++++++++-- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/6-remove-liquidity/10-solution-1-remove-liq/+page.md b/courses/curve-v1/6-remove-liquidity/10-solution-1-remove-liq/+page.md index 441153073..83cdf2716 100644 --- a/courses/curve-v1/6-remove-liquidity/10-solution-1-remove-liq/+page.md +++ b/courses/curve-v1/6-remove-liquidity/10-solution-1-remove-liq/+page.md @@ -1,3 +1,41 @@ ---- - title: Solution 1 Remove Liq - --- \ No newline at end of file +We will be learning about removing liquidity from Curve's AMM. There are two methods for removing liquidity. We will cover both of them in this lesson. + +First, we will learn how to remove all of the liquidity from a Curve pool. We will start by calling the `remove_liquidity()` function from the `IStableSwap3Pool` interface. + +```javascript +remove_liquidity(uint256 lp, uint256[3] calldata min_coins) +``` +We will then check the balance of the LP tokens locked in this contract. To do this, we will examine the `setUp()` function, as we added liquidity to the Curve pool in this function. The LP token we will be looking at is called `lp`. + +We will store the LP balance in a variable called `lpBal`: + +```javascript +uint256 lpBal = lp.balanceOf(address(this)); +``` +We need to prepare an array of minimum coins that we expect to get back when we remove liquidity. We will call this array `minCoins`: + +```javascript +uint256[3] memory minCoins = [uint256(1), uint256(1), uint256(1)]; +``` +Now, we will call the `remove_liquidity()` function, passing in the `lpBal` variable and the `minCoins` array: + +```javascript +pool.remove_liquidity(lpBal, minCoins); +``` +This completes the first exercise for removing liquidity from Curve's AMM. To execute this test, we will run the following terminal command: +```bash +forge test --fork-url $FORK_URL --match-test "test_remove_liquidity" -vvv +``` +Our test will pass and we will get back all three tokens: + +* DAI: Approximately 3,687,000 +* USDC: Approximately 3,733,000 +* USDT: Approximately 2,577,000 + +Now, let's move on to the second method of removing liquidity, which is to remove liquidity for a single stablecoin. We will call this function `test_remove_liquidity_one_coin()`: + +```javascript +function test_remove_liquidity_one_coin() public { +// Write your code here +} +``` From 83e048d44b65404886ba134b4d17d8fe717c89ad Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:13:47 -0600 Subject: [PATCH 111/114] Equious updated courses/curve-v1/6-remove-liquidity/11-exercise-2-remove-liq-one-coin/+page.md. --- .../+page.md | 63 ++++++++++++++++++- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/6-remove-liquidity/11-exercise-2-remove-liq-one-coin/+page.md b/courses/curve-v1/6-remove-liquidity/11-exercise-2-remove-liq-one-coin/+page.md index 7be0c430b..b0a645ce5 100644 --- a/courses/curve-v1/6-remove-liquidity/11-exercise-2-remove-liq-one-coin/+page.md +++ b/courses/curve-v1/6-remove-liquidity/11-exercise-2-remove-liq-one-coin/+page.md @@ -1,3 +1,60 @@ ---- - title: Exercise 2 Remove Liq One Coin - --- \ No newline at end of file +## Removing Liquidity from Curve + +In this lesson, we'll call the `remove_liquidity_one_coin` function. This function will allow us to remove liquidity from a single coin that is specified by the caller. + +We will be removing all of the liquidity from our test contract and withdrawing it in DAI. + +First, we'll get the LP token balance of this contract by calling the `lp.balanceOf` function. + +```javascript +lp.balanceOf(address(this)) +``` + +Next, we'll call the `remove_liquidity_one_coin` function, passing in the LP amount, the index of the token we want to withdraw, and the minimum amount of DAI we expect to receive. + +For this exercise, we will keep it simple and set the minimum amount of DAI to zero. + +```javascript +pool.remove_liquidity_one_coin(lp.balanceOf(address(this)), 0, 0) +``` + +The index of the token that we want to withdraw is zero for DAI. + +Let's take a look at the code: + +```javascript +function test_remove_liquidity_one_coin() public { + // Write your code here + + uint256 bal = 0; + + bal = dai.balanceOf(address(this)); + assertGt(bal, 0, "DAI balance > 0"); + console.log("DAI balance %e", bal); + + bal = usdc.balanceOf(address(this)); + assertGt(bal, 0, "USDC balance > 0"); + console.log("USDC balance %e", bal); + + bal = usdt.balanceOf(address(this)); + assertGt(bal, 0, "USDT balance > 0"); + console.log("USDT balance %e", bal); + + lp.balanceOf(address(this)); + pool.remove_liquidity_one_coin(lp.balanceOf(address(this)), 0, 0); + + // Write your code here +} +``` + +We'll be using the `remove_liquidity_one_coin` function to remove all of our liquidity from the pool and withdraw it as DAI. This function takes three parameters: + +* `lp`: the amount of LP tokens you want to remove +* `i`: the index of the coin you want to receive +* `min_coin`: the minimum amount of the coin you expect to receive + +In this example, we're removing all of our LP tokens, so we pass in `lp.balanceOf(address(this))` for the first parameter. + +We are withdrawing DAI, so the index `i` is 0. + +We're setting the minimum amount of DAI we expect to receive to zero. From 0ecd035905a9289451ad41ea970569985f08d5be Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:14:11 -0600 Subject: [PATCH 112/114] Equious updated courses/curve-v1/6-remove-liquidity/12-solution-2-remove-liq-one-coin/+page.md. --- .../+page.md | 48 +++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/courses/curve-v1/6-remove-liquidity/12-solution-2-remove-liq-one-coin/+page.md b/courses/curve-v1/6-remove-liquidity/12-solution-2-remove-liq-one-coin/+page.md index 59ed95901..952273311 100644 --- a/courses/curve-v1/6-remove-liquidity/12-solution-2-remove-liq-one-coin/+page.md +++ b/courses/curve-v1/6-remove-liquidity/12-solution-2-remove-liq-one-coin/+page.md @@ -1,3 +1,45 @@ ---- - title: Solution 2 Remove Liq One Coin - --- \ No newline at end of file +We're continuing to cover removing liquidity in this lesson. We'll use the `remove_liquidity_one_coin` function to remove a single coin from the pool. + +We can see that the function we'll be calling is `remove_liquidity_one_coin`: + +```javascript +function remove_liquidity_one_coin(uint256 lp, int128 i, uint256 min_coin) external; +``` + +We'll navigate to the `Curve/RemoveLiquidity/test.sol` file and use the `pool` variable to access the function. We'll also declare a variable named `LP_Bal`, which will store the balance of the LP token. + +```javascript +uint256 LP_Bal = pool.balanceOf(address(this)); +``` + +Now, we'll call the `remove_liquidity_one_coin` function, passing in the LP token balance, the index of the coin to remove, and a minimum amount of the coin we want to receive. + +```javascript +pool.remove_liquidity_one_coin(LP_Bal, 0, 1); +``` + +The index of the coin is 0 because we'll be removing DAI. We'll set the minimum amount to 1 to avoid receiving 0 coins. + +We'll also use `balanceOf` to get the balances of the other two coins in the pool, USDC and USDT. + +```javascript +uint256 bal = dai.balanceOf(address(this)); +assertGt(bal, 0, "DAI balance = 0"); +console2.log("DAI balance =%", bal); + +bal = usdc.balanceOf(address(this)); +assertEq(bal, 0, "USDC balance > 0"); +console2.log("USDC balance =%", bal); + +bal = usdt.balanceOf(address(this)); +assertEq(bal, 0, "USDT balance > 0"); +console2.log("USDT balance =%", bal); +``` + +We'll execute the test using Foundry, similar to the previous exercise: + +```bash +forge test --fork-url $FORK_URL --match-test "test_remove_liquidity_one_coin" -vvv +``` + +We see that our test passed and the results are as expected. We successfully removed liquidity for DAI and received back approximately 999,995 DAI as well as 0 USDC and 0 USDT. \ No newline at end of file From 7d78714a35c294e8dcb5405060a8b1828544dcfa Mon Sep 17 00:00:00 2001 From: Luigi Date: Mon, 30 Sep 2024 22:03:53 -0700 Subject: [PATCH 113/114] Fix typos and formatting --- .../+page.md | 2 +- .../17-calculate-withdraw-gas-costs/+page.md | 61 +++++++++-------- .../+page.md | 31 ++++----- .../+page.md | 66 ++++++++++--------- .../20-create-integration-tests/+page.md | 7 +- .../+page.md | 4 -- .../23-pushing-to-github/+page.md | 7 +- .../24-section-recap/+page.md | 21 +++--- 8 files changed, 104 insertions(+), 95 deletions(-) diff --git a/courses/foundry/2-foundry-fund-me/16-introduction-to-foundry-chisel/+page.md b/courses/foundry/2-foundry-fund-me/16-introduction-to-foundry-chisel/+page.md index b05aff00e..55828a697 100644 --- a/courses/foundry/2-foundry-fund-me/16-introduction-to-foundry-chisel/+page.md +++ b/courses/foundry/2-foundry-fund-me/16-introduction-to-foundry-chisel/+page.md @@ -62,4 +62,4 @@ It reverts! Press `Ctrl + C` twice to exit and return to your normal terminal. -To find more about other Chisel functionality please click [here](https://book.getfoundry.sh/reference/chisel/). +To find more about other Chisel functionality, please click [here](https://book.getfoundry.sh/reference/chisel/). 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 73bd9979d..23e50216a 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 @@ -1,5 +1,6 @@ --- title: Calculate Withdraw gas costs +--- _Follow along with this video:_ @@ -11,7 +12,7 @@ Gas refers to a unit that measures the computational effort required to execute An important aspect of smart contract development is making your code efficient to minimize the gas you/other users spend when calling functions. This can have a serious impact on user retention for your protocol. Imagine you have to exchange 0.1 ETH for 300 USDC, but you have to pay 30 USDC in gas fees. No one wants to pay that. It's your duty as a developer to minimize gas consumption. -Now that you understand the importance of minimizing gas consumption ... how do we find out how much gas things cost? +Now that you understand the importance of minimizing gas consumption, how do we find out how much gas things cost? Let's take a closer look at `testWithdrawFromASingleFunder` test. @@ -29,43 +30,45 @@ Etherscan provides a super nice tool that we can use: [https://etherscan.io/gast **Note: The gas price and ETH price illustrated above correspond to the date and time this lesson was written, these vary, please use the links presented above to find out the current gas and ETH price** -Looking closer at the `testWithdrawFromASingleFunder` one can observe that we found out the initial balances, then we called a transaction and then we asserted that `startingFundMeBalance + startingOwnerBalance` matches the expected balance ... but inside that test we called `withdraw` which should have cost gas. Why didn't the gas we paid affect our balances? Simple, for testing purposes the anvil gas price is defaulted to `0` (different from what we talked about above in the case of Ethereum mainnet where the gas price was around `7 gwei`), so it wouldn't interfere with our testing. +Looking closer at the `testWithdrawFromASingleFunder` one can observe that we found out the initial balances, then we called a transaction and then we asserted that `startingFundMeBalance + startingOwnerBalance` matches the expected balance, but inside that test we called `withdraw` which should have cost gas. Why didn't the gas we paid affect our balances? Simple, for testing purposes the Anvil gas price is defaulted to `0` (different from what we talked about above in the case of Ethereum mainnet where the gas price was around `7 gwei`), so it wouldn't interfere with our testing. Let's change that and force the `withdraw` transaction to have a gas price. At the top of your `FundMeTest` contract define the following variable: -```javascript +```solidity uint256 constant GAS_PRICE = 1; ``` and refactor the `testWithdrawFromASingleFunder` function as follows: -```javascript - function testWithdrawFromASingleFunder() public funded { - // Arrange - uint256 startingFundMeBalance = address(fundMe).balance; - uint256 startingOwnerBalance = fundMe.getOwner().balance; - - vm.txGasPrice(GAS_PRICE); - uint256 gasStart = gasleft(); - // Act - vm.startPrank(fundMe.getOwner()); - fundMe.withdraw(); - vm.stopPrank(); - - uint256 gasEnd = gasleft(); - uint256 gasUsed = (gasStart - gasEnd) * tx.gasprice; - console.log("Withdraw consummed: %d gas", gasUsed); - // Assert - uint256 endingFundMeBalance = address(fundMe).balance; - uint256 endingOwnerBalance = fundMe.getOwner().balance; - assertEq(endingFundMeBalance, 0); - assertEq( - startingFundMeBalance + startingOwnerBalance, - endingOwnerBalance - ); - } +```solidity +function testWithdrawFromASingleFunder() public funded { + // Arrange + uint256 startingFundMeBalance = address(fundMe).balance; + uint256 startingOwnerBalance = fundMe.getOwner().balance; + + vm.txGasPrice(GAS_PRICE); + uint256 gasStart = gasleft(); + + // Act + vm.startPrank(fundMe.getOwner()); + fundMe.withdraw(); + vm.stopPrank(); + + uint256 gasEnd = gasleft(); + uint256 gasUsed = (gasStart - gasEnd) * tx.gasprice; + console.log("Withdraw consumed: %d gas", gasUsed); + + // Assert + uint256 endingFundMeBalance = address(fundMe).balance; + uint256 endingOwnerBalance = fundMe.getOwner().balance; + assertEq(endingFundMeBalance, 0); + assertEq( + startingFundMeBalance + startingOwnerBalance, + endingOwnerBalance + ); +} ``` We changed the following: @@ -94,4 +97,4 @@ Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 2.67ms (2.06ms CPU Cool! -Now that we learned how to calculate the amount of gas used, let's learn how to make it better! \ No newline at end of file +Now that we learned how to calculate the amount of gas used, let's learn how to make it better! 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 f3801df09..d314957de 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 @@ -1,5 +1,6 @@ --- title: Introduction to Storage optimization +--- _Follow along with this video:_ @@ -7,7 +8,7 @@ _Follow along with this video:_ ### Optimizing GAS consumption by properly managing Storage -**Storage** is the specific area within the blockchain where data associated with a smart contract is permanently saved. These are the variables that we defined at the top of our contract, before going into functions, also called `state variable` or `global variables`. +**Storage** is the specific area within the blockchain where data associated with a smart contract is permanently saved. These are the variables that we defined at the top of our contract, before going into functions, also called **state variables** or **global variables**. Imagine yourself being in a giant locker room, and in each locker, you have a space of 32 bytes. Each locker (storage space) is numbered/labeled and its number/label acts as the key, in the key-value pair, thus using this number/label we can access what's stored in the locker. Think of state variables as the labels you give to these lockers, allowing you to easily retrieve the information you've stored. But remember, space on this shelf isn't unlimited, and every time you add or remove something, it comes at a computational cost. From the previous lessons, we learned that this computational cost bears the name of `gas`. @@ -33,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 uint256 var1 = 1337; uint256 var2 = 9000; uint64 var3 = 0; @@ -43,7 +44,7 @@ How are these stored? In `slot 0` we have `var1`, in `slot 1` we have `var2`, and in `slot 3` we have `var 3`. Because `var 3` only used 8 bytes, we have 24 bytes left in that slot. Let's try another one: -``` +```solidity uint64 var1 = 1337; uint128 var2 = 9000; bool var3 = true; @@ -91,23 +92,23 @@ Mappings and Dynamic Arrays can't be stored in between the state variables as we Make sure that you have the following getter in `FundMe.sol`: -```javascript - function getPriceFeed() public view returns (AggregatorV3Interface) { - return s_priceFeed; - } +```solidity +function getPriceFeed() public view returns (AggregatorV3Interface) { + return s_priceFeed; +} ``` Please add the following function in your `FundMe.t.sol`: -```javascript - function testPrintStorageData() public { - for (uint256 i = 0; i < 3; i++) { - bytes32 value = vm.load(address(fundMe), bytes32(i)); - console.log("Vaule at location", i, ":"); - console.logBytes32(value); - } - console.log("PriceFeed address:", address(fundMe.getPriceFeed())); +```solidity +function testPrintStorageData() public { + for (uint256 i = 0; i < 3; i++) { + bytes32 value = vm.load(address(fundMe), bytes32(i)); + console.log("Vaule at location", i, ":"); + console.logBytes32(value); } + console.log("PriceFeed address:", address(fundMe.getPriceFeed())); +} ``` In the test above we used a new cheatcode: `vm.load`. Its sole purpose is to load the value found in the provided storage slot of the provided address. Read more about it [here](https://book.getfoundry.sh/cheatcodes/load). diff --git a/courses/foundry/2-foundry-fund-me/19-optimise-the-withdraw-function-gas-costs/+page.md b/courses/foundry/2-foundry-fund-me/19-optimise-the-withdraw-function-gas-costs/+page.md index b54c6d469..56d4ca7f3 100644 --- a/courses/foundry/2-foundry-fund-me/19-optimise-the-withdraw-function-gas-costs/+page.md +++ b/courses/foundry/2-foundry-fund-me/19-optimise-the-withdraw-function-gas-costs/+page.md @@ -1,5 +1,6 @@ --- title: Optimise the withdraw function gas costs +--- _Follow along with this video:_ @@ -16,13 +17,17 @@ Open a new terminal, and type `anvil` to start a new `anvil` instance. Deploy the `fundMe` contract using the following script: -`forge script DeployFundMe --rpc-url http://127.0.0.1:8545 --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --broadcast` +```bash +forge script DeployFundMe --rpc-url http://127.0.0.1:8545 --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --broadcast` +``` Copy the `fundMe` contract address. Run the following command: - -`cast code 0xcf7ed3acca5a467e9e704c703e8d87f634fb0fc9` (replace the address here with the address of your newly deployed `fundMe` contract) +(replace the address here with the address of your newly deployed `fundMe` contract) +```bash +cast code 0xcf7ed3acca5a467e9e704c703e8d87f634fb0fc9` +``` Ok, the output looks like an extremely big chunk of random numbers and letters. Perfect! @@ -62,17 +67,17 @@ We start with a `for` loop, that is initializing a variable called `funderIndex` Let's rewrite the function. Add the following to your `FundMe.sol`: -```javascript +```solidity function cheaperWithdraw() public onlyOwner { uint256 fundersLength = s_funders.length; for(uint256 funderIndex = 0; funderIndex < fundersLength; funderIndex++) { - address funder = s_funders[funderIndex]; - s_addressToAmountFunded[funder] = 0; + address funder = s_funders[funderIndex]; + s_addressToAmountFunded[funder] = 0; } - s_funders = new address[](0); + s_funders = new address[](0); - (bool callSuccess,) = payable(msg.sender).call{value: address(this).balance}(""); - require(callSuccess, "Call failed"); + (bool callSuccess,) = payable(msg.sender).call{value: address(this).balance}(""); + require(callSuccess, "Call failed"); } ``` @@ -86,27 +91,27 @@ Let's find out how much we saved. Open `FundMe.t.sol`. Let's copy the `testWithdrawFromMultipleFunders` function and replace the `withdraw` function with `cheaperWithdraw`. -``` - function testWithdrawFromMultipleFundersCheaper() public funded { - uint160 numberOfFunders = 10; - uint160 startingFunderIndex = 1; - for (uint160 i = startingFunderIndex; i < numberOfFunders + startingFunderIndex; i++) { - // we get hoax from stdcheats - // prank + deal - hoax(address(i), SEND_VALUE); - fundMe.fund{value: SEND_VALUE}(); - } - - uint256 startingFundMeBalance = address(fundMe).balance; - uint256 startingOwnerBalance = fundMe.getOwner().balance; - - vm.startPrank(fundMe.getOwner()); - fundMe.cheaperWithdraw(); - vm.stopPrank(); - - assert(address(fundMe).balance == 0); - assert(startingFundMeBalance + startingOwnerBalance == fundMe.getOwner().balance); - assert((numberOfFunders + 1) * SEND_VALUE == fundMe.getOwner().balance - startingOwnerBalance); +```solidity +function testWithdrawFromMultipleFundersCheaper() public funded { + uint160 numberOfFunders = 10; + uint160 startingFunderIndex = 1; + for (uint160 i = startingFunderIndex; i < numberOfFunders + startingFunderIndex; i++) { + // we get hoax from stdcheats + // prank + deal + hoax(address(i), SEND_VALUE); + fundMe.fund{value: SEND_VALUE}(); + } + + uint256 startingFundMeBalance = address(fundMe).balance; + uint256 startingOwnerBalance = fundMe.getOwner().balance; + + vm.startPrank(fundMe.getOwner()); + fundMe.cheaperWithdraw(); + vm.stopPrank(); + + assert(address(fundMe).balance == 0); + assert(startingFundMeBalance + startingOwnerBalance == fundMe.getOwner().balance); + assert((numberOfFunders + 1) * SEND_VALUE == fundMe.getOwner().balance - startingOwnerBalance); } ``` @@ -120,4 +125,3 @@ FundMeTest:testWithdrawFromMultipleFundersCheaper() (gas: 534219) As you can see, we saved up 929 gas just by caching one variable. One of the reasons we easily identified this optimization was the use of `s_` in the `s_funders` array declaration. The ability to know, at any time, what comes from storage and what is in memory facilitates this type of optimization. That's why we recommend using the `s_` and `i_` and all upper case for constants, to always know what comes from where. Familiarize yourself with the style guide available [here](https://docs.soliditylang.org/en/v0.8.4/style-guide.html). - diff --git a/courses/foundry/2-foundry-fund-me/20-create-integration-tests/+page.md b/courses/foundry/2-foundry-fund-me/20-create-integration-tests/+page.md index 2d7c19c2e..e0166ffc9 100644 --- a/courses/foundry/2-foundry-fund-me/20-create-integration-tests/+page.md +++ b/courses/foundry/2-foundry-fund-me/20-create-integration-tests/+page.md @@ -1,5 +1,6 @@ --- title: Create integration tests +--- _Follow along with this video:_ @@ -25,7 +26,9 @@ Each contract will contain one script, and for it to work each needs to inherit In order to properly interact with our `fundMe` contract we would want to interact only with the most recent deployment we made. This task is easily achieved using the `foundry-devops` library. Please install it using the following command: -`forge install Cyfrin/foundry-devops --no-commit` +```bash +forge install Cyfrin/foundry-devops --no-commit +``` Ok, now with that out of the way, let's work on our scripts. @@ -168,4 +171,4 @@ Forge FFI, which stands for Foreign Function Interface, is a cheatcode within th Read more about it [here](https://book.getfoundry.sh/cheatcodes/ffi?highlight=ffi#ffi). -A word of caution: FFI bypasses the normal security checks and limitations of Solidity. By running external commands, you introduce potential security risks if not used carefully. Malicious code within the commands you execute could compromise your setup. Whenever you clone repos or download other projects please make sure they don't have `ffi = true` in their `foundry.toml` file. If they do, we advise you not to run anything before you thoroughly examine where `ffi` is used and what commands is it calling. Stay safe! \ No newline at end of file +A word of caution: FFI bypasses the normal security checks and limitations of Solidity. By running external commands, you introduce potential security risks if not used carefully. Malicious code within the commands you execute could compromise your setup. Whenever you clone repos or download other projects please make sure they don't have `ffi = true` in their `foundry.toml` file. If they do, we advise you not to run anything before you thoroughly examine where `ffi` is used and what commands is it calling. Stay safe! 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 e492145b0..825ed286a 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 @@ -141,7 +141,3 @@ And you just deployed a fresh `FundMe` contract on a fresh `anvil` blockchain. S We could do the same for Sepolia by running `make deploy ARGS="--network sepolia"`. Makefile is amazing! - - - - diff --git a/courses/foundry/2-foundry-fund-me/23-pushing-to-github/+page.md b/courses/foundry/2-foundry-fund-me/23-pushing-to-github/+page.md index 3f27129d2..05792e9d1 100644 --- a/courses/foundry/2-foundry-fund-me/23-pushing-to-github/+page.md +++ b/courses/foundry/2-foundry-fund-me/23-pushing-to-github/+page.md @@ -1,5 +1,6 @@ --- title: Pushing to Github +--- _Follow along with this video:_ @@ -11,7 +12,7 @@ What a journey! Congratulations on reaching this far! One of the most important parts of development is sharing the stuff you work on for other people to see and contribute to. If you don't want to do that you still need a system for version control, a place where you save different stages of your project that can be accessed as simple as pressing 3 clicks. As you've guessed by now the thing we'll introduce now is GitHub. -Before doing any other actions, please verify that your .gitignore contains at least the `.env` file, to avoid pushing our keys on the internet, and other things that you consider irrelevant for other people, for example, the information about your deployments. +Before doing any other actions, please verify that your `.gitignore` contains at least the `.env` file, to avoid pushing our keys on the internet, and other things that you consider irrelevant for other people, for example, the information about your deployments. Here is a `.gitignore` example: @@ -37,7 +38,7 @@ docs/ .keystore ``` -Following this point, we will assume that you have your own GitHub account. If not please read [this page](https://docs.github.com/en/get-started/start-your-journey/creating-an-account-on-github) to find out how to get one. Having a GitHub account opens up a ton of possibilities in terms of developing your project or contributing to existing open-source projects. You have the option of forking an existing project and building on top of it, enhancing or adding extra functionality. You can open up issues on existing projects and make contributions to the codebases of other people, there are a lot of stories about people who contributed to other people's code and formed a strong bond and found business partners and friends that way. Moreover, GitHub profiles are crucial when applying for jobs. Safe to say, that having a great GitHub profile that's interesting and stands out can open up a world of opportunities. +Following this point, we will assume that you have your own GitHub account. If not, please read [this page](https://docs.github.com/en/get-started/start-your-journey/creating-an-account-on-github) to find out how to get one. Having a GitHub account opens up a ton of possibilities in terms of developing your project or contributing to existing open-source projects. You have the option of forking an existing project and building on top of it, enhancing or adding extra functionality. You can open up issues on existing projects and make contributions to the codebases of other people, there are a lot of stories about people who contributed to other people's code and formed a strong bond and found business partners and friends that way. Moreover, GitHub profiles are crucial when applying for jobs. Safe to say, that having a great GitHub profile that's interesting and stands out can open up a world of opportunities. If you want to get started or want a quick start, [GitHub](https://docs.github.com/en) docs provide numerous sets of documentation that you can refer to. In this lesson, we will learn how to do all these using our terminal and not the GitHub website interface. @@ -182,4 +183,4 @@ cd 2023-10-PasswordStore code . ``` -Amazing! You can now show off your newly created GitHub project! Click [here](https://twitter.com/intent/tweet?text=I%20just%20made%20my%20first%20Smart%20Contract%20repo%20using%20@solidity_lang,%20foundry,%20@chainlink,%20@AlchemyPlatform,%20and%20more!%0a%0aThanks%20@PatrickAlphaC!!) to tweet about this celebratory moment! Make sure to link your repository! \ No newline at end of file +Amazing! You can now show off your newly created GitHub project! Click [here](https://twitter.com/intent/tweet?text=I%20just%20made%20my%20first%20Smart%20Contract%20repo%20using%20@solidity_lang,%20foundry,%20@chainlink,%20@AlchemyPlatform,%20and%20more!%0a%0aThanks%20@PatrickAlphaC!!) to tweet about this celebratory moment! Make sure to link your repository! diff --git a/courses/foundry/2-foundry-fund-me/24-section-recap/+page.md b/courses/foundry/2-foundry-fund-me/24-section-recap/+page.md index f27fb0b51..46f5114ef 100644 --- a/courses/foundry/2-foundry-fund-me/24-section-recap/+page.md +++ b/courses/foundry/2-foundry-fund-me/24-section-recap/+page.md @@ -1,5 +1,6 @@ --- title: Section recap +--- _Follow along with this video:_ @@ -11,16 +12,16 @@ This was a monumental section! And you are a true hero for completing it! Let's quickly go through what we learned in this one: -- We learned more about how to set up a Foundry project; -- We learned how to organize our files into folders, following the convention; -- We learned how to refactor smart contracts to make them modular and chain-agnostic; -- We learned how to write scripts that act as interaction commands; -- We learned more about using mocks; -- We did a bunch of unit tests, we even did an integration test; -- We learned a bit about Makefiles; -- We learned how to create a GitHub repository and push our code in it; -- We also learned how to clone a GitHub repository. +- We learned more about how to set up a Foundry project +- We learned how to organize our files into folders, following the convention +- We learned how to refactor smart contracts to make them modular and chain-agnostic +- We learned how to write scripts that act as interaction commands +- We learned more about using mocks +- We did a bunch of unit tests, we even did an integration test +- We learned a bit about Makefiles +- We learned how to create a GitHub repository and push our code in it +- We also learned how to clone a GitHub repository This was a lot and you deserve a break! Take a walk, play a game and come back for more! -See you in the next section! \ No newline at end of file +See you in the next section! From 1bcdb51bbbcf2fb1a0a8623b8e91d895c8b33b74 Mon Sep 17 00:00:00 2001 From: Luigi Date: Mon, 30 Sep 2024 22:13:31 -0700 Subject: [PATCH 114/114] Update repository URL --- .../3-html-fund-me/1-introduction/+page.md | 2 +- .../foundry/3-html-fund-me/2-setup/+page.md | 6 ++--- .../3-html-fund-me/3-metamask/+page.md | 24 +++++++++---------- .../4-function-selectors/+page.md | 6 ++--- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/courses/foundry/3-html-fund-me/1-introduction/+page.md b/courses/foundry/3-html-fund-me/1-introduction/+page.md index e01e81669..a260908c1 100644 --- a/courses/foundry/3-html-fund-me/1-introduction/+page.md +++ b/courses/foundry/3-html-fund-me/1-introduction/+page.md @@ -8,4 +8,4 @@ _Follow along with the video_ > To get started, visit the GitHub repository and navigate to the [lesson 8](https://github.com/Cyfrin/html-fund-me-cu) codebase. -In this section, we will delve into how MetaMask or your wallet interacts with websites and ensure that the transactions sent by the wallet are executed as intended. Although we won't be building a full-stack application here, we have plans to launch a comprehensive full-stack course soon. For now, our focus will be on the _HTML FundMe f23 project_, a basic, fully functional website built with raw JavaScript. +In this section, we will delve into how MetaMask or your wallet interacts with websites and ensure that the transactions sent by the wallet are executed as intended. Although we won't be building a full-stack application here, we have plans to launch a comprehensive full-stack course soon. For now, our focus will be on the _HTML FundMe cu project_, a basic, fully functional website built with raw JavaScript. diff --git a/courses/foundry/3-html-fund-me/2-setup/+page.md b/courses/foundry/3-html-fund-me/2-setup/+page.md index fcc3c0c22..d67441697 100644 --- a/courses/foundry/3-html-fund-me/2-setup/+page.md +++ b/courses/foundry/3-html-fund-me/2-setup/+page.md @@ -18,7 +18,7 @@ _Follow along the course with this video._ ### Overview -Let's look at how what we've built interacts with a wallet. Remember, you can find all the code for this lesson [**here**](https://github.com/Cyfrin/html-fund-me-f23). +Let's look at how what we've built interacts with a wallet. Remember, you can find all the code for this lesson [**here**](https://github.com/Cyfrin/html-fund-me-cu). We won't be going over a whole full-stack application here, but the repo above contains a raw front-end you can try to replicate if you would like to challenge yourself. @@ -35,13 +35,13 @@ Now that you've installed Git and created a GitHub in previous lessons, we're go **Step 1:** In our terminal use the command: ```bash -git clone https://github.com/Cyfrin/html-fund-me-f23.git +git clone https://github.com/Cyfrin/html-fund-me-cu.git ``` **Step 2:** Now we can open this in a new instance of VS Code with: ```bash -code html-fund-me-f23 +code html-fund-me-cu ``` In order to spin up a local front end, we're going to use an extension called [**Live Server**](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer). Once installed you can simply press the `Go Live` button in the bottom right. 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 3b70cd20b..0f8cba1f9 100644 --- a/courses/foundry/3-html-fund-me/3-metamask/+page.md +++ b/courses/foundry/3-html-fund-me/3-metamask/+page.md @@ -8,7 +8,7 @@ _Follow along the course with this video._ ### Browser Wallets -The first concept we need to grasp when working with a website in Web3 is that of a browser wallet - in our case Metamask. It's through a wallet like Metamask that we are able to interact with the blockchain and the Web3 ecosystem. +The first concept we need to grasp when working with a website in Web3 is that of a browser wallet - in our case MetaMask. It's through a wallet like MetaMask that we are able to interact with the blockchain and the Web3 ecosystem. We can gain more insight into how this works by right-clicking our `FundMe` website and selecting `inspect`. You can also open this panel by pressing F12. @@ -26,7 +26,7 @@ As seen in the image, there are some properties of this object which are not the > Try inspecting a browser without a browser wallet installed. You'll see that `window.ethereum` doesn't exist! -I recommend reading the [**Metamask documentation**](https://docs.metamask.io/guide/) on the window.ethereum object to learn more. +I recommend reading the [**MetaMask documentation**](https://docs.metamask.io/guide/) on the window.ethereum object to learn more. ### The Code @@ -78,7 +78,7 @@ This grabs the element of the webpage by the `id` we set and then uses the `onCl ### Connecting in Action -Clicking on the `Connect` button on our `html-fund-me` front end, should trigger our Metamask to pop up. From there we can select an account and click connect. +Clicking on the `Connect` button on our `html-fund-me` front end, should trigger our MetaMask to pop up. From there we can select an account and click connect. ::image{src='/html-fundme/2-metamask/metamask3.png' style='width: 75%; height: auto;'} @@ -114,7 +114,7 @@ As before, we're checking for the existence of `window.ethereum` and then .. def `ethers` is a javascript package that simplifies the use and interacation 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. +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. ::image{src='/html-fundme/2-metamask/metamask5.png' style='width: 75%; height: auto;'} @@ -122,17 +122,17 @@ When we call functions on our front-end. We're effectively making API calls via ### Trying it Out -In order to get some experience trying this ourselves, we'll need to set up the backend of our project and import our anvil account into Metamask. +In order to get some experience trying this ourselves, we'll need to set up the backend of our project and import our anvil account into MetaMask. Open your foundry-fund-me directory in VS Code and in your terminal run `anvil`. -This should spin up a local test chain for you. Copy one of the mock private keys it provides you in the terminal, we'll need this to import the account into our Metamask wallet. +This should spin up a local test chain for you. Copy one of the mock private keys it provides you in the terminal, we'll need this to import the account into our MetaMask wallet. With this chain running, open a second terminal and run the command `make deploy`. This will compile and deploy our FundMe project onto our locally running blockchain. Assuming you've not run into errors. That's all that's required to set up the back end. -Return to Metamask, and within your network selector choose `Add Network`. +Return to MetaMask, and within your network selector choose `Add Network`. ::image{src='/html-fundme/2-metamask/metamask6.png' style='width: 75%; height: auto;'} @@ -144,17 +144,17 @@ In the subsequent page, inter your local network information as follows and clic Next, we need to add one of our `anvil` accounts to the wallet! -Click the account displayed at the top of your Metamask and select `Add an account or hardware wallet` from the bottom of the list. +Click the account displayed at the top of your MetaMask and select `Add an account or hardware wallet` from the bottom of the list. You'll be prompted to `add a new account`, `import an account`, or `add a hardware wallet`. Select `import an account` and enter your previously copied mock private key into the field provided. ::image{src='/html-fundme/2-metamask/metamask7.png' style='width: 75%; height: auto;'} -ALRIGHT. With all the set up done, we should be able to select our `anvil` chain in Metamask, then select the account we just added and click the `connect` button. +ALRIGHT. With all the set up done, we should be able to select our `anvil` chain in MetaMask, then select the account we just added and click the `connect` button. If we click `getBalance` we should have `0` returned in our console reflecting the balance of our deployed contract. At this point, we should be able to enter an amount and click `fund`. -Our Metamask pops up and has us sign the transaction, funding the contract with the amount we've entered! +Our MetaMask pops up and has us sign the transaction, funding the contract with the amount we've entered! ```js async function fund() { @@ -184,11 +184,11 @@ The function being called when we click this button is very similar in structure - define our `provider` - acquire the `signer` (account credentials) - define the contract/target of our call - - these are hardcoded for simplification purposes in this example and can be found in the [**constants.js**](https://github.com/Cyfrin/html-fund-me-f23/blob/main/constants.js) file of our [**html-fund-me repo**](https://github.com/Cyfrin/html-fund-me-f23). + - these are hardcoded for simplification purposes in this example and can be found in the [**constants.js**](https://github.com/Cyfrin/html-fund-me-cu/blob/main/constants.js) file of our [**html-fund-me repo**](https://github.com/Cyfrin/html-fund-me-cu). - submit transaction to the target contract with provided arguments. > **Note:** I'll stress again that this call being made by the front-end does **not** give the front-end access to private key data. The transaction is always sent to the wallet for confirmation/signing. ### Wrap Up -We've learnt a lot about how browser wallets like Metamask work under the hood and actually send our transactions to the blockchain. Great work - we've more low level concepts to cover in our next lesson. +We've learnt a lot about how browser wallets like MetaMask work under the hood and actually send our transactions to the blockchain. Great work - we've more low level concepts to cover in our next lesson. diff --git a/courses/foundry/3-html-fund-me/4-function-selectors/+page.md b/courses/foundry/3-html-fund-me/4-function-selectors/+page.md index 3e0b59d5e..f45e611c2 100644 --- a/courses/foundry/3-html-fund-me/4-function-selectors/+page.md +++ b/courses/foundry/3-html-fund-me/4-function-selectors/+page.md @@ -8,7 +8,7 @@ _Follow along the course with this video._ ### Intro to Function Selectors -Continuing from the last lesson, when we call the `fund` function our Metamask is going to pop up with a bunch of information about the transaction. +Continuing from the last lesson, when we call the `fund` function our MetaMask is going to pop up with a bunch of information about the transaction. ::image{src='/html-fundme/3-function-selector/function-selector1.png' style='width: 75%; height: auto;'} @@ -24,7 +24,7 @@ When we call our `fund` function, this is converted to a `function selector` tha cast sig "fund()" ``` -The above should result in the output `0xb60d4288` and when we compare this to the `Hex` data in our Metamask, we see that it does indeed match! +The above should result in the output `0xb60d4288` and when we compare this to the `Hex` data in our MetaMask, we see that it does indeed match! Were the function being called something secret/nefarious like `stealMoney()`. This function selector would be completely different. Running our cast command again confirms this clearly with a return of `0xa7ea5e4e`. @@ -43,7 +43,7 @@ function fund(uint256 amount) public payable { } ``` -If we were to call this function, the information Metamask gives us is a little different. +If we were to call this function, the information MetaMask gives us is a little different. ::image{src='/html-fundme/3-function-selector/function-selector3.png' style='width: 75%; height: auto;'}