From b0b799776aecd8bcbe8e352093192e24e8edaafa Mon Sep 17 00:00:00 2001 From: Luigi Date: Thu, 28 Nov 2024 17:59:55 -0800 Subject: [PATCH 001/255] Fix typos --- .../4-merkle-airdrop/14-blob-transactions/+page.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/courses/advanced-foundry/4-merkle-airdrop/14-blob-transactions/+page.md b/courses/advanced-foundry/4-merkle-airdrop/14-blob-transactions/+page.md index 7d38919b7..d29009d7b 100644 --- a/courses/advanced-foundry/4-merkle-airdrop/14-blob-transactions/+page.md +++ b/courses/advanced-foundry/4-merkle-airdrop/14-blob-transactions/+page.md @@ -12,7 +12,7 @@ In a default transaction, data is stored and visible on-chain permanently. Blob ### EIP4844 -These transactions originate from EIP4844, also known as "Proto-DankSharding", introduced in the Dancun upgrade in March 2024. The purpose of this transaction type is to address Ethereum's high transaction costs. +These transactions originate from EIP4844, also known as "Proto-Danksharding", introduced in the Dencun upgrade in March 2024. The purpose of this transaction type is to address Ethereum's high transaction costs. Roll-ups help scale Ethereum by executing multiple transactions on their own chains, compressing them into batches, and submitting these batches back to Ethereum. Prior to the upgrade, all compressed transaction data had to be permanently stored on Ethereum nodes, which was inefficient and costly. With EIP4844, the data can be submitted **temporarily** for validation, avoiding permanent storage. From d71472ed3a7621a2722abcfca207cf0abe345bd3 Mon Sep 17 00:00:00 2001 From: Luigi Date: Sat, 30 Nov 2024 03:28:28 -0800 Subject: [PATCH 002/255] Update written lesson's code and CLI commands to match video lesson --- .../4-merkle-airdrop/16-implementing-signatures/+page.md | 6 ++++-- .../4-merkle-airdrop/17-modifying-the-tests/+page.md | 4 ++-- .../4-merkle-airdrop/18-test-on-zksync-(optional)/+page.md | 4 ++-- .../4-merkle-airdrop/19-create-claiming-script/+page.md | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/courses/advanced-foundry/4-merkle-airdrop/16-implementing-signatures/+page.md b/courses/advanced-foundry/4-merkle-airdrop/16-implementing-signatures/+page.md index b0ab46479..00d62c350 100644 --- a/courses/advanced-foundry/4-merkle-airdrop/16-implementing-signatures/+page.md +++ b/courses/advanced-foundry/4-merkle-airdrop/16-implementing-signatures/+page.md @@ -88,15 +88,17 @@ With this setup, we can correctly encode and hash the `MESSAGE_TYPEHASH`, accoun Finally, implement the `_isValidSignature` function: ```js +import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; + function _isValidSignature( - address signer, + address account, bytes32 digest, uint8 v, bytes32 r, bytes32 s ) internal pure returns (bool) { (address actualSigner,,) = ECDSA.tryRecover(digest, v, r, s); - return (actualSigner == signer); + return (actualSigner == account); } ``` diff --git a/courses/advanced-foundry/4-merkle-airdrop/17-modifying-the-tests/+page.md b/courses/advanced-foundry/4-merkle-airdrop/17-modifying-the-tests/+page.md index c09a5512f..bf6d3391d 100644 --- a/courses/advanced-foundry/4-merkle-airdrop/17-modifying-the-tests/+page.md +++ b/courses/advanced-foundry/4-merkle-airdrop/17-modifying-the-tests/+page.md @@ -32,7 +32,7 @@ The `signMessage` function will calculate the **message digest**, which will be ```js function signMessage(uint256 privKey, address account) public view returns (uint8 v, bytes32 r, bytes32 s) { - bytes32 hashedMessage = airdrop.getMessageHash(account, amountToCollect); + bytes32 hashedMessage = airdrop.getMessageHash(account, AMOUNT_TO_CLAIM); (v, r, s) = vm.sign(privKey, hashedMessage); } ``` @@ -43,7 +43,7 @@ Finally, the `gasPayer` address can call the `MerkleAirdrop::claim` function on ```js vm.prank(gasPayer); -airdrop.claim(user, amountToCollect, proof, v, r, s); +airdrop.claim(user, AMOUNT_TO_CLAIM, PROOF, v, r, s); ``` Afterward, we can verify that the test passes: the user's balance increases as expected, indicating that the `gasPayer` successfully claimed the tokens on the `user`'s behalf. diff --git a/courses/advanced-foundry/4-merkle-airdrop/18-test-on-zksync-(optional)/+page.md b/courses/advanced-foundry/4-merkle-airdrop/18-test-on-zksync-(optional)/+page.md index 20a11312b..7af9f5ec4 100644 --- a/courses/advanced-foundry/4-merkle-airdrop/18-test-on-zksync-(optional)/+page.md +++ b/courses/advanced-foundry/4-merkle-airdrop/18-test-on-zksync-(optional)/+page.md @@ -11,10 +11,10 @@ _Follow along with the video_ We can also run our `MerkleAirdrop.t::testUsersCanClaim` test on the ZKsync chain. -To do this, we can start by switching to the ZKsync version by running `foundryup --zksync`. Since the ZKsync compiler operates differently from the standard solc compiler, it's better to verify that everything builds correctly before deploying. +To do this, we can start by switching to the ZKsync version by running `foundryup-zksync`. Since the ZKsync compiler operates differently from the standard solc compiler, it's better to verify that everything builds correctly before deploying. ```js -forge build --ZK Sync +forge build --zksync ``` > 🗒️ **NOTE**:br diff --git a/courses/advanced-foundry/4-merkle-airdrop/19-create-claiming-script/+page.md b/courses/advanced-foundry/4-merkle-airdrop/19-create-claiming-script/+page.md index aa351b677..d112365fc 100644 --- a/courses/advanced-foundry/4-merkle-airdrop/19-create-claiming-script/+page.md +++ b/courses/advanced-foundry/4-merkle-airdrop/19-create-claiming-script/+page.md @@ -39,7 +39,7 @@ function run() external { The `claimAirdrop` function will take the deployed `MerkleAirdrop` address as a parameter. -First, we need to broadcast the transaction on the blockchain by wrapping our code between `vm.startBroadcast` and `vm.endBroadcast`. +First, we need to broadcast the transaction on the blockchain by wrapping our code between `vm.startBroadcast` and `vm.stopBroadcast`. Next, we invoke the `MerkleAirdrop::claim` function, passing the following required parameters: From 753b2e7d44c35004d8a5230bc075f27411cced52 Mon Sep 17 00:00:00 2001 From: Luigi Date: Mon, 2 Dec 2024 14:46:35 +0100 Subject: [PATCH 003/255] Fix written lesson's Anvil default key --- .../4-merkle-airdrop/20-creating-a-signature/+page.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/courses/advanced-foundry/4-merkle-airdrop/20-creating-a-signature/+page.md b/courses/advanced-foundry/4-merkle-airdrop/20-creating-a-signature/+page.md index 3cbc09a58..4aa34145f 100644 --- a/courses/advanced-foundry/4-merkle-airdrop/20-creating-a-signature/+page.md +++ b/courses/advanced-foundry/4-merkle-airdrop/20-creating-a-signature/+page.md @@ -19,7 +19,7 @@ Copy the [Makefile content](https://github.com/Cyfrin/foundry-merkle-airdrop-cu/ To obtain the data for signing, use the `getMessageHash` function on the `MerkleAirdrop` contract. This function requires an account address, a `uint256` amount, and the Anvil node URL (`http://localhost:8545`). ```bash -cast call 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512 "getMessageHash(address,uint256)" 0xf39Fd6e51aad88F6f4ce6aB88272ffFb92266 25000000000000000000 --rpc-url http://localhost:8545 +cast call 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512 "getMessageHash(address,uint256)" 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 25000000000000000000 --rpc-url http://localhost:8545 0x184e30c4b19f5e304a893524210d50346dad61c461e79155b910e73fd856dc72 ``` From 44bdf0086b34355a99a382014de75849e16c58c2 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 05:36:43 -0500 Subject: [PATCH 004/255] PatrickAlphaC updated courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md. --- courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md b/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md new file mode 100644 index 000000000..b7e64e913 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md @@ -0,0 +1,3 @@ +--- + title: Intro + --- \ No newline at end of file From 478dd3701610273aac1567c0caa5112700b479ce Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 05:37:17 -0500 Subject: [PATCH 005/255] PatrickAlphaC updated courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md. --- courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md b/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md new file mode 100644 index 000000000..fcc7a149d --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md @@ -0,0 +1,3 @@ +--- + title: Setup + --- \ No newline at end of file From a6a534c67b31433a21b99fd3308dd46fa793f407 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 05:51:29 -0500 Subject: [PATCH 006/255] PatrickAlphaC updated courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md. --- .../advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md b/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md new file mode 100644 index 000000000..1c1ce1385 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md @@ -0,0 +1,3 @@ +--- + title: What Is An Nft + --- \ No newline at end of file From 72ef08083da6a6bd59016872ee83a615b3bd3ced Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 05:56:48 -0500 Subject: [PATCH 007/255] PatrickAlphaC updated courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md. --- .../1-moccasin-nft/4-building-an-erc721-contract/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md b/courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md new file mode 100644 index 000000000..881ccd3b9 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md @@ -0,0 +1,3 @@ +--- + title: Building An Erc721 Contract + --- \ No newline at end of file From c60b4fe502c100f3c168245846e85eebb4c195d5 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 05:59:38 -0500 Subject: [PATCH 008/255] PatrickAlphaC updated courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md. --- courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md b/courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md new file mode 100644 index 000000000..d2aeab7ef --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md @@ -0,0 +1,3 @@ +--- + title: Tokenuri + --- \ No newline at end of file From 32418868469cfc724daa60922f7cdc84560874ca Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 06:00:17 -0500 Subject: [PATCH 009/255] PatrickAlphaC updated courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md. --- courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md b/courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md new file mode 100644 index 000000000..7ff466b05 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md @@ -0,0 +1,3 @@ +--- + title: Deploy + --- \ No newline at end of file From 52e9a60172b68638d8b54136fd5cd672b0ebd32e Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 06:05:23 -0500 Subject: [PATCH 010/255] PatrickAlphaC updated courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md. --- .../advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md b/courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md new file mode 100644 index 000000000..2f65fda3e --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md @@ -0,0 +1,3 @@ +--- + title: What Is Ipfs + --- \ No newline at end of file From c0a648a56cbdd484c8cb1edaea6b7d0e6f516ce1 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 06:06:49 -0500 Subject: [PATCH 011/255] PatrickAlphaC updated courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md. --- .../1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md b/courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md new file mode 100644 index 000000000..01b735559 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md @@ -0,0 +1,3 @@ +--- + title: Viewing An Nft In Metamask + --- \ No newline at end of file From c333e94e8addd310b0b9a892eee258fa5ed0c71c Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 06:07:47 -0500 Subject: [PATCH 012/255] PatrickAlphaC updated courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md. --- .../1-moccasin-nft/9-deploying-to-zksync/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md b/courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md new file mode 100644 index 000000000..c0d9d9943 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md @@ -0,0 +1,3 @@ +--- + title: Deploying To Zksync + --- \ No newline at end of file From 724b3f37108f663e191033f7c664af672c3db552 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 06:08:16 -0500 Subject: [PATCH 013/255] PatrickAlphaC updated courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md. --- .../10-note-what-happens-when-we-stop-anvil/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md b/courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md new file mode 100644 index 000000000..16d0dc804 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md @@ -0,0 +1,3 @@ +--- + title: Note What Happens When We Stop Anvil + --- \ No newline at end of file From 4146530b893d6940d0df5f22e431c378ef48a2e3 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 06:10:39 -0500 Subject: [PATCH 014/255] PatrickAlphaC updated courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md. --- .../advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md b/courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md new file mode 100644 index 000000000..1c0984466 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md @@ -0,0 +1,3 @@ +--- + title: Workshop 1 + --- \ No newline at end of file From e4a6c5a51cc6ba4236faa2d603b3ebb6f861746d Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 06:17:02 -0500 Subject: [PATCH 015/255] PatrickAlphaC updated courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md. --- .../1-moccasin-nft/12-what-is-an-svg/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md b/courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md new file mode 100644 index 000000000..812a8b80d --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md @@ -0,0 +1,3 @@ +--- + title: What Is An Svg + --- \ No newline at end of file From 1486f88abf533c5256a9ce81c7b353b2f1a61b1c Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 06:17:50 -0500 Subject: [PATCH 016/255] PatrickAlphaC updated courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md. --- courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md b/courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md new file mode 100644 index 000000000..9fe904d8a --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md @@ -0,0 +1,3 @@ +--- + title: Mood Nft + --- \ No newline at end of file From 026c005951359adb3b0fd53ceba634d005a89e04 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 06:19:33 -0500 Subject: [PATCH 017/255] PatrickAlphaC updated courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md. --- .../1-moccasin-nft/14-base-64-encoding-images/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md b/courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md new file mode 100644 index 000000000..0eb6c72b4 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md @@ -0,0 +1,3 @@ +--- + title: Base 64 Encoding Images + --- \ No newline at end of file From aecee80615ba95baf4e51c13f4b2690bc3249df2 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 06:26:27 -0500 Subject: [PATCH 018/255] PatrickAlphaC updated courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md. --- .../1-moccasin-nft/15-base-64-encoding-json/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md b/courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md new file mode 100644 index 000000000..c85718bcc --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md @@ -0,0 +1,3 @@ +--- + title: Base 64 Encoding Json + --- \ No newline at end of file From 112c023435a2092c1c0f84233fd18a65089b183f Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 06:30:06 -0500 Subject: [PATCH 019/255] PatrickAlphaC updated courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md. --- .../advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md b/courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md new file mode 100644 index 000000000..720a585fe --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md @@ -0,0 +1,3 @@ +--- + title: Abi Encoding + --- \ No newline at end of file From 606a796c83fa816fcdebdd2abf083a992523ffda Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 06:33:30 -0500 Subject: [PATCH 020/255] PatrickAlphaC updated courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md. --- .../17-function-selectors-and-signatures/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md b/courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md new file mode 100644 index 000000000..7561fb7ab --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md @@ -0,0 +1,3 @@ +--- + title: Function Selectors And Signatures + --- \ No newline at end of file From 8376df3e203febf0ed8119e87889685fc00a44e9 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 06:35:24 -0500 Subject: [PATCH 021/255] PatrickAlphaC updated courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md. --- .../1-moccasin-nft/18-calling-functions-raw/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md b/courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md new file mode 100644 index 000000000..b234f677f --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md @@ -0,0 +1,3 @@ +--- + title: Calling Functions Raw + --- \ No newline at end of file From 7ce55a5aaa2a8a08726d3f28dca02c23d85578b8 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 06:36:11 -0500 Subject: [PATCH 022/255] PatrickAlphaC updated courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md. --- .../1-moccasin-nft/19-manually-crafting-calldata/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md b/courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md new file mode 100644 index 000000000..d710a4f9c --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md @@ -0,0 +1,3 @@ +--- + title: Manually Crafting Calldata + --- \ No newline at end of file From a8c9b6cc0aeb581fed79853e8841eb2e3d431da7 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 06:37:17 -0500 Subject: [PATCH 023/255] PatrickAlphaC updated courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md. --- .../1-moccasin-nft/20-mid-section-recap/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md b/courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md new file mode 100644 index 000000000..b7e84d122 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md @@ -0,0 +1,3 @@ +--- + title: Mid Section Recap + --- \ No newline at end of file From de66dcef9e41b3c1ba5a8daff4cc07f6bc278f01 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 06:42:54 -0500 Subject: [PATCH 024/255] PatrickAlphaC updated courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md. --- .../1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md b/courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md new file mode 100644 index 000000000..6c761a39a --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md @@ -0,0 +1,3 @@ +--- + title: Verifying Calldata In Metamask + --- \ No newline at end of file From ce2d92b6c0ac856414e330e401cd631973b99613 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 06:45:33 -0500 Subject: [PATCH 025/255] PatrickAlphaC updated courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md. --- .../1-moccasin-nft/22-finishing-the-mood-nft/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md b/courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md new file mode 100644 index 000000000..489949655 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md @@ -0,0 +1,3 @@ +--- + title: Finishing The Mood Nft + --- \ No newline at end of file From db588f5dfb7991e8f211f6be04ecb3fccee23535 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 06:46:30 -0500 Subject: [PATCH 026/255] PatrickAlphaC updated courses/advanced-moccasin/1-moccasin-nft/23-workshop-2/+page.md. --- .../advanced-moccasin/1-moccasin-nft/23-workshop-2/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/23-workshop-2/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/23-workshop-2/+page.md b/courses/advanced-moccasin/1-moccasin-nft/23-workshop-2/+page.md new file mode 100644 index 000000000..a653fcc03 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/23-workshop-2/+page.md @@ -0,0 +1,3 @@ +--- + title: Workshop 2 + --- \ No newline at end of file From c21abfe89c5aa2c74ded3942a84c1980126c3af8 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 06:50:45 -0500 Subject: [PATCH 027/255] PatrickAlphaC updated courses/advanced-moccasin/1-moccasin-nft/24-recap/+page.md. --- courses/advanced-moccasin/1-moccasin-nft/24-recap/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/24-recap/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/24-recap/+page.md b/courses/advanced-moccasin/1-moccasin-nft/24-recap/+page.md new file mode 100644 index 000000000..385e6edfe --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/24-recap/+page.md @@ -0,0 +1,3 @@ +--- + title: Recap + --- \ No newline at end of file From ffdc4cd53d16d4c4bc380873a6272d0ed527aa46 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 06:55:37 -0500 Subject: [PATCH 028/255] PatrickAlphaC updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/1-intro/+page.md. --- .../2-moccasin-portfolio-rebalance/1-intro/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/1-intro/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/1-intro/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/1-intro/+page.md new file mode 100644 index 000000000..b7e64e913 --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/1-intro/+page.md @@ -0,0 +1,3 @@ +--- + title: Intro + --- \ No newline at end of file From db3b68747e8167317546d2387c7c4b989083f039 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 06:58:06 -0500 Subject: [PATCH 029/255] PatrickAlphaC updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/2-real-demo/+page.md. --- .../2-moccasin-portfolio-rebalance/2-real-demo/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/2-real-demo/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/2-real-demo/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/2-real-demo/+page.md new file mode 100644 index 000000000..2166cf79d --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/2-real-demo/+page.md @@ -0,0 +1,3 @@ +--- + title: Real Demo + --- \ No newline at end of file From 94c4637e0ebdcbdbd1bca093705200ccd2f03ab9 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 06:58:44 -0500 Subject: [PATCH 030/255] PatrickAlphaC updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/3-setup/+page.md. --- .../2-moccasin-portfolio-rebalance/3-setup/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/3-setup/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/3-setup/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/3-setup/+page.md new file mode 100644 index 000000000..fcc7a149d --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/3-setup/+page.md @@ -0,0 +1,3 @@ +--- + title: Setup + --- \ No newline at end of file From 67eb0b6a7338545cb69b7c3c420bf0c94382199e Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 07:01:08 -0500 Subject: [PATCH 031/255] PatrickAlphaC updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/4-forked-network-setup/+page.md. --- .../4-forked-network-setup/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/4-forked-network-setup/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/4-forked-network-setup/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/4-forked-network-setup/+page.md new file mode 100644 index 000000000..197805050 --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/4-forked-network-setup/+page.md @@ -0,0 +1,3 @@ +--- + title: Forked Network Setup + --- \ No newline at end of file From f5fc7001c5007ca61428af35eda18eb68dd56263 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 07:01:44 -0500 Subject: [PATCH 032/255] PatrickAlphaC updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/5-minting-weth/+page.md. --- .../2-moccasin-portfolio-rebalance/5-minting-weth/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/5-minting-weth/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/5-minting-weth/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/5-minting-weth/+page.md new file mode 100644 index 000000000..03c9f6eb3 --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/5-minting-weth/+page.md @@ -0,0 +1,3 @@ +--- + title: Minting Weth + --- \ No newline at end of file From ff7b6c77238243b258cc5e36252c31893db58166 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 07:02:56 -0500 Subject: [PATCH 033/255] PatrickAlphaC updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/6-getting-abis-from-the-explorer/+page.md. --- .../6-getting-abis-from-the-explorer/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/6-getting-abis-from-the-explorer/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/6-getting-abis-from-the-explorer/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/6-getting-abis-from-the-explorer/+page.md new file mode 100644 index 000000000..3ce73c93f --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/6-getting-abis-from-the-explorer/+page.md @@ -0,0 +1,3 @@ +--- + title: Getting Abis From The Explorer + --- \ No newline at end of file From ed3f8b0b27c11cfe091b5caadbb5479438bc2733 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 07:04:29 -0500 Subject: [PATCH 034/255] PatrickAlphaC updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/7-minting-usdc/+page.md. --- .../2-moccasin-portfolio-rebalance/7-minting-usdc/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/7-minting-usdc/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/7-minting-usdc/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/7-minting-usdc/+page.md new file mode 100644 index 000000000..f2b83d10a --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/7-minting-usdc/+page.md @@ -0,0 +1,3 @@ +--- + title: Minting Usdc + --- \ No newline at end of file From 45afd2957604182b5239a631962bfcb4997f932f Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 07:06:29 -0500 Subject: [PATCH 035/255] PatrickAlphaC updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md. --- .../2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md new file mode 100644 index 000000000..575eb50e6 --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md @@ -0,0 +1,3 @@ +--- + title: Juypter Notebook + --- \ No newline at end of file From 778fb6db3d2944a307367d8669ce831c1d864b4b Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 07:10:12 -0500 Subject: [PATCH 036/255] PatrickAlphaC updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/9-depositing-into-aave/+page.md. --- .../9-depositing-into-aave/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/9-depositing-into-aave/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/9-depositing-into-aave/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/9-depositing-into-aave/+page.md new file mode 100644 index 000000000..b11c9625e --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/9-depositing-into-aave/+page.md @@ -0,0 +1,3 @@ +--- + title: Depositing Into Aave + --- \ No newline at end of file From 10dfda38b0a9b905d3ef32640c20c1b95f9e7255 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 07:13:00 -0500 Subject: [PATCH 037/255] PatrickAlphaC updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/10-atokens/+page.md. --- .../2-moccasin-portfolio-rebalance/10-atokens/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/10-atokens/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/10-atokens/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/10-atokens/+page.md new file mode 100644 index 000000000..33db236c3 --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/10-atokens/+page.md @@ -0,0 +1,3 @@ +--- + title: Atokens + --- \ No newline at end of file From fdbfc6c67ed183f79d0e852e6560c139619beb57 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 07:16:03 -0500 Subject: [PATCH 038/255] PatrickAlphaC updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/11-portfolio-allocations/+page.md. --- .../11-portfolio-allocations/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/11-portfolio-allocations/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/11-portfolio-allocations/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/11-portfolio-allocations/+page.md new file mode 100644 index 000000000..07bf480e4 --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/11-portfolio-allocations/+page.md @@ -0,0 +1,3 @@ +--- + title: Portfolio Allocations + --- \ No newline at end of file From 8bb5762bfa632759764f2ca50fa4a84abbf43cc1 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 07:16:49 -0500 Subject: [PATCH 039/255] PatrickAlphaC updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/12-withdrawing-from-aave/+page.md. --- .../12-withdrawing-from-aave/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/12-withdrawing-from-aave/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/12-withdrawing-from-aave/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/12-withdrawing-from-aave/+page.md new file mode 100644 index 000000000..f1d6c57f7 --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/12-withdrawing-from-aave/+page.md @@ -0,0 +1,3 @@ +--- + title: Withdrawing From Aave + --- \ No newline at end of file From 4c8ddd4d7d9957f2cbf5049788fdc23d2e932736 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 07:25:09 -0500 Subject: [PATCH 040/255] PatrickAlphaC updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/13-uniswap/+page.md. --- .../2-moccasin-portfolio-rebalance/13-uniswap/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/13-uniswap/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/13-uniswap/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/13-uniswap/+page.md new file mode 100644 index 000000000..e36f58bf8 --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/13-uniswap/+page.md @@ -0,0 +1,3 @@ +--- + title: Uniswap + --- \ No newline at end of file From c32ce652db59e2e01fa12e95da37cf66e1ff5cf9 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 07:26:32 -0500 Subject: [PATCH 041/255] PatrickAlphaC updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/14-finish-rebalance/+page.md. --- .../14-finish-rebalance/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/14-finish-rebalance/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/14-finish-rebalance/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/14-finish-rebalance/+page.md new file mode 100644 index 000000000..3dca590d9 --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/14-finish-rebalance/+page.md @@ -0,0 +1,3 @@ +--- + title: Finish Rebalance + --- \ No newline at end of file From 5ddb914787f7c402f9a9142423e2a4c6e492f566 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 07:28:04 -0500 Subject: [PATCH 042/255] PatrickAlphaC updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/15-zksync-demo/+page.md. --- .../2-moccasin-portfolio-rebalance/15-zksync-demo/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/15-zksync-demo/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/15-zksync-demo/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/15-zksync-demo/+page.md new file mode 100644 index 000000000..ad5ddb5e5 --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/15-zksync-demo/+page.md @@ -0,0 +1,3 @@ +--- + title: Zksync Demo + --- \ No newline at end of file From 22d959773d4ebd6904f3c36eaf4a2edbfb71697a Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 07:30:13 -0500 Subject: [PATCH 043/255] PatrickAlphaC updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/16-workshop/+page.md. --- .../2-moccasin-portfolio-rebalance/16-workshop/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/16-workshop/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/16-workshop/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/16-workshop/+page.md new file mode 100644 index 000000000..789149836 --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/16-workshop/+page.md @@ -0,0 +1,3 @@ +--- + title: Workshop + --- \ No newline at end of file From 6afb4b1edb094d7aac78f52aeb29f860c59a1d40 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 07:42:51 -0500 Subject: [PATCH 044/255] PatrickAlphaC updated courses/advanced-moccasin/3-moccasin-stablecoin/1-intro/+page.md. --- .../advanced-moccasin/3-moccasin-stablecoin/1-intro/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/3-moccasin-stablecoin/1-intro/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/1-intro/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/1-intro/+page.md new file mode 100644 index 000000000..b7e64e913 --- /dev/null +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/1-intro/+page.md @@ -0,0 +1,3 @@ +--- + title: Intro + --- \ No newline at end of file From 6dfbb70784ef2700bf152537dc0df2e9bf87ccfb Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 08:55:19 -0500 Subject: [PATCH 045/255] PatrickAlphaC updated courses/advanced-moccasin/3-moccasin-stablecoin/2-what-is-a-stablecoin/+page.md. --- .../3-moccasin-stablecoin/2-what-is-a-stablecoin/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/3-moccasin-stablecoin/2-what-is-a-stablecoin/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/2-what-is-a-stablecoin/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/2-what-is-a-stablecoin/+page.md new file mode 100644 index 000000000..763bb0081 --- /dev/null +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/2-what-is-a-stablecoin/+page.md @@ -0,0 +1,3 @@ +--- + title: What Is A Stablecoin + --- \ No newline at end of file From 86ac4c03a7c9e36a35e7cb940d93befdf06b45b6 Mon Sep 17 00:00:00 2001 From: hunter <104146303+solhosty@users.noreply.github.com> Date: Wed, 4 Dec 2024 17:36:06 +0100 Subject: [PATCH 046/255] reset --- courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md | 3 --- .../10-note-what-happens-when-we-stop-anvil/+page.md | 3 --- .../advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md | 3 --- .../1-moccasin-nft/12-what-is-an-svg/+page.md | 3 --- courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md | 3 --- .../1-moccasin-nft/14-base-64-encoding-images/+page.md | 3 --- .../1-moccasin-nft/15-base-64-encoding-json/+page.md | 3 --- .../advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md | 3 --- .../17-function-selectors-and-signatures/+page.md | 3 --- .../1-moccasin-nft/18-calling-functions-raw/+page.md | 3 --- .../1-moccasin-nft/19-manually-crafting-calldata/+page.md | 3 --- courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md | 3 --- .../1-moccasin-nft/20-mid-section-recap/+page.md | 3 --- .../1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md | 3 --- .../1-moccasin-nft/22-finishing-the-mood-nft/+page.md | 3 --- .../advanced-moccasin/1-moccasin-nft/23-workshop-2/+page.md | 3 --- courses/advanced-moccasin/1-moccasin-nft/24-recap/+page.md | 3 --- .../advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md | 3 --- .../1-moccasin-nft/4-building-an-erc721-contract/+page.md | 3 --- courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md | 3 --- courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md | 3 --- .../advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md | 3 --- .../1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md | 3 --- .../1-moccasin-nft/9-deploying-to-zksync/+page.md | 3 --- .../2-moccasin-portfolio-rebalance/1-intro/+page.md | 3 --- .../2-moccasin-portfolio-rebalance/10-atokens/+page.md | 3 --- .../11-portfolio-allocations/+page.md | 3 --- .../12-withdrawing-from-aave/+page.md | 3 --- .../2-moccasin-portfolio-rebalance/13-uniswap/+page.md | 3 --- .../14-finish-rebalance/+page.md | 3 --- .../2-moccasin-portfolio-rebalance/15-zksync-demo/+page.md | 3 --- .../2-moccasin-portfolio-rebalance/16-workshop/+page.md | 3 --- .../2-moccasin-portfolio-rebalance/2-real-demo/+page.md | 3 --- .../2-moccasin-portfolio-rebalance/3-setup/+page.md | 3 --- .../4-forked-network-setup/+page.md | 3 --- .../2-moccasin-portfolio-rebalance/5-minting-weth/+page.md | 3 --- .../6-getting-abis-from-the-explorer/+page.md | 3 --- .../2-moccasin-portfolio-rebalance/7-minting-usdc/+page.md | 3 --- .../2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md | 3 --- .../9-depositing-into-aave/+page.md | 3 --- .../advanced-moccasin/3-moccasin-stablecoin/1-intro/+page.md | 3 --- .../3-moccasin-stablecoin/2-what-is-a-stablecoin/+page.md | 3 --- 42 files changed, 126 deletions(-) delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/23-workshop-2/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/24-recap/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md delete mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/1-intro/+page.md delete mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/10-atokens/+page.md delete mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/11-portfolio-allocations/+page.md delete mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/12-withdrawing-from-aave/+page.md delete mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/13-uniswap/+page.md delete mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/14-finish-rebalance/+page.md delete mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/15-zksync-demo/+page.md delete mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/16-workshop/+page.md delete mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/2-real-demo/+page.md delete mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/3-setup/+page.md delete mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/4-forked-network-setup/+page.md delete mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/5-minting-weth/+page.md delete mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/6-getting-abis-from-the-explorer/+page.md delete mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/7-minting-usdc/+page.md delete mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md delete mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/9-depositing-into-aave/+page.md delete mode 100644 courses/advanced-moccasin/3-moccasin-stablecoin/1-intro/+page.md delete mode 100644 courses/advanced-moccasin/3-moccasin-stablecoin/2-what-is-a-stablecoin/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md b/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md deleted file mode 100644 index b7e64e913..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Intro - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md b/courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md deleted file mode 100644 index 16d0dc804..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Note What Happens When We Stop Anvil - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md b/courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md deleted file mode 100644 index 1c0984466..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Workshop 1 - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md b/courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md deleted file mode 100644 index 812a8b80d..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: What Is An Svg - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md b/courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md deleted file mode 100644 index 9fe904d8a..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Mood Nft - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md b/courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md deleted file mode 100644 index 0eb6c72b4..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Base 64 Encoding Images - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md b/courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md deleted file mode 100644 index c85718bcc..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Base 64 Encoding Json - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md b/courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md deleted file mode 100644 index 720a585fe..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Abi Encoding - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md b/courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md deleted file mode 100644 index 7561fb7ab..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Function Selectors And Signatures - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md b/courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md deleted file mode 100644 index b234f677f..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Calling Functions Raw - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md b/courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md deleted file mode 100644 index d710a4f9c..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Manually Crafting Calldata - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md b/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md deleted file mode 100644 index fcc7a149d..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Setup - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md b/courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md deleted file mode 100644 index b7e84d122..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Mid Section Recap - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md b/courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md deleted file mode 100644 index 6c761a39a..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Verifying Calldata In Metamask - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md b/courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md deleted file mode 100644 index 489949655..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Finishing The Mood Nft - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/23-workshop-2/+page.md b/courses/advanced-moccasin/1-moccasin-nft/23-workshop-2/+page.md deleted file mode 100644 index a653fcc03..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/23-workshop-2/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Workshop 2 - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/24-recap/+page.md b/courses/advanced-moccasin/1-moccasin-nft/24-recap/+page.md deleted file mode 100644 index 385e6edfe..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/24-recap/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Recap - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md b/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md deleted file mode 100644 index 1c1ce1385..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: What Is An Nft - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md b/courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md deleted file mode 100644 index 881ccd3b9..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Building An Erc721 Contract - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md b/courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md deleted file mode 100644 index d2aeab7ef..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Tokenuri - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md b/courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md deleted file mode 100644 index 7ff466b05..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Deploy - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md b/courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md deleted file mode 100644 index 2f65fda3e..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: What Is Ipfs - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md b/courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md deleted file mode 100644 index 01b735559..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Viewing An Nft In Metamask - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md b/courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md deleted file mode 100644 index c0d9d9943..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Deploying To Zksync - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/1-intro/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/1-intro/+page.md deleted file mode 100644 index b7e64e913..000000000 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/1-intro/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Intro - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/10-atokens/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/10-atokens/+page.md deleted file mode 100644 index 33db236c3..000000000 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/10-atokens/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Atokens - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/11-portfolio-allocations/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/11-portfolio-allocations/+page.md deleted file mode 100644 index 07bf480e4..000000000 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/11-portfolio-allocations/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Portfolio Allocations - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/12-withdrawing-from-aave/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/12-withdrawing-from-aave/+page.md deleted file mode 100644 index f1d6c57f7..000000000 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/12-withdrawing-from-aave/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Withdrawing From Aave - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/13-uniswap/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/13-uniswap/+page.md deleted file mode 100644 index e36f58bf8..000000000 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/13-uniswap/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Uniswap - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/14-finish-rebalance/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/14-finish-rebalance/+page.md deleted file mode 100644 index 3dca590d9..000000000 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/14-finish-rebalance/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Finish Rebalance - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/15-zksync-demo/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/15-zksync-demo/+page.md deleted file mode 100644 index ad5ddb5e5..000000000 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/15-zksync-demo/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Zksync Demo - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/16-workshop/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/16-workshop/+page.md deleted file mode 100644 index 789149836..000000000 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/16-workshop/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Workshop - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/2-real-demo/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/2-real-demo/+page.md deleted file mode 100644 index 2166cf79d..000000000 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/2-real-demo/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Real Demo - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/3-setup/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/3-setup/+page.md deleted file mode 100644 index fcc7a149d..000000000 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/3-setup/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Setup - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/4-forked-network-setup/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/4-forked-network-setup/+page.md deleted file mode 100644 index 197805050..000000000 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/4-forked-network-setup/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Forked Network Setup - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/5-minting-weth/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/5-minting-weth/+page.md deleted file mode 100644 index 03c9f6eb3..000000000 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/5-minting-weth/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Minting Weth - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/6-getting-abis-from-the-explorer/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/6-getting-abis-from-the-explorer/+page.md deleted file mode 100644 index 3ce73c93f..000000000 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/6-getting-abis-from-the-explorer/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Getting Abis From The Explorer - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/7-minting-usdc/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/7-minting-usdc/+page.md deleted file mode 100644 index f2b83d10a..000000000 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/7-minting-usdc/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Minting Usdc - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md deleted file mode 100644 index 575eb50e6..000000000 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Juypter Notebook - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/9-depositing-into-aave/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/9-depositing-into-aave/+page.md deleted file mode 100644 index b11c9625e..000000000 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/9-depositing-into-aave/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Depositing Into Aave - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/1-intro/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/1-intro/+page.md deleted file mode 100644 index b7e64e913..000000000 --- a/courses/advanced-moccasin/3-moccasin-stablecoin/1-intro/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Intro - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/2-what-is-a-stablecoin/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/2-what-is-a-stablecoin/+page.md deleted file mode 100644 index 763bb0081..000000000 --- a/courses/advanced-moccasin/3-moccasin-stablecoin/2-what-is-a-stablecoin/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: What Is A Stablecoin - --- \ No newline at end of file From dfc4947a6ffc9cab69352176b57b22ab7bd0e2c3 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 11:49:49 -0500 Subject: [PATCH 047/255] PatrickAlphaC updated courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md. --- courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md b/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md new file mode 100644 index 000000000..b7e64e913 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md @@ -0,0 +1,3 @@ +--- + title: Intro + --- \ No newline at end of file From 67d9960868d3dc33a7679f2afab1f1393c089db5 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 11:50:42 -0500 Subject: [PATCH 048/255] PatrickAlphaC updated courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md. --- courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md b/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md new file mode 100644 index 000000000..fcc7a149d --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md @@ -0,0 +1,3 @@ +--- + title: Setup + --- \ No newline at end of file From 7f3e18aff05cb9bbc23a0ea31603b74a9e0b8e77 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 12:08:41 -0500 Subject: [PATCH 049/255] PatrickAlphaC updated courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md. --- .../advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md b/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md new file mode 100644 index 000000000..1c1ce1385 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md @@ -0,0 +1,3 @@ +--- + title: What Is An Nft + --- \ No newline at end of file From 6cf4727aea19167c019313eea2ee7df4deb5ee9a Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Wed, 4 Dec 2024 12:14:20 -0500 Subject: [PATCH 050/255] PatrickAlphaC updated courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md. --- .../1-moccasin-nft/4-building-an-erc721-contract/+page.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md b/courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md new file mode 100644 index 000000000..881ccd3b9 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md @@ -0,0 +1,3 @@ +--- + title: Building An Erc721 Contract + --- \ No newline at end of file From 203442dbddc5fa3f8bcd757482cc21caa2082e39 Mon Sep 17 00:00:00 2001 From: hunter <104146303+solhosty@users.noreply.github.com> Date: Thu, 5 Dec 2024 04:16:21 +0100 Subject: [PATCH 051/255] new --- courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md | 3 --- courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md | 3 --- .../advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md | 3 --- .../1-moccasin-nft/4-building-an-erc721-contract/+page.md | 3 --- 4 files changed, 12 deletions(-) delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md b/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md deleted file mode 100644 index b7e64e913..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Intro - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md b/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md deleted file mode 100644 index fcc7a149d..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Setup - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md b/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md deleted file mode 100644 index 1c1ce1385..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: What Is An Nft - --- \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md b/courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md deleted file mode 100644 index 881ccd3b9..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - title: Building An Erc721 Contract - --- \ No newline at end of file From e880a9dc594d5cf687ed8b7d88844395760d235d Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 13:35:42 -0500 Subject: [PATCH 052/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md. --- courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md b/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md new file mode 100644 index 000000000..c3de78c13 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md @@ -0,0 +1,5 @@ + + --- + title: Intro + --- + \ No newline at end of file From da8ab84891776b9888895747ddcbf95883c2930b Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 13:35:58 -0500 Subject: [PATCH 053/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md. --- courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md b/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md new file mode 100644 index 000000000..b8774470f --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md @@ -0,0 +1,5 @@ + + --- + title: Setup + --- + \ No newline at end of file From 9ee4530343fb05501cecb807d03c22535ffde20c Mon Sep 17 00:00:00 2001 From: hunter <104146303+solhosty@users.noreply.github.com> Date: Thu, 5 Dec 2024 19:44:32 +0100 Subject: [PATCH 054/255] new --- courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md | 5 ----- courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md | 5 ----- 2 files changed, 10 deletions(-) delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md b/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md deleted file mode 100644 index c3de78c13..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md +++ /dev/null @@ -1,5 +0,0 @@ - - --- - title: Intro - --- - \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md b/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md deleted file mode 100644 index b8774470f..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md +++ /dev/null @@ -1,5 +0,0 @@ - - --- - title: Setup - --- - \ No newline at end of file From ab7324b5f2aff01973f14d724cdc48e095ae0ba6 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 13:49:02 -0500 Subject: [PATCH 055/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md. --- courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md b/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md new file mode 100644 index 000000000..c3de78c13 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md @@ -0,0 +1,5 @@ + + --- + title: Intro + --- + \ No newline at end of file From d2607e2c05ffdb74912a494733244218bb663db6 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 13:49:17 -0500 Subject: [PATCH 056/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md. --- courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md b/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md new file mode 100644 index 000000000..b8774470f --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md @@ -0,0 +1,5 @@ + + --- + title: Setup + --- + \ No newline at end of file From 8744381118d8ec7ee7616482454591a72f615f86 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 13:55:05 -0500 Subject: [PATCH 057/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md. --- .../1-moccasin-nft/3-what-is-an-nft/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md b/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md new file mode 100644 index 000000000..20ffe0298 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md @@ -0,0 +1,5 @@ + + --- + title: What Is An Nft + --- + \ No newline at end of file From e69c279dc9bab6948579ccd7c6415288d2bed9f7 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 13:58:56 -0500 Subject: [PATCH 058/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md. --- .../1-moccasin-nft/4-building-an-erc721-contract/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md b/courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md new file mode 100644 index 000000000..5ef234088 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md @@ -0,0 +1,5 @@ + + --- + title: Building An Erc721 Contract + --- + \ No newline at end of file From 9885efd764f285b5d4104017ac61953f17be183c Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 13:59:31 -0500 Subject: [PATCH 059/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md. --- courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md b/courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md new file mode 100644 index 000000000..9e08dd6eb --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md @@ -0,0 +1,5 @@ + + --- + title: Tokenuri + --- + \ No newline at end of file From 190746e6783f53abb6098050a9650029d69958c0 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 13:59:46 -0500 Subject: [PATCH 060/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md. --- courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md b/courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md new file mode 100644 index 000000000..016761360 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md @@ -0,0 +1,5 @@ + + --- + title: Deploy + --- + \ No newline at end of file From b239b9c891bc80c8e254c448522b19c97e95c5df Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 14:03:37 -0500 Subject: [PATCH 061/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md. --- .../advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md b/courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md new file mode 100644 index 000000000..53a655154 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md @@ -0,0 +1,5 @@ + + --- + title: What Is Ipfs + --- + \ No newline at end of file From cbc71e370ac642fffffbceb891ed2d2ad7824b4f Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 14:03:56 -0500 Subject: [PATCH 062/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md. --- .../1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md b/courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md new file mode 100644 index 000000000..d154c82d8 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md @@ -0,0 +1,5 @@ + + --- + title: Viewing An Nft In Metamask + --- + \ No newline at end of file From d6be5d08dce87cd68a7d0ff362677ca82a6b2549 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 14:04:12 -0500 Subject: [PATCH 063/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md. --- .../1-moccasin-nft/9-deploying-to-zksync/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md b/courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md new file mode 100644 index 000000000..1c2eef215 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md @@ -0,0 +1,5 @@ + + --- + title: Deploying To Zksync + --- + \ No newline at end of file From eec7235241b2e3805f3d1bf72fc9fc4dad55cddc Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 14:04:27 -0500 Subject: [PATCH 064/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md. --- .../10-note-what-happens-when-we-stop-anvil/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md b/courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md new file mode 100644 index 000000000..5a0a8d1a9 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md @@ -0,0 +1,5 @@ + + --- + title: Note What Happens When We Stop Anvil + --- + \ No newline at end of file From e6e0e2a934406aa5bec5a3a01f3d74b6e459cc64 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 14:06:07 -0500 Subject: [PATCH 065/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md. --- .../advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md b/courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md new file mode 100644 index 000000000..c61b71da8 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md @@ -0,0 +1,5 @@ + + --- + title: Workshop 1 + --- + \ No newline at end of file From 0021822a8c1ec5f13b0722b948c96ce286519363 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 14:10:20 -0500 Subject: [PATCH 066/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md. --- .../1-moccasin-nft/12-what-is-an-svg/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md b/courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md new file mode 100644 index 000000000..86f9e7c4c --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md @@ -0,0 +1,5 @@ + + --- + title: What Is An Svg + --- + \ No newline at end of file From b5edf78c728e2f256ced64399ffafc826f57df82 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 14:10:37 -0500 Subject: [PATCH 067/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md. --- .../advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md b/courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md new file mode 100644 index 000000000..1ec100844 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md @@ -0,0 +1,5 @@ + + --- + title: Mood Nft + --- + \ No newline at end of file From c1d4b3e0f5add111bc0a99ea7a4f63a3be12f8a7 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 14:10:58 -0500 Subject: [PATCH 068/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md. --- .../1-moccasin-nft/14-base-64-encoding-images/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md b/courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md new file mode 100644 index 000000000..0090106c4 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md @@ -0,0 +1,5 @@ + + --- + title: Base 64 Encoding Images + --- + \ No newline at end of file From 88b9f477b22adcf0c0f5163d9116b7d5737162f0 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 14:16:48 -0500 Subject: [PATCH 069/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md. --- .../1-moccasin-nft/15-base-64-encoding-json/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md b/courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md new file mode 100644 index 000000000..908004ce2 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md @@ -0,0 +1,5 @@ + + --- + title: Base 64 Encoding Json + --- + \ No newline at end of file From 7e986a1cb462f9690155c8032227215dd0e97631 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 14:17:24 -0500 Subject: [PATCH 070/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md. --- .../1-moccasin-nft/16-abi-encoding/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md b/courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md new file mode 100644 index 000000000..46afd45b0 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md @@ -0,0 +1,5 @@ + + --- + title: Abi Encoding + --- + \ No newline at end of file From 2b9919d3d0f84124c2ac61bbeb08767dba6e9dd7 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 14:17:59 -0500 Subject: [PATCH 071/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md. --- .../17-function-selectors-and-signatures/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md b/courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md new file mode 100644 index 000000000..8e2d34d02 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md @@ -0,0 +1,5 @@ + + --- + title: Function Selectors And Signatures + --- + \ No newline at end of file From b13547689e876843d29864c30a0ec6b55045725c Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 14:18:18 -0500 Subject: [PATCH 072/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md. --- .../1-moccasin-nft/18-calling-functions-raw/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md b/courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md new file mode 100644 index 000000000..7e6b2afb8 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md @@ -0,0 +1,5 @@ + + --- + title: Calling Functions Raw + --- + \ No newline at end of file From 0285641ce0e9246c51503f7e1e5813cf38802dbf Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 14:18:34 -0500 Subject: [PATCH 073/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md. --- .../1-moccasin-nft/19-manually-crafting-calldata/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md b/courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md new file mode 100644 index 000000000..3aea25cb0 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md @@ -0,0 +1,5 @@ + + --- + title: Manually Crafting Calldata + --- + \ No newline at end of file From 58fd039ad65e7ceefdcff663f9fd29f2f8012a53 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 14:18:51 -0500 Subject: [PATCH 074/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md. --- .../1-moccasin-nft/20-mid-section-recap/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md b/courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md new file mode 100644 index 000000000..328000d3c --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md @@ -0,0 +1,5 @@ + + --- + title: Mid Section Recap + --- + \ No newline at end of file From 364053cfd1ab37cbaa5bb57c4c82aed3e066b15a Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 14:22:53 -0500 Subject: [PATCH 075/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md. --- .../21-verifying-calldata-in-metamask/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md b/courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md new file mode 100644 index 000000000..86bf6d8ca --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md @@ -0,0 +1,5 @@ + + --- + title: Verifying Calldata In Metamask + --- + \ No newline at end of file From de57667255bf645d14f1b34d6acf36c0cd966807 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 14:23:28 -0500 Subject: [PATCH 076/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md. --- .../1-moccasin-nft/22-finishing-the-mood-nft/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md b/courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md new file mode 100644 index 000000000..758431000 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md @@ -0,0 +1,5 @@ + + --- + title: Finishing The Mood Nft + --- + \ No newline at end of file From 56cc1fc3daa487e68952c4ccb4f0a5939308c5b1 Mon Sep 17 00:00:00 2001 From: hunter <104146303+solhosty@users.noreply.github.com> Date: Thu, 5 Dec 2024 20:26:33 +0100 Subject: [PATCH 077/255] new --- courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md | 5 ----- .../10-note-what-happens-when-we-stop-anvil/+page.md | 5 ----- .../advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md | 5 ----- .../1-moccasin-nft/12-what-is-an-svg/+page.md | 5 ----- .../advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md | 5 ----- .../1-moccasin-nft/14-base-64-encoding-images/+page.md | 5 ----- .../1-moccasin-nft/15-base-64-encoding-json/+page.md | 5 ----- .../1-moccasin-nft/16-abi-encoding/+page.md | 5 ----- .../17-function-selectors-and-signatures/+page.md | 5 ----- .../1-moccasin-nft/18-calling-functions-raw/+page.md | 5 ----- .../1-moccasin-nft/19-manually-crafting-calldata/+page.md | 5 ----- courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md | 5 ----- .../1-moccasin-nft/20-mid-section-recap/+page.md | 5 ----- .../21-verifying-calldata-in-metamask/+page.md | 5 ----- .../1-moccasin-nft/22-finishing-the-mood-nft/+page.md | 5 ----- .../1-moccasin-nft/3-what-is-an-nft/+page.md | 5 ----- .../1-moccasin-nft/4-building-an-erc721-contract/+page.md | 5 ----- courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md | 5 ----- courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md | 5 ----- .../advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md | 5 ----- .../1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md | 5 ----- .../1-moccasin-nft/9-deploying-to-zksync/+page.md | 5 ----- 22 files changed, 110 deletions(-) delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md b/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md deleted file mode 100644 index c3de78c13..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md +++ /dev/null @@ -1,5 +0,0 @@ - - --- - title: Intro - --- - \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md b/courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md deleted file mode 100644 index 5a0a8d1a9..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md +++ /dev/null @@ -1,5 +0,0 @@ - - --- - title: Note What Happens When We Stop Anvil - --- - \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md b/courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md deleted file mode 100644 index c61b71da8..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md +++ /dev/null @@ -1,5 +0,0 @@ - - --- - title: Workshop 1 - --- - \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md b/courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md deleted file mode 100644 index 86f9e7c4c..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md +++ /dev/null @@ -1,5 +0,0 @@ - - --- - title: What Is An Svg - --- - \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md b/courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md deleted file mode 100644 index 1ec100844..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md +++ /dev/null @@ -1,5 +0,0 @@ - - --- - title: Mood Nft - --- - \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md b/courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md deleted file mode 100644 index 0090106c4..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md +++ /dev/null @@ -1,5 +0,0 @@ - - --- - title: Base 64 Encoding Images - --- - \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md b/courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md deleted file mode 100644 index 908004ce2..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md +++ /dev/null @@ -1,5 +0,0 @@ - - --- - title: Base 64 Encoding Json - --- - \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md b/courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md deleted file mode 100644 index 46afd45b0..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md +++ /dev/null @@ -1,5 +0,0 @@ - - --- - title: Abi Encoding - --- - \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md b/courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md deleted file mode 100644 index 8e2d34d02..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md +++ /dev/null @@ -1,5 +0,0 @@ - - --- - title: Function Selectors And Signatures - --- - \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md b/courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md deleted file mode 100644 index 7e6b2afb8..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md +++ /dev/null @@ -1,5 +0,0 @@ - - --- - title: Calling Functions Raw - --- - \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md b/courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md deleted file mode 100644 index 3aea25cb0..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md +++ /dev/null @@ -1,5 +0,0 @@ - - --- - title: Manually Crafting Calldata - --- - \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md b/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md deleted file mode 100644 index b8774470f..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md +++ /dev/null @@ -1,5 +0,0 @@ - - --- - title: Setup - --- - \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md b/courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md deleted file mode 100644 index 328000d3c..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md +++ /dev/null @@ -1,5 +0,0 @@ - - --- - title: Mid Section Recap - --- - \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md b/courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md deleted file mode 100644 index 86bf6d8ca..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md +++ /dev/null @@ -1,5 +0,0 @@ - - --- - title: Verifying Calldata In Metamask - --- - \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md b/courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md deleted file mode 100644 index 758431000..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md +++ /dev/null @@ -1,5 +0,0 @@ - - --- - title: Finishing The Mood Nft - --- - \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md b/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md deleted file mode 100644 index 20ffe0298..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md +++ /dev/null @@ -1,5 +0,0 @@ - - --- - title: What Is An Nft - --- - \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md b/courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md deleted file mode 100644 index 5ef234088..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md +++ /dev/null @@ -1,5 +0,0 @@ - - --- - title: Building An Erc721 Contract - --- - \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md b/courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md deleted file mode 100644 index 9e08dd6eb..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md +++ /dev/null @@ -1,5 +0,0 @@ - - --- - title: Tokenuri - --- - \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md b/courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md deleted file mode 100644 index 016761360..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md +++ /dev/null @@ -1,5 +0,0 @@ - - --- - title: Deploy - --- - \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md b/courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md deleted file mode 100644 index 53a655154..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md +++ /dev/null @@ -1,5 +0,0 @@ - - --- - title: What Is Ipfs - --- - \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md b/courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md deleted file mode 100644 index d154c82d8..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md +++ /dev/null @@ -1,5 +0,0 @@ - - --- - title: Viewing An Nft In Metamask - --- - \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md b/courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md deleted file mode 100644 index 1c2eef215..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md +++ /dev/null @@ -1,5 +0,0 @@ - - --- - title: Deploying To Zksync - --- - \ No newline at end of file From ac308ccc35aad0040ef755d3675a9eb1ea7052e3 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 14:36:35 -0500 Subject: [PATCH 078/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md. --- courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md b/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md new file mode 100644 index 000000000..c3de78c13 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md @@ -0,0 +1,5 @@ + + --- + title: Intro + --- + \ No newline at end of file From f1d8c16c167aaaeef3655e06d7099216d382f54e Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 14:36:50 -0500 Subject: [PATCH 079/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md. --- courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md b/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md new file mode 100644 index 000000000..b8774470f --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md @@ -0,0 +1,5 @@ + + --- + title: Setup + --- + \ No newline at end of file From b2410d13f32c9f4cdafb1c9ee7eded2506de49be Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 14:41:55 -0500 Subject: [PATCH 080/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md. --- .../1-moccasin-nft/3-what-is-an-nft/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md b/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md new file mode 100644 index 000000000..20ffe0298 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md @@ -0,0 +1,5 @@ + + --- + title: What Is An Nft + --- + \ No newline at end of file From 1b72e7eb4a074fea01faa562bb76e3cf88f272fd Mon Sep 17 00:00:00 2001 From: hunter <104146303+solhosty@users.noreply.github.com> Date: Thu, 5 Dec 2024 20:47:07 +0100 Subject: [PATCH 081/255] new --- courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md | 5 ----- courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md | 5 ----- .../1-moccasin-nft/3-what-is-an-nft/+page.md | 5 ----- 3 files changed, 15 deletions(-) delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md delete mode 100644 courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md b/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md deleted file mode 100644 index c3de78c13..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md +++ /dev/null @@ -1,5 +0,0 @@ - - --- - title: Intro - --- - \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md b/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md deleted file mode 100644 index b8774470f..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md +++ /dev/null @@ -1,5 +0,0 @@ - - --- - title: Setup - --- - \ No newline at end of file diff --git a/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md b/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md deleted file mode 100644 index 20ffe0298..000000000 --- a/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md +++ /dev/null @@ -1,5 +0,0 @@ - - --- - title: What Is An Nft - --- - \ No newline at end of file From 92f189821dac2b95f0cb27e28ba5ac2db7803ae7 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 14:51:24 -0500 Subject: [PATCH 082/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md. --- courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md b/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md new file mode 100644 index 000000000..c3de78c13 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md @@ -0,0 +1,5 @@ + + --- + title: Intro + --- + \ No newline at end of file From 161cf9f53905998ae5315a8fb97b973a5cec5bee Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 14:51:40 -0500 Subject: [PATCH 083/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md. --- courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md b/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md new file mode 100644 index 000000000..b8774470f --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md @@ -0,0 +1,5 @@ + + --- + title: Setup + --- + \ No newline at end of file From ea95f36ac7e7f804f7fcfee63353ded68b3ccb86 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 14:57:47 -0500 Subject: [PATCH 084/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md. --- .../1-moccasin-nft/3-what-is-an-nft/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md b/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md new file mode 100644 index 000000000..20ffe0298 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md @@ -0,0 +1,5 @@ + + --- + title: What Is An Nft + --- + \ No newline at end of file From 5e061376eb3bf285172c23647b08260895040c30 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:01:10 -0500 Subject: [PATCH 085/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md. --- .../1-moccasin-nft/4-building-an-erc721-contract/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md b/courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md new file mode 100644 index 000000000..5ef234088 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md @@ -0,0 +1,5 @@ + + --- + title: Building An Erc721 Contract + --- + \ No newline at end of file From 32c16931cf3daf7d34062a6bfa4f2cf7a5ff67e3 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:01:50 -0500 Subject: [PATCH 086/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md. --- courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md b/courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md new file mode 100644 index 000000000..9e08dd6eb --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md @@ -0,0 +1,5 @@ + + --- + title: Tokenuri + --- + \ No newline at end of file From 43996a73ab9eb81f5fe4d0ef1b995456529106af Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:02:06 -0500 Subject: [PATCH 087/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md. --- courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md b/courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md new file mode 100644 index 000000000..016761360 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md @@ -0,0 +1,5 @@ + + --- + title: Deploy + --- + \ No newline at end of file From d3bbf328695f51dd3198304722eb71fc26016831 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:05:49 -0500 Subject: [PATCH 088/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md. --- .../advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md b/courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md new file mode 100644 index 000000000..53a655154 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md @@ -0,0 +1,5 @@ + + --- + title: What Is Ipfs + --- + \ No newline at end of file From 98d5a594f34715307a3a8094ee5166c02c0e94bc Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:06:10 -0500 Subject: [PATCH 089/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md. --- .../1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md b/courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md new file mode 100644 index 000000000..d154c82d8 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md @@ -0,0 +1,5 @@ + + --- + title: Viewing An Nft In Metamask + --- + \ No newline at end of file From 4db03b33e22c9902d9a3790954b38a03d4a2fd01 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:06:28 -0500 Subject: [PATCH 090/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md. --- .../1-moccasin-nft/9-deploying-to-zksync/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md b/courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md new file mode 100644 index 000000000..1c2eef215 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md @@ -0,0 +1,5 @@ + + --- + title: Deploying To Zksync + --- + \ No newline at end of file From d3e1b0ae154c1bba125676fe819ae49bd87c696b Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:06:42 -0500 Subject: [PATCH 091/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md. --- .../10-note-what-happens-when-we-stop-anvil/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md b/courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md new file mode 100644 index 000000000..5a0a8d1a9 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md @@ -0,0 +1,5 @@ + + --- + title: Note What Happens When We Stop Anvil + --- + \ No newline at end of file From c8a3d68cc46c83e1915e808ec60d46b8c62b396f Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:08:14 -0500 Subject: [PATCH 092/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md. --- .../advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md b/courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md new file mode 100644 index 000000000..c61b71da8 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md @@ -0,0 +1,5 @@ + + --- + title: Workshop 1 + --- + \ No newline at end of file From 0ca9faa0749726764f880896e27f0df62bc6339b Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:12:09 -0500 Subject: [PATCH 093/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md. --- .../1-moccasin-nft/12-what-is-an-svg/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md b/courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md new file mode 100644 index 000000000..86f9e7c4c --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md @@ -0,0 +1,5 @@ + + --- + title: What Is An Svg + --- + \ No newline at end of file From 4bf90923447ee81e93692a52230c1f99bb3d63cc Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:12:27 -0500 Subject: [PATCH 094/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md. --- .../advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md b/courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md new file mode 100644 index 000000000..1ec100844 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md @@ -0,0 +1,5 @@ + + --- + title: Mood Nft + --- + \ No newline at end of file From 49c03ffb8d1fc29f7e961db318f3d6a53e726dc0 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:12:49 -0500 Subject: [PATCH 095/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md. --- .../1-moccasin-nft/14-base-64-encoding-images/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md b/courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md new file mode 100644 index 000000000..0090106c4 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md @@ -0,0 +1,5 @@ + + --- + title: Base 64 Encoding Images + --- + \ No newline at end of file From 0e9ae52900dca9ea44d83981c586561c9b0e6d89 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:18:39 -0500 Subject: [PATCH 096/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md. --- .../1-moccasin-nft/15-base-64-encoding-json/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md b/courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md new file mode 100644 index 000000000..908004ce2 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md @@ -0,0 +1,5 @@ + + --- + title: Base 64 Encoding Json + --- + \ No newline at end of file From 4bc64ee4d4cd64d35d37641632e30758564d966e Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:19:21 -0500 Subject: [PATCH 097/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md. --- .../1-moccasin-nft/16-abi-encoding/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md b/courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md new file mode 100644 index 000000000..46afd45b0 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md @@ -0,0 +1,5 @@ + + --- + title: Abi Encoding + --- + \ No newline at end of file From 3c2a8fc5039f4dfb282e5a512553073284df7aec Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:20:02 -0500 Subject: [PATCH 098/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md. --- .../17-function-selectors-and-signatures/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md b/courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md new file mode 100644 index 000000000..8e2d34d02 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md @@ -0,0 +1,5 @@ + + --- + title: Function Selectors And Signatures + --- + \ No newline at end of file From 3ee8bde13013af6b031832b445e5f99849e2e8fb Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:20:34 -0500 Subject: [PATCH 099/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md. --- .../1-moccasin-nft/18-calling-functions-raw/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md b/courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md new file mode 100644 index 000000000..7e6b2afb8 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md @@ -0,0 +1,5 @@ + + --- + title: Calling Functions Raw + --- + \ No newline at end of file From efb01e678260e551318ee948570c7d83449f6925 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:20:51 -0500 Subject: [PATCH 100/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md. --- .../1-moccasin-nft/19-manually-crafting-calldata/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md b/courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md new file mode 100644 index 000000000..3aea25cb0 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md @@ -0,0 +1,5 @@ + + --- + title: Manually Crafting Calldata + --- + \ No newline at end of file From c3f3ceebe36747bf810e6efcba4200a109eb0438 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:21:09 -0500 Subject: [PATCH 101/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md. --- .../1-moccasin-nft/20-mid-section-recap/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md b/courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md new file mode 100644 index 000000000..328000d3c --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md @@ -0,0 +1,5 @@ + + --- + title: Mid Section Recap + --- + \ No newline at end of file From f6d0a2f4f307f4e2dc23149ffa9900fd89004103 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:25:24 -0500 Subject: [PATCH 102/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md. --- .../21-verifying-calldata-in-metamask/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md b/courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md new file mode 100644 index 000000000..86bf6d8ca --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md @@ -0,0 +1,5 @@ + + --- + title: Verifying Calldata In Metamask + --- + \ No newline at end of file From 604924ed2d15b7d1d96be0dcc81db581808f13c5 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:26:03 -0500 Subject: [PATCH 103/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md. --- .../1-moccasin-nft/22-finishing-the-mood-nft/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md b/courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md new file mode 100644 index 000000000..758431000 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md @@ -0,0 +1,5 @@ + + --- + title: Finishing The Mood Nft + --- + \ No newline at end of file From f5a9fd00d2358228f7bd1b841ebb7fd813fd93ec Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:26:21 -0500 Subject: [PATCH 104/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/23-workshop-2/+page.md. --- .../advanced-moccasin/1-moccasin-nft/23-workshop-2/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/23-workshop-2/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/23-workshop-2/+page.md b/courses/advanced-moccasin/1-moccasin-nft/23-workshop-2/+page.md new file mode 100644 index 000000000..82ac362be --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/23-workshop-2/+page.md @@ -0,0 +1,5 @@ + + --- + title: Workshop 2 + --- + \ No newline at end of file From 6ddea5443dae917d2b1d78bca4616813566fa6a9 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:29:03 -0500 Subject: [PATCH 105/255] solhosty updated courses/advanced-moccasin/1-moccasin-nft/24-recap/+page.md. --- courses/advanced-moccasin/1-moccasin-nft/24-recap/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/1-moccasin-nft/24-recap/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/24-recap/+page.md b/courses/advanced-moccasin/1-moccasin-nft/24-recap/+page.md new file mode 100644 index 000000000..520a7c357 --- /dev/null +++ b/courses/advanced-moccasin/1-moccasin-nft/24-recap/+page.md @@ -0,0 +1,5 @@ + + --- + title: Recap + --- + \ No newline at end of file From e42d63b05ea37cf11f209949dda7c9159fd634d3 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:32:57 -0500 Subject: [PATCH 106/255] solhosty updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/1-intro/+page.md. --- .../2-moccasin-portfolio-rebalance/1-intro/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/1-intro/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/1-intro/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/1-intro/+page.md new file mode 100644 index 000000000..c3de78c13 --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/1-intro/+page.md @@ -0,0 +1,5 @@ + + --- + title: Intro + --- + \ No newline at end of file From 234c727e793fe6568a60fce5e8375b693f07659b Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:33:21 -0500 Subject: [PATCH 107/255] solhosty updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/2-real-demo/+page.md. --- .../2-moccasin-portfolio-rebalance/2-real-demo/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/2-real-demo/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/2-real-demo/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/2-real-demo/+page.md new file mode 100644 index 000000000..8cccb17e9 --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/2-real-demo/+page.md @@ -0,0 +1,5 @@ + + --- + title: Real Demo + --- + \ No newline at end of file From 55920f6a77c0563668edc7988d89890fe6aa905a Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:33:37 -0500 Subject: [PATCH 108/255] solhosty updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/3-setup/+page.md. --- .../2-moccasin-portfolio-rebalance/3-setup/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/3-setup/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/3-setup/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/3-setup/+page.md new file mode 100644 index 000000000..b8774470f --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/3-setup/+page.md @@ -0,0 +1,5 @@ + + --- + title: Setup + --- + \ No newline at end of file From a243bf68ec07ea1f8794db1f262e6741af867360 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:34:02 -0500 Subject: [PATCH 109/255] solhosty updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/4-forked-network-setup/+page.md. --- .../4-forked-network-setup/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/4-forked-network-setup/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/4-forked-network-setup/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/4-forked-network-setup/+page.md new file mode 100644 index 000000000..d825a83e4 --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/4-forked-network-setup/+page.md @@ -0,0 +1,5 @@ + + --- + title: Forked Network Setup + --- + \ No newline at end of file From 55ddde9e664d56b40c387f853178697446be4e88 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:34:18 -0500 Subject: [PATCH 110/255] solhosty updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/5-minting-weth/+page.md. --- .../2-moccasin-portfolio-rebalance/5-minting-weth/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/5-minting-weth/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/5-minting-weth/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/5-minting-weth/+page.md new file mode 100644 index 000000000..8e1fc4990 --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/5-minting-weth/+page.md @@ -0,0 +1,5 @@ + + --- + title: Minting Weth + --- + \ No newline at end of file From 90911254b8e286b836202fba3c6cd16ae317d795 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:34:37 -0500 Subject: [PATCH 111/255] solhosty updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/6-getting-abis-from-the-explorer/+page.md. --- .../6-getting-abis-from-the-explorer/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/6-getting-abis-from-the-explorer/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/6-getting-abis-from-the-explorer/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/6-getting-abis-from-the-explorer/+page.md new file mode 100644 index 000000000..71f85eeff --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/6-getting-abis-from-the-explorer/+page.md @@ -0,0 +1,5 @@ + + --- + title: Getting Abis From The Explorer + --- + \ No newline at end of file From 230e885f444cbd5ed4b3e346db9f600696ce08db Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:34:58 -0500 Subject: [PATCH 112/255] solhosty updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/7-minting-usdc/+page.md. --- .../2-moccasin-portfolio-rebalance/7-minting-usdc/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/7-minting-usdc/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/7-minting-usdc/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/7-minting-usdc/+page.md new file mode 100644 index 000000000..f1fa81333 --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/7-minting-usdc/+page.md @@ -0,0 +1,5 @@ + + --- + title: Minting Usdc + --- + \ No newline at end of file From ff6a6b4e34cfbdaabfc1bae281c1a059d4b2ef4f Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:35:21 -0500 Subject: [PATCH 113/255] solhosty updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md. --- .../8-juypter-notebook/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md new file mode 100644 index 000000000..720acd517 --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md @@ -0,0 +1,5 @@ + + --- + title: Juypter Notebook + --- + \ No newline at end of file From 9ec29fc5a8fa3f3200c597bf568362c1e26d5314 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:36:03 -0500 Subject: [PATCH 114/255] solhosty updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/9-depositing-into-aave/+page.md. --- .../9-depositing-into-aave/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/9-depositing-into-aave/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/9-depositing-into-aave/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/9-depositing-into-aave/+page.md new file mode 100644 index 000000000..ee8aafeab --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/9-depositing-into-aave/+page.md @@ -0,0 +1,5 @@ + + --- + title: Depositing Into Aave + --- + \ No newline at end of file From ca74a3ea8e6d6c3607826a682b99e75a1e2fa795 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:36:45 -0500 Subject: [PATCH 115/255] solhosty updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/10-atokens/+page.md. --- .../2-moccasin-portfolio-rebalance/10-atokens/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/10-atokens/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/10-atokens/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/10-atokens/+page.md new file mode 100644 index 000000000..3662307dd --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/10-atokens/+page.md @@ -0,0 +1,5 @@ + + --- + title: Atokens + --- + \ No newline at end of file From b5904c06d1d30168a632a9c529d157ceb81939c3 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:37:28 -0500 Subject: [PATCH 116/255] solhosty updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/11-portfolio-allocations/+page.md. --- .../11-portfolio-allocations/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/11-portfolio-allocations/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/11-portfolio-allocations/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/11-portfolio-allocations/+page.md new file mode 100644 index 000000000..a1a5e794a --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/11-portfolio-allocations/+page.md @@ -0,0 +1,5 @@ + + --- + title: Portfolio Allocations + --- + \ No newline at end of file From d19b0f25116866306eb69190f658053c6f0761d4 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:37:45 -0500 Subject: [PATCH 117/255] solhosty updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/12-withdrawing-from-aave/+page.md. --- .../12-withdrawing-from-aave/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/12-withdrawing-from-aave/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/12-withdrawing-from-aave/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/12-withdrawing-from-aave/+page.md new file mode 100644 index 000000000..a57a18b9b --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/12-withdrawing-from-aave/+page.md @@ -0,0 +1,5 @@ + + --- + title: Withdrawing From Aave + --- + \ No newline at end of file From 79c0bce984708567373b7f4c52447287d337ce83 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:47:03 -0500 Subject: [PATCH 118/255] solhosty updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/13-uniswap/+page.md. --- .../2-moccasin-portfolio-rebalance/13-uniswap/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/13-uniswap/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/13-uniswap/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/13-uniswap/+page.md new file mode 100644 index 000000000..892ee74c0 --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/13-uniswap/+page.md @@ -0,0 +1,5 @@ + + --- + title: Uniswap + --- + \ No newline at end of file From c5d154cf9b62904c194ff12de94817c0243ae588 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:47:25 -0500 Subject: [PATCH 119/255] solhosty updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/14-finish-rebalance/+page.md. --- .../14-finish-rebalance/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/14-finish-rebalance/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/14-finish-rebalance/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/14-finish-rebalance/+page.md new file mode 100644 index 000000000..30a5ed7dd --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/14-finish-rebalance/+page.md @@ -0,0 +1,5 @@ + + --- + title: Finish Rebalance + --- + \ No newline at end of file From 36801b08ea78152540b1b267518ce1eb95e7b986 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:47:48 -0500 Subject: [PATCH 120/255] solhosty updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/15-zksync-demo/+page.md. --- .../2-moccasin-portfolio-rebalance/15-zksync-demo/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/15-zksync-demo/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/15-zksync-demo/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/15-zksync-demo/+page.md new file mode 100644 index 000000000..d052ae0af --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/15-zksync-demo/+page.md @@ -0,0 +1,5 @@ + + --- + title: Zksync Demo + --- + \ No newline at end of file From dcc5ef73a90248f3ea22225f0019f1e36aa80aa1 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:49:20 -0500 Subject: [PATCH 121/255] solhosty updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/16-workshop/+page.md. --- .../2-moccasin-portfolio-rebalance/16-workshop/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/16-workshop/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/16-workshop/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/16-workshop/+page.md new file mode 100644 index 000000000..d8fee3739 --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/16-workshop/+page.md @@ -0,0 +1,5 @@ + + --- + title: Workshop + --- + \ No newline at end of file From a5504bf8cf24dc7342aa3c16073bbd568b0ca9cd Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:49:21 -0500 Subject: [PATCH 122/255] solhosty updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/17-recap/+page.md. --- .../2-moccasin-portfolio-rebalance/17-recap/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/2-moccasin-portfolio-rebalance/17-recap/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/17-recap/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/17-recap/+page.md new file mode 100644 index 000000000..520a7c357 --- /dev/null +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/17-recap/+page.md @@ -0,0 +1,5 @@ + + --- + title: Recap + --- + \ No newline at end of file From ba1847e5b006d16bb57af00bc378cb6cdf845437 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 15:52:37 -0500 Subject: [PATCH 123/255] solhosty updated courses/advanced-moccasin/3-moccasin-stablecoin/1-intro/+page.md. --- .../advanced-moccasin/3-moccasin-stablecoin/1-intro/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/3-moccasin-stablecoin/1-intro/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/1-intro/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/1-intro/+page.md new file mode 100644 index 000000000..c3de78c13 --- /dev/null +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/1-intro/+page.md @@ -0,0 +1,5 @@ + + --- + title: Intro + --- + \ No newline at end of file From fbc72df8db7d03fd1bc0841a5eb3fe9bd84fc806 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 16:25:00 -0500 Subject: [PATCH 124/255] solhosty updated courses/advanced-moccasin/3-moccasin-stablecoin/2-what-is-a-stablecoin/+page.md. --- .../3-moccasin-stablecoin/2-what-is-a-stablecoin/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/3-moccasin-stablecoin/2-what-is-a-stablecoin/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/2-what-is-a-stablecoin/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/2-what-is-a-stablecoin/+page.md new file mode 100644 index 000000000..faa9d44a8 --- /dev/null +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/2-what-is-a-stablecoin/+page.md @@ -0,0 +1,5 @@ + + --- + title: What Is A Stablecoin + --- + \ No newline at end of file From 1bfb0c6083d3f842cd23f98e58d8ea391c6b55d0 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 16:25:35 -0500 Subject: [PATCH 125/255] solhosty updated courses/advanced-moccasin/3-moccasin-stablecoin/3-setup/+page.md. --- .../advanced-moccasin/3-moccasin-stablecoin/3-setup/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/3-moccasin-stablecoin/3-setup/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/3-setup/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/3-setup/+page.md new file mode 100644 index 000000000..b8774470f --- /dev/null +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/3-setup/+page.md @@ -0,0 +1,5 @@ + + --- + title: Setup + --- + \ No newline at end of file From 5690bc0b9dad169ad0ad03fab1aeef8b24dc4c4c Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 16:25:58 -0500 Subject: [PATCH 126/255] solhosty updated courses/advanced-moccasin/3-moccasin-stablecoin/4-engine-intro/+page.md. --- .../3-moccasin-stablecoin/4-engine-intro/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/3-moccasin-stablecoin/4-engine-intro/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/4-engine-intro/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/4-engine-intro/+page.md new file mode 100644 index 000000000..36e0d1a48 --- /dev/null +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/4-engine-intro/+page.md @@ -0,0 +1,5 @@ + + --- + title: Engine Intro + --- + \ No newline at end of file From cd570e220a25708a8824bfc66c4f4c04201e34c6 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 16:26:32 -0500 Subject: [PATCH 127/255] solhosty updated courses/advanced-moccasin/3-moccasin-stablecoin/5-deposit-collateral/+page.md. --- .../3-moccasin-stablecoin/5-deposit-collateral/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/3-moccasin-stablecoin/5-deposit-collateral/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/5-deposit-collateral/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/5-deposit-collateral/+page.md new file mode 100644 index 000000000..e89d3139a --- /dev/null +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/5-deposit-collateral/+page.md @@ -0,0 +1,5 @@ + + --- + title: Deposit Collateral + --- + \ No newline at end of file From ce5732acbb4ea55519f9b8af55e7e0504b8ac319 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 16:27:42 -0500 Subject: [PATCH 128/255] solhosty updated courses/advanced-moccasin/3-moccasin-stablecoin/6-health-factor/+page.md. --- .../3-moccasin-stablecoin/6-health-factor/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/3-moccasin-stablecoin/6-health-factor/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/6-health-factor/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/6-health-factor/+page.md new file mode 100644 index 000000000..defc39586 --- /dev/null +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/6-health-factor/+page.md @@ -0,0 +1,5 @@ + + --- + title: Health Factor + --- + \ No newline at end of file From bd3c518ed4f554f367dd4240d2676235cf1e8f52 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 16:28:02 -0500 Subject: [PATCH 129/255] solhosty updated courses/advanced-moccasin/3-moccasin-stablecoin/7-minting-dsc/+page.md. --- .../3-moccasin-stablecoin/7-minting-dsc/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/3-moccasin-stablecoin/7-minting-dsc/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/7-minting-dsc/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/7-minting-dsc/+page.md new file mode 100644 index 000000000..da8cd1d96 --- /dev/null +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/7-minting-dsc/+page.md @@ -0,0 +1,5 @@ + + --- + title: Minting Dsc + --- + \ No newline at end of file From 76f35719887e00710e7696073e0ba3fcfe4b67ba Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 16:28:52 -0500 Subject: [PATCH 130/255] solhosty updated courses/advanced-moccasin/3-moccasin-stablecoin/8-redeem-collateral/+page.md. --- .../3-moccasin-stablecoin/8-redeem-collateral/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/3-moccasin-stablecoin/8-redeem-collateral/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/8-redeem-collateral/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/8-redeem-collateral/+page.md new file mode 100644 index 000000000..a319758c8 --- /dev/null +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/8-redeem-collateral/+page.md @@ -0,0 +1,5 @@ + + --- + title: Redeem Collateral + --- + \ No newline at end of file From 325c6dcd97db3bc1650c19ee61e0a187fa4d01e1 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 16:29:49 -0500 Subject: [PATCH 131/255] solhosty updated courses/advanced-moccasin/3-moccasin-stablecoin/9-liquidation/+page.md. --- .../3-moccasin-stablecoin/9-liquidation/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/3-moccasin-stablecoin/9-liquidation/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/9-liquidation/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/9-liquidation/+page.md new file mode 100644 index 000000000..2bf4f831c --- /dev/null +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/9-liquidation/+page.md @@ -0,0 +1,5 @@ + + --- + title: Liquidation + --- + \ No newline at end of file From 0693cd6fe89cf333398b8e80ce374593c83dfc8f Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 16:30:41 -0500 Subject: [PATCH 132/255] solhosty updated courses/advanced-moccasin/3-moccasin-stablecoin/10-deployment/+page.md. --- .../3-moccasin-stablecoin/10-deployment/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/3-moccasin-stablecoin/10-deployment/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/10-deployment/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/10-deployment/+page.md new file mode 100644 index 000000000..3c00e7ea9 --- /dev/null +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/10-deployment/+page.md @@ -0,0 +1,5 @@ + + --- + title: Deployment + --- + \ No newline at end of file From 9c01877a758a5a44dba2d932446200035d122d04 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 16:36:35 -0500 Subject: [PATCH 133/255] solhosty updated courses/advanced-moccasin/3-moccasin-stablecoin/11-testing/+page.md. --- .../3-moccasin-stablecoin/11-testing/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/3-moccasin-stablecoin/11-testing/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/11-testing/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/11-testing/+page.md new file mode 100644 index 000000000..c1839c795 --- /dev/null +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/11-testing/+page.md @@ -0,0 +1,5 @@ + + --- + title: Testing + --- + \ No newline at end of file From 74225937f8b2b8c7187729e432873fbe476e4ed2 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 16:38:43 -0500 Subject: [PATCH 134/255] solhosty updated courses/advanced-moccasin/3-moccasin-stablecoin/12-workshop-1/+page.md. --- .../3-moccasin-stablecoin/12-workshop-1/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/3-moccasin-stablecoin/12-workshop-1/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/12-workshop-1/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/12-workshop-1/+page.md new file mode 100644 index 000000000..c61b71da8 --- /dev/null +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/12-workshop-1/+page.md @@ -0,0 +1,5 @@ + + --- + title: Workshop 1 + --- + \ No newline at end of file From 07cfc0ccc2883059b2252ea3c8c6c9ad6c7c6206 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 16:42:27 -0500 Subject: [PATCH 135/255] solhosty updated courses/advanced-moccasin/3-moccasin-stablecoin/13-fuzz-setup/+page.md. --- .../3-moccasin-stablecoin/13-fuzz-setup/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/3-moccasin-stablecoin/13-fuzz-setup/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/13-fuzz-setup/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/13-fuzz-setup/+page.md new file mode 100644 index 000000000..a411fc23b --- /dev/null +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/13-fuzz-setup/+page.md @@ -0,0 +1,5 @@ + + --- + title: Fuzz Setup + --- + \ No newline at end of file From cf06336f052e4e93e88f7db7751c8557b1f72b14 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 16:45:18 -0500 Subject: [PATCH 136/255] solhosty updated courses/advanced-moccasin/3-moccasin-stablecoin/14-invariant/+page.md. --- .../3-moccasin-stablecoin/14-invariant/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/3-moccasin-stablecoin/14-invariant/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/14-invariant/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/14-invariant/+page.md new file mode 100644 index 000000000..678aef389 --- /dev/null +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/14-invariant/+page.md @@ -0,0 +1,5 @@ + + --- + title: Invariant + --- + \ No newline at end of file From 2f6288cce87a458a8bc5d03c03214214f9238ca5 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 16:58:18 -0500 Subject: [PATCH 137/255] solhosty updated courses/advanced-moccasin/3-moccasin-stablecoin/15-rules-deposit-and-redeem/+page.md. --- .../15-rules-deposit-and-redeem/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/3-moccasin-stablecoin/15-rules-deposit-and-redeem/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/15-rules-deposit-and-redeem/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/15-rules-deposit-and-redeem/+page.md new file mode 100644 index 000000000..27e85cb6e --- /dev/null +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/15-rules-deposit-and-redeem/+page.md @@ -0,0 +1,5 @@ + + --- + title: Rules Deposit And Redeem + --- + \ No newline at end of file From 47e307d0cb354e439021ddd09780c58f5e7eef44 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 16:59:01 -0500 Subject: [PATCH 138/255] solhosty updated courses/advanced-moccasin/3-moccasin-stablecoin/16-rules-mint-dsc/+page.md. --- .../3-moccasin-stablecoin/16-rules-mint-dsc/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/3-moccasin-stablecoin/16-rules-mint-dsc/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/16-rules-mint-dsc/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/16-rules-mint-dsc/+page.md new file mode 100644 index 000000000..ad5a976aa --- /dev/null +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/16-rules-mint-dsc/+page.md @@ -0,0 +1,5 @@ + + --- + title: Rules Mint Dsc + --- + \ No newline at end of file From cef69d38ea280caf61636988fe818445352d69c4 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 16:59:52 -0500 Subject: [PATCH 139/255] solhosty updated courses/advanced-moccasin/3-moccasin-stablecoin/17-rules-update-price/+page.md. --- .../3-moccasin-stablecoin/17-rules-update-price/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/3-moccasin-stablecoin/17-rules-update-price/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/17-rules-update-price/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/17-rules-update-price/+page.md new file mode 100644 index 000000000..76632171c --- /dev/null +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/17-rules-update-price/+page.md @@ -0,0 +1,5 @@ + + --- + title: Rules Update Price + --- + \ No newline at end of file From ad2539efb6940f10fc362730a0e51c6088e8d383 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 17:00:14 -0500 Subject: [PATCH 140/255] solhosty updated courses/advanced-moccasin/3-moccasin-stablecoin/18-workshop-2/+page.md. --- .../3-moccasin-stablecoin/18-workshop-2/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/3-moccasin-stablecoin/18-workshop-2/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/18-workshop-2/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/18-workshop-2/+page.md new file mode 100644 index 000000000..82ac362be --- /dev/null +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/18-workshop-2/+page.md @@ -0,0 +1,5 @@ + + --- + title: Workshop 2 + --- + \ No newline at end of file From 2e2657a9355a08abdd11c34a69e13d1b3fc2305e Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 17:07:55 -0500 Subject: [PATCH 141/255] solhosty updated courses/advanced-moccasin/3-moccasin-stablecoin/19-audit-readiness/+page.md. --- .../3-moccasin-stablecoin/19-audit-readiness/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/3-moccasin-stablecoin/19-audit-readiness/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/19-audit-readiness/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/19-audit-readiness/+page.md new file mode 100644 index 000000000..c3eadc976 --- /dev/null +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/19-audit-readiness/+page.md @@ -0,0 +1,5 @@ + + --- + title: Audit Readiness + --- + \ No newline at end of file From 5feae896b486ba864cc403047072d2cbc215bf03 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 17:09:10 -0500 Subject: [PATCH 142/255] solhosty updated courses/advanced-moccasin/3-moccasin-stablecoin/20-recap/+page.md. --- .../3-moccasin-stablecoin/20-recap/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/3-moccasin-stablecoin/20-recap/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/20-recap/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/20-recap/+page.md new file mode 100644 index 000000000..520a7c357 --- /dev/null +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/20-recap/+page.md @@ -0,0 +1,5 @@ + + --- + title: Recap + --- + \ No newline at end of file From 8f64e8099633819c6e01e3504aa95e71fa54be2e Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 17:11:04 -0500 Subject: [PATCH 143/255] solhosty updated courses/advanced-moccasin/4-moccasin-signatures/1-intro/+page.md. --- .../advanced-moccasin/4-moccasin-signatures/1-intro/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/4-moccasin-signatures/1-intro/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/1-intro/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/1-intro/+page.md new file mode 100644 index 000000000..c3de78c13 --- /dev/null +++ b/courses/advanced-moccasin/4-moccasin-signatures/1-intro/+page.md @@ -0,0 +1,5 @@ + + --- + title: Intro + --- + \ No newline at end of file From ed13183ae069f8bb225bcf8da07b6d74c663eaf6 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 17:11:22 -0500 Subject: [PATCH 144/255] solhosty updated courses/advanced-moccasin/4-moccasin-signatures/2-setup/+page.md. --- .../advanced-moccasin/4-moccasin-signatures/2-setup/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/4-moccasin-signatures/2-setup/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/2-setup/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/2-setup/+page.md new file mode 100644 index 000000000..b8774470f --- /dev/null +++ b/courses/advanced-moccasin/4-moccasin-signatures/2-setup/+page.md @@ -0,0 +1,5 @@ + + --- + title: Setup + --- + \ No newline at end of file From 99f7f7e92dc38d53d44a6b1a9111ea9434817959 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 17:18:16 -0500 Subject: [PATCH 145/255] solhosty updated courses/advanced-moccasin/4-moccasin-signatures/3-merkle-trees/+page.md. --- .../4-moccasin-signatures/3-merkle-trees/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/4-moccasin-signatures/3-merkle-trees/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/3-merkle-trees/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/3-merkle-trees/+page.md new file mode 100644 index 000000000..1a3f36b7e --- /dev/null +++ b/courses/advanced-moccasin/4-moccasin-signatures/3-merkle-trees/+page.md @@ -0,0 +1,5 @@ + + --- + title: Merkle Trees + --- + \ No newline at end of file From 7b465273552ddb4ab358244ab2966d55bfce8533 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 17:19:06 -0500 Subject: [PATCH 146/255] solhosty updated courses/advanced-moccasin/4-moccasin-signatures/4-making-a-merkle/+page.md. --- .../4-moccasin-signatures/4-making-a-merkle/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/4-moccasin-signatures/4-making-a-merkle/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/4-making-a-merkle/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/4-making-a-merkle/+page.md new file mode 100644 index 000000000..b7be47f9f --- /dev/null +++ b/courses/advanced-moccasin/4-moccasin-signatures/4-making-a-merkle/+page.md @@ -0,0 +1,5 @@ + + --- + title: Making A Merkle + --- + \ No newline at end of file From 620b7d6a3253447a16abb91d0f0cb2dec147398e Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 17:19:51 -0500 Subject: [PATCH 147/255] solhosty updated courses/advanced-moccasin/4-moccasin-signatures/5-merkle-proof/+page.md. --- .../4-moccasin-signatures/5-merkle-proof/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/4-moccasin-signatures/5-merkle-proof/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/5-merkle-proof/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/5-merkle-proof/+page.md new file mode 100644 index 000000000..56c50ef51 --- /dev/null +++ b/courses/advanced-moccasin/4-moccasin-signatures/5-merkle-proof/+page.md @@ -0,0 +1,5 @@ + + --- + title: Merkle Proof + --- + \ No newline at end of file From 96d3e01862fdbde7c24af4086a1f12c9ab7b3487 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 17:20:28 -0500 Subject: [PATCH 148/255] solhosty updated courses/advanced-moccasin/4-moccasin-signatures/6-claiming-a-proof/+page.md. --- .../4-moccasin-signatures/6-claiming-a-proof/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/4-moccasin-signatures/6-claiming-a-proof/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/6-claiming-a-proof/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/6-claiming-a-proof/+page.md new file mode 100644 index 000000000..3d6602a5f --- /dev/null +++ b/courses/advanced-moccasin/4-moccasin-signatures/6-claiming-a-proof/+page.md @@ -0,0 +1,5 @@ + + --- + title: Claiming A Proof + --- + \ No newline at end of file From 8488dceafea7b7a770a0f29fb6462f71bf6df9e0 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 17:34:02 -0500 Subject: [PATCH 149/255] solhosty updated courses/advanced-moccasin/4-moccasin-signatures/7-signature-standards/+page.md. --- .../4-moccasin-signatures/7-signature-standards/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/4-moccasin-signatures/7-signature-standards/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/7-signature-standards/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/7-signature-standards/+page.md new file mode 100644 index 000000000..05e42f97d --- /dev/null +++ b/courses/advanced-moccasin/4-moccasin-signatures/7-signature-standards/+page.md @@ -0,0 +1,5 @@ + + --- + title: Signature Standards + --- + \ No newline at end of file From 72f143e69714df60232c96f13323d082a28532ed Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 17:37:35 -0500 Subject: [PATCH 150/255] solhosty updated courses/advanced-moccasin/4-moccasin-signatures/8-eip-712-in-vyper/+page.md. --- .../4-moccasin-signatures/8-eip-712-in-vyper/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/4-moccasin-signatures/8-eip-712-in-vyper/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/8-eip-712-in-vyper/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/8-eip-712-in-vyper/+page.md new file mode 100644 index 000000000..4d49f70ad --- /dev/null +++ b/courses/advanced-moccasin/4-moccasin-signatures/8-eip-712-in-vyper/+page.md @@ -0,0 +1,5 @@ + + --- + title: Eip 712 In Vyper + --- + \ No newline at end of file From 5732d054a80e1795b1b28be1b8477b9907f1437e Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 17:49:01 -0500 Subject: [PATCH 151/255] solhosty updated courses/advanced-moccasin/4-moccasin-signatures/9-ecdsa/+page.md. --- .../advanced-moccasin/4-moccasin-signatures/9-ecdsa/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/4-moccasin-signatures/9-ecdsa/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/9-ecdsa/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/9-ecdsa/+page.md new file mode 100644 index 000000000..65f4879b0 --- /dev/null +++ b/courses/advanced-moccasin/4-moccasin-signatures/9-ecdsa/+page.md @@ -0,0 +1,5 @@ + + --- + title: Ecdsa + --- + \ No newline at end of file From a4f74a54cf5724a77b641fb900a885e7d27aaac5 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 17:54:04 -0500 Subject: [PATCH 152/255] solhosty updated courses/advanced-moccasin/4-moccasin-signatures/10-transaction-types/+page.md. --- .../4-moccasin-signatures/10-transaction-types/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/4-moccasin-signatures/10-transaction-types/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/10-transaction-types/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/10-transaction-types/+page.md new file mode 100644 index 000000000..8f6407a9e --- /dev/null +++ b/courses/advanced-moccasin/4-moccasin-signatures/10-transaction-types/+page.md @@ -0,0 +1,5 @@ + + --- + title: Transaction Types + --- + \ No newline at end of file From e6fd1f4899e217f7a81860c6d1d0ff64c777a425 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 18:04:06 -0500 Subject: [PATCH 153/255] solhosty updated courses/advanced-moccasin/4-moccasin-signatures/11-blobs/+page.md. --- .../4-moccasin-signatures/11-blobs/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/4-moccasin-signatures/11-blobs/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/11-blobs/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/11-blobs/+page.md new file mode 100644 index 000000000..25167253a --- /dev/null +++ b/courses/advanced-moccasin/4-moccasin-signatures/11-blobs/+page.md @@ -0,0 +1,5 @@ + + --- + title: Blobs + --- + \ No newline at end of file From 6f8c1a68580f0a48241e354e4afbe49449765867 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 18:05:27 -0500 Subject: [PATCH 154/255] solhosty updated courses/advanced-moccasin/4-moccasin-signatures/12-type-113-transactions/+page.md. --- .../4-moccasin-signatures/12-type-113-transactions/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/4-moccasin-signatures/12-type-113-transactions/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/12-type-113-transactions/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/12-type-113-transactions/+page.md new file mode 100644 index 000000000..e28fccb87 --- /dev/null +++ b/courses/advanced-moccasin/4-moccasin-signatures/12-type-113-transactions/+page.md @@ -0,0 +1,5 @@ + + --- + title: Type 113 Transactions + --- + \ No newline at end of file From af2778e7d3eb6bcced172bdd2733841d81956fcd Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 18:09:48 -0500 Subject: [PATCH 155/255] solhosty updated courses/advanced-moccasin/4-moccasin-signatures/13-adding-signature-verification/+page.md. --- .../13-adding-signature-verification/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/4-moccasin-signatures/13-adding-signature-verification/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/13-adding-signature-verification/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/13-adding-signature-verification/+page.md new file mode 100644 index 000000000..44dff73cb --- /dev/null +++ b/courses/advanced-moccasin/4-moccasin-signatures/13-adding-signature-verification/+page.md @@ -0,0 +1,5 @@ + + --- + title: Adding Signature Verification + --- + \ No newline at end of file From 63a9eb2cb0050ac136fa1406aaf406fced96d347 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 18:10:05 -0500 Subject: [PATCH 156/255] solhosty updated courses/advanced-moccasin/4-moccasin-signatures/14-deploy/+page.md. --- .../4-moccasin-signatures/14-deploy/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/4-moccasin-signatures/14-deploy/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/14-deploy/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/14-deploy/+page.md new file mode 100644 index 000000000..016761360 --- /dev/null +++ b/courses/advanced-moccasin/4-moccasin-signatures/14-deploy/+page.md @@ -0,0 +1,5 @@ + + --- + title: Deploy + --- + \ No newline at end of file From a8afe3fa9bf1cf5e26fddaa8bbc5ba4355c19392 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 18:10:46 -0500 Subject: [PATCH 157/255] solhosty updated courses/advanced-moccasin/4-moccasin-signatures/15-testing/+page.md. --- .../4-moccasin-signatures/15-testing/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/4-moccasin-signatures/15-testing/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/15-testing/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/15-testing/+page.md new file mode 100644 index 000000000..c1839c795 --- /dev/null +++ b/courses/advanced-moccasin/4-moccasin-signatures/15-testing/+page.md @@ -0,0 +1,5 @@ + + --- + title: Testing + --- + \ No newline at end of file From e441b928b56e44c0b130c35d7bb86a4852377811 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 18:11:04 -0500 Subject: [PATCH 158/255] solhosty updated courses/advanced-moccasin/4-moccasin-signatures/16-workshop-1/+page.md. --- .../4-moccasin-signatures/16-workshop-1/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/4-moccasin-signatures/16-workshop-1/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/16-workshop-1/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/16-workshop-1/+page.md new file mode 100644 index 000000000..c61b71da8 --- /dev/null +++ b/courses/advanced-moccasin/4-moccasin-signatures/16-workshop-1/+page.md @@ -0,0 +1,5 @@ + + --- + title: Workshop 1 + --- + \ No newline at end of file From 97c943c74f2d9e10c5073dea5d8b60e88bb8c46a Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 18:12:58 -0500 Subject: [PATCH 159/255] solhosty updated courses/advanced-moccasin/4-moccasin-signatures/17-recap/+page.md. --- .../4-moccasin-signatures/17-recap/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/4-moccasin-signatures/17-recap/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/17-recap/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/17-recap/+page.md new file mode 100644 index 000000000..520a7c357 --- /dev/null +++ b/courses/advanced-moccasin/4-moccasin-signatures/17-recap/+page.md @@ -0,0 +1,5 @@ + + --- + title: Recap + --- + \ No newline at end of file From 42a02a92aa481c34dd08a79bae5907f47e9f455c Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 18:25:05 -0500 Subject: [PATCH 160/255] solhosty updated courses/advanced-moccasin/5-moccasin-upgrades/1-intro/+page.md. --- .../advanced-moccasin/5-moccasin-upgrades/1-intro/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/5-moccasin-upgrades/1-intro/+page.md diff --git a/courses/advanced-moccasin/5-moccasin-upgrades/1-intro/+page.md b/courses/advanced-moccasin/5-moccasin-upgrades/1-intro/+page.md new file mode 100644 index 000000000..c3de78c13 --- /dev/null +++ b/courses/advanced-moccasin/5-moccasin-upgrades/1-intro/+page.md @@ -0,0 +1,5 @@ + + --- + title: Intro + --- + \ No newline at end of file From 3439de7616519e538ec284323ae7ee17f64443a9 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 18:28:43 -0500 Subject: [PATCH 161/255] solhosty updated courses/advanced-moccasin/5-moccasin-upgrades/2-erc-1967-and-delegatecall/+page.md. --- .../5-moccasin-upgrades/2-erc-1967-and-delegatecall/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/5-moccasin-upgrades/2-erc-1967-and-delegatecall/+page.md diff --git a/courses/advanced-moccasin/5-moccasin-upgrades/2-erc-1967-and-delegatecall/+page.md b/courses/advanced-moccasin/5-moccasin-upgrades/2-erc-1967-and-delegatecall/+page.md new file mode 100644 index 000000000..bb2fdb9cb --- /dev/null +++ b/courses/advanced-moccasin/5-moccasin-upgrades/2-erc-1967-and-delegatecall/+page.md @@ -0,0 +1,5 @@ + + --- + title: Erc 1967 And Delegatecall + --- + \ No newline at end of file From 7663d7aa755dbb06566b7437817c459684d4bfd2 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 18:29:07 -0500 Subject: [PATCH 162/255] solhosty updated courses/advanced-moccasin/5-moccasin-upgrades/3-delegatecall/+page.md. --- .../5-moccasin-upgrades/3-delegatecall/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/5-moccasin-upgrades/3-delegatecall/+page.md diff --git a/courses/advanced-moccasin/5-moccasin-upgrades/3-delegatecall/+page.md b/courses/advanced-moccasin/5-moccasin-upgrades/3-delegatecall/+page.md new file mode 100644 index 000000000..01bcfe675 --- /dev/null +++ b/courses/advanced-moccasin/5-moccasin-upgrades/3-delegatecall/+page.md @@ -0,0 +1,5 @@ + + --- + title: Delegatecall + --- + \ No newline at end of file From de8a8329fcc4cc1e0a339911216434cf19e25fd4 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 18:29:24 -0500 Subject: [PATCH 163/255] solhosty updated courses/advanced-moccasin/5-moccasin-upgrades/4-how-proxies-upgrade/+page.md. --- .../5-moccasin-upgrades/4-how-proxies-upgrade/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/5-moccasin-upgrades/4-how-proxies-upgrade/+page.md diff --git a/courses/advanced-moccasin/5-moccasin-upgrades/4-how-proxies-upgrade/+page.md b/courses/advanced-moccasin/5-moccasin-upgrades/4-how-proxies-upgrade/+page.md new file mode 100644 index 000000000..758dc1d74 --- /dev/null +++ b/courses/advanced-moccasin/5-moccasin-upgrades/4-how-proxies-upgrade/+page.md @@ -0,0 +1,5 @@ + + --- + title: How Proxies Upgrade + --- + \ No newline at end of file From d50c2428f2ba3c5acf5dc026ed711a89f181e5fd Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 18:29:42 -0500 Subject: [PATCH 164/255] solhosty updated courses/advanced-moccasin/5-moccasin-upgrades/5-workshop/+page.md. --- .../5-moccasin-upgrades/5-workshop/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/5-moccasin-upgrades/5-workshop/+page.md diff --git a/courses/advanced-moccasin/5-moccasin-upgrades/5-workshop/+page.md b/courses/advanced-moccasin/5-moccasin-upgrades/5-workshop/+page.md new file mode 100644 index 000000000..d8fee3739 --- /dev/null +++ b/courses/advanced-moccasin/5-moccasin-upgrades/5-workshop/+page.md @@ -0,0 +1,5 @@ + + --- + title: Workshop + --- + \ No newline at end of file From d95a36e4badc7ea6337c69808d49d4d5e3c49928 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 18:29:57 -0500 Subject: [PATCH 165/255] solhosty updated courses/advanced-moccasin/5-moccasin-upgrades/6-recap/+page.md. --- .../advanced-moccasin/5-moccasin-upgrades/6-recap/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/5-moccasin-upgrades/6-recap/+page.md diff --git a/courses/advanced-moccasin/5-moccasin-upgrades/6-recap/+page.md b/courses/advanced-moccasin/5-moccasin-upgrades/6-recap/+page.md new file mode 100644 index 000000000..520a7c357 --- /dev/null +++ b/courses/advanced-moccasin/5-moccasin-upgrades/6-recap/+page.md @@ -0,0 +1,5 @@ + + --- + title: Recap + --- + \ No newline at end of file From 657d83aa22e898f582c9755543df761228df8807 Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 18:31:03 -0500 Subject: [PATCH 166/255] solhosty updated courses/advanced-moccasin/5-moccasin-upgrades/7-what-do-i-do-now_/+page.md. --- .../5-moccasin-upgrades/7-what-do-i-do-now_/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/5-moccasin-upgrades/7-what-do-i-do-now_/+page.md diff --git a/courses/advanced-moccasin/5-moccasin-upgrades/7-what-do-i-do-now_/+page.md b/courses/advanced-moccasin/5-moccasin-upgrades/7-what-do-i-do-now_/+page.md new file mode 100644 index 000000000..d5f0bb35b --- /dev/null +++ b/courses/advanced-moccasin/5-moccasin-upgrades/7-what-do-i-do-now_/+page.md @@ -0,0 +1,5 @@ + + --- + title: What Do I Do Now_ + --- + \ No newline at end of file From 137a83c8f38ba860f55f296cc88761e245111ddc Mon Sep 17 00:00:00 2001 From: solhosty Date: Thu, 5 Dec 2024 18:31:20 -0500 Subject: [PATCH 167/255] solhosty updated courses/advanced-moccasin/5-moccasin-upgrades/8-finale/+page.md. --- .../advanced-moccasin/5-moccasin-upgrades/8-finale/+page.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 courses/advanced-moccasin/5-moccasin-upgrades/8-finale/+page.md diff --git a/courses/advanced-moccasin/5-moccasin-upgrades/8-finale/+page.md b/courses/advanced-moccasin/5-moccasin-upgrades/8-finale/+page.md new file mode 100644 index 000000000..cd8892b05 --- /dev/null +++ b/courses/advanced-moccasin/5-moccasin-upgrades/8-finale/+page.md @@ -0,0 +1,5 @@ + + --- + title: Finale + --- + \ No newline at end of file From 64626fa7ee08d1dace858fa1a62624918f0a4b75 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:28:02 -0700 Subject: [PATCH 168/255] Equious updated courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md. --- .../1-moccasin-nft/1-intro/+page.md | 97 ++++++++++++++++++- 1 file changed, 92 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md b/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md index c3de78c13..3c363b983 100644 --- a/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md +++ b/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md @@ -1,5 +1,92 @@ - - --- - title: Intro - --- - \ No newline at end of file +## Moccasin NFTs + +This section is about Moccasin NFTs, and will continue to help us build our skills as we begin to work more independently with AI tools. + +We'll be working with NFTs, building a decentralized stablecoin, understanding signatures and upgrades, and learning some amazing new things as we explore the industry and develop our own skills. + +Remember to do all of the workshops associated with each of these sections. They are the heart of the course and how we will truly drill in all of the skills we're learning here. + +Our first section is on Moccasin NFTs. + +Here is the link to the full code we will be working with. + +``` +https://github.com/Cyfrin/mox-nft-cu +``` + +It's a classic Moccasin project and has a moccasin.toml file, which we will be diving into more in later sections. + +The code we're working with here is pretty simple; just a basic NFT. +```python +from moccasin.boa_tools import VyperContract +from src import basic_nft + +def deploy_basic_nft() -> VyperContract: + basic_nft_contract = basic_nft.deploy() + print(f"Deployed basic NFT to {basic_nft_contract.address}") + PUG_URI = "Qm1i6J98JYHB9Y36rUu0tDDm6LdEeNdAAgmrrx3s1tMa" + print(f"Minted Pug NFT with URI {PUG_URI}") + basic_nft_contract.mint(PUG_URI) + return basic_nft_contract + +def moccasin_main(): + return deploy_basic_nft() +``` + +This will deploy our basic NFT and give us a link to our IPFS file that will point to a JSON file that represents our NFT. + +We can then import this into our MetaMask wallet and actually see our NFT. + +We can then import this into our MetaMask wallet and actually see our NFT. + +We'll also be going over some low-level encoding and some low-level raw calls. + +Now, we will go over a slightly more advanced NFT. It's the Mood NFT. Let's go over it in the terminal. + +```bash +mox run deploy_mood_nft --network anvil --account Vyper-cour +``` + +And this will get us a base 64 encoded URL where we can take this entire URL and then stick it into our browser to see our NFT which looks like this. + +Now, we're going to go over the advanced, Sub-Lesson, where we learn how to call anything, we learn about encoding, we learn about raw calls, and a lot of the low-level functionality that we have been skipping over. + +The final thing we will be showing you in this section, is this more advanced Sub-Lesson, where we learn how to call anything and we learn about encoding. + +```python +from moccasin.boa_tools import VyperContract +from src import mood_nft + +def deploy_mood_nft() -> VyperContract: + mood_nft_contract = mood_nft.deploy() + print(f"Deployed mood NFT to {mood_nft_contract.address}") + PUG_URI = "Qm1i6J98JYHB9Y36rUu0tDDm6LdEeNdAAgmrrx3s1tMa" + print(f"Minted Pug NFT with URI {PUG_URI}") + mood_nft_contract.mint(PUG_URI) + return mood_nft_contract + +def moccasin_main(): + return deploy_mood_nft() +``` + +Now, we will go over this more advanced sub-lesson where we learn how to call anything, we learn about encoding. + +```python +from moccasin.boa_tools import VyperContract +from src import mood_nft + +def deploy_mood_nft() -> VyperContract: + mood_nft_contract = mood_nft.deploy() + print(f"Deployed mood NFT to {mood_nft_contract.address}") + PUG_URI = "Qm1i6J98JYHB9Y36rUu0tDDm6LdEeNdAAgmrrx3s1tMa" + print(f"Minted Pug NFT with URI {PUG_URI}") + mood_nft_contract.mint(PUG_URI) + return mood_nft_contract + +def moccasin_main(): + return deploy_mood_nft() +``` + +We'll also be going over some low-level encoding and some low-level raw calls. + +Stay tuned for more amazing things as we move forward in this course! From 224185385ebc1c2833b9dbde15b137f45d0352f3 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:28:15 -0700 Subject: [PATCH 169/255] Equious updated courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md. --- .../10-note-what-happens-when-we-stop-anvil/+page.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md b/courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md index 5a0a8d1a9..0d842e1fc 100644 --- a/courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md +++ b/courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md @@ -1,5 +1,7 @@ - - --- - title: Note What Happens When We Stop Anvil - --- - \ No newline at end of file +## What happens when we stop our Anvil and Era Test Node? + +When we stop our Era test node or Anvil node, our NFTs might still show up in our network, and they may go away. + +If we start getting some weird errors, we can click on the account in the top right corner of MetaMask, click on Settings, Advanced, and then click on Clear activity tab data. This will do a kind of reset. + +Obviously, right now, if we tried to send money because our Era test node is down, it would just gray out, which is really annoying. So, just know that we could even do a little refresh list, and it's going to just nothing's going to happen. So, just know that if our networks are down, if we're locally running networks are down, we might get some weird stuff showing up in our MetaMask. So, just be sure to keep that in mind. From 9a3d82add898f5b2a9c7b123c80bf3a87edc4c9d Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:28:29 -0700 Subject: [PATCH 170/255] Equious updated courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md. --- .../1-moccasin-nft/11-workshop-1/+page.md | 39 ++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md b/courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md index c61b71da8..d14156007 100644 --- a/courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md +++ b/courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md @@ -1,5 +1,34 @@ - - --- - title: Workshop 1 - --- - \ No newline at end of file +### Workshop 1: Mocksen NFTs + +We are going to be working with a centralized gateway. The centralized option we are using is: + +```text +https://gateway.pinata.cloud/ipfs/QmAnOFS6q43HRTW32wVSv6ITTFv3aKqFTf8qKFfTmciJMK +``` + +The first workshop involves completing two prompts: + +1. **Upload your own dog image to IPFS, mint it as an NFT, and then see it in your Metamask!** +2. **Write tests to get at least 80% coverage!** + +If we are using our own IPFS, our IPFS node must be running. Our desktop app has a node option in the top right. If we want to stop it, we can turn it off. + +Alternatively, we can use a centralized service like Pinata Cloud. Pinata Cloud allows us to upload directly to the service. + +We need to ensure that our token URI returns a JSON object. The JSON object must include the image and image attributes. + +If we want to use the dog images provided in the Github repo for this course, we can find them under the /images/static directory. + +### Workshop 2: Mocksen DeFi | Algorithmic Trading + +The second workshop prompt is: + +**Spend at most 25 minutes on all of these prompts without the aide of AI. If you�re unable to solve them after 25 minutes, stop, take a break, and then work with an AI or the discussions to help you solve them. Good luck!** + +We can test our code in the terminal: + +```bash +mox test --coverage +``` + +This completes our introduction to the Mocksen NFTs and testing workshops. Pause the video, complete these workshops, and we'll see you in a bit! From e9f89655bcd8089c58f03db5586c83f618d4e255 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:28:42 -0700 Subject: [PATCH 171/255] Equious updated courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md. --- .../1-moccasin-nft/12-what-is-an-svg/+page.md | 39 ++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md b/courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md index 86f9e7c4c..49c44d456 100644 --- a/courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md +++ b/courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md @@ -1,5 +1,34 @@ - - --- - title: What Is An Svg - --- - \ No newline at end of file +## NFTs: What is an SVG? + +We're going to use something called an SVG. + +Now, an SVG is something that we can store all on chain, but the issue is that we have to be able to encode our image as an SVG. We can also encode our JSON on chain as a base 64 encoded URI. + +What the heck do both of those mean? Well, first, let's go start with what is an SVG. + +SVG stands for Scalable Vector Graphics. SVG defines vector-based graphics in XML format. + +We can actually scroll down, and we can see an example right in this SVG example, right? So, this is it. So, it looks it's just kind of this tag where it has very specific parameters for defining what an image looks like. + +And, the reason that SVGs are so cool is because no matter how big or small you make them, they're always going to have the exact same quality because they're scalable. You know how, like, if you take an image like this one, let me view this, you know, if we take this image, right, and I make it super super big, and I make it super big. The bigger I make it, the worse the quality gets. With an SVG, you don't ever have to deal with that because you define exactly what it will look like, no matter what size. + +And what we can do is we can actually make our own SVG sort of like this, right? And if you're in the W3Schools, if you try for yourself, you can see my first SVG over here, and I can change this. I can say the fill is now blue. We'll run, and now it turns blue. I can say the stroke is black, right, and it turns black. + +So, there's a ton of different parameters and functions that we can do to make an SVG look a certain way. Right, so if we're back in our VS Code, we can even go up to IMG, new file, example.svg. We can code some SVG in here, so we'll do SVG xml ns equals, and this is just version stuff, http. +```bash +cd img/ +base64 -i example.svg +``` +We can actually base 64 encode the output, everything in here, and what I can say is, I could do base 64 - i, which means we're going to input a file and we're going to pass in this example.svg. We'll see we get this weird thing as an output. + +So, now if we take this weird thing, and I'm going to actually create a little little README to make some notes here. + +So, this weird output is the base 64 encoded example.svg we just created. + +Now, at the start of this, we can add a beginning piece to tell our browser that this is an SVG. So, I'm going to say data colon image slash svg plus xml colon base 64 comma like this. And, if I copy this whole thing, oops, sorry, this is in this should be a semicolon here. If I copy this whole thing, and I paste it into any browser, we're going to get this Hi, your browser decoded this. So, basically what we did was we encoded this SVG file, and put this data image, SVG plus xml colon base 64, so our browser knew how to decode it, and then just passed the entire image through our browser URL. And boom. So, we can also do this with images. So, if I go back to the repo associated with this lesson, go to images, dynamic NFT, we go to happy.svg, we go down to code instead of preview, and see the exact code here, right? So we create this viewBox, oops, we create some circles, we create this path, which is how we just kind of draw lines, and I can copy this whole thing, paste it into my image, so I'm going to say, oops, image, I'm going to do happy.svg, happy.svg, paste it in here. If I pull up the preview, I see the preview is a happy. Now what I can do is I can do base 64 - i happy.svg, we get this output. I can copy this output. Let me go over to the README, paste it. I'm going to add this beginning piece to it, and then copy this whole thing. We go back to my browser, paste it in, and boom. We've passed all of this data to generate this SVG right in the URL. And, this is looks like Yes it does. a token URI, right? So, now, instead of using an IPFS hash for our token URI, we can actually 100% on-chain use this SVG thing. And, because this SVG is basically coded on chain, we can update it and interact with it to make it do whatever we want it, right? + +For example, if our has happy SVG, we could say, okay, if if somebody has 10 tokens, right, they get 10 circles or something like that, right? We could do whatever we want with this. +```bash +base64 -i happy.svg +``` +Welcome back. \ No newline at end of file From bdb6730c34dd803f479815b8f202d262631295c5 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:28:55 -0700 Subject: [PATCH 172/255] Equious updated courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md. --- .../1-moccasin-nft/13-mood-nft/+page.md | 45 ++++++++++++++++--- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md b/courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md index 1ec100844..3ce690402 100644 --- a/courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md +++ b/courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md @@ -1,5 +1,40 @@ - - --- - title: Mood Nft - --- - \ No newline at end of file +Now that we know what an SVG is and how we can code it, we can use this coding to build an NFT where all the metadata is stored directly on chain. Let's go ahead and build this NFT. + +We'll call our new contract "mood_nft.vy" and inside we will code: + +```javascript +pragma version 0.4.0 +@license MIT +@title Mood NFT +``` + +We'll use a few imports here: + +```javascript +from snekmate.tokens import erc721 +from snekmate.auth import ownable as ow +``` + +We will then define a constructor for our contract: + +```javascript +initializes: + ow + erc721: ownable = ow + +def init(): + ow._init() + erc721.init_(NAME, SYMBOL, BASE_URI, NAME, EIP_712_VERSION) +``` + +Finally, we'll need to define some state variables: + +```javascript +# STATE VARIABLES +NAME: constant(String[25]) = "Mood NFT" +SYMBOL: constant(String[5]) = "MNFT" +BASE_URI: public(constant(String[34])) = "https://gateway.pinata.cloud/ipfs/" +EIP_712_VERSION: constant(String[1]) = "1" +``` + +We are now ready to start deploying our dynamic NFT, which we'll do in the next video! From 2877d017ce289397b91e6bf2aba0bd0f32f3ab27 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:29:08 -0700 Subject: [PATCH 173/255] Equious updated courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md. --- .../14-base-64-encoding-images/+page.md | 86 +++++++++++++++++-- 1 file changed, 81 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md b/courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md index 0090106c4..00a80067f 100644 --- a/courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md +++ b/courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md @@ -1,5 +1,81 @@ - - --- - title: Base 64 Encoding Images - --- - \ No newline at end of file +## Base64 Encoding Images + +In this lesson, we will learn how to encode an image to Base64. + +First, we will create a new folder called "images" and save our two SVG files (happy.svg and sad.svg) in it. + +Next, we will import the base64 library and create a new function: + +```python +import base64 + +def svg_to_base64_uri(svg): + svg_bytes = svg.encode("utf-8") + base64_bytes = base64.b64encode(svg_bytes).decode("utf-8") + return f"data:image/svg+xml;base64,{base64_bytes}" +``` + +Now, we can use the `svg_to_base64_uri()` function to encode our SVGs to Base64 and assign the results to the `happy_svg_uri` and `sad_svg_uri` variables. + +```python +def deploy_mood(): + happy_svg_uri = "" + sad_svg_uri = "" + with open("./images/happy.svg", "r") as f: + happy_svg = f.read() + happy_svg_uri = svg_to_base64_uri(happy_svg) + print(happy_svg_uri) + + with open("./images/sad.svg", "r") as f: + sad_svg = f.read() + sad_svg_uri = svg_to_base64_uri(sad_svg) + + mood_nft = mood_nft.deploy(happy_svg_uri, sad_svg_uri) +``` + +Finally, we will import the "mood_nft" contract and use it to pass our encoded image data. + +```python +from src import mood_nft +``` + +```python +def deploy_mood(): + happy_svg_uri = "" + sad_svg_uri = "" + with open("./images/happy.svg", "r") as f: + happy_svg = f.read() + happy_svg_uri = svg_to_base64_uri(happy_svg) + print(happy_svg_uri) + + with open("./images/sad.svg", "r") as f: + sad_svg = f.read() + sad_svg_uri = svg_to_base64_uri(sad_svg) + + mood_nft = mood_nft.deploy(happy_svg_uri, sad_svg_uri) +``` + +We can then run our script using the following terminal command: + +```bash +mox run deploy_mood_nft +``` + +This will return a Base64 encoded string that can be used to render our SVG image in a browser. We can copy and paste the string into our browser to verify that it works as expected. + +We will then make the `happy_svg_uri` and `sad_svg_uri` constant variables in our contract file. + +```python +HAPPY_SVG_URI: immutable(String[800]) = "" +SAD_SVG_URI: immutable(String[800]) = "" +``` + +We will pass these into the constructor of the contract so the image data is stored there. + +```python +def init(happy_svg_uri: String[800], sad_svg_uri: String[800]): + ow.init() + erc721.init(NAME, SYMBOL, BASE_URI, NAME, EIP_712_VERSION) + HAPPY_SVG_URI = happy_svg_uri + SAD_SVG_URI = sad_svg_uri +``` \ No newline at end of file From 6060539357fc98476c8d0f6ec338121913807d59 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:29:22 -0700 Subject: [PATCH 174/255] Equious updated courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md. --- .../15-base-64-encoding-json/+page.md | 89 +++++++++++++++++-- 1 file changed, 84 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md b/courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md index 908004ce2..de542ec33 100644 --- a/courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md +++ b/courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md @@ -1,5 +1,84 @@ - - --- - title: Base 64 Encoding Json - --- - \ No newline at end of file +## Base64 Encoding JSON on-chain + +We are going to gloss over some of the actual method we use to do this. It's really low level and not critical to your learning. If you want to pause and try to figure out how to base64 encode the JSON string yourself, or figure out how it works, go for it! + +So, now we have the SVG stored here, we need to figure out how to convert this, or add this to the token metadata, right? 'Cause this is what we need to show. Right? Something that looks like like this. + +So, what we can do, and this is why we didn't export the ERC721 functions, is we can actually create our own + +```python +@external +def tokenURI(token_id: uint256) -> String[FINAL_STRING_SIZE]: + pass +``` + +function ourselves. + +So, if we go to the ERC721.vy look up def tokenURI. We can do the exact same thing. It does except we're going to have our tokenURI. Actually let's do return like this. We are going to have our tokenURI do some clever stuff. + +So, we need to create a tokenURI that returns something that looks like this. + +Right? So, what we can do is we can use the concat feature in Vyper. + +So Vyper has another built in function called concat which takes two or more bytes arrays, or basically strings, of type bytes, bytes or string, and combines them into a single value. If the input arguments are all string, the return type is string, otherwise it's will be bytes. + +So, what we can do is, I can do a little I can say json string. We'll say string 1024 equals concat and this is where I can literally pass in this kind of data here. Right? So, I could say a little single quote bracket name double quote single quote comma. And here's where it's going to get a little confusing. So, we're basically going to be piece mailing together this this JSON object, but then we'll say name comma single quote double quote comma double quote description + +```python +json_string: String[1024] = concat( + "{\"name\":", NAME, ", \"description\":\"A Mood NFT that reflects the mood of the owner, 100% on Chain!\",", + "\"attributes\":[{\"trait_type\":\"moodiness\",\"value\":100}],\"image\":\"", + image_uri, + "}\"" +) +``` + +um and if you want, if you're like, "What? I'm going to screw this up because there's all these single quotes and double quotes." You just go to the GitHub repo associated with this. Go to src/ mood-nft.vy scroll down to the tokenURI and just copy this section here. Right? Just, just so that you don't actually screw something up. You don't have imageURI yet, but that's okay. So, this is kind of us piece mailing together that JSON string that JSON metadata. Right? The only thing that we don't have yet is the imageURI, so we could though, we could just say imageURI type string 800 equals happy SVGURI, right? Boom. And this would this would make a JSON string that looks you know, just like this, but with this imageURI of the happy SVGURI. Nice. Now this having this JSON string is great, but the tokenURI needs to return a tokenURI, right? And this this needs to return something that looks like, you know, ipfs/ blah blah blah blah blah, right? Not this JSON thing, this or like https/ blah blah blah blah blah. And then this returns this. I know that's kind of confusing, but so we need to convert this. We need to encode this to be base64 encoded. And, don't worry, we're going to make this dynamic pretty soon. + +So, when I was originally creating this course, I was going to walk you through kind of the giant process of converting this from a string to a base64 encoded object, but I don't know if it's really worth it because it's just kind of like a lot of math with the base64 encoding and doing all this weird chunking and stuff. So, here's what I'm going to say that you can do for now. Same thing. Go to the GitHub repo associated with this. scroll down and you'll see this SVG to URI and this set indice truncated. Copy both of those. Bring them over to the contract. Paste them in and and up at the top you're going to have to say from + +```python +from snekmate.utils import base64 +``` + +You're going to need to do final string size is going to be a constant uint256 equals it's going to be four times base + +```python +FINAL_STRING_SIZE: constant uint256 = 4 * base64.DATA_OUTPUT_BOUND + 80 +``` + +constant and then additionally you're going to have a JSON base URI which will be a constant + +```python +JSON_BASE_URI: constant String[29] = "data:application/json;base64," +``` + +string of 29 equals data colon application slash JSON semicolon base64 comma and then you're going to need an image base URI size. image base URI size constant + +```python +IMG_BASE_URI_SIZE: constant uint256 = 26 +``` + +constant + +```python +IMG_BASE_URI: constant String[IMG_BASE_URI_SIZE] = "data:image/svg+xml;base64," +``` + +of constant string of size that equals data colon image slash SVG plus XML base64. + +So, I know this is a little bit anticlimactic in working with this this stuff, but we do kind of a lot of low level Vyper stuff here which I could walk you through, but what I'd rather do is I'd actually rather just teach you all the different concepts that are in here so that you know what this is doing. We do our sub lessons, which is going to teach us about ABI encoding and decoding, so that you can understand everything in here. But, actually writing it, I think it will kind of go over a lot of your heads at the moment, so I know, like like I said, it was a little anticlimactic, but just copy paste this. I'm going to explain what these do and yeah, and then actually same thing with the with the tokenURI, we're going to cheat a little bit more here. Go to the GitHub repo underneath the JSON string, there's all of this stuff. Just copy this for now. Paste it in JSON base URI size. We need that as well. JSON base URI size is going to be constant uint256 equals 29. So, I know that's kind of a lot of copy pasting. Return results. And, this is going to be final string size like that. So, a bit anticlimactic, but let me walk you through kind of all this stuff that we just put in here. What the heck is going on? um so that we can actually understand this code and and keep going. + +So, we were running into the problem where this is what we had. Right? We had JSON string and we had nothing else. We basically had like kind of this object like this this stringified object. Right? And, we needed to convert it from the stringified object to a tokenURI. Right? Something that looks like this, like a base64 encoded tokenURI. And, what we did to do that was first we converted it from a string to a bytes using the Vyper built in convert. And, this is where it starts to get weird is + +```python +json_bytes: Bytes[1024] = convert(json_string, Bytes[1024]) +``` + +We chunked it. So, we called base64.encode. If you look in your lib here in the lib, pypi snekmate.utils base64, there's this encode function that it has and essentially what it does is it returns the maximum 4-character user-readable string array that combined results in the base64 encoding of data. What does that mean? Well, this encode function basically converted this JSON bytes into the base64 encoded object except instead of it being a string it was this array of arrays. Right? So it's this kind of low level blah blah blah comma uh, OX blah blah blah or, I guess it's four here. Yeah, so it's this low level array of arrays which is essentially a base64 encoded string and we needed to take it from this weird array of arrays bytes data and convert it into a string. So, we loop through the array, created this custom function called set indice truncated which did some kind of bizarre array multiple uh, array manipulation and then did this weird ABI encode and decode which we definitely have not gone over and we will go over very soon. Essentially, it was, we looped through this array of raw bytes data and we updated it into a string and boom return results. That's kind of the final string the base64 encoded string. So, essentially we did a lot of weird encoding and decoding stuff, array manipulation to get this JSON object from a JSON string into a base64 encoded string. Everything in here you pretty much should recognize. Right? Everything in here you pretty much should recognize. So, we have this encode function. We don't really know what it does, but we have a dynamic array of type string four. So, you yes you can have an array of strings. This is the max size here. That's one we understand. Yep, we understand this. We understand this. We have a four loop here. Great. We understand four loops. We have this set indice truncated. + +```python +encoded_chunks: DynArray[String[4]] = base64.encode(json_bytes, True) +``` + +slice is new, slice is something we haven't gone over, but it's pretty straightforward, basically copies a list of bytes and returns a specified slice. So, for example um yeah, here's here's a perfect example. example contract .foo why hello, how are you? If we just say, hey grab grab just a slice of this string starting at position four and going for five. So, we'd go 0 1 2 3 4. We'd start with the H. We go for 5 1 2 3 4 5. Boom, and it prints out hello. So slice is just getting like a subsection of an array. So, for example this string 32 elements size four, we would just get hello. But, the thing we do not know is this ABI encode and decode and we're finally going to learn what this is. How does this ABI encode stuff and so much more. PP. From b6821011d90989ae11de6d379e2017a2218c4bf9 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:29:36 -0700 Subject: [PATCH 175/255] Equious updated courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md. --- .../1-moccasin-nft/16-abi-encoding/+page.md | 147 +++++++++++++++++- 1 file changed, 142 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md b/courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md index 46afd45b0..86a126c20 100644 --- a/courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md +++ b/courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md @@ -1,5 +1,142 @@ - - --- - title: Abi Encoding - --- - \ No newline at end of file +## ABI Encoding Introduction + +We are going to jump over to Remix so we can show you some encoding and decoding examples. + +Let's make a function: + +```python +@external +@pure +def combine_strings(string_one: String[50], string_two: String[50]) -> String[100]: + return concat(string_one, string_two) +``` + +We will compile this using the Vyper compiler and deploy it. + +We can call the `combine_strings` function to see how it combines two strings: + +```python +combine_str(string_one, string_two) +``` + +Let's try calling the function with two strings: + +```python +combine_str('hi', 'hello') +``` + +The output is: + +``` +0: string: hihello +``` + +We can also encode numbers using the `abi_encode` function. Let's make a function to encode a `uint256` number: + +```python +@external +@pure +def encode_number() -> Bytes[128]: + amount: uint256 = 1 + return abi_encode(amount) +``` + +Compiling and deploying this, then calling the `encode_number` function, will output a hex representation of the number 1: + +```bash +encode_nu +``` + +The output will be: + +``` +0: bytes: 0x0000000000000000000000000000000000000000000000000000000000000001 +``` + +We can also encode strings. Let's make an internal, pure function to encode a string: + +```python +@internal +@pure +def _encode_string() -> Bytes[128]: + my_string: String[50] = "Hello World!" + return abi_encode(my_string) +``` + +Then, let's make an external, pure function to call the `_encode_string` function and return the output: + +```python +@external +@pure +def encode_string() -> Bytes[128]: + return self._encode_string() +``` + +After compiling and deploying, then calling `encode_string`, we will see the hex representation of the string "Hello World!". + +We can also decode strings and numbers from their hex representations. Let's create a function that will decode the hex representation of a string back into a string: + +```python +@external +@pure +def decode_string(string: String[50]) -> String[50]: + return abi_decode(string, String[50]) +``` + +We can also do multiple encodes and decodes. Let's make an internal, pure function to encode multiple strings: + +```python +@internal +@pure +def _multi_encode() -> Bytes[256]: + my_string: String[50] = "Hi Mom" + my_string_two: String[50] = "Miss you" + return abi_encode(my_string, my_string_two) +``` + +Let's make an external, pure function to call the `_multi_encode` function: + +```python +@external +@pure +def multi_encode_view() -> Bytes[256]: + return self._multi_encode() +``` + +Let's make an external, pure function to decode multiple strings: + +```python +@external +@pure +def multi_decode(string: String[50]) -> (String[50], String[50]): + my_encoded_strings: Bytes[256] = self.multi_encode() + my_string: String[50] = empty(String[50]) + my_string_two: String[50] = empty(String[50]) + return abi_decode(my_encoded_strings, (String[50], String[50])) +``` + +We are now able to encode numbers and strings as hex bytes and decode them back to their original data types. This is very useful for working with raw calls. + +Remember when we did the `buy_me_a_coffee` example? + +We made a raw call with bytes of zero, which will unlock the power to call any contract without using an interface or an ABI. You can build the bytes yourself to call the right function. + +Let me show you. We are going to learn about function selectors, function signatures and how ABI encoding fits in. + +This is the line that we had you copy-paste earlier, and we now know what this function is doing: + +```python +return abi_decode(abi_encode(buffer), String[FINAL_STRING_SIZE]) +``` + +The `abi_encode` function takes the `buffer` object, which is of type string and encodes it to be of type `bytes`. We then call `abi_decode` to decode the bytes back to a string of a given size (`FINAL_STRING_SIZE`). + +So we have a buffer object and we encode it to a bytes object. We then decode the bytes object back to a string of a given size. We call this encoding and decoding of bytes and strings a raw call. + +Let's take a look at the `buy_me_a_coffee.vy` file: + +```python +raw_call(OWNER, "tm", value = self.balance) +``` + +We use the `raw_call` function. We learned about `raw_call` in a previous video. From efd4b126ab7dcce9dde04e7f5e74965ef2fae09f Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:29:50 -0700 Subject: [PATCH 176/255] Equious updated courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md. --- .../+page.md | 136 +++++++++++++++++- 1 file changed, 131 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md b/courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md index 8e2d34d02..40f95ebc2 100644 --- a/courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md +++ b/courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md @@ -1,5 +1,131 @@ - - --- - title: Function Selectors And Signatures - --- - \ No newline at end of file +## Function Selectors and Function Signatures + +Let's create a new file called `call_anything.vy`. We'll unlock your superpower here. We'll take this code and stick it into our new file: + +```python +# pragma version 0.4.8 +@license GPL-3.0-or-later +@title Encoding +# ... +def transfer(to: address, amount: uint256): + self.some_address = to + self.amount = amount +# ... +``` + +Let's break down this contract. We have a state variable called `some_address`, which is a public address. We also have a state variable called `amount`, which is a public uint256. We have a function called `transfer`. It takes two arguments: `to`, which is an address, and `amount`, which is a uint256. This function simply updates the state variables `some_address` and `amount`. + +Now, imagine two contracts, Contract A and Contract B. Contract A calls `transfer` on Contract B. How does Contract A know which `transfer` function to call? Well, on chain, everything is represented as hex data. + +Vyper does a lot of encoding and decoding behind the scenes. It's the same way that we encode numbers and strings. We can encode function selection, too. + +Recall when we were deploying our first contract in web3.py, we built transactions. If we look at the ethereum.org documentation on transactions, we'll find a section called "The data field". This field contains the instructions for what we want a contract to do. We send this data to the contract's address, and this data, or the input, represents the instructions. If we look at any transaction that does something other than just transferring raw ETH, we will always see this input data field. + +Let's take a look at an example on Etherscan. If we view the input as raw, we'll see a jumble of hex data. This hex data tells the contract what to do. + +This hex data is often called the "called data", and this "called data" is essentially the computer's encoded version of our instructions. + +Let's go back to our contract. If we want to call `transfer` on Contract B, we need to pass some data to Contract B. If we compile and deploy this contract: + +```python +# pragma version 0.4.8 +@license GPL-3.0-or-later +@title Call Anything +# ... +def transfer(to: address, amount: uint256): + self.some_address = to + self.amount = amount +# Us -> Contract B (transfer) +``` + +We'll deploy it, then we can call this function. We will provide an address and an amount, then we will call transfer. We'll click the button and watch what happens in the terminal: + +```bash +commands +``` + +The data that is being passed to the contract is the ABI-encoded version of the function call. + +Let's take a step further and call `transfer` without any parameters. We'll redeploy this contract: + +```python +# pragma version 0.4.8 +@license GPL-3.0-or-later +@title Call Anything +# ... +def transfer(): + self.amount = 100 +# Us -> Contract B (transfer) +``` + +We'll redeploy it. And, we'll call `transfer` in our remix terminal. + +The input data is: + +```python +0x8a4068dd +``` + +This input is known as the function selector. The function selector is the first four bytes of the function signature ABI encoded. We can actually calculate this ourselves, and there are a few ways to do this. + +For example, we can create a function called `_get_selector_` in our contract: + +```python +# pragma version 0.4.8 +@license GPL-3.0-or-later +@title Call Anything +# ... +def transfer(): + self.amount = 100 +# Us -> Contract B (transfer) +def _get_selector_one() -> bytes4: + return method_id("transfer(address, uint256)", output_type=bytes4) +``` + +We'll redeploy it. + +Then, we can call this function in the remix terminal to get our function selector: + +```bash +commands +``` + +We get the same function selector we got in the previous example. + +Vyper provides a built-in function called `method_id`. We can use this function to calculate the function selector. In Solidity, these values are known as function selectors, and in Vyper, they are called method ID's. It's basically the same thing. + +We could also create a function called `_get_selector_one` in our contract and return `bytes4`. + +```python +# pragma version 0.4.8 +@license GPL-3.0-or-later +@title Call Anything +# ... +def transfer(): + self.amount = 100 +# Us -> Contract B (transfer) +def _get_selector_one() -> bytes4: + return method_id("transfer(address, uint256)", output_type=bytes4) +def get_selector_one() -> bytes4: + return self._get_selector_one() +# Example function selector: +# 0xa9059cbb +# Example Function Signature +# "transfer(address, uint256)" +``` + +And we'll redeploy it. + +Let's call `get_selector_one` in remix. + +The function selector returned is: + +```python +0xa9059cbb +``` + +The same as before! + +The function selector is the first four bytes of the function signature ABI-encoded. So, if we had this `transfer` function, and we were to ABI encode this, the first four bytes would be this. + +Let's summarize this lesson. Anytime we call a function, it gets converted to this hex data. This hex data contains the function selector. Function selectors are an important part of interacting with smart contracts. We use them to identify the specific function we want to call. From c4164c683ef5b833d76488ec03ba48bad7b7ea18 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:30:04 -0700 Subject: [PATCH 177/255] Equious updated courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md. --- .../18-calling-functions-raw/+page.md | 46 +++++++++++++++++-- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md b/courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md index 7e6b2afb8..d93129979 100644 --- a/courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md +++ b/courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md @@ -1,5 +1,41 @@ - - --- - title: Calling Functions Raw - --- - \ No newline at end of file +## Calling Functions Using "raw" Hexdata + +We can call any other smart contract from our contract using raw hex data without using the ABI library. To do this, we need to define our function with the following: + +```python +@external +def call_function_directly(address_to_call: address, address: address, new_amount: uint256, update_address: address) -> Bytes[32]: + success: bool = False + response: Bytes[32] = b'' + success, response = raw_call( + address_to_call, + abi.encode( + update_address, + new_amount, + method_id='transfer(address,uint256)' + ), + max_outsize=32, + revert_on_failure=False + ) + assert success + return response +``` + +In this example, we: + +1. Define a function called `call_function_directly` with the following parameters: + * `address_to_call`: the address of the contract we are calling. + * `address`: the address to send the tokens to. + * `new_amount`: the amount of tokens to send. + * `update_address`: the address to update. + +2. We set the `success` variable to `False` and the `response` variable to an empty bytes object. +3. We use the `raw_call` function with the following parameters: + * `address_to_call`: the address of the contract we are calling. + * `abi.encode`: encoding our data (we use the `abi` library to encode our data). + * `max_outsize=32`: the maximum size of the response. + * `revert_on_failure=False`: set to `False` in case of failure. + +4. We then assert that the `success` variable is `True` and return the `response`. + +By using the `raw_call` function, we can directly call any other smart contract without using the ABI library. This can be useful for interacting with contracts that do not have an ABI available. From ba8dda0fb9ab229a0bb5ec1b7ff26067a582b79a Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:30:17 -0700 Subject: [PATCH 178/255] Equious updated courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md. --- .../19-manually-crafting-calldata/+page.md | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md b/courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md index 3aea25cb0..294b38f21 100644 --- a/courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md +++ b/courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md @@ -1,5 +1,30 @@ - - --- - title: Manually Crafting Calldata - --- - \ No newline at end of file +## Manually Creating The Hexdata + +We've learned how to use remix to send raw hexadecimal data to our contracts. This hexdata that is sent is also known as the *calldata*. + +Now we can go a step further. Let's check this out. We'll go back in our terminal. + +We can use the *cast* tool to manually create the hex, doing the same thing that we did in *vipper*. We can do +```bash +% cast calldata --help +``` + +We can see it takes the function signature and the arguments, and it will encode them to create that hex object. + +Let's clear. We'll do +```bash +% cast calldata "transfer(address,uint256)" +``` + +Let's use the address for account four in Metamask: +```bash +% cast calldata "transfer(address,uint256)" "0xBC989fDe54Ca4d2aB4392Af6dF60f6d04873A033A" +``` + +And for an amount we'll do 31337. Enter. + +So, this is the raw hex here, and now if we copy this, the amount right now is 100 and some address is this one. We can paste this raw data into the low level interactions, and hit transact. + +Now we can scroll up and see the amount is now 31337 and some address has also been changed. + +This is how we can use low level power to call anything. We now know how this hex data in transactions is being generated. We can make sure we know what's going on here, what the first section is, et cetera. From a6818d51aa473adda5141a6821b8602bb6dfe879 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:30:31 -0700 Subject: [PATCH 179/255] Equious updated courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md. --- .../1-moccasin-nft/2-setup/+page.md | 79 +++++++++++++++++-- 1 file changed, 74 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md b/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md index b8774470f..8772725d8 100644 --- a/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md +++ b/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md @@ -1,5 +1,74 @@ - - --- - title: Setup - --- - \ No newline at end of file +## Project Setup + +We are once again in our `mox-cu` folder and we're going to create a new project called `mox-nft-cu`. + +```bash +mkdir mox-nft-cu +cd mox-nft-cu +``` + +We'll do a `mox init --vscode --pyproject` to initialize the project with Visual Studio Code. + +```bash +mox init --vscode --pyproject +``` + +After the command runs, we'll open the folder in Visual Studio Code by running: + +```bash +code . +``` + +You can also do this by going to `File > Open` and selecting the folder in your file explorer. We'll then open Visual Studio Code in a new window. + +Next, we'll delete the default files generated by `mox init` so we can start with a clean slate. We'll also open the `README.md` file to add a description of what we will be building. + +We will be creating two NFTs. The first is a basic NFT, to get familiar with the basics of creating NFTs. The second is a more advanced NFT that will have a dynamic image. We will call this the `mood` NFT. The image will change depending on a `mood` parameter. If the parameter is set to `happy`, then we'll display a smiley face image. If the parameter is `sad`, then we'll display a frowning face. + +```bash +cd images/dynamic/ +``` + +We'll then open the `happy.svg` and `sad.svg` files in our browser to view them. + +```bash +cd .. +``` + +We can then create the two NFT contracts to fulfill our needs. + +```bash +mox create mood-nft +mox create basic-nft +``` + +Let's create a script to deploy both of these NFTs. + +```bash +mox create deploy-script +``` + +Now let's open the `deploy-script.py` file: + +```bash +cd script +code deploy.py +``` + +We'll edit `deploy-script.py` and include the following code: + +```python +from src.mocassin.tools import Counter +from boa.contracts.vyper_contract import VyperContract + +def deploy() -> VyperContract: + counter: Counter = Counter.deploy() + print("Starting count:", counter.number()) + counter.increment() + print("Ending count:", counter.number()) + return counter + +def moccasin_main() -> VyperContract: + return deploy() +``` + From 05609551489a4184be7c2c71bddd17eacaa7a129 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:30:44 -0700 Subject: [PATCH 180/255] Equious updated courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md. --- .../20-mid-section-recap/+page.md | 47 +++++++++++++++++-- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md b/courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md index 328000d3c..f2093a248 100644 --- a/courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md +++ b/courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md @@ -1,5 +1,42 @@ - - --- - title: Mid Section Recap - --- - \ No newline at end of file +We learned about encoding, which is how we can represent various data types in hex and bytes, such as strings, numbers, and concatenated strings. We then looked at how the EVM uses encoding to build function calls, such as `transfer(to: address, amount: uint256)`, which is the function signature of a function we've used before. + +We can decode this using the built-in `method_id` function, which returns the function selector. This function selector will look like this: + +```python +return method_id("transfer(address,uint256)", output_type=bytes4) +``` + +The first four bytes of the encoded function call will be the function selector, which tells the contract which function to call. + +We then saw how we can use `raw_call` to call a function directly. We can combine a function signature with parameter values and create the raw hex data we need to make a function call. In the below example, we can use `raw_call` to call the transfer function. + +```python +def call_function_directly(address_to_call: address, new_amount: uint256, update_address: address): + success: bool = False + response: Bytes[32] = b"" + success, response = raw_call( + address_to_call, + abi_encode( + update_address, + new_amount, + method_id="transfer(address,uint256)" + ), + max_outsize=32, + revert_on_failure=False + ) + assert success + return response +``` + +The `abi_encode` function will encode the arguments with the `method_id` and return raw hex data. + +We also saw how we can import interfaces to call functions within the imported contract. For example, we can call the `transfer` function within an imported contract called `myInterface`. + +```python +from interfaces import myInterface +myInterface(address).transfer(to_call: address, amount: uint256) +``` + +We can also use raw hex data to make calls to other contracts without using the ABI or interface. + +This is a little bit of a deeper dive into EVM function calls, but we'll practice more in the future. From eff37d22a4327fcb0995601852caeddb7f66ae3d Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:30:58 -0700 Subject: [PATCH 181/255] Equious updated courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md. --- .../+page.md | 61 +++++++++++++++++-- 1 file changed, 56 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md b/courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md index 86bf6d8ca..4388a6f12 100644 --- a/courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md +++ b/courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md @@ -1,5 +1,56 @@ - - --- - title: Verifying Calldata In Metamask - --- - \ No newline at end of file +## NFTs: Verifying Metamask Transactions + +We're going to learn how to verify transactions in Metamask and this is so powerful so that you don't accidentally sign transactions that you don't want to sign. So you don't accidentally sign transactions that are malicious. This is how you can make sure that the call data that you get in your Metamask is actually what you expect. + +This is going to be a little excerpt from the Foundry/Solidity of Sifon Updraft. So there might be references to Foundry or Solidity but it's all basically the same. So let's go ahead, let's follow along here and learn how to verify transactions in Metamask. + +We can finally go back to what we were talking about with Metamask and that decoding the transaction data and all this weird stuff. If we come to a contract address, and this is WETH. This is a contract that wraps native ETH and turns it into an ERC20 token. But, if we come to a contract, right, we hit "write contract", let's connect to web3. Sure. You don't have to actually do this, just feel free to follow along with me. We're going to open up our Metamask. Let's go to Sepolia here. We're going to connect here. Okay, cool. + +And, we wanted to call "transferFrom", right? And let's just add some stuff here. Let's do source address and you know, this. This is probably won't go through, cuz I don't have any WETH right now. But let's just hit, right, "Write". This transactions Metamask is probably going to be like, "Hey, this is going to fail." Whatever. Yeah, sure, whatever. But, when we get a Metamask transaction that pops up, if we scroll over to the hex, we scroll down. We can now actually start to understand what is going on here. + +And, this is what we always want to make sure is actually correct when we're working with our Metamask and when we're dealing with all of this. So, what we can do is we can actually copy this whole thing and pull up our terminal here. I'm just going to make this nice and big here. What we can do is we can do "cast --help". We hit "cast --help" and we scroll all the way up. There's a command in here called "calldata-to-code". To code ABI encoded input data. So, if we do +```bash +cast --calldata-decode +``` +we can see we need to pass in a sig and the call data. + +So, luckily, for this transaction, our Metamask was smart enough to know that we're calling the "transferFrom" function. But sometimes, it's actually not going to be smart enough to figure this out. So, that's where we are going to need to match what we expect this to be calling. To what it's actually calling, right? So first off, we are expecting this to be calling the "transferFrom" function. So, I can grab this function selector, which we just learned. Come back here. I can do +```bash +cast sig +``` +I'll pass pass in here "transferFrom" the whole function signature, which what? It takes an address, address, and a uint256. So we'll do address, address, uint256. + +And, we'll see that this is what the function selector should be. So, I can say, "Okay, great. The two of these match". This indeed is calling the function selector that I wanted to call. Okay, awesome. If it doesn't match, what can happen sometimes, again we can go to something like the Sam CZ Sun signature database or openchain.xyz/signatures. Paste this in, hit search. And we can see that there's actually two different functions that have the same signature. One is "transferFrom" and one is "gasprice_bit_ether" with an int 128. + +So, what's interesting here is you can't have a function with the same function selector. So, if I actually went into Remix/solidity.org, let's actually create a new contract called conflicting.sol. Right. And we'll do a little a little zoom in here. +```solidity +SPDX-License-Identifier: MIT contract Conflicting { + function transferFrom(address, uint256, address) public { + // hello, uint256 sup + } + function gasprice_bit_ether(int128) public { + // sup + } +} +``` +And I try to compile this. Guess what's going to happen? Compile. + +No, let's pragma solidity 0.8.18. This should be an address too. And now I try to compile. We scroll down, it'll say function signature hash collision for "gasprice_bit_ether" (int128). You can't have a contract in Solidity where two functions have the same function selector. + +So, in any case, we could be calling one of these two functions on our. This is where it's important to actually go through the contract code and say, "Hmm, there could be a couple different function selectors here. Let's make sure it's the one that we expect", right? So, in any case, so this is calling this "transferFrom" function. + +If this contract has a gas bit "gasprice_bit_ether", it might be calling that. But, in any case, we know, so we could go through the code, right? We go through "transferFrom". Okay, great. There's a "transferFrom" function. That is indeed what we want to call. The function selector is working. Perfect. Okay. + +So, now that we've verified the function selector, we should also verify the rest of this stuff. So, now that we know what the function selector is and we know what the function signature is, we can take this whole hex here and go back into our terminal and use that "calldata-to-code". So we can say +```bash +cast --calldata-decode +``` +and we can see what it what we need. We need the sig and the call data. So, I'll hit up, the sig is going to be "transferFrom" and it takes an address, an address, and a uint256, right? We can just double check that. Address, address, uint256. Sure does. + +And, we can paste in that call data and hit enter. And we can see what this call data stuff is using for input parameters to that function. So, it's our address, our address, and then 1,000. And then if that's what we expected, we'll maybe reject this for now. Go back to, right. And, that and if that's what we wanted to call on this function, we would go ahead and put this through. + +This is especially important when we're using front ends, like, for example, if I wanted to use Uniswap, right? Let's go ahead and connect here, to Metamask. Yep, connect. Looks good. Go away. Go to, let's say if I was on ETH mainnet and I wanted to swap ETH for, so so I'm going to test this here, so obviously nothing's showing up, but when I hit swap, if I was on a real network with real money, what I want to do then is do that same process of going through and checking to make sure that the transaction that it's sending is actually the one that I wanted to be sending, right? + +So, if we want to be absolutely sure of what our transactions are doing, we can first check the address. We can take these exact steps to say I know exactly what transaction, I know exactly what function my transaction is calling. So, we check the address to make sure that the contract is what we expected to be. And then, we can read the function of that contract that we want. We check the function selector that we're using, so that it, it, so that we know that it is indeed the function that we're calling. And, then we decode the call data to check the parameters that we're sending. + +So, this is how we can actually make sure our wallets are doing what we expect them to do. From d28adc42075c5b3c016c0a92057dfe37afcef423 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:31:11 -0700 Subject: [PATCH 182/255] Equious updated courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md. --- .../22-finishing-the-mood-nft/+page.md | 152 +++++++++++++++++- 1 file changed, 147 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md b/courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md index 758431000..b428cc95b 100644 --- a/courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md +++ b/courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md @@ -1,5 +1,147 @@ - - --- - title: Finishing The Mood Nft - --- - \ No newline at end of file +## Finishing the Mood NFT + +We've learned a lot about low-level encoding, ABI and calling contracts. We kind of cheated by doing copy-pasting, but if you really want to know what these functions are doing, feel free to pause the video and walk through them yourself. + +We have our token URI but right now it is just happy, right? Because we have image URI set to the happy SVG. + +Of course, what we want to do is create a little `@external` function called `flipMood`. + +Now, in order to flip the mood we're going to need to have some type of state variable that keeps track of the mood, and to do that we're going to create a little enum, or a little flag. + +So up near the top, we're going to create a new flagMood. + +```python +flag Mood: + HAPPY: int128 = 0 + SAD: int128 = 1 +``` + +We could just as easily do a uint256 but this is going to be a better way to write this out. So, we'll say `flag Mood` and then we'll create a storage variable. This will be a storage called tokenId to Mood. This will be a public `HashMap unit256, Mood`. + +```python +# Storage +token_id_to_mood: public(HashMap[uint256, Mood]) +``` + +So, we'll map the token ID of each NFT to a specific mood. + +So when we call `flipMood`, we're going to have to pass in the tokenId, which will be a type unit256. We don't want anybody to be able to flip the mood. We only want the owner of the NFT to be able to flip the mood. + +So the ERC721 contract comes with the function built-in, so we can do `assert ERC721._is_approved_or_owner(msg.sender, token_id)`. + +```python +@external +def flip_mood(token_id: uint256): + assert erc721._is_approved_or_owner(msg.sender, token_id) + if self.token_id_to_mood[token_id] == Mood.HAPPY: + self.token_id_to_mood[token_id] = Mood.SAD + else: + self.token_id_to_mood[token_id] = Mood.HAPPY +``` + +We're also going to need `@external def mintNFT`. And we'll say do the same thing, `tokenId unit256 = ERC721._counter`. + +```python +@external +def mint_nft(): + token_id: uint256 = erc721._counter + erc721._counter = token_id + 1 + self.token_id_to_mood[token_id] = Mood.HAPPY + erc721.safe_mint(msg.sender, token_id, b"") +``` + +We'll say ERC counter, equals tokenID + 1. Then, we'll say `self.tokenId to mood` of that tokenId. We'll set the default to be `Mood.HAPPY`. + +And then, finally, `safeMint` the tokenId with no data. That looks pretty good to me. Let's write a little deploy script for this. Oh, we already have a deploy script. Oh nice, okay cool. uh, mood NFT to deploy. We'll say `mood contract` equals `mood NFT to deploy`. + +```python +# Deploy +mood_contract = mood_nft.deploy(happy_svg_uri, sad_svg_uri) +``` + +And then we'll just do `mood contract.mintNFT`. + +```python +# Deploy +mood_contract = mood_nft.deploy(happy_svg_uri, sad_svg_uri) +mood_contract.mint_nft() +``` + +Does the `def mintNFT`. + +```python +def mint_nft(): + token_id: uint256 = erc721._counter + erc721._counter = token_id + 1 + self.token_id_to_mood[token_id] = Mood.HAPPY + erc721.safe_mint(msg.sender, token_id, b"") +``` + +Then, `print(f"TokenURI: {mood_contract.tokenURI(0)}")`. + +```python +def mint_nft(): + token_id: uint256 = erc721._counter + erc721._counter = token_id + 1 + self.token_id_to_mood[token_id] = Mood.HAPPY + erc721.safe_mint(msg.sender, token_id, b"") +print(f"TokenURI: {mood_contract.tokenURI(0)}") +``` + +So let's try this out. + +```bash +mox run deploy mood NFT +``` + +We get a token URI that looks like this. Okay, great. That looks pretty base64 encoded. Uh-huh, okay. I can even pretty-print this because I'm brave. Let's see if this image looks correct. + +We have a happy smiling face. Now, what though, if we went ahead and did `mood contract.flip mood` of zero. We reran it. Let's try this now. So this is the new token URI. Paste it in here. Get this, paste it up here. It's still sad. So, do we not flip the mood? Look at our `flip mood`. It's happy, make it sad. Oh. Of course, because we forgot to switch it. Because, we actually forgot to update our token URI. + +Of course. Let's do, here we go. Chat GPT got it. If `self.tokenId to mood, tokenId equals Mood.SAD`. + +```python +@external +def flip_mood(token_id: uint256): + assert erc721._is_approved_or_owner(msg.sender, token_id) + if self.token_id_to_mood[token_id] == Mood.HAPPY: + self.token_id_to_mood[token_id] = Mood.SAD + image_uri = SAD_SVG_URI + else: + self.token_id_to_mood[token_id] = Mood.HAPPY + image_uri = HAPPY_SVG_URI +``` + +Make it sad. Now let's try one more time. Great. Let's grab this. Boom, paste it in. Grab the image. Boom, and outside. So in the final bit that we should do in this in here as well is we should really update our our NFT here so that it exports all the functions of an ERC721. + +But remember, we cannot export tokenURI, because we have created one ourselves. What we can do is we can just cheat a little bit. Typically AIs work great at that. We're going to come in here. Go to SRC, mood NFT. Scroll down. There's also some nicer syntax in here and just grab this whole `exports`. + +```python +exports: + erc721.owner, + erc721.balanceOf, + erc721.ownerOf, + erc721.getApproved, + erc721.approve, + erc721.setApprovalForAll, + erc721.transferFrom, + erc721.safeTransferFrom, + # erc721.tokenURI, + erc721.totalSupply, + erc721.tokenByIndex, + erc721.tokenOfOwnerByIndex, + # erc721.burn, + # erc721.safeMint, + # erc721.set_minter, + erc721.permit, + erc721.DOMAIN_SEPARATOR, + erc721.transferOwnership, + erc721.renounceOwnership, + erc721.name, + erc721.symbol, + erc721.isApprovedForAll, + erc721.isMinter, + erc721.nonces, +``` + +And paste it right here. Tada. You can see here that we didn't use tokenURI, we also didn't use `safeMint` or `setMinter`. This is how you can kind of make sure that you know you're not exporting some functions as well. Just kind of commenting them out like that. So, nice. From f3390e345653eb81bd06d651c11eb6369b9688a0 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:31:25 -0700 Subject: [PATCH 183/255] Equious updated courses/advanced-moccasin/1-moccasin-nft/23-workshop-2/+page.md. --- .../1-moccasin-nft/23-workshop-2/+page.md | 94 ++++++++++++++++++- 1 file changed, 89 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/1-moccasin-nft/23-workshop-2/+page.md b/courses/advanced-moccasin/1-moccasin-nft/23-workshop-2/+page.md index 82ac362be..ad98a035b 100644 --- a/courses/advanced-moccasin/1-moccasin-nft/23-workshop-2/+page.md +++ b/courses/advanced-moccasin/1-moccasin-nft/23-workshop-2/+page.md @@ -1,5 +1,89 @@ - - --- - title: Workshop 2 - --- - \ No newline at end of file +## Workshop 2: Mood NFT + +In this workshop, we'll continue our journey into the world of NFTs by working through some real-world workshop examples. We've already learned how to make a basic NFT and customize it. + +Let's start with workshop number 2, which involves creating a "mood NFT." + +The goal of workshop 2 is to: + +1. Deploy your mood NFT to a locally running chain. +2. Flip its mood. +3. View it in Metamask. + +We've already deployed to a local chain in the previous lesson, so we'll focus on the second and third parts of this workshop. + +We've also written some tests for you in the GitHub repo, which you can use to check your work. + +Here are some examples: + +* `test_unit_mood.py` + +```python +import boa +import eth +import pytest +import vyper + +from eth_utils import to_bytes + +STARTING_TOKEN_URI = "data:application/json;base64,eyJ1dGwiOiJTWlZvciIuQzIuQzFJLCAxLjg0djIuOTIuNjk2b29kIE5GVCJ9" +ENDING_TOKEN_URI = "data:application/json;base64,eyJ1dGwiOiJTWlZvciIuQzIuQzFJLCAyLjA0djIuOTIuNjk2b29kIE5GVCJ9" + +def test_initialized_correctly(mood_nft): + assert mood_nft.name() == "Mood NFT" + assert mood_nft.symbol() == "MNFT" + assert mood_nft.token_id_to_mood(0) == 1 # flags are 1 indexed! + +def test_flip_mood(mood_nft): + mood_nft.flip_mood() + assert mood_nft.token_id_to_mood(0) == 2 + +def test_uri_changes_based_on_mood(mood_nft): + assert mood_nft.tokenURI(0) == STARTING_TOKEN_URI + mood_nft.flip_mood() + assert mood_nft.tokenURI(0) == ENDING_TOKEN_URI + mood_nft.flip_mood() + assert mood_nft.tokenURI(0) == STARTING_TOKEN_URI + +def test_safe_mint_fails_if_safe_mint_is_false( + mood_nft, +): + with pytest.raises(Exception) as exc: + boa.env.raw_call( + mood_nft.address, + data_to_bytes( + vyper.utils.method_id("safeMint(address,string)"), + [mood_nft.address, ""] + ), + selector=mood_nft.address, + ) + assert "revert" in exc.value.message +``` + +* `test_unit_sub_lesson.py` + +```python +def test_encoding_string_combination(encoding): + string_one = "Hi Mom" + string_two = "Miss You" + combined = encoding.combine_strings(string_one, string_two) + assert combined == string_one + string_two + +def test_multi_encoding(encoding): + decoded_strings = encoding.multi_decode() + (string_one, string_two) = decoded_strings + assert string_one == "Hi Mom" + assert string_two == "Miss You" + +@pytest.mark.staging +def test_raw_call_anything(raw_call, call_anything): + new_address = "0x8b74378a524f2a866419a6c9e3c2447c9e278c46332" + new_amount = 888 + raw_call.function_call_directly(new_address, new_amount, call_anything.address) + assert call_anything.some_address() == new_address + assert call_anything.some_amount() == new_amount +``` + +We've also written some tests for you in the GitHub repo, which you can use to check your work. We can use those tests to ensure our code is working correctly. + +You can use these tests as a starting point for your own tests and work through the workshops at your own pace. Don't worry if you don't get everything right the first time, you can always refer to the GitHub repo or ask questions in the discussions or Discord. The important thing is to keep learning and experimenting. From 886b3947feb32a1ab5ec33ca84938bccbeba3916 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:31:40 -0700 Subject: [PATCH 184/255] Equious updated courses/advanced-moccasin/1-moccasin-nft/24-recap/+page.md. --- .../1-moccasin-nft/24-recap/+page.md | 120 +++++++++++++++++- 1 file changed, 115 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/1-moccasin-nft/24-recap/+page.md b/courses/advanced-moccasin/1-moccasin-nft/24-recap/+page.md index 520a7c357..1b32ae0b0 100644 --- a/courses/advanced-moccasin/1-moccasin-nft/24-recap/+page.md +++ b/courses/advanced-moccasin/1-moccasin-nft/24-recap/+page.md @@ -1,5 +1,115 @@ - - --- - title: Recap - --- - \ No newline at end of file +## Recap + +In this lesson, we learned about NFTs and how to implement them in our blockchain contracts. We started by defining a basic NFT contract and then built our way up to more complex examples. + +We also learned about ABI encoding and decoding, which is essential for interacting with contracts on the blockchain. We can use ABI encoding to create raw data that can be sent to a contract to call functions. We can also use ABI decoding to get the data from a transaction and understand what function was called and what parameters were passed in. + +Finally, we built a custom token URI for our NFT that dynamically changes based on the mood of the owner. This was accomplished by adding a �flip mood� function to our NFT contract, and we used a mapping to store the mood of each token. + + +Here�s an example of the code we created: + +```python +# pragma version 0.4.0 +# license MIT +# title Mood NFT + +from snekmate.tokens import erc721 +from snekmate.auth import ownable as ow +from snekmate.utils import base64 + +initializes: ow.Ownable = ow +exports: erc721.Interface + +Flag Mood: + HAPPY + SAD + +HAPPY_SVG_URI: immutable String[800] = "" +SAD_SVG_URI: immutable String[800] = "" +FINAL_STRING_URI_SIZE: constant uint256 = 29 +JSON_BASE_URI: constant String[26] = "data:application/json;base64," +IMG_BASE_URI_SIZE: constant uint256 = 29 +IMG_BASE_URI: constant String[128] = "data:image/svg+xml;base64," + +token_id_to_mood: public HashMap[uint256, Mood] + +def _init_: + ow._init_ + erc721._init_(NAME, SYMBOL, BASE_URI, EIP_712_VERSION) + HAPPY_SVG_URI = sad_svg_uri + SAD_SVG_URI = sad_svg_uri + +external: + def mint_nft(): + token_id: uint256 = erc721.counter + erc721.counter = erc721.counter + 1 + self.token_id_to_mood[token_id] = Mood.HAPPY + erc721.safe_mint(msg.sender, token_id, b"") + erc721.set_token_uri(token_id, "happy") + + def flip_mood(token_id: uint256): + assert erc721.is_approved_or_owner(msg.sender, token_id) + if self.token_id_to_mood[token_id] == Mood.HAPPY: + self.token_id_to_mood[token_id] = Mood.SAD + else: + self.token_id_to_mood[token_id] = Mood.HAPPY + + def tokenURI(token_id: uint256) -> String[FINAL_STRING_URI_SIZE]: + image_uri: String[800] = HAPPY_SVG_URI + if self.token_id_to_mood[token_id] == Mood.SAD: + image_uri = SAD_SVG_URI + + json_string: String[1024] = concat( + "{", + '"name": "', NAME, '"', + ",", + '"description": "An NFT that reflects the mood of the owner, 100% on Chain!",', + ",", + '"attributes": [{"trait_type": "moodiness", "value": 1001}, {"image": "', image_uri, '"}', + "]", + "}" + ) + + json_bytes: Bytes[1024] = convert(json_string, Bytes[1024]) + encoded_chunks: DynArray[Bytes[128]] + String[64].encode(base64, json_bytes, True) + base64: encode(json_bytes, True) + + result: String[FINAL_STRING_URI_SIZE] = JSON_BASE_URI + counter: uint256 = IMG_BASE_URI_SIZE + for encoded_chunk in encoded_chunks: + result = self.set_indice_truncated(counter, result, encoded_chunk) + counter += 4 + + return result + + def svg_to_uri(svg: String[1024]) -> String[FINAL_STRING_URI_SIZE]: + svg_bytes: Bytes[1024] = convert(svg, Bytes[1024]) + encoded_chunks: DynArray[Bytes[128]] + String[64].encode(base64, svg_bytes, True) + base64: encode(svg_bytes, True) + + result: String[FINAL_STRING_URI_SIZE] = JSON_BASE_URI + counter: uint256 = IMG_BASE_URI_SIZE + for encoded_chunk in encoded_chunks: + result = self.set_indice_truncated(counter, result, encoded_chunk) + counter += 4 + + return result + + internal: + def set_indice_truncated( + result: String[FINAL_STRING_URI_SIZE], + index: uint256, + chunk_to_set: String[4] + ) -> String[4]: + # We set the index of a string, while truncating all values after the index + buffer: String[FINAL_STRING_URI_SIZE] = concat(result, chunk_to_set) + slice(buffer, 0, index + 4) + return abi.decode(buffer, encode(String[FINAL_STRING_URI_SIZE])) +``` + +We learned that we can get the entire hex data from a transaction by encoding the function selector and parameters with ABI encoding. We can then use this data to call any function on the blockchain. We can even use a block explorer like Etherscan to see the hex data that was sent in a transaction and to verify that it matches the function selector and parameters we used. + +We learned a lot in this section and you should be proud of yourself for completing it. Congratulations! From de8ccf70fc9a4908b3796e98b89137d5075c76c7 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:31:55 -0700 Subject: [PATCH 185/255] Equious updated courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md. --- .../1-moccasin-nft/3-what-is-an-nft/+page.md | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md b/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md index 20ffe0298..e9208077c 100644 --- a/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md +++ b/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md @@ -1,5 +1,25 @@ - - --- - title: What Is An Nft - --- - \ No newline at end of file +## What is an NFT? + +Let's learn about NFTs. + +NFTs stand for Non-Fungible Tokens. They are a token standard similar to ERC20, which we're already familiar with. ERC20s are like LINK, AAVE, MAKER, which are all common tokens on the Ethereum blockchain. + +NFTs are *non-fungible*, meaning they are unique and cannot be directly replaced with another token. Think of a dollar bill. Any dollar bill is equivalent to another. This is *fungible*. + +A Pokemon, on the other hand, is not fungible. It's going to have different stats and different move sets, which makes it unique from other Pokemons. + +The most common way to think of NFTs is as *digital art*. They represent digital items that are unique and incorruptible, with a permanent record of ownership and transactions. + +We can make NFTs do much more than just represent art. We can give them stats, make them battle, or create games. But the current focus is on digital art. + +Since these digital assets are unique, and we want to be able to visualize them, we need a way to define what they look like. This is where *metadata* and *token URIs* come in. + +We can use a decentralized service like IPFS to store our NFTs. + +If you're trying to render an image of an NFT, here's how we can use IPFS: + +1. Get IPFS +2. Add a *tokenURI JSON file* to IPFS +3. Add the IPFS URI to your NFT URI + +In the next lesson, we'll walk through a D&D example using Chainlink. From 04bea29b21463f81ca9a2a93596a1032e3fcc72b Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:32:06 -0700 Subject: [PATCH 186/255] Equious updated courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md. --- .../4-building-an-erc721-contract/+page.md | 88 +++++++++++++++++-- 1 file changed, 83 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md b/courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md index 5ef234088..60f8c6d8f 100644 --- a/courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md +++ b/courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md @@ -1,5 +1,83 @@ - - --- - title: Building An Erc721 Contract - --- - \ No newline at end of file +## Building an ERC721 contract + +We've learned that an NFT is similar to an ERC20. It's the ERC721 standard. + +We can find all about the different functions in this standard by going to the Ethereum website. If we scroll down, we can see some different events. We've learned about events. We know how to make events. We see some different functions as well. These are the Solidity functions, so we can just easily write them as Vyper. + +We could start grabbing these. We could take this, go to our AI agent, and ask it to write this in Vyper, please. We could do this for all of the functions. Or, we could check to see if our good friend Snakemake has one of these already. + +We go to Snakemake, then to SRC / Snakemake / tokens, just like the ERC20.vvy. There's an ERC721. + +We could pause and look through all of the functions here. Now's a great time to pause and look through all of the functions here. A couple of these aren't going to make sense to you. For example, those domain separators, EIP 712. That's something we're going to learn much, much later in this signature section. + +But, if you want to pause, you want to look over some of these functions so that you can really understand what's going on. Great. Otherwise, we're just going to go ahead. We're going to use Snakemake or Snakemake in our codebase to make writing our NFTs much easier. + +We're going to go back over here. I'm going to remove my README, pull up my terminal, and I'm going to do: + +```bash +mox install snekmate +``` + +You'll notice I'm not in a virtual environment, and in a previous lesson I might have told you to go in a virtual environment. We no longer need to be inside of a virtual environment because we made a little issue on UV and they changed it. So this is the power of open source. We made an issue, we said, "Hey, we get this little error here, I have to be in a virtual environment, I don't think I need to be in one, " and the UV people said, "Yup, makes sense," and they changed UV and updated it. Now, we can just run: + +```bash +mox install snekmate +``` + +Nice. So, now we have Snakemake installed. We could also do: + +```bash +mox install psacasfasfasdfas/snekmate +``` + +But, you know, whatever you want to do here. We can see it has been installed in our PyPI folder. And, that is great for us. + +Okay, so we have that installed. Now we can start using it in a new contract called: + +```python +basic_nft.vy +``` + +We'll create a little basic NFT in here. Now, I know in that video we went over some concepts. We'll go over them again in here, because the token UI thing can be a little squirrely. So, we're going to make it make sense. So, let's go ahead, let's do: + +```python +# pragma version 0.4.0 +@license MIT +@title Puppy NFT +from snekmate.tokens import erc721 +from snekmate.auth import ownable as ow +initializes: ow +initializes: erc721(owmable := ow) +@deploy +def __init__(): + ow.__init__() + erc721.__init__(name=NAME, symbol=SYMBOL, base_uri=BASE_URI, name_eip712=NAME_EIP712, version_eip712=VERSION) +``` + +We haven't really gone over BASE URI. We kind of briefly went over it in that "What is an NFT?" video. This doesn't make any sense to you. This doesn't make any sense to you, and that's okay because this These two make sense to you, and this will make sense to you. + + +Now, let's just clean this up a little bit with headers. State or header. + +```python +# STATE VARIABLES +NAME: constant String[25] = "Puppy NFT" +SYMBOL: constant String[5] = "PNFT" +BASE_URI: constant String[7] = "ipfs://" +EIP_712_VERSION: constant String[1] = "1" +``` + +Boom. Let's do: + +```python +# HEADER FUNCTIONS +``` + +Boom. And that looks a little bit nicer already. And then, we're also going to do exports: + +```python +exports: erc721.interface +``` + +So, we get all the functions of the ERC721. Nice. + From 7db73ece9a1078efb44db67ca00bc5866863c7dd Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:32:20 -0700 Subject: [PATCH 187/255] Equious updated courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md. --- .../1-moccasin-nft/5-tokenuri/+page.md | 55 +++++++++++++++++-- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md b/courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md index 9e08dd6eb..9e5a26feb 100644 --- a/courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md +++ b/courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md @@ -1,5 +1,50 @@ - - --- - title: Tokenuri - --- - \ No newline at end of file +## TokenURI / Base URI + +We have our basic NFT setup. Let's go into this base URI thing. + +We briefly talked about what a TokenURI was in the *What is an NFT* video that we just watched. So, just a quick recap: a TokenURI is the URI of the token. A URI is a Uniform Resource Identifier. Basically, it's like a link, right, like `https://some-website.com/some.json.jpg` or even something like this: + +```javascript +"ipfs://Qm16U9B3JY9HB3Y5f8rGUtUiUtwDm6LdEe4dAAgmnrx3t1Ma" +``` + +where the protocol instead of being HTTPS is IPFS. The protocol down here is HTTPS. It's just basically some way of saying "here's a link that you can use to access some type of information." And HTTPS is one of the most popular ones, right? This is what we use on websites every day, right? If I go over here, go to `github.com` We see that up at the top left, we see this HTTPS here. You can have lots of different protocols like IPFS that also work great. + +Now, this TokenURI, this link, this website needs to return JSON or JavaScript object notation, basically, some type of object that looks like this: + +```javascript +{ +"name": "PUG", +"description": "An adorable PUG pup!", +"image": "ipfs://QmSsYRx3LpDAB1gGZom7Zz21AuHZj1fbPKdD6j7S9r41xu1mFF8", +"attributes": [ +{ +"trait_type": "cuteness", +"value": 100 +} +] +} +``` + +and it has a couple of different fields like: name, description, image, and attributes. Image is actually the most important one here, where that must return another link to an image. So, this is another URI, but instead of returning a JSON object, this URI would return an image. And it might return an image that looks like this instead. So, this, this part at the beginning, though, this protocol, this is what's known as the base URI for our NFT, right? So, our base URI here, I said hey, just put in IPFS. Our contract is smart enough to say "Okay, the protocol or the beginning string of your TokenURI is probably going to stay the same." So, set that as your base URI. + +If we go look at the ERC721, and we look up `def tokenURI`, we scroll down here, we can kind of read this code to see what's going on. We see that internally, this contract has this mapping `self.tokenURIs` of token ID which returns this TokenURI, and it has some weird conditionals. But basically, we see this line here: + +```javascript +if (len(token_uri) != BASE_URI.len()): +return concat(BASE_URI, token_uri) +``` + +if the TokenURI isn't empty, then we're just going to concat the base URI plus the TokenURI. Right? For TokenURI, might be something like this, right? So, TokenURI will be something like this: + +```javascript +"ipfs://Qm16U9B3JY9HB3Y5f8rGUtUiUtwDm6LdEe4dAAgmnrx3t1Ma" +``` + +and then the base URI. So, the two of these together will make our actually excuse me, this it would be _tokenURI. So, the two of these together would make our NFT's TokenURI. + +Now, I have already uploaded this image and this TokenURI to something called IPFS, or the InterPlanetary File System. We'll talk about that more in just a second. + +Now, let's go to our basic NFT, and let's make that TokenURI actually customizable. So, we create a little external function called `mint`, and this will take in a URI of string type of length 432. And, we're using 432 because in the ERC721, the internal mapping of TokenURIs is of size string 432. So, we're just going to be matching that. And, what we're going to be doing is in the ERC721.vy from Snekmate, they have this mint function, which will allow us to mint one of these NFTs. So, what we can do is we'll first create a little token ID of type uint256, which will equal ERC721._counter. So, each one of these NFTs is going to have a unique token ID. And inside of here, there's _counter, there's this storage variable _counter, and you can see that every time `safemint` gets called, this gets incremented, um and we're going to do something very similar to what happens in `safemint`. So, then we're going to say 721._safemint. Actually, if we go in here, we do _safe mint. So, this safemint thing, it says it safely mints. Uh, basically, all safemint does is check to see that we're not sending to like a zero address. So, you'll typically see like `safemint` or `safe transfer`, and they do just some additional checks, like checking for zero address. So, we're going to call `safemint`, and we need to send a new owner, token ID, and then data. So, the owner is going to be the message.sender. We're going to let anybody mint our token here. We'll give it a token ID, this token ID that we just got from the counter. And, then, we'll do just blank data. We're going to learn very shortly more about this data stuff and how it works. And particularly, this check on ERC721 received, like why this wants data and what the heck this is, this is Uh that's going to be super exciting when we learn that. + +And, then finally, we're going to do ERC721. _set tokenURI token ID. And, if we look in here, there's also this other function called `set tokenURI`, which does kind of exactly what you'd expect in this `tokenURIs hashmap`. It basically sets it to our TokenURI like so. And, what's nice is we don't have to store the base URI, so we get to save a little bit of gas, not putting this in storage every time. And, we just add in this kind of second half here, if you will, not this IPFS. Oh, and then additionally, we need to make sure we do ERC721._counter equals token ID + 1. We need to make sure we increment the counter as well. From 934621c98f3634178afc92a517190be03bc00735 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:32:35 -0700 Subject: [PATCH 188/255] Equious updated courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md. --- .../1-moccasin-nft/6-deploy/+page.md | 117 +++++++++++++++++- 1 file changed, 112 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md b/courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md index 016761360..b183150de 100644 --- a/courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md +++ b/courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md @@ -1,5 +1,112 @@ - - --- - title: Deploy - --- - \ No newline at end of file +## Writing a Deploy Script + +In our script, we will create a file called `deploy_basic_nft.py`. + +```python +def moccasin_main(): + pass +``` + +We should be very familiar with this at this point. Let's do a little `def deploy_basic_nft()`. + +```python +def deploy_basic_nft(): + pass +``` + +We are actually going to do `deploy_basic_nft` and in here we're going to say + +```python +from src import basic_nft +``` + +So we call it. Yep. + +Then we'll say `contract` equals `basic_nft.deploy()`. + +```python +def deploy_basic_nft(): + contract = basic_nft.deploy() + print(f"Deployed BasicNFT contract to: {contract.address}") +``` + +Then we'll do `contract.mint` and this is where we can pass in a URI. I'm going to say `pug_uri` equals + +```python +PUG_URI = "QmWt16U9B3JryY9HBY36r6tUUtdmDnmGLdeEendAAggmrx3tMel" +``` + +and I'm going to paste this in here. + +```python +PUG_URI = "QmWt16U9B3JryY9HBY36r6tUUtdmDnmGLdeEendAAggmrx3tMel" + +def deploy_basic_nft(): + contract = basic_nft.deploy() + print(f"Deployed BasicNFT contract to: {contract.address}") + contract.mint(PUG_URI) +``` + +So I already have this uploaded to my IPFS. + +So for now just follow along with me. I'll show you how to upload and work with and add your own custom IPFS stuff in just a second, and why we're using this weird IPFS thing in the first place. + +But for now if you want to just copy this from the script here, paste it in, boom. + +This will resemble the NFT associated with that pug. And we're going to pass in this pug URI that we've set here. + +```python +PUG_URI = "QmWt16U9B3JryY9HBY36r6tUUtdmDnmGLdeEendAAggmrx3tMel" + +def deploy_basic_nft(): + contract = basic_nft.deploy() + print(f"Deployed BasicNFT contract to: {contract.address}") + contract.mint(PUG_URI) + print("Contract deployed at", contract.address) +``` + +And now, since this mint function right this mint function should have minted us a new token, and we should start with counter of 0 or token ID 0. + +We should be able to do `token_metadata` equals `contract.tokenURI(0)`. + +```python +PUG_URI = "QmWt16U9B3JryY9HBY36r6tUUtdmDnmGLdeEendAAggmrx3tMel" + +def deploy_basic_nft(): + contract = basic_nft.deploy() + print(f"Deployed BasicNFT contract to: {contract.address}") + contract.mint(PUG_URI) + print("Contract deployed at", contract.address) + token_metadata = contract.tokenURI(0) + print(f"Token metadata: {token_metadata}") +``` + +And we could print `token_metadata`. + +```bash +mox run deploy_basic_nft +``` + +This is actually `token_uri`. + +```python +PUG_URI = "QmWt16U9B3JryY9HBY36r6tUUtdmDnmGLdeEendAAggmrx3tMel" + +def deploy_basic_nft(): + contract = basic_nft.deploy() + print(f"Deployed BasicNFT contract to: {contract.address}") + contract.mint(PUG_URI) + print("Contract deployed at", contract.address) + token_uri = contract.tokenURI(0) + print(token_uri) +``` + +Now if I run `mox run deploy_basic_nft` we should see this. + +```bash +mox run deploy_basic_nft +``` + +So, if I pull this up now and I just run `mox run deploy_basic_nft`. + +This is the token URI itself and that's exactly what we want. So this is actually `token_uri`. From 4c052363e0fbe4181d81eb1ee58076f71fd0366a Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:32:48 -0700 Subject: [PATCH 189/255] Equious updated courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md. --- .../1-moccasin-nft/7-what-is-ipfs/+page.md | 56 +++++++++++++++++-- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md b/courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md index 53a655154..2ebb77ccf 100644 --- a/courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md +++ b/courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md @@ -1,5 +1,51 @@ - - --- - title: What Is Ipfs - --- - \ No newline at end of file +## What is IPFS? What is a CID? + +IPFS is a distributed, decentralized data structure that is similar to a blockchain. + +- It is a peer-to-peer hypermedia protocol +- designed to preserve and grow humanity's knowledge +- by making the web upgradeable, resilient, and more open. + +IPFS does not have mining, but it does have *pinning data*. We can add data to IPFS and it will split the data into smaller chunks. These smaller chunks are cryptographically hashed, and given a unique fingerprint called a *Content Identifier (CID)*. + +The CID acts as a permanent record of the file as it exists at that point in time. + +When other nodes *look up* your file, they ask their peer nodes who's storing the content referenced by the file's CID. When they view or download the file, they cache a copy and become another provider of your content until their cache is cleared. + +A node can *pin* content to keep and provide it forever, or discard content it hasn't used in a while to save space. This means each node in the network only stores content it is interested in, plus some indexing information that helps figure out which node is storing what. + +If we add a new version of a file to IPFS, its cryptographic hash is different, and it gets a new CID. This means files stored on IPFS are resistant to tampering and censorship - any changes to a file don't overwrite the original, and common chunks across files can be reused to minimize storage costs. + +If we have a code or file we want to use with IPFS: + +1. We can *hash* that data and receive a unique output. +2. Our IPFS node does the hashing for us. +3. Every single IPFS node on the planet has the exact same hashing function. +4. We can *pin* that data to our node. +5. This means that other nodes can find the data associated with that hash. +6. We can easily allow the entire IPFS network to replicate any code or data in a decentralized manner. +7. Other nodes can *pin* our data to their node. + +The issue here is that in order for our data to be truly decentralized, another node needs to pin our data. If our node is the only node that has pinned the data and our node goes down, our data is gone and the network will not be able to access it. We can look at strategies in the future to have other people pin our data. + +However, this is a way we can host data and send code and have it be decentralized. + +Unlike a blockchain where every single node in a blockchain has a copy of the entire blockchain, IPFS nodes can optionally choose which data they want to pin. They can't do execution. So, you could have an IPFS node that's 0.5 MB, and you could have an IPFS node that's several TB. It's up to the node operators how much data and what data they want to pin. + +To go the extra mile, we can go to the IPFS website and download the IPFS desktop or the IPFS app. Once it's installed, it will look like this. We can then pin different objects to our own IPFS node. + +For example, we can look at some data we have pinned. We can see a JSON object and an image. We can copy the *Content Identifier (CID)*. + +We can paste the CID into a file. You can see it's just this string. + +We can use this CID as our URI for our image when it's combined with the IPFS prefix: + +```javascript +"ipfs://Qmwi16U9B3JY9HBBY36r0tUUtDmm6LdEEenDAAggmrx3tHMa" +``` + +This is the unique identifier for that piece of content, whether it's a pug image or the JSON or really any data at all. + +IPFS is much better than using a centralized service like Google Cloud or AWS. We've seen a ton of NFTs deploy with the token URI pointing to a centralized service like AWS or GCP or Microsoft Azure Cloud. Only for those JPEGs to stop rendering once those servers go down. That kind of defeats the purpose of having an immutable NFT. + +IPFS is much better. We're also going to show you cooler ways to store your NFTs using SFGs and RWeave, but we'll get to those shortly. Anyways, that's more about IPFS. If you want to upload your own image, this is how you would do it. You would want to just import the image. Import your JSON object as well where this image here or your image attributes would point to your image that you uploaded. So, boom. So, there would be two files you'd want to upload: a JSON object and an image object. So, I did it for you so you could get this. PUG URI. From 7a4557378eedd4ace0eaac8ea9249ade83db26dc Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:33:00 -0700 Subject: [PATCH 190/255] Equious updated courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md. --- .../8-viewing-an-nft-in-metamask/+page.md | 84 +++++++++++++++++-- 1 file changed, 79 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md b/courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md index d154c82d8..bf49aff45 100644 --- a/courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md +++ b/courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md @@ -1,5 +1,79 @@ - - --- - title: Viewing An Nft In Metamask - --- - \ No newline at end of file +## Viewing in Metamask + +We will learn how to view our NFT in Metamask. + +Metamask currently doesn't support IPFS for NFTs. So, we need to use a workaround, which is a centralized gateway. A centralized gateway is often used by marketplaces like OpenSea or Rarible. It is a method for viewing IPFS data without going through IPFS itself. + +First, we will deploy our NFT to our own Anvil chain. + +We need to define a new network in our `mocassin.toml` file. + +```toml +[networks.anvil] +name = "anvil" +url = "http://127.0.0.1:8545" +prompt_live = false +default_account_name = "anvil1" +default_account_key = "0x" +``` + +Then, we will open a terminal window and run the following command: + +```bash +mox wallet list +``` + +This will list all of our wallets that are defined in the `mocassin.toml` file. + +Next, we will import our Anvil wallet key. To import our key, we run the following command in our terminal: + +```bash +mox wallet import anvil1 +``` + +We then copy the private key for our wallet from our terminal output, and paste it into the Metamask account import screen. + +Now, we can deploy our NFT contract using the following command: + +```bash +mox run deploy_basic_nft.py --network anvil +``` + +Next, we will add Anvil to our Metamask wallet. + +We can do that in Metamask by expanding view, going to networks, and clicking on "Add a Custom Network." + +We will then enter the following values: + +* Network name: Anvil +* Default RPC URL: (Paste your RPC URL here, which was retrieved from the terminal) +* Chain ID: 31337 +* Currency symbol: ETH + +Click save, and you should now see Anvil in your available networks. We can now switch to our new Anvil chain in Metamask. + +We can now import our NFT into Metamask. We will grab the address of our deployed NFT from our terminal output. + +Paste the address into the Metamask import screen. + +We will set the token ID to 0, and click import. + +You should now see your newly deployed NFT. + +To view our NFT in Metamask, we can change the `BASE_URI` constant in our `basic_nft.vy` file to use the gateway. + +Here is an example of a centralized gateway address: + +```python +BASE_URI: public(constant(String[34])) = "https://gateway.pinata.cloud/ipfs/" +``` + +We will then need to redeploy our contract with the following command: + +```bash +mox run deploy_basic_nft.py --network anvil +``` + +After we redeploy, our NFT should now be visible in Metamask and we can view the image through the gateway. + +Using a centralized gateway is less secure than using IPFS, as the gateway could go down, and your image would no longer be visible. IPFS is a better long-term solution for storing NFT data. From 95a3a1e2ac84e30d51384fc5c3c507b7bc4f48f4 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:33:14 -0700 Subject: [PATCH 191/255] Equious updated courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md. --- .../9-deploying-to-zksync/+page.md | 67 +++++++++++++++++-- 1 file changed, 62 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md b/courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md index 1c2eef215..527deb5e7 100644 --- a/courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md +++ b/courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md @@ -1,5 +1,62 @@ - - --- - title: Deploying To Zksync - --- - \ No newline at end of file +## Deploying to ZkSync Era Test Node + +We can deploy our NFT smart contract to the ZkSync Era Test Node using moccasin. + +We need to: + +1. Import a private key from the ZkSync Era Test Node to our moccasin environment. +2. Add the ZkSync Era Test Node to our moccasin configuration file. +3. Deploy our smart contract to the Era Test Node. +4. Add the deployed smart contract to our MetaMask account. + +**Import a Private Key into Moccasin** + +We can import a private key from the Era Test Node into our moccasin environment using the following command: + +```bash +mox wallet import zk-rich1 +``` + +This will prompt us to enter the private key and a password to encrypt it. + +**Add the Era Test Node to our Moccasin Configuration File** + +We'll add the Era Test Node to our moccasin configuration file, `mocassin.toml`, by copying an existing network configuration and replacing the values with the Era Test Node settings. + +The Era Test Node URL will be `http://127.0.0.1:8011`. + +```bash +url = "http://127.0.0.1:8011" +is_zksync = true +prompt_live = false +default_account_name = "zk-rich1" +``` + +**Deploy the Smart Contract to the Era Test Node** + +We can deploy our smart contract to the Era Test Node using the following command: + +```bash +mox run deploy basic-nft --network era-test-node +``` + +This will prompt us to enter the password for our keystore. + +**Add the Deployed Smart Contract to our MetaMask Account** + +We need to add the deployed smart contract to our MetaMask account so that we can interact with it. + +First, we need to add the Era Test Node to MetaMask as a custom network. + +1. Go to MetaMask and click the "Add a custom network" button. +2. Enter the network name "Era Test Node", the URL `http://127.0.0.1:8011`, the Chain ID 260, and the currency symbol ETH. +3. Save the network. + +We can then import the smart contract using the following steps: + +1. Go to the NFTs section in MetaMask. +2. Click the "Import NFT" button. +3. Enter the smart contract address and the token ID. +4. Click "Import". + +We've now deployed our NFT smart contract to the ZkSync Era Test Node and imported it into our MetaMask account. From e69007d90926ead1abc306fb38fc24bfb5cdd6c3 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:33:27 -0700 Subject: [PATCH 192/255] Equious updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/1-intro/+page.md. --- .../1-intro/+page.md | 43 ++++++++++++++++--- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/1-intro/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/1-intro/+page.md index c3de78c13..8e69998b3 100644 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/1-intro/+page.md +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/1-intro/+page.md @@ -1,5 +1,38 @@ - - --- - title: Intro - --- - \ No newline at end of file +## Algorithmic Trading Introduction + +In this lesson, we will be exploring the world of DeFi and algorithmic trading. We will be building scripts that allow us to automate the process of portfolio rebalancing. We will learn how to use platforms like Aave and Uniswap to manage our cryptocurrency assets. + +The idea is that we want to automate the process of transferring a portion of our USDC (a stablecoin) to ETH, so that we have a larger percentage of our portfolio invested in ETH. + +While we will not be writing smart contracts in this lesson, we will learn how to use existing DeFi smart contracts to manage our assets. + +The DeFi space is all about using smart contracts to replace traditional finance applications, and this lesson will give us the tools to begin building our own decentralized financial tools. + +We can see the difference in interest rates for various tokens, such as USDC and ETH: + +``` +Assets Wallet balance APY +ZK 0 0.02% +ETH 0 0.32% +WETH 0 0.32% +wsETH 0 0.10% +USDC 0 4.45% +USDT 0 4.52% +``` + +Here is a simplified way to represent the process: + +**What we have** +* USDC (a stablecoin) - 50% of our portfolio +* ETH - 50% of our portfolio + +**What we want** +* USDC - 30% of our portfolio +* ETH - 70% of our portfolio + +The process of automatically rebalancing our portfolio will involve using a combination of DeFi tools, such as: + +* **Aave:** We will use Aave to deposit and earn interest on our crypto assets. +* **Uniswap:** We will use Uniswap to swap tokens to achieve the desired portfolio allocation. + +We will use these tools together to rebalance our portfolio automatically without having to manually interact with the interfaces. This is an example of how we can leverage DeFi to automate financial processes and gain greater control over our assets. \ No newline at end of file From d3a60fdf03ca9c6964642bcab8cbd94939e94950 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:33:39 -0700 Subject: [PATCH 193/255] Equious updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/10-atokens/+page.md. --- .../10-atokens/+page.md | 69 +++++++++++++++++-- 1 file changed, 64 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/10-atokens/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/10-atokens/+page.md index 3662307dd..72a266605 100644 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/10-atokens/+page.md +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/10-atokens/+page.md @@ -1,5 +1,64 @@ - - --- - title: Atokens - --- - \ No newline at end of file +## Aave ATokens + +In this lesson, we will continue to explore Aave's mechanics by learning how to withdraw our funds. + +We deposited USDC and WETH into Aave. To see how much of each asset we have, we can look at our Aave dashboard. + +We can also confirm these balances in our MetaMask wallet. + +Aave gives us ATokens, tokens that are minted and burned upon supply and withdraw of assets. + +ATokens denote the amount of crypto assets supplied to the protocol and the yield earned on those assets. + +The value of an AToken is pegged to the value of the corresponding supplied asset at a 1:1 ratio and can be safely stored, transferred or traded. + +To withdraw funds, we will need to learn how to find the addresses of the ATokens. We will use the Aave documentation for this. + +We will find the Aave Protocol Data Provider contract address and add it to our `mocassin.toml` file, saving the file to our Aave protocol data provider.json file: + +```bash +moc explorer get 0x41393e5633760dc321075a4f765AE84D7688CD8D --save-name aave_protocol_data_provider +``` + +Next, we will open our notebook.py file. + +We need to manifest this new address. We will paste the name of our Aave protocol data provider into our notebook.py file. Here we will use the `.manifest_named()` method: + +```python +config.reload() +active_network = config.get_active_network() +aave_protocol_data_provider = active_network.manifest_named("aave_protocol_data_provider") +``` + +Now, we can use this to get a list of ATokens using the `.get_all_a_tokens()` method: + +```python +a_tokens = aave_protocol_data_provider.get_all_a_tokens() +``` + +We can print this list of ATokens to check the output: + +```python +print(a_tokens) +``` + +We will use a `for` loop to find the addresses of the USDC and WETH ATokens. + +```python +for a_token in a_tokens: + if "WETH" in a_token.name: + a_weth = active_network.manifest_named("weth") + if "USDC" in a_token.name: + a_usdc = active_network.manifest_named("usdc", address=a_token[1]) +``` + +We can then print the addresses: + +```python +print(a_usdc) +print(a_weth) +``` + +As you can see, this will return the AaveUSDC and AaveWETH addresses. We can confirm these addresses on Etherscan or Blockscout. We will see a tag indicating the name of the AToken, along with the address of the AToken. + +We can now withdraw the USDC and WETH from our Aave portfolio! \ No newline at end of file From 42b980c17393af3616742dcdbdefa07cbef54138 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:33:53 -0700 Subject: [PATCH 194/255] Equious updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/11-portfolio-allocations/+page.md. --- .../11-portfolio-allocations/+page.md | 142 +++++++++++++++++- 1 file changed, 137 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/11-portfolio-allocations/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/11-portfolio-allocations/+page.md index a1a5e794a..63a429c55 100644 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/11-portfolio-allocations/+page.md +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/11-portfolio-allocations/+page.md @@ -1,5 +1,137 @@ - - --- - title: Portfolio Allocations - --- - \ No newline at end of file +## Calculating Portfolio Allocations + +In this lesson, we'll continue working with the Aave protocol and focus on calculating portfolio allocations. + +We'll be focusing on two main concepts: + +* Getting our asset balances after depositing into Aave +* Calculating the percentage allocation of each asset to our total portfolio value + +We'll use the code we have written before to interact with the Aave protocol, and then we'll add new code to calculate our allocations. Let's get started! + +### Getting Our Balances in Aave + +First, we'll get our balances of our Aave assets (`a_usdc` and `a_weth`) in Aave. + +We've already deposited our USDC and ETH into our Aave account, and now we need to get the current balances for those assets. + +```python +a_tokens = aave_protocol_data_provider.getAlATokens() +print(a_tokens) +``` + +We can then use these `a_tokens` and loop through them to get the balances for our Aave assets: + +```python +for token in a_tokens: + if "WETH" in token[0]: + a_weth = active_network.manifest_named("usdc", address=token[1]) + if "USDC" in token[0]: + a_usdc = active_network.manifest_named("usdc", address=token[1]) +``` + +Now, we need to actually get the balances for those Aave assets. We'll use the `balanceOf` function for each: + +```python +a_usdc_balance = a_usdc.balanceOf(boa.env.eoa) +a_weth_balance = a_weth.balanceOf(boa.env.eoa) +``` + +It's important to remember the number of decimals for each asset. `a_usdc` has 6 decimals, and `a_weth` has 18 decimals. + +We need to normalize the balances to use them for calculation. We can do this by dividing the balance by the corresponding number of decimals. + +```python +a_usdc_balance_normalized = a_usdc_balance / 1_000_000 +a_weth_balance_normalized = a_weth_balance / 1_000_000_000_000_000 +``` + +Let's print out the normalized balances to see them: + +```python +print(a_usdc_balance_normalized) +print(a_weth_balance_normalized) +``` + +### Getting The Prices + +Now, we'll get the prices for USDC and ETH. + +We can do this by using the Chainlink price feeds. These feeds allow us to query the price for an asset on the blockchain, which will be slightly out of sync with real-time market data. + +First, we need to get the address for the Chainlink price feed. We can do this by searching for the price feed on the Chainlink documentation. + +After getting the address for the USDC/USD price feed, we can now use it to get the price of USDC. We'll create a function called `get_price` that takes a string representing the feed name and returns the price. + +```python +def get_price(feed_name: str) -> float: + active_network = get_active_network() + price_feed = active_network.manifest_named(feed_name) + price = price_feed.latestAnswer() + decimals = price_feed.decimals() + decimals_normalized = 10 ** decimals + return price / decimals_normalized +``` + +This function gets the price for the provided feed and normalizes the price to 18 decimals. + +Now, we can call this function to get the price of USDC and ETH. We'll then print the prices: + +```python +usdc_price = get_price("usdc_usd") +weth_price = get_price("eth_usd") +print(usdc_price) +print(weth_price) +``` + +### Calculating Portfolio Allocations + +Now, we can use the normalized balances and prices to calculate the percentage allocation of each asset to our total portfolio value. + +We'll first calculate the value of USDC and ETH, and then sum them to get the total value of our portfolio. + +```python +usdc_value = a_usdc_balance_normalized * usdc_price +weth_value = a_weth_balance_normalized * weth_price +total_value = usdc_value + weth_value +``` + +Next, we'll calculate the target allocation for USDC and ETH, which we previously defined as 30% for USDC and 70% for ETH. + +```python +target_usdc_value = 0.3 +target_weth_value = 0.7 +``` + +We'll then calculate the current percentage allocation for USDC and ETH. + +```python +usdc_percent_allocation = usdc_value / total_value +weth_percent_allocation = weth_value / total_value +``` + +We can also add a small buffer to account for the potential discrepancies between our desired allocation and the actual allocation. + +```python +BUFFER = 0.1 +``` + +Finally, we'll create a boolean variable called `needs_rebalancing` to indicate whether our portfolio needs to be rebalanced. + +```python +needs_rebalancing = (abs(usdc_percent_allocation - target_usdc_value) > BUFFER or abs(weth_percent_allocation - target_weth_value) > BUFFER) +``` + +Let's print out our results: + +```python +print(needs_rebalancing) +print(usdc_percent_allocation) +print(weth_percent_allocation) +``` + +### Conclusion + +We have now successfully calculated our portfolio allocations. We have the normalized balances and prices, and can now use this information to determine if we need to rebalance our portfolio. + +In the next lesson, we'll build on this and create a system to automatically rebalance our portfolio based on the current market prices and our target allocations. \ No newline at end of file From a7a9ab32ad7629a43571705879437d5fea1b326e Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:34:06 -0700 Subject: [PATCH 195/255] Equious updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/12-withdrawing-from-aave/+page.md. --- .../12-withdrawing-from-aave/+page.md | 40 ++++++++++++++++--- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/12-withdrawing-from-aave/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/12-withdrawing-from-aave/+page.md index a57a18b9b..a0a0ce321 100644 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/12-withdrawing-from-aave/+page.md +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/12-withdrawing-from-aave/+page.md @@ -1,5 +1,35 @@ - - --- - title: Withdrawing From Aave - --- - \ No newline at end of file +## Withdrawing from Aave + +We are going to withdraw all the tokens from our Aave pool. We are going to use a function that will withdraw the tokens depending on what we're selling. This will help us save gas by only withdrawing the WETH we need to sell to buy USDC. + +To start, we will grab the pool contract: + +```python +pool_contract = active_network.manifest("pool", address_pool_address) +``` + +Then, we will approve the pool contract to withdraw the tokens. + +```python +a_weth.approve(pool_contract.address, a_weth.balanceOf(boa.env.eoa)) +``` + +Finally, we will withdraw the tokens: + +```python +pool_contract.withdraw(weth.address, a_weth.balanceOf(boa.env.eoa), boa.env.eoa) +``` + +Now, we will check to see that our balance is updated: + +```python +def print_token_balances(): + print(f"USDC balance: {usdc.balanceOf(boa.env.eoa)}") + print(f"WETH balance: {weth.balanceOf(boa.env.eoa)}") + print(f"aUSDC balance: {a_usdc.balanceOf(boa.env.eoa)}") + print(f"aWETH balance: {a_weth.balanceOf(boa.env.eoa)}") + +print_token_balances() +``` + +We have now successfully withdrawn all of our tokens from our Aave pool. From 3be9ade6e1957145980141f7ff9313e046ad65fa Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:34:18 -0700 Subject: [PATCH 196/255] Equious updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/13-uniswap/+page.md. --- .../13-uniswap/+page.md | 95 ++++++++++++++++++- 1 file changed, 90 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/13-uniswap/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/13-uniswap/+page.md index 892ee74c0..541deb9a6 100644 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/13-uniswap/+page.md +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/13-uniswap/+page.md @@ -1,5 +1,90 @@ - - --- - title: Uniswap - --- - \ No newline at end of file +## Using Uniswap + +Uniswap is a decentralized exchange built on Ethereum. This lesson will show you how to use it with Python. + +First, we'll need to establish our connection to Uniswap. We can do this by using Python and the `web3.py` library. We'll need the ABI of the contract. You can access this by going to Uniswap Docs and clicking the "Contracts" tab. Then, navigate to the "V3 Protocol" and "Deployments" sections. Click on "Ethereum Deployments". Now, you can see a list of contracts, and the one we are going to use is "SwapRouter02". Click on it. Now, navigate to the "Write as Proxy" tab, and you will see a list of functions. The function we want to use is called "exactInputSingle". + +In this lesson, we'll be using the `mocassin.toml` file to store the addresses we need for our contracts. This file is a standard TOML file that will store these values in key-value pairs. + +To start, we'll create a new key-value pair within `mocassin.toml` called "uniswap_swap_router" and set its value to the address of the "SwapRouter02" contract. We'll also need to set the "abi" of the "SwapRouter02" contract. + +Here is the code: + +```toml +uniswap_swap_router = "0x68b3465833b727a7ce0cfDF485e9eD866c65f4C7" +uniswap_swap_router_abi = "uniswap_swap_router.json" +``` + +Next, let's create some variables we will be using within our code. We'll need a variable called "uniswap_swap_router", and we'll set this to the contract from our `mocassin.toml` file. +```python +uniswap_swap_router = active_network.manifest.named("uniswap_swap_router") +``` + +After that, we are going to use the `web3.py` library to interact with the Uniswap contract. + +Here is the code: + +```python +uniswap_swap_router.exactInputSingle( + weth.address, + usdc.address, + 3000, + boa.env.eoa, + weth_to_sell, + min_out, + 0 +) +``` + +In this code block, we pass in the parameters of the `exactInputSingle` function: +* **weth.address:** The address of WETH +* **usdc.address:** The address of USDC +* **3000:** The fee +* **boa.env.eoa:** The address of our recipient (BOA). +* **weth_to_sell:** The amount of WETH we want to sell +* **min_out:** The minimum amount of USDC we want to receive. This is important for preventing MEV. +* **0:** The square root price limit + +In this scenario, we want to swap WETH for USDC, and so we'll set the "weth_to_sell" value to the value of WETH we want to sell. To find that value, we'll create a variable called "amount_weth", and set this to the value of "weth_to_sell" from the function we created. + +Here is the code: + +```python +amount_weth = weth_to_sell * (10 ** 18) +``` + +We'll also need to approve Uniswap to use our WETH by creating a function using `weth.approve`. + +Here is the code: + +```python +weth.approve(uniswap_swap_router.address, amount_weth) +``` + +Now, we'll run a print function. + +```python +print("Let's swap!") +``` + +To swap WETH for USDC, we'll use the following line: + +```python +uniswap_swap_router.exactInputSingle( + weth.address, + usdc.address, + 3000, + boa.env.eoa, + weth_to_sell, + min_out, + 0 +) +``` + +We'll also run a print function to check the token balances, which we created earlier in the lesson. + +```python +print_token_balances() +``` + +That's how you use Uniswap with Python! From 5586cdbff302c24849a2cd5453932e53f94ee9af Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:34:32 -0700 Subject: [PATCH 197/255] Equious updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/14-finish-rebalance/+page.md. --- .../14-finish-rebalance/+page.md | 77 +++++++++++++++++-- 1 file changed, 72 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/14-finish-rebalance/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/14-finish-rebalance/+page.md index 30a5ed7dd..3ed44fb2e 100644 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/14-finish-rebalance/+page.md +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/14-finish-rebalance/+page.md @@ -1,5 +1,72 @@ - - --- - title: Finish Rebalance - --- - \ No newline at end of file +We will be finishing our rebalance of our USDC and WETH tokens. + +```python +def print_token_balances( ): + print (f"WETH BALANCE: {weth.balanceOf( boa.env.eoa )}") + print (f"aWETH BALANCE: {a_weth.balanceOf( boa.env.eoa )}") + print (f"aUSDC BALANCE: {a_usdc.balanceOf( boa.env.eoa )}") + print (f"aAMETH BALANCE: {a_ameth.balanceOf( boa.env.eoa )}") +``` + +We wrote a little script to handle our deposit. + +Let's create our deposit function: + +```python +def deposit_pool_contract (pool_contract, token, amount ): + allowed_amount = token.allowance(boa.env.eoa, pool_contract.address ) + if allowed_amount < amount: + token.approve (pool_contract.address, amount ) + print (f"Approving {token.name()} into Aave contract: {pool_contract.address}") + print (f"Depositing {token.name()} into Aave contract: {pool_contract.address}") + pool_contract.supply( token.address, amount, boa.env.eoa, REFERRAL_CODE ) +``` + +```python +REFERRAL_CODE = 0 +``` + +Now, let's get our token balances. + +```python +print_token_balances( ) +``` + +We will grab the USDC token balance and use it to deposit into our pool contract. + +```python +amount = usdc.balanceOf( boa.env.eoa ) +deposit_pool_contract (pool_contract, usdc, amount) +``` + +We will do the same for WETH: + +```python +print_token_balances( ) +a_usdc_balance = a_usdc.balanceOf( boa.env.eoa ) +a_weth_balance = a_weth.balanceOf( boa.env.eoa ) +a_usdc_balance_normalized = a_usdc_balance / (1000 * 1000) +a_weth_balance_normalized = a_weth_balance / (1000 * 1000 * 1000 * 1000 * 1000 * 1000) + +usdc_value = a_usdc_balance_normalized * usdc_price +weth_value = a_weth_balance_normalized * weth_price +total_value = usdc_value + weth_value + +target_usdc_value = 0.3 +target_weth_value = 0.7 + +weth_percent_allocation = weth_value / (usdc_value + weth_value) +usdc_percent_allocation = usdc_value / (usdc_value + weth_value) + +print (f"Current percent allocation of USDC: {usdc_percent_allocation}") +print (f"Current percent allocation of WETH: {weth_percent_allocation}") +``` + +We will go ahead and deposit our WETH now. + +```python +amount = weth.balanceOf( boa.env.eoa ) +deposit_pool_contract(pool_contract, weth, amount) +``` + +We successfully rebalanced our portfolio! From 17eb4f8d9742989edf7c7ceff4d382bf9f521490 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:34:44 -0700 Subject: [PATCH 198/255] Equious updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/15-zksync-demo/+page.md. --- .../15-zksync-demo/+page.md | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/15-zksync-demo/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/15-zksync-demo/+page.md index d052ae0af..3315a429e 100644 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/15-zksync-demo/+page.md +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/15-zksync-demo/+page.md @@ -1,5 +1,26 @@ - - --- - title: Zksync Demo - --- - \ No newline at end of file +## ZkSync Demo + +This is a demo showing how to work with ZkSync. We'll use the code we've written previously and make a few changes so that it can be executed on ZkSync. + +The only change we need to make is to set up a ZkSync chain, and then add the contract addresses for each of the contracts that we're using. + +We've done this in our `mocassin.toml` file. + +```toml +[networks.zksync] +url = "$ZKSYNC_RPC_URL" +fork = false +is_zksync = true +explorer_url = "https://api-era.zksync.network/api" +explorer_type = "zksyncExplorer" +explorer_api_id = "$ETHERCAN_ZKSYNC_API_KEY" +chain_id = 324 +``` + +We'll then run our script, which will deposit funds, rebalance, and withdraw our funds. + +```bash +mox run deposit_and_rebalance --network zksync --account smallmoney +``` + +This will deposit our funds into ZkSync, trade some of the funds, and withdraw the funds again. \ No newline at end of file From 94b2f9b2fcd724c72f07026de4d76a31ab2f293f Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:34:56 -0700 Subject: [PATCH 199/255] Equious updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/16-workshop/+page.md. --- .../16-workshop/+page.md | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/16-workshop/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/16-workshop/+page.md index d8fee3739..d5f21f963 100644 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/16-workshop/+page.md +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/16-workshop/+page.md @@ -1,5 +1,28 @@ - - --- - title: Workshop - --- - \ No newline at end of file +We've just completed our notebook exploration, which is a great way to experiment with new concepts. Now, we can transform this code into scripts to streamline our operations. + +Let's take the code we wrote in the notebook and copy it into scripts. These scripts will be our building blocks for automated processes. + +If you want to "cheat" a little, you can find all the scripts we created in the GitHub repo. + +Here's the GitHub repo link: [GitHub Repo Link] + +Once you have your scripts, you'll want to run them on a network. We can use either Tenderly (a virtual network) or a forked network. + +We can run our script by opening our terminal and typing: +```bash +mox test -s +``` + +or + +```bash +mox run deposit_and_rebalance --network zksync --fork false --account your_account +``` + +Remember that when running on a forked network, ensure the fork option is set to true. + +These workshops are essential. They allow us to apply the knowledge we've gained and see if it's truly retained. + +Take your time, and don't be afraid to use the AI or discussions to help you solve the problems you encounter. + +We'll be back for a recap shortly. See you soon! From b0d685559357f318a14b2c5e8ce4e39b7629c62f Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:35:10 -0700 Subject: [PATCH 200/255] Equious updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/17-recap/+page.md. --- .../17-recap/+page.md | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/17-recap/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/17-recap/+page.md index 520a7c357..5b5fa3f0d 100644 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/17-recap/+page.md +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/17-recap/+page.md @@ -1,5 +1,19 @@ - - --- - title: Recap - --- - \ No newline at end of file +## Moccasin DeFi | Algorithmic Trading + +We've just completed our section on Moccasin DeFi | Algorithmic Trading. + +Let's recap what we've learned: + +* **DeFi** is a term used to describe decentralized finance happening within the blockchain space. +* We learned about two DeFi protocols: + * **Aave**, similar to a classic bank, allows us to deposit money and gain interest. Aave also allows us to borrow money. + * **Uniswap** is a decentralized exchange, allowing us to trade different assets. +* We practiced using these DeFi protocols in our Python notebook by: + * Setting up and minting fake tokens. + * Setting ourselves a fake balance. + * Using a chainlink price feed to get the current price of our tokens. + * Calculating our portfolio allocation. + * Rebalancing our portfolio using Uniswap. + * Depositing our tokens into Aave. + +We are now ready to move on to the next section, Moccasin DeFi | Stablecoin. Take a break, go for a walk, or grab some ice cream. We will see you soon! From 722adbf434b3f48d3032e33f3e3ddb1c87ac8568 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:35:24 -0700 Subject: [PATCH 201/255] Equious updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/2-real-demo/+page.md. --- .../2-real-demo/+page.md | 40 ++++++++++++++++--- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/2-real-demo/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/2-real-demo/+page.md index 8cccb17e9..1a6d53b1b 100644 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/2-real-demo/+page.md +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/2-real-demo/+page.md @@ -1,5 +1,35 @@ - - --- - title: Real Demo - --- - \ No newline at end of file +## Real Aave and Uniswap Scripting Demonstration + +In this lesson, we'll be showcasing a script that automatically manages our assets on the ZkSync network. + +The script we'll be building will utilize real money to demonstrate the process on the Aave application. We'll be working with ETH and USDC tokens. + +Our goal is to rebalance our portfolio to achieve a target allocation of 70% ETH and 30% USDC. Currently, our portfolio is skewed towards USDC, with 56% allocated to USDC and 43% to ETH. + +The script will perform the following actions: + +- **Deposit:** Deposit all our tokens into the Aave protocol. +- **Rebalance:** Trade our tokens to reach our target allocation. We'll be using Uniswap for these trades. +- **Deposit:** Deposit the rebalanced tokens back into the Aave protocol. + +Let's first examine our current portfolio: + +- Aave: + - USDC: $68.86 + - ETH: $180.05 + +- Metamask: + - USDC: $160.00 + - ETH: $31.96 + +Now, let's run our script to rebalance this portfolio. + +```bash +mox run deposit_and_rebalance --network zkysnc --account smallMoney +``` + +Our script will first deposit all of our tokens into the Aave protocol. It will then analyze the current allocation and determine the necessary trades. Finally, it will execute these trades on Uniswap and deposit the rebalanced tokens back into Aave. + +This script demonstrates the power of algorithmic trading, allowing us to automate the management of our portfolio and achieve our desired asset allocation. + +We'll be delving deeper into this process in later lessons, including how to create a notebook to test and refine our scripts. Stay tuned! From 6e174c03a89d666156640d981b1d25825494d917 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:35:36 -0700 Subject: [PATCH 202/255] Equious updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/3-setup/+page.md. --- .../3-setup/+page.md | 42 ++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/3-setup/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/3-setup/+page.md index b8774470f..826cc6d18 100644 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/3-setup/+page.md +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/3-setup/+page.md @@ -1,5 +1,37 @@ - - --- - title: Setup - --- - \ No newline at end of file +## Project Setup + +We're going to get started by building a project from scratch. The first thing we need to do is to create a directory. + +```bash +mkdir mox-algorithmic-trading-cu +``` + +Next we want to open this directory with Visual Studio Code: + +```bash +code mox-algorithmic-trading-cu +``` + +We also need to initialize our project. We are going to be using a Python project. + +```bash +mox init --vscode --pyproject +``` + +Now we are ready to remove some of the files that were created when we initialized our project. + +```bash +rm -rf script/deploy.py +``` + +Now, we will make a small change to our `README.md` file. The goal of this project is to interact with Aave, Uniswap, and to rebalance our portfolio. + +```markdown +# What do we want to do? + +1. Deposit into Aave +2. Withdraw from Aave +3. Trade tokens through Uniswap +``` + +We will cover all of these tasks in greater detail as we go along. From ab398be294528e4fed9cdd860c114508a88c3735 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:35:49 -0700 Subject: [PATCH 203/255] Equious updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/4-forked-network-setup/+page.md. --- .../4-forked-network-setup/+page.md | 125 +++++++++++++++++- 1 file changed, 120 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/4-forked-network-setup/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/4-forked-network-setup/+page.md index d825a83e4..c140534cb 100644 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/4-forked-network-setup/+page.md +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/4-forked-network-setup/+page.md @@ -1,5 +1,120 @@ - - --- - title: Forked Network Setup - --- - \ No newline at end of file +## Forked Network Setup + +We'll start by creating a new network called `networks.eth-forked`. This will be a forked network of Ethereum Mainnet, meaning that it will be a copy of the Ethereum Mainnet blockchain but will allow us to make changes to it. + +```toml +[networks.eth-forked] +forked = true +url = "https://eth-mainnet.alchemyapi.io/v2/your-api-key" +``` + +We can access this network by setting up a `.env` file in the root directory of the project. + +```bash +touch .env +``` + +Then, we'll add the following line to the file: + +``` +MAINNET_RPC_URL = "https://eth-mainnet.g.alchemy.com/v2/your-api-key" +``` + +We'll also need to make sure that the `.env` file is added to our `.gitignore` file. + +```bash +cat .gitignore +``` + +We'll use a tool called `boa` to interact with the blockchain. + +```python +from boa.contracts.abi.contract import ABIContract +from typing import Tuple + +def setup_script() -> Tuple[ABIContract, ABIContract, ABIContract, ABIContract]: + print("Starting setup script...") + # 1. Give ourselves some ETH + # 2. Give ourselves some USDC and WETH + active_network = get_active_network() + usdc = active_network.manifest_named("usdc") + weth = active_network.manifest_named("weth") + + if active_network.is_local_or_forked_network(): + _add_eth_balance() + _add_token_balance(usdc, weth, active_network) + +def _add_eth_balance(): + boa.env.set_balance(boa.env.eoa, STARTING_ETH_BALANCE) + +def _add_token_balance(usdc: ABIContract, weth: ABIContract, active_network: Network): + my_address = boa.env.eoa + with boa.env.pranked(my_address): + usdc.configureMasterMinter(my_address) + usdc.updateDelegateminter(my_address, STARTING_USDC_BALANCE) + usdc.mint(my_address, STARTING_USDC_BALANCE) + weth.deposit(value=STARTING_WETH_BALANCE) +``` + +We need to import the `boa` library to work with the blockchain. + +```python +import boa +``` + +We also need to import the `get_active_network` function from the `mocassin.config` module. This function will tell us what network we're currently connected to. + +```python +from mocassin.config import get_active_network +``` + +We will create two functions: `_add_eth_balance` and `_add_token_balance`. The `_add_eth_balance` function will add a starting ETH balance of 1,000 ETH to our account. + +```python +STARTING_ETH_BALANCE = int(1000e18) +``` + +The `_add_token_balance` function will mint fake USDC and WETH tokens to our account. We will need to pass the USDC and WETH contracts and the active network as arguments to the function. We will use the `manifest_named` function to get the addresses of the USDC and WETH contracts. + +```python +def _add_token_balance(usdc: ABIContract, weth: ABIContract, active_network: Network): +``` + +We'll use the `set_balance` function to add the ETH balance. + +```python +boa.env.set_balance(boa.env.eoa, STARTING_ETH_BALANCE) +``` + +We'll use the `configureMasterMinter` and `updateDelegateminter` functions to give our account the ability to mint USDC. + +```python +usdc.configureMasterMinter(my_address) +usdc.updateDelegateminter(my_address, STARTING_USDC_BALANCE) +``` + +Then, we'll use the `mint` function to mint USDC to our account. + +```python +usdc.mint(my_address, STARTING_USDC_BALANCE) +``` + +We'll use the `deposit` function to mint WETH to our account. + +```python +weth.deposit(value=STARTING_WETH_BALANCE) +``` + +We can test the script by running the following command in the terminal: + +```bash +python setup_script.py +``` + +This will print the following output to the console: + +``` +Starting setup script... +``` + +This means that the script has successfully run and we've added fake ETH, USDC, and WETH tokens to our account. We can now use these tokens to test our other scripts. From 7c90f5733fc61e0d19f65298e889e8e60b8a759d Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:36:01 -0700 Subject: [PATCH 204/255] Equious updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/5-minting-weth/+page.md. --- .../5-minting-weth/+page.md | 67 +++++++++++++++++-- 1 file changed, 62 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/5-minting-weth/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/5-minting-weth/+page.md index 8e1fc4990..0f9d4f236 100644 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/5-minting-weth/+page.md +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/5-minting-weth/+page.md @@ -1,5 +1,62 @@ - - --- - title: Minting Weth - --- - \ No newline at end of file +## Minting WETH + +We are going to start by writing a script that will give us some WETH. To do this, we will need the address and the ABI of the WETH contract, or we could work with function selectors and signatures. + +However, it's easier to work with the ABI in Python. + +We are going to be working on the Goerli test network, so we will need to check what the current network is. We can do this with the following code: + +```javascript +active_network = get_active_network() +``` + +We are going to be working with the Goerli test network, so we will check to see if we're on the Goerli test network. If we are, then we will add our ETH and USDC balances: + +```javascript +if active_network.is_local or forked_network(): +``` + +We will add 1000 ETH and 1000 USDC to our balances: + +```javascript +add_eth_balance() +add_token_balance(usdc, weth, active_network) +``` + +Let's run our script in the terminal: + +```bash +python setup_script.py +``` + +Now, we need to call the deposit function to get some WETH. We'll need to include the address of the WETH contract. + +We can do this by adding the following code to our script: + +```javascript +STARTING_ETH_BALANCE = int(1000e18) +``` +```javascript +def add_eth_balance(): + boa.env.set_balance(boa.env.eoa, STARTING_ETH_BALANCE) +``` + +```javascript +def add_token_balance(usdc, weth, active_network): + with boa.env.block_owner(): + usdc.configureUpdateMinster(my_address, STARTING_USDC_BALANCE) + weth.deposit(my_address, STARTING_WETH_BALANCE) +``` + +```javascript +def setup_script() -> Tuple[ABIContract, ABIContract, ABIContract, ABIContract]: + print("Starting setup script......") + # 1. Give ourselves some ETH + # 2. Give ourselves some USDC and WETH + active_network = get_active_network() + usdc = active_network.manifest.named("usdc") + weth = active_network.manifest.named("weth") + if active_network.is_local or forked_network(): + add_eth_balance() + add_token_balance(usdc, weth, active_network) +``` \ No newline at end of file From 552afcbb5ee267ecd63bd8d087bc735dce87c830 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:36:15 -0700 Subject: [PATCH 205/255] Equious updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/6-getting-abis-from-the-explorer/+page.md. --- .../6-getting-abis-from-the-explorer/+page.md | 95 ++++++++++++++++++- 1 file changed, 90 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/6-getting-abis-from-the-explorer/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/6-getting-abis-from-the-explorer/+page.md index 71f85eeff..28779f1fc 100644 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/6-getting-abis-from-the-explorer/+page.md +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/6-getting-abis-from-the-explorer/+page.md @@ -1,5 +1,90 @@ - - --- - title: Getting Abis From The Explorer - --- - \ No newline at end of file +## Getting ABIs from an Explorer + +We can use the Mox explorer functionality to retrieve ABIs. Mox has a built-in explorer functionality. If we type: + +```bash +mox explorer +``` + +we'll get a list of commands we can run. As of now, the only explorer supported is Etherscan. We can fetch ABIs from Etherscan and save them locally. + +In our `mocassin.toml` file, at the top of our `project` field, we can assign ABIs to our contracts. For example: + +```toml +[project] +save_abi_path = "abis" +``` + +We'll make a new folder called `abis`: + +```bash +mkdir abis +``` + +Then, we can get the ABI for WETH using the following command: + +```bash +mox explorer get 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 --save --name weth +``` + +Moccasin will default to Etherscan and retrieve the ABI for WETH, saving it as `weth.json` in the `abis` folder. + +We can then assign that ABI to the WETH contract. In our `mocassin.toml` file, in the `networks.eth-forked.contracts` field, we can add the following: + +```toml +weth = { abi = "abis/weth.json" } +``` + +We can then call functions on the WETH contract. + +We can also give ourselves a starting WETH balance in our `setup_script.py` file. + +First, we'll define a variable: + +```python +STARTING_WETH_BALANCE = int(1e18) +``` + +Next, we'll define a function called `add_token_balance` that we can use to give ourselves a starting balance of a token, in this case WETH: + +```python +def add_token_balance(usdc, weth, active_network): + print(f"Starting balance of WETH: {weth.balance_of(boa.env.eoa)}") + weth.deposit(value=STARTING_WETH_BALANCE) + print(f"Ending balance of WETH: {weth.balance_of(boa.env.eoa)}") +``` + +This will mint us some fake WETH. + +We can then call this function in our `setup_script` function: + +```python +def setup_script() -> Tuple[ABIContract, ABIContract, ABIContract, ABIContract]: + print("Starting setup script...") + usdc = active_network.manifest(named="usdc") + weth = active_network.manifest(named="weth") + if active_network.is_local() or active_network.forked(): + add_token_balance(usdc, weth, active_network) +``` + +Finally, we'll call `setup_script` in our `mocassin_main` function: + +```python +def mocassin_main(): + setup_script() +``` + +We'll ensure we have our network set to `eth-forked` in our `mocassin.toml` file: + +```toml +[networks.eth-forked] +forked = true +``` + +Then we can run our script with the following command: + +```bash +mox run setup_script --network eth-forked +``` + +This will successfully mint us some WETH. From 25ea1b7a8596f4c3fc8df4a6abe92c6dfb7d23fd Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:36:28 -0700 Subject: [PATCH 206/255] Equious updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/7-minting-usdc/+page.md. --- .../7-minting-usdc/+page.md | 101 +++++++++++++++++- 1 file changed, 96 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/7-minting-usdc/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/7-minting-usdc/+page.md index f1fa81333..bd8ab0a67 100644 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/7-minting-usdc/+page.md +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/7-minting-usdc/+page.md @@ -1,5 +1,96 @@ - - --- - title: Minting Usdc - --- - \ No newline at end of file +## Minting Fake USDC + +USDC is a little more complicated than most tokens. We're going to learn how to mint fake USDC using a Python script. + +USDC's contract is very centralized. Circle controls the contract and has a lot of governance utilities. We can take advantage of this centralization to "mock" ourselves some USDC using the `boa` library. + +**Setting up our script** +We can use the `boa.env.prank` function to pretend to be the owner of the USDC contract. + +```python +with boa.env.prank(usdc.owner()): +``` + +We can now call the `updateMasterMinter` function with our address. We'll also set a starting USDC balance. + +```python + with boa.env.prank(usdc.owner()): + usdc.updateMasterMinter(boa.env.eoa) + usdc.configureMinter(boa.env.eoa, STARTING_USDC_BALANCE) + usdc.mint(boa.env.eoa, STARTING_USDC_BALANCE) +``` + +We also need to include the USDC ABI. We'll use `mox explorer` to get the USDC ABI. + +```bash +mox explorer get 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 --save --name usdc +``` + +**Let's run the script** + +First, we'll need to make sure that our environment is set up to run our script. + +```bash +mox run setup_script --network eth-forked +``` + +We can see in the terminal that our script is running and that we have our starting USDC balance. + +```bash +USDC balance before: 0 +USDC balance after: 1000000000 +``` + +We've now successfully minted ourselves some fake USDC! + +**Depositing our USDC** +Next, we'll learn how to deposit our fake USDC into Aave. But, first we'll need to create a script called `deposit.py`. + +```python +from boa.contracts.abi.contract import ABIContract +from typing import Tuple +from moccasin.config import get_active_network +import boa + +STARTING_ETH_BALANCE = int(1000e18) +STARTING_WETH_BALANCE = int(1e18) +STARTING_USDC_BALANCE = int(100e6) + +def add_eth_balance(): + boa.env.set_balance(boa.env.eoa, STARTING_ETH_BALANCE) + +def add_token_balance(usdc: ABIContract, weth: ABIContract, active_network: Any): + weth.deposit(value=STARTING_WETH_BALANCE) + with boa.env.prank(usdc.owner()): + usdc.updateMasterMinter(boa.env.eoa) + usdc.configureMinter(boa.env.eoa, STARTING_USDC_BALANCE) + usdc.mint(boa.env.eoa, STARTING_USDC_BALANCE) + print(f"USDC balance before: {usdc.balanceOf(boa.env.eoa)}") + print(f"USDC balance after: {usdc.balanceOf(boa.env.eoa)}") + +def setup_script() -> Tuple[ABIContract, ABIContract, ABIContract, ABIContract]: + print("Starting setup script...") + # 1. Give ourselves some ETH + # 2. Give ourselves some USDC and WETH + active_network = get_active_network() + usdc = active_network.manifest(named='usdc') + weth = active_network.manifest(named='weth') + if active_network.is_local or active_network.is_forked: + add_eth_balance() + add_token_balance(usdc, weth, active_network) + +def moccasin_main(): + setup_script() + +if __name__ == "__main__": + mocassin_main() +``` + +Let's go ahead and run this. +```bash +mox run deposit.py --network eth-forked +``` + +And, you should see in the terminal that we have a successful deposit. + +We've now learned how to mock our own USDC and deposit it into Aave. From 7a69087dcb08716916747a04f3b8fa01340f4843 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:36:41 -0700 Subject: [PATCH 207/255] Equious updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md. --- .../8-juypter-notebook/+page.md | 61 +++++++++++++++++-- 1 file changed, 56 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md index 720acd517..b836faacd 100644 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md @@ -1,5 +1,56 @@ - - --- - title: Juypter Notebook - --- - \ No newline at end of file +## Jupyter Notebook with Mocassin + +We're going to be moving from writing scripts in a text editor to using a Jupyter notebook. A Jupyter notebook is like a giant Python shell. The main advantage of using a Jupyter notebook is that we can run each line of code individually. This allows us to test our code as we write it and see the results immediately. + +Before we can use a Jupyter notebook, we'll need to create one. To do this, create a new file in your project directory called `notebook.ipyNB`. This will give you a basic notebook with a code cell in it. + +The next step is to select the kernel. We want to make sure we're using the correct Python environment. To do this, click on the kernel selector, and then select "Python Environments". We want to choose the ".venv" environment. If we haven't already added Mocassin to our ".venv", we can do this using the following terminal commands: + +```bash +uv add moccasain +uv sync +``` + +Now that we've selected our kernel, we'll go ahead and copy and paste the following code into the first cell. + +```python +from moccasain import setup_notebook +setup_notebook() +``` + +To run this code, hit Shift Enter. Now, let's add a new code cell and copy the following code: + +```python +from moccasain.config import get_active_network +active_network = get_active_network() +print(active_network.name) +``` + +Next, we'll restart the terminal by clicking on "Restart". We can now run the code. It should take some time to run, and we'll see "eth-forked" printed out. + +Let's add a new code cell, and copy the following code. + +```python +usdc = active_network.manifest_named("usdc") +weth = active_network.manifest_named("weth") +``` + +We can now run these lines of code. + +In another code cell, we'll paste the following code: + +```python +usdc.balance_of(boa.env.eoa) +``` + +The output of this code should be "1000000000" because that's the amount of USDC we gave ourselves in the previous setup script. + +We can also see our WETH balance by running this code: + +```python +weth.balance_of(boa.env.eoa) +``` + +We should see "1000000000000000000" as the output, which is the amount of WETH we set up. + +This is how we can tinker with our code and test it quickly using a Jupyter notebook. Eventually, we'll be moving these lines of code back into the script, but it's important to test the code first and ensure it's working as expected. From f6343fb3efe3392da8372455ad0dc2e400bdfdd1 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:36:54 -0700 Subject: [PATCH 208/255] Equious updated courses/advanced-moccasin/2-moccasin-portfolio-rebalance/9-depositing-into-aave/+page.md. --- .../9-depositing-into-aave/+page.md | 146 +++++++++++++++++- 1 file changed, 141 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/9-depositing-into-aave/+page.md b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/9-depositing-into-aave/+page.md index ee8aafeab..257b30604 100644 --- a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/9-depositing-into-aave/+page.md +++ b/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/9-depositing-into-aave/+page.md @@ -1,5 +1,141 @@ - - --- - title: Depositing Into Aave - --- - \ No newline at end of file +## Depositing Into Aave + +In this lesson we will learn how to deposit our tokens into Aave, specifically, USDC and WETH. This is a fundamental skill for DeFi developers to learn, so let's dive in. + +First, we will need to define a function called `deposit`, which will take the following arguments: + +* pool_contract +* token +* amount + +```javascript +def deposit(pool_contract, token, amount): +``` + +We will then need to calculate the amount that the user is allowed to deposit into Aave. We can do this using the `allowance` function. + +```javascript + allowed_amount = token.allowance(boa.env.eoa, pool_contract.address) +``` + +Next we will define a condition to check if the `allowed_amount` is less than the `amount` requested by the user: + +```javascript + if allowed_amount < amount: +``` + +If the `allowed_amount` is less than the `amount`, then we will need to get the token approved. We can do this by calling the `approve` function. + +```javascript + token.approve(pool_contract.address, amount) +``` + +We can print a statement indicating that the token was approved. + +```javascript + print(f"Approving {token.name()} address {amount}") +``` + +Finally, we can deposit our tokens into Aave by calling the `supply` function. This function will take the following arguments: + +* `token.address` +* `amount` +* `boa.env.eoa` +* `REFERRAL_CODE` + +```javascript + pool_contract.supply(token.address, amount, boa.env.eoa, REFERRAL_CODE) +``` + +We can also print a message to the console indicating that the tokens have been deposited into Aave: + +```javascript + print(f"Depositing {token.name()} into Aave contract {pool_contract.address}") +``` + +Now we will define our USDC and WETH balances, and call the `deposit` function if the respective balances are greater than 0. + +```javascript + usdc_balance = usdc.balance_of(boa.env.eoa) + weth_balance = weth.balance_of(boa.env.eoa) + + if usdc_balance > 0: + deposit(pool_contract, usdc, usdc_balance) + + if weth_balance > 0: + deposit(pool_contract, weth, weth_balance) +``` + +In addition to our deposit function, we can also use the `getUserAccountData` function to retrieve information about the user's account. This function will return the user's total collateral base, total debt base, available borrows base, current liquidation threshold, ltv, and health factor. + +```javascript + pool_contract.get_user_account_data(boa.env.eoa) + + print(f"""User account data: + totalCollateralBase: {totalCollateralBase} + totalDebtBase: {totalDebtBase} + availableBorrowsBase: {availableBorrowsBase} + currentLiquidationThreshold: {currentLiquidationThreshold} + ltv: {ltv} + healthFactor: {healthFactor} + """) +``` + +Let's run the code we have written and review the output. + +We can see that our USDC and WETH were deposited into Aave, as well as our user account data, which includes: + +* totalCollateralBase +* totalDebtBase +* availableBorrowsBase +* currentLiquidationThreshold +* ltv +* healthFactor + +It is important to be familiar with the Aave documentation, so you can understand what each of these values mean. You can learn more about Aave by visiting [aave.com](https://aave.com/). + +Now, we will need to configure a `.toml` file and save the ABI. + +First, we will need to run the following terminal command: + +```bash +mox explorer get 0x2f9d218133aaf8bf2bb19b1066c7e344d94e9e ��-save ��-name aaveV3_pool_address_provider +``` + +We can save the ABI by running the following terminal command: + +```bash +mox explorer get 0x878708ca3f3f0d63353cf4ce8392d6935d844faE2 ��-save ��-name pool +``` + +Next, we will need to open our `.toml` file, which is where we will save our Pool Addresses Provider. + +```javascript +[networks.eth-forked.contracts] +aaveV3_pool_address_provider = { abi = "abis/aaveV3_pool_address_provider.json" } +``` + +And, in the same file, we need to save the Pool Address. + +```javascript +pool = { abi = "abis/pool.json" } +``` + +We can now go back to our Jupyter notebook to see the output of our code. + +```javascript +config = get_config() +config.reload() + +active_network = config.get_active_network() + +aaveV3_pool_address_provider = active_network.manifest_named("aaveV3_pool_address_provider") +pool_address = aaveV3_pool_address_provider.getPool() +print(pool_address) + +pool_contract = active_network.manifest_named("pool", address=pool_address) +``` + +We can see that the Pool Address is printed out. + +Great! We have successfully learned how to deposit tokens into Aave, how to get the ABI, and how to retrieve user account data. This is a valuable skill for any DeFi developer to have! From 8714674a52efdad9d07e9762eb809523e163ead9 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:37:07 -0700 Subject: [PATCH 209/255] Equious updated courses/advanced-moccasin/3-moccasin-stablecoin/1-intro/+page.md. --- .../3-moccasin-stablecoin/1-intro/+page.md | 96 ++++++++++++++++++- 1 file changed, 91 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/1-intro/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/1-intro/+page.md index c3de78c13..5f298bb69 100644 --- a/courses/advanced-moccasin/3-moccasin-stablecoin/1-intro/+page.md +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/1-intro/+page.md @@ -1,5 +1,91 @@ - - --- - title: Intro - --- - \ No newline at end of file +## Section: Mox Stablecoin + +Welcome back to the stablecoin section of Cyfrin Updraft. + +The complete code that we're going to be working with is right here, as always. + +```bash +git clone https://github.com/Cyfrin/mox-stablecoin-cu +cd mox-stablecoin-cu +mox install +``` + +```bash +mox run deploy +``` + +Now, stablecoins are something that we've worked on in the past, and you are going to build your own stablecoin. You�re going to be building one of these tokens that we worked with over in the algorithmic trading portion of this course. However, this is going to be an incredibly powerful stablecoin and one of the most impressive DeFi applications you've created up to this point. + +Stablecoins are quite often incorrect. So we�re going to be learning a lot about what stablecoins actually are, as well as going through and building our own. + +Let me go ahead and show you what the final code base for this is going to look like here. And this is going to be a project you should try to go all out on. Writing fantastic tests, making the contracts look beautiful. This is going to be your chance to say, �Okay. I�m going to build this end-to-end. I�m going to build this full project, and I'm going to make it as good as I possibly can.� In fact, the Solidity implementation of this was actually audited on the CodeHawks platform. And you can see a list of findings, a list of security issues that were found on that original implementation in the GitHub repo as well. You can even click on the link in the GitHub repo, which will bring you to the actual contest, the known issues. You can even view the contest results as well. If you go to contest details, you can hit view results here, and you can see how well people did, how much money they made, and then obviously the final report on this GitHub, on this project, on this code base as well. Obviously, it was Solidity so it's a little bit different, but, that digresses. + +So, the final code base we're going to be doing is we're going to have this decentralized stablecoin. + +```python +@deploy +def init(): + ow._init() + erc20._init(NAME, SYMBOL, DECIMALS, NAME, EIP712_VERSION) +``` + +Now, looking at this decentralized stablecoin, it looks pretty minimal, right? It doesn't look like there's really anything interesting about it. But what we're going to be doing is the owner of this stablecoin is actually going to be this DSC engine. So, the owner of the stablecoin is actually going to be another smart contract. And if we scroll down in here, there is a lot more going on in here. We�re going to be able to mint the stablecoin by depositing and redeeming collateral. What we�re going to be doing here is building something similar to, if we go to DeFiLlama and scroll down here, we�re going to be something similar to what this protocol called Maker created. So, Maker, the MakerDAO created this thing called Dai, which is a decentralized stablecoin. So if we hit use Dai on their website, you can earn 9.5% on your stablecoin. That's pretty crazy! + +Um, but basically this Dai token, you go to CoinGecko, look up this Dai token. This also is worth a dollar. It looks like it's recently been rebranded to USDDS, which we can also look at as well. And we can see if we go to kind of like the max timeline on this, it's been pretty much around a dollar for its entire career, keeping it's trying to stay true to its value as a stablecoin. + +And, our stablecoin that we're going to be building here is going to be very similar to how Dai works or, I guess I should say the original implementation of Dai. We�re going to be able to deposit collateral to mint the Dai token, and redeem our collateral as well, similar to working with Ave or working with the WETH token. + +Now, the superpower of this is in this liquidate function. If people don�t have enough collateral, if people have minted more Dai than they put down collateral, other users can liquidate them. And we'll talk about that a little bit more when we get to that section. People can redeem collateral, they can burn their USDC, we�ll implement this thing called a health factor. We'll be getting pricing information, and so much more. + +```python +@external +def liquidateCollateral(address user, address address, debt_to_cover: uint256): + assert debt_to_cover > 0, "DSCEngine: NeedsMoreThanZero" + starting_user_health_factor: uint256 = self.health_factor(user) + assert ( + starting_user_health_factor < MIN_HEALTH_FACTOR + ), "DSCEngine: HealthFactorOk" + token_amount_from_debt_covered: uint256 = self.get_token_amount_from_usd( + collateral, debt_to_cover + ) + bonus_collateral: uint256 = ( + token_amount_from_debt_covered * LIQUIDATION_BONUS + ) // LIQUIDATION_PRECISION + self.redeemCollateral( + token_amount_from_debt_covered + bonus_collateral, + user, + msg.sender, + ) + self.burnDscToCover(debt_to_cover, user, msg.sender) + ending_user_health_factor: uint256 = self.health_factor(user) + assert ( + ending_user_health_factor > starting_user_health_factor + ), "DSCEngine: HealthFactorNotImproved" + self.revert_if_health_factor_is_broken(msg.sender) +``` + +And it�s this, like I said, it's this contract, it's this set of rules that will govern how users can buy and sell and work with this stablecoin. Additionally, we'll be adding this oracle contract to try to make working with the oracles a little bit safer. We, of course, are going to have some deploy scripts to deploy everything, and some verification scripts as well. We additionally are going to have a ton of unit tests, and you should write even more than what we have here. But additionally, we will have some fuzz tests, some stateful fuzzing fuzz tests as well, to get everything going. We can run + +```bash +mox run deploy +``` + +which should go ahead, deploy our token, deploy well, a mock contract, and deploy the DSC engine as well. And we should be able to run + +```bash +mox test +``` + +which will run all of our tests, fuzzing, and you�ll notice we're taking quite some time to run a lot of fuzz tests on this. And yes, this will highly likely take some time. But then we run the rest of the tests as well. We could also, of course, do + +```bash +mox test -n auto +``` + +to run our tests in parallel to run everything a little bit quicker here. Still, the slowest bit is going to be the fuzz tests, so we're still going to have to wait for it sometime. All right, but everything passes. + +So, this is going to be your flagship project of your entire Vyper and Python curriculum. That's why there's this giant star next to it, if we go to the to the GitHub repo. There's this giant star next to it because this is going to be one of the most advanced projects you work on. Period. Probably one of the most advanced projects you ever work on. + +After we get through this, we have a couple of quick ones to end out the course. So, this is the one you should probably be spending the most time on, working the hardest on to get it really right and make it really good. And be sure to push this up to your GitHub after you finish. + +And we're going to code this as if we're going to be deploying this. Every single one of your smart contracts you want to build you want to keep in mind. I'm going to build this as if I'm going to be deploying this. I'm going to make sure my code is clean. I'm going to make sure my tests are clean. I'm going to think about security. I know we haven't done too much thinking about security, but we're going to write very dispensable code with really good tests, and the like. Additionally, we�re going to be going over some DeFi stuff, some DeFi concepts, and oftentimes that's going to be the hardest part of working with this. So if some of this DeFi stuff goes over your head, if it's confusing, AIs are phenomenal at understanding finance, so ask your AIs, ask your discussions, ask your friends, jump to the discord, ask questions. It�ll get confusing, and that's okay. There's no stupid questions. I want you to just rapidly fire ask questions here. From 1498e2037030c32452dfafbe8e17006250734ce7 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:37:20 -0700 Subject: [PATCH 210/255] Equious updated courses/advanced-moccasin/3-moccasin-stablecoin/10-deployment/+page.md. --- .../10-deployment/+page.md | 107 +++++++++++++++++- 1 file changed, 102 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/10-deployment/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/10-deployment/+page.md index 3c00e7ea9..31a19a069 100644 --- a/courses/advanced-moccasin/3-moccasin-stablecoin/10-deployment/+page.md +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/10-deployment/+page.md @@ -1,5 +1,102 @@ - - --- - title: Deployment - --- - \ No newline at end of file +In this lesson, we'll talk about deployment in our stablecoin. We have a way for people to deposit collateral into the system and those deposits will allow them to mint DSC, mint this stablecoin. They can also redeem their collateral and they can burn the amount of stablecoins that they've minted. If all of a sudden, their health factor is bad, meaning their ratio of collateral to DSC minted is bad, other people can then come in and liquidate them, and they are incentivized to do so because they get bonus collateral to liquidate them. + +So, we really don't want to be liquidated because someone's going to take a lot of your collateral to just slightly improve your health factor, and we don't want that. + +So, this is kind of our final codebase, but not quite yet because you know we're trying to test this. You know we're trying to make sure this works. So, let's go ahead over to our script, and let's create a deploy.py. Now, in the GitHub repo associated with this, we got a script. We have everything kind of in this deploy DSC engine uh, we're going to create two more. We're going to do deploy DSC .py and deploy DSC engine .py. So, we have to deploy our decentralized stablecoin first. So, we'll do a little def moccasin main, deploy DSC. def deploy DSC, pass, def moccasin main, deploy DSC. + +```python +def deploy_dsc(): + pass + +def moccasin_main(): + deploy_dsc() +``` + +We will say, from DSC import decentralized stable coin. And, we'll do decentralized stable coin .deploy. And, we will return this. So, this is going to return a Vyper contract, which we're going to say, from moccasin .boa tools import VyperContract. I'm going to do UV add moccasin just to get rid of those squiggly lines. I'm going to hit yes to update my Python environment in my VS Code. That looks great, and we'll also have this return of Vyper contract as well. + +```python +from src import decentralized_stable_coin + +def deploy_dsc(): + return decentralized_stable_coin.deploy() + +from moccasin.boa_tools import VyperContract + +def moccasin_main(): + return deploy_dsc() +``` + +Cool. Now, in deploy DSC engine, we're going to do def deploy DSC engine, which will take a DSC, which is a Vyper contract as an input variable. So, we'll do from moccasin .boa tools import VyperContract. And, what we'll do is, we need a number of things in here. We're going to go to our moccasin .toml. I'm going to go ahead and delete everything. And, we're going to grab some contract addresses. Let me zoom out a bit here. So, I'm going to do networks .zk sync .contracts. And, because you've done this a hundred times at this point, I'm not going to make you do it again. We can go to the mox stablecoin GitHub draft, we can grab all these addresses from the zk sync network. We can see we have ETH USD price feed here, WETH and wrapped Bitcoin, WETH and wrapped Bitcoin are going to be our two collaterals and we have price feeds for both of them. So, we're going to go ahead and copy these all. Boom. Paste them in here. And, then if we scroll up, we see we have some mock deployer scripts as well for everything. I'm also going to copy all of these, paste them into here as well because we've written these kind of deploy mocks a hundred times as well. And, because of that, I'm also going to save you all the trouble. You can go to scripts mocks deploy price feed. We can grab this because we've already done that. I'm going to add it to mine as well, new folder, new folder, mocks, deploy price feed .py. Paste this in from SRC .mocks import mock V3 aggregator, which means we need a new folder mocks in here. And, a new mock V3 aggregator .py. This is also one you've done a few times now, so I'm not going to make you do that either. We're going to grab that from SRC mocks, mock V3 aggregator .py. We're just going to go ahead and copy this whole thing. + +```python +from moccasin.boa_tools import VyperContract +from moccasin.config import get_active_network +from src import dsc_engine + +def deploy_dsc_engine(dsc: VyperContract): + active_network = get_active_network() + btc_usd = active_network.manifest_named("btc_usd_price_feed") + eth_usd = active_network.manifest_named("eth_usd_price_feed") + wbtc = active_network.manifest_named("wbtc") + weth = active_network.manifest_named("weth") + dsc_engine_contract = dsc_engine.deploy( + [wbtc.address, weth.address], + [btc_usd.address, eth_usd.address], + dsc + ) + dsc_engine_contract.set_minter(dsc_engine_contract.address, True) + dsc_engine_contract.transfer_ownership(dsc_engine_contract.address) + return dsc_engine_contract + +def moccasin_main(): + active_network = get_active_network() + dsc = active_network.manifest_named("decentralized_stable_coin") + return deploy_dsc_engine(dsc).address +``` + +And, paste it in here. Looks good to me. So, from SRC .mocks, mock V3 aggregator, that looks good now. We have a little deploy price feed here. That looks nice. Great. We're also going to need a deploy collateral script. Let's go ahead. Let's create that too. deploy collateral .py. This one's also going to be pretty simple. I am going to make you write this one because we haven't done this that often. Return deploy collateral. def deploy collateral, print deploying token . . . . mock token contract equals. We're going to need a mock token as well. You can copy this as well from the GitHub repo associated with this because you don't need to spend your time and efforts writing mock contracts when they're already done for you. So, mocks, mock token .vy. Paste that in. + +```python +def deploy_collateral(): + print("Deploying token...") + mock_token_contract = ... + +def moccasin_main(): + return deploy_collateral() +``` + +And, now that we have that, I can do from SRC .mocks import mock token. And, I can just say, mock token .deploy like this. I can actually just do return token .deploy. Lovely. Oh. Okay, then I'm going to need deploy DSC. Okay, lovely. Now, that we have all of that stuff, where even was I? Deploy DSC engine, deploy DSC, deploy DSC engine. Oh, okay. Now, that I have all that stuff, we can finally do from moccasin .config import get active network. Active network equals get active network. Now, we'll say BTC USD equals active network .manifest named uh, what do we call it? BTC USD price feed? BTC USD price feed. Paste. ETH USD will be ETH USD price feed. Then, we'll say wrapped Bitcoin equals active network .manifest named wrapped Bitcoin, and then we'll do the same thing for WETH here. WETH, WETH. Now, that we have our price feeds and we have our tokens and we've given them deployer scripts, so that if we run on pie VM, or pie VM will deploy them as mocks for us. I can finally do DSC engine contract equals from SRC import DSC engine. DSC engine .deploy, [wrapped Bitcoin .address, WETH .address], [BTC USD .address, ETH USD .address], DSC. Then, we're going to say on the DSC contract. We want to do DSC .set minter to the DSC engine contract .address to true. And, we also want to do DSC .transfer ownership to the DSC engine contract address. And then return DSC engine contract. + +```python +from moccasin.boa_tools import VyperContract +from moccasin.config import get_active_network +from src import dsc_engine + +def deploy_dsc_engine(dsc: VyperContract): + active_network = get_active_network() + btc_usd = active_network.manifest_named("btc_usd_price_feed") + eth_usd = active_network.manifest_named("eth_usd_price_feed") + wbtc = active_network.manifest_named("wbtc") + weth = active_network.manifest_named("weth") + dsc_engine_contract = dsc_engine.deploy( + [wbtc.address, weth.address], + [btc_usd.address, eth_usd.address], + dsc + ) + dsc_engine_contract.set_minter(dsc_engine_contract.address, True) + dsc_engine_contract.transfer_ownership(dsc_engine_contract.address) + return dsc_engine_contract + +def moccasin_main(): + active_network = get_active_network() + dsc = active_network.manifest_named("decentralized_stable_coin") + return deploy_dsc_engine(dsc).address +``` + +Do a little def moccasin main. I'll do active network equals get active network, DSC equals active network .manifest named DSC. Go to our moccasin .toml. We're actually calling it decentralized stablecoin. So, we'll do manifest named decentralized stable coin. And then return deploy DSC engine DSC .address. So, let's try this out. See if this works. + +```bash +mox run deploy_dsc_engine +``` + +Deploying token. Deploying token. Oh, this is coming along great. My scripts seem to be working. I don't know if the codebase if my code is actually good, but I can rip through the deploy scripts really quickly cuz I've done them a hundred times. I can write a stablecoin really quickly. I haven't done that a hundred times, well, I have, but you haven't done that a hundred times, but you're getting the feel of it and this is incredibly exciting. From 7fbeaacbb37e1d17f2321c3c323242d079b06651 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:37:33 -0700 Subject: [PATCH 211/255] Equious updated courses/advanced-moccasin/3-moccasin-stablecoin/11-testing/+page.md. --- .../3-moccasin-stablecoin/11-testing/+page.md | 99 ++++++++++++++++++- 1 file changed, 94 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/11-testing/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/11-testing/+page.md index c1839c795..8814db179 100644 --- a/courses/advanced-moccasin/3-moccasin-stablecoin/11-testing/+page.md +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/11-testing/+page.md @@ -1,5 +1,94 @@ - - --- - title: Testing - --- - \ No newline at end of file +## Testing + +We've built out our stablecoin engine. Now, the next step is to make sure it works correctly by adding tests. + +First, we'll set up a conftest.py file to help us with our testing. We'll add a few session-scoped fixtures to help us quickly grab the information we need. + +```python +from moccasin.config import get_active_network +import pytest + +@pytest.fixture(scope="session") +def active_network(): + return get_active_network() + +@pytest.fixture(scope="session") +def weth(active_network): + return active_network.manifest_named("weth") + +@pytest.fixture(scope="session") +def wbtc(active_network): + return active_network.manifest_named("wbtc") + +@pytest.fixture(scope="session") +def eth_usdc(active_network): + return active_network.manifest_named("eth_usd_price_feed") + +@pytest.fixture(scope="session") +def btc_usd(active_network): + return active_network.manifest_named("btc_usd_price_feed") +``` + +Next, we'll create a fixture for our decentralized stablecoin engine. + +```python +@pytest.fixture +def dsc(active_network): + return active_network.manifest_named("dsc") + +@pytest.fixture +def dsce(active_network): + return active_network.manifest_named("dsce") +``` + +We also need a fixture to create a user with a starting balance of 10 ETH. + +```python +from eth.account import Account +import boa +from eth.utils import to_wei + +BALANCE = to_wei(10, "ether") + +@pytest.fixture +def some_user(weth, wbtc): + entropy = 13 + account = Account.create(entropy) + boa.env.set_balance(account.address, BALANCE) + with boa.env.prank(account.address): + weth.mock_mint(BALANCE) + wbtc.mock_mint(1) + return account.address +``` + +Now we're ready to write some tests. + +We'll create a tests/unit/tests*dsc_engine.py file and write some tests for the \_init* method of the decentralized stablecoin engine. + +```python +from src import dsc_engine +import pytest +from eth_codex.abi.exceptions import EncodeError +from tests.conftest import COLLATERAL_AMOUNT + +def test_reverts_if_token_lengths_are_different(dsc, eth_usd, btc_usd, weth, wbtc): + with pytest.raises(EncodeError): + dsc_engine.deploy(wbtc, weth, weth, eth_usd, btc_usd, dsc.address) + +def test_reverts_if_collateral_zero(some_user, weth, dsce): + with boa.env.prank(some_user): + weth.approve(dsce, COLLATERAL_AMOUNT) + dsce.deposit_collateral(weth, 0) +``` + +We'll use the pytest.raises() context manager to test that the code raises an EncodeError when it is passed an invalid set of token addresses. We also test that the deposit_collateral() method reverts when passed a collateral amount of 0. + +Now, let's run our tests. + +```bash +mox test +``` + +If we run this command, we'll see all of our tests pass. + +We'll soon get to the workshop, where you'll write more tests to ensure our code works as expected. From 8a728b4d097ef65f425b7cf405b77c2def3bec12 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:37:46 -0700 Subject: [PATCH 212/255] Equious updated courses/advanced-moccasin/3-moccasin-stablecoin/12-workshop-1/+page.md. --- .../12-workshop-1/+page.md | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/12-workshop-1/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/12-workshop-1/+page.md index c61b71da8..0033b2fb2 100644 --- a/courses/advanced-moccasin/3-moccasin-stablecoin/12-workshop-1/+page.md +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/12-workshop-1/+page.md @@ -1,5 +1,19 @@ - - --- - title: Workshop 1 - --- - \ No newline at end of file +## Introduction to Testing + +Now we are going to talk about testing our contracts, and how we can write very robust tests that will help us to be confident in our code. Our first workshop is very simple. If we run: + +```bash +mox test --coverage +``` + +You should see a list of files with their coverage. We are primarily interested in the `dsc_engine.vy` file which has a coverage of 9%. Your first workshop is very simple, try to get the coverage above 80%. + +You should not skip this workshop. We really want you to drill in on writing these tests, and understanding them. This is a great time to work with AI, and use AI to write these tests. We are not even talking about fuzz tests yet, just unit tests. + +If you do get lost, we have a ton of tests in the GitHub repo associated with this section. Feel free to refer to them, pick and choose any number of the tests in here, or multiple of the tests in here. However, do not copy and paste these tests, try to write them yourself. We want you to take at least 30 minutes to an hour to write some tests yourself, so that you really understand what is going on. + +Pause the course, write some tests, and come back here, or ask questions, or compare. + +And if you do not understand why some tests are in here, great! Go to the discussions in the course and ask a question, ask your AI, etc. + +Let's continue. From 8593370caee007a452bc7af79656fb1850348be5 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:37:59 -0700 Subject: [PATCH 213/255] Equious updated courses/advanced-moccasin/3-moccasin-stablecoin/13-fuzz-setup/+page.md. --- .../13-fuzz-setup/+page.md | 134 +++++++++++++++++- 1 file changed, 129 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/13-fuzz-setup/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/13-fuzz-setup/+page.md index a411fc23b..1fa77b68d 100644 --- a/courses/advanced-moccasin/3-moccasin-stablecoin/13-fuzz-setup/+page.md +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/13-fuzz-setup/+page.md @@ -1,5 +1,129 @@ - - --- - title: Fuzz Setup - --- - \ No newline at end of file +## Fuzz Tests Setup + +Now that we have written a lot of unit tests, we are going to write some fuzz tests. + +Let's create a new folder called `fuzz`. We will create a test file called `test_fuzz.py`. + +```python +from hypothesis.stateful import RuleBasedStateMachine, initialize, rule +from script.deploy_dsc_engine import deploy_dsc_engine +from moccasin.config import get_active_network +from eth_constants import ZERO_ADDRESS +from boa.util.abi import Address + +USERS_SIZE = 10 + +class StablecoinFuzzer(RuleBasedStateMachine): + def __init__(self): + super().__init__() + self.dsc = deploy_dsc() + self.dsc = deploy_dsc_engine(self.dsc) + self.active_network = get_active_network() + self.weth = self.active_network.manifest(named="weth") + self.wbtc = self.active_network.manifest(named="wbtc") + self.eth_usd = self.active_network.manifest(named="eth_usd_price_feed") + self.btc_usd = self.active_network.manifest(named="btc_usd_price_feed") + self.users = [Address("0x" + ZERO_ADDRESS.hex())] + while Address("0x" + ZERO_ADDRESS.hex()) in self.users: + self.users = [Address("0x" + ZERO_ADDRESS.hex()) for _ in range(USERS_SIZE)] + +stablecoin_fuzzer = StablecoinFuzzer.TestCase + +``` + +We are going to import the `rule` from the `hypothesis.stateful` module. We will initialize our test suite here using the `initialize` function, and we need to import the `deploy_dsc_engine` from the `deploy_dsc_engine` module. We will set up all of our contracts. + +```python +from hypothesis.stateful import RuleBasedStateMachine, initialize, rule +from script.deploy_dsc_engine import deploy_dsc_engine +from moccasin.config import get_active_network +from eth_constants import ZERO_ADDRESS +from boa.util.abi import Address + +USERS_SIZE = 10 + +class StablecoinFuzzer(RuleBasedStateMachine): + def __init__(self): + super().__init__() + self.dsc = deploy_dsc() + self.dsc = deploy_dsc_engine(self.dsc) + self.active_network = get_active_network() + self.weth = self.active_network.manifest(named="weth") + self.wbtc = self.active_network.manifest(named="wbtc") + self.eth_usd = self.active_network.manifest(named="eth_usd_price_feed") + self.btc_usd = self.active_network.manifest(named="btc_usd_price_feed") + self.users = [Address("0x" + ZERO_ADDRESS.hex())] + while Address("0x" + ZERO_ADDRESS.hex()) in self.users: + self.users = [Address("0x" + ZERO_ADDRESS.hex()) for _ in range(USERS_SIZE)] + +stablecoin_fuzzer = StablecoinFuzzer.TestCase + +``` + +We are going to create an array of users as well. We will create an array of ten different users, and we can even print the array. + +```python +from hypothesis.stateful import RuleBasedStateMachine, initialize, rule +from script.deploy_dsc_engine import deploy_dsc_engine +from moccasin.config import get_active_network +from eth_constants import ZERO_ADDRESS +from boa.util.abi import Address + +USERS_SIZE = 10 + +class StablecoinFuzzer(RuleBasedStateMachine): + def __init__(self): + super().__init__() + self.dsc = deploy_dsc() + self.dsc = deploy_dsc_engine(self.dsc) + self.active_network = get_active_network() + self.weth = self.active_network.manifest(named="weth") + self.wbtc = self.active_network.manifest(named="wbtc") + self.eth_usd = self.active_network.manifest(named="eth_usd_price_feed") + self.btc_usd = self.active_network.manifest(named="btc_usd_price_feed") + self.users = [Address("0x" + ZERO_ADDRESS.hex())] + while Address("0x" + ZERO_ADDRESS.hex()) in self.users: + self.users = [Address("0x" + ZERO_ADDRESS.hex()) for _ in range(USERS_SIZE)] + +stablecoin_fuzzer = StablecoinFuzzer.TestCase + +``` + +We will import the Boa module and create a rule for our protocol. + +```python +from hypothesis.stateful import RuleBasedStateMachine, initialize, rule +from script.deploy_dsc_engine import deploy_dsc_engine +from moccasin.config import get_active_network +from eth_constants import ZERO_ADDRESS +from boa.util.abi import Address + +USERS_SIZE = 10 + +class StablecoinFuzzer(RuleBasedStateMachine): + def __init__(self): + super().__init__() + self.dsc = deploy_dsc() + self.dsc = deploy_dsc_engine(self.dsc) + self.active_network = get_active_network() + self.weth = self.active_network.manifest(named="weth") + self.wbtc = self.active_network.manifest(named="wbtc") + self.eth_usd = self.active_network.manifest(named="eth_usd_price_feed") + self.btc_usd = self.active_network.manifest(named="btc_usd_price_feed") + self.users = [Address("0x" + ZERO_ADDRESS.hex())] + while Address("0x" + ZERO_ADDRESS.hex()) in self.users: + self.users = [Address("0x" + ZERO_ADDRESS.hex()) for _ in range(USERS_SIZE)] + +stablecoin_fuzzer = StablecoinFuzzer.TestCase + +@rule +def pass_me(): + pass + +``` + +Now, we can initialize our test suite and see it print out ten different addresses. + +```bash +mox test -s -k stablecoin_fuzzer +``` \ No newline at end of file From 8ea97a736edbf8716ea50076b188d4e86e508de9 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:38:13 -0700 Subject: [PATCH 214/255] Equious updated courses/advanced-moccasin/3-moccasin-stablecoin/14-invariant/+page.md. --- .../14-invariant/+page.md | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/14-invariant/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/14-invariant/+page.md index 678aef389..f3c1fef93 100644 --- a/courses/advanced-moccasin/3-moccasin-stablecoin/14-invariant/+page.md +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/14-invariant/+page.md @@ -1,5 +1,30 @@ - - --- - title: Invariant - --- - \ No newline at end of file +## Invariants + +Invariants are a key testing concept when fuzzing smart contracts. + +Invariants are properties of the system that should always hold true. We can use the *invariant* keyword in Hypothesis to check these invariants. + +The *invariant* keyword automatically runs a function after every rule that's executed. If the invariant is false, an exception is raised. + +Let's write an invariant for our stablecoin protocol: + +```python +@invariant +def protocol_must_have_more_value_than_total_supply(self): + total_supply = self.dsc.total_supply() + weth_deposited = self.weth.balance_of(self.dsce.address) + wbtc_deposited = self.wbtc.balance_of(self.dsce.address) + weth_value = self.dsc.get_usd_value(self.weth, weth_deposited) + wbtc_value = self.dsc.get_usd_value(self.wbtc, wbtc_deposited) + assert (weth_value + wbtc_value) >= total_supply +``` + +This invariant checks that the total value of the collateral deposited (WETH and WBTC) is greater than or equal to the total supply of the stablecoin. + +We can run our fuzzer with this invariant to see if it holds true. + +```bash +mox test-s stablecoin_fuzzer +``` + +This will run the fuzzer and automatically test our invariant. If any rule breaks the invariant, the fuzzer will throw an exception. From f7d0f021e8be008997188606a67ddc0a4b48743e Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:38:26 -0700 Subject: [PATCH 215/255] Equious updated courses/advanced-moccasin/3-moccasin-stablecoin/15-rules-deposit-and-redeem/+page.md. --- .../15-rules-deposit-and-redeem/+page.md | 144 +++++++++++++++++- 1 file changed, 139 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/15-rules-deposit-and-redeem/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/15-rules-deposit-and-redeem/+page.md index 27e85cb6e..088ca1e95 100644 --- a/courses/advanced-moccasin/3-moccasin-stablecoin/15-rules-deposit-and-redeem/+page.md +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/15-rules-deposit-and-redeem/+page.md @@ -1,5 +1,139 @@ - - --- - title: Rules Deposit And Redeem - --- - \ No newline at end of file +## Deposit & Redeem Collateral + +In this video, we are going to learn how to test the deposit and redeem functionality of a decentralized stablecoin project. + +### Rules + +We can define rules that specify how the fuzzer should interact with the smart contracts. These rules will dictate what actions the fuzzer should take. For instance, we can create a rule called "Deposit and Mint" that will randomly mint collateral for users and deposit it into the protocol. + +We can also define rules that specify conditions that must be met during fuzzing. + +### Invariants + +An invariant is a property of the system that should always be true. We can define invariants that represent the conditions that should be met during the fuzzing process to ensure the protocol's integrity. + +For instance, we can set an invariant to ensure the total value of deposited collateral is always greater than the total supply of the stablecoin. This invariant can be enforced during fuzzing by using the "assume" command. + +### Example Rules + +Here are some example rules that we can define: + +**1. Deposit Collateral:** + +```python +@rule +def deposit_collateral(self, collateral_seed, user_seed, amount): + collateral = self.get_collateral_from_seed(collateral_seed) + user = self.users[user_seed] + with boa.env.prank(user): + collateral.approve(self.dsc.address, amount) + self.dsc.deposit_collateral(collateral, amount) +``` + +**2. Redeem Collateral:** + +```python +@rule +def redeem_collateral(self, collateral_seed, user_seed, percentage): + user = self.users[user_seed] + collateral = self.get_collateral_from_seed(collateral_seed) + max_redeemable = self.dsc.get_collateral_balance_of_user(user, collateral) + to_redeem = (max_redeemable * percentage) // 100 + assume(to_redeem > 0) + with boa.env.prank(user): + self.dsc.redeem_collateral(collateral, to_redeem) +``` + +### Running the Fuzz Test + +To run the fuzz test, we can use the following command: + +```bash +mox test -s stablecoin_fuzzer +``` + +The fuzzer will execute the rules and invariants we defined. If any of the invariants are broken, the fuzzer will identify it as a bug. + +### External View Functions + +External view functions are functions that allow the fuzzer to interact with the smart contract's state. These functions do not modify the state, but they provide visibility into it. + +For example, we can define an external view function to retrieve the USD value of a collateral. + +```python +@external +@view +def get_usd_value(collateral_address: address, amount: uint256) -> uint256: + return self.get_usd_value(collateral_address, amount) +``` + +### Code Walkthrough + +Let's take a look at the code we wrote in this video. + +First, we imported the necessary libraries and defined constants: + +```python +from hypothesis.stateful import RuleBasedStateMachine, initialize, rule, invariant, assume +from script_deploy_dsc_engine import deploy_dsc_engine +from moccasin.config import get_active_network +from eth_constants import ZERO_ADDRESS +from boa.utils.abi import Address +import boa +from hypothesis import strategies as st +from eth_utils import to_wei + +USERS_SIZE = 10 +MAX_DEPOSIT_SIZE = to_wei(1000, "ether") +``` + +Next, we defined the "StablecoinFuzzer" class, which is a RuleBasedStateMachine. Inside the class, we defined the "setup" method to initialize the state machine. + +```python +class StablecoinFuzzer(RuleBasedStateMachine): + def __init__(self): + super().__init__() + @initialize() + def setup(self): + self.dsc = deploy_dsc() + self.dsce = deploy_dsc_engine(self.dsc) + active_network = get_active_network() + self.weth = active_network.manifest_named("weth") + self.wbtc = active_network.manifest_named("wbtc") + self.eth_usd = active_network.manifest_named("eth_usd_price_feed") + self.btc_usd = active_network.manifest_named("btc_usd_price_feed") + self.users = [Address("0x" + ZERO_ADDRESS.hex())] * 1 + while Address("0x" + ZERO_ADDRESS.hex()) in self.users: + self.users = boa.env.generate_address(USERS_SIZE) +``` + +We then define the "deposit_and_mint" rule that randomly deposits collateral into the protocol. This is done with the following code: + +```python +@rule +def deposit_and_mint(self, collateral_seed, user_seed, amount): + collateral = self.get_collateral_from_seed(collateral_seed) + user = self.users[user_seed] + with boa.env.prank(user): + collateral.mint(amount) + collateral.approve(self.dsc.address, amount) + self.dsc.deposit_collateral(collateral, amount) +``` + +Finally, we defined the "redeem_collateral" rule, which randomly redeems collateral from users: + +```python +@rule +def redeem_collateral(self, collateral_seed, user_seed, percentage): + user = self.users[user_seed] + collateral = self.get_collateral_from_seed(collateral_seed) + max_redeemable = self.dsc.get_collateral_balance_of_user(user, collateral) + to_redeem = (max_redeemable * percentage) // 100 + assume(to_redeem > 0) + with boa.env.prank(user): + self.dsc.redeem_collateral(collateral, to_redeem) +``` + +### Conclusion + +This video provides a brief introduction to fuzz testing and how we can apply it to decentralized stablecoin projects. The techniques we covered can be applied to other smart contracts to identify potential vulnerabilities and improve their security. From 7e01305824a0e6eb2e9d6826ee9544cca71ea84c Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:38:40 -0700 Subject: [PATCH 216/255] Equious updated courses/advanced-moccasin/3-moccasin-stablecoin/16-rules-mint-dsc/+page.md. --- .../16-rules-mint-dsc/+page.md | 75 +++++++++++++++++-- 1 file changed, 70 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/16-rules-mint-dsc/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/16-rules-mint-dsc/+page.md index ad5a976aa..dab6a8b06 100644 --- a/courses/advanced-moccasin/3-moccasin-stablecoin/16-rules-mint-dsc/+page.md +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/16-rules-mint-dsc/+page.md @@ -1,5 +1,70 @@ - - --- - title: Rules Mint Dsc - --- - \ No newline at end of file +## Minting DSC + +In the previous lesson, we added code to our fuzzer to mint and redeem collateral, but that code wasn't actually minting any DSC. To make the code more effective, we need to add a way to actually mint DSC. + +Let's start by adding a new rule to our fuzzer to generate a random user and mint some DSC. We'll use the `st.integers` strategy to generate a random user seed between 0 and `USERS_SIZE - 1`, and we'll also define a rule for a random amount of DSC to mint, using `st.integers` with a min value of 0 and a max value of `MAX_DEPOSIT_SIZE`. + +```python +@rule +user_seed=st.integers(min_value=0, max_value=USERS_SIZE - 1) +``` + +```python +@rule +amount=st.integers(min_value=0, max_value=MAX_DEPOSIT_SIZE) +``` + +Next, we'll define a new function called `mint_dsc`, which will take the user seed, the amount of DSC to mint, and the collateral seed as parameters. + +```python +def mint_dsc(self, user_seed, amount, collateral_seed): +``` + +We'll use the `boa.env.prank` context manager to impersonate the user, and then call the `mint_dsc` function on the DSC engine. + +```python + user = self.users[user_seed] + with boa.env.prank(user): + self.dsce.mint_dsc(amount) +``` + +Now, let's run our fuzzer and see what happens. + +```bash +python3 -k stablecoin_fuzzer +``` + +We get the following error message: + +``` +DSCEngine: Health factor broken +``` + +This error is happening because our fuzzer is trying to mint DSC without first providing the user with enough collateral. + +To fix this issue, we need to add a try/except block around the `mint_dsc` function. If we encounter a `BoaError`, we'll check if the error message contains the phrase "Health factor broken". If it does, we'll call the internal `get_token_amount_from_usd` function on the DSC engine to calculate the amount of collateral needed, and then deposit the collateral into the user's account. + +```python +def mint_dsc(self, user_seed, amount, collateral_seed): + user = self.users[user_seed] + with boa.env.prank(user): + try: + self.dsce.mint_dsc(amount) + except BoaError as e: + if "DSCEngine: Health factor broken" in str(e.stack_trace.vm_error): + collateral = self._get_collateral_from_seed(collateral_seed) + amount = self.dsce.get_token_amount_from_usd(collateral.address, amount) + self.dsce.deposit_collateral(collateral.address, amount) + if amount == 0: + self.mint_and_deposit(collateral_seed, user_seed, amount) +``` + +The `get_token_amount_from_usd` function is an external view on the DSC engine that takes the token address, the user's address, and the USD amount to deposit, and returns the amount of the token required to represent the given USD amount. + +Now, let's run our fuzzer again. This time, we should see that the fuzzer passes without encountering the health factor broken error. + +```bash +python3 -k stablecoin_fuzzer +``` + +As we can see, the fuzzer passes. This is because we have implemented a mechanism to handle the health factor broken error, and it's now possible to successfully mint DSC through our fuzzer. \ No newline at end of file From 7a33f958516e9479aa19868b82441ad346ab5084 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:38:53 -0700 Subject: [PATCH 217/255] Equious updated courses/advanced-moccasin/3-moccasin-stablecoin/17-rules-update-price/+page.md. --- .../17-rules-update-price/+page.md | 71 +++++++++++++++++-- 1 file changed, 66 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/17-rules-update-price/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/17-rules-update-price/+page.md index 76632171c..a04df7f7e 100644 --- a/courses/advanced-moccasin/3-moccasin-stablecoin/17-rules-update-price/+page.md +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/17-rules-update-price/+page.md @@ -1,5 +1,66 @@ - - --- - title: Rules Update Price - --- - \ No newline at end of file +## Rules (Actions) Update Price + +We will start by adding a rule to our fuzzer that updates the price. This rule will be called `update_collateral_price`. + +```python +@rule +def update_collateral_price(self, collateral_seed, percentage_new_price): + collateral = self.get_collateral_from_seed(collateral_seed) + price_feed = MockV3Aggregator.at( + self.dsc.token_to_price_feed(collateral.address) + ) + current_price = price_feed.latestAnswer() + new_price = int(current_price * percentage_new_price) + price_feed.updateAnswer(new_price) + +``` + +We also need to add a new rule to our fuzzer, called `mint_and_update`, which will allow us to mint the stablecoin and then immediately update the price. + +```python +@rule +def mint_and_update(self, collateral_seed, user_seed, amount): + self.mint_and_deposit(collateral_seed, user_seed, amount) + self.update_collateral_price(collateral_seed, 0.3) + +``` + +To ensure that our fuzzer is actually testing these price updates, we can adjust our fuzzer settings. Specifically, we'll change the `max_examples` and `stateful_step_count` to 64. + +```python +stablecoin_fuzzer = StablecoinFuzzer.TestCase +stablecoin_fuzzer.settings = settings(max_examples=64, stateful_step_count=64) + +``` + +We should also add a `MockV3Aggregator` to our imports section and make sure we're importing settings from our `src.mocks` directory. + +```python +from src.mocks import MockV3Aggregator, settings + +``` + +Running our fuzzer now should produce an error. Our fuzzer will find a state where the collateral value is less than the total supply of our stablecoin, which will break our protocol. + +The code below shows an example of how we can update our `mint_and_deposit` function to double the collateral. + +```python +def mint_and_deposit(self, collateral_seed, user_seed, amount): + user = self.users[user_seed] + with boa.env.prank(user): + try: + self.dsc.mint_dsc(amount) + except BoaError as e: + if "DSCEngine: Health factor broken" in str(e.stack_trace(0).vm_error): + collateral = self.get_collateral_from_seed(collateral_seed) + collateral_amount = self.dsc.get_token_amount_from_usd( + collateral.address, amount + ) + self.mint_and_deposit( + collateral_seed, user_seed, collateral_amount * 2 + ) + self.dsc.mint_dsc(amount) + +``` + +We'll run our fuzz test again and it should produce an error. We've now tested that the collateralization ratio of our stablecoin is correct. From 16ee42c3b88aab3f5fcdd737574a8233e0c54109 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:39:07 -0700 Subject: [PATCH 218/255] Equious updated courses/advanced-moccasin/3-moccasin-stablecoin/18-workshop-2/+page.md. --- .../18-workshop-2/+page.md | 98 ++++++++++++++++++- 1 file changed, 93 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/18-workshop-2/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/18-workshop-2/+page.md index 82ac362be..e712e9419 100644 --- a/courses/advanced-moccasin/3-moccasin-stablecoin/18-workshop-2/+page.md +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/18-workshop-2/+page.md @@ -1,5 +1,93 @@ - - --- - title: Workshop 2 - --- - \ No newline at end of file +## Intro to Fuzz Testing: A Workshop + +We've set up a system where we want to maintain a specific invariant: we want to ensure that the protocol has more value in collateral than in its total supply. + +### Our invariant +Our goal is to write code that will demonstrate our invariant remains true even after we make a series of changes. To do that, we're going to set up a fuzz tester that will automatically run a series of tests and then check to see if the invariant is still met. + +### Our fuzz tester +Let's create a `StablecoinFuzzer` class that incorporates rules and invariants. + +```python +class StablecoinFuzzer(RuleBasedStateMachine): + def __init__(self): + super().__init__() + self.setup() + + def setup(self): + active_network = get_active_network() + self.weth = active_network.manifest(named="weth") + self.wbtc = active_network.manifest(named="wbtc") + self.eth_usd = active_network.manifest(named="eth_usd_price_feed") + self.btc_usd = active_network.manifest(named="btc_usd_price_feed") + self.users = [] + while len(self.users) < USERS_SIZE: + user_address = Address(f"0x{ZERO_ADDRESS.hex()}") + self.users.append(user_address) +``` + +We then set up a series of rules and invariants for our fuzz tester to work with. + +### Rules + +```python +@rule +def collateral_seed(self, min_value=0, max_value=1): + collateral_seed = st.integers(min_value=min_value, max_value=max_value) + user_seed = st.integers(min_value=0, max_value=USERS_SIZE - 1) + amount_strategy = st.integers(min_value=1, max_value=MAX_DEPOSIT_SIZE) + return collateral_seed, user_seed, amount_strategy + +@rule +def mint_and_deposit(self, collateral_seed, user_seed, amount): + user = self.users[user_seed] + collateral = self.get_collateral_from_seed(collateral_seed) + self.mint_and_deposit(collateral_seed, user_seed, collateral) + +@rule +def update_collateral_price(self, collateral_seed, percentage_new_price): + collateral = self.get_collateral_from_seed(collateral_seed) + price = collateral.price_feed.latestAnswer() + new_price = int(current_price * percentage_new_price) + price_feed.updateAnswer(new_price) +``` + +### Invariants + +```python +@invariant() +def protocol_must_have_more_value_than_total_supply(self): + total_supply = self.dsc.totalSupply() + weth_deposited = self.weth.balanceOf(self.dsc.address) + wbtc_deposited = self.wbtc.balanceOf(self.dsc.address) + weth_value = self.dsc.get_usd_value(self.weth, weth_deposited) + wbtc_value = self.dsc.get_usd_value(self.wbtc, wbtc_deposited) + assert (weth_value + wbtc_value) >= total_supply +``` + +Finally, we want to create a `liquidate()` function for our fuzz tester that allows us to simulate market effects in our protocol. + +### Liquidate + +```python +@invariant() +def liquidate(self): + for user in self.users: + health_factor = self.dsc.health_factor(user) + if health_factor < int(1e18): + print(f"Liquidating user: {user}") + total_dsc_minted, total_value_usd = self.dsc.get_account_information(user) + debt_to_cover = total_dsc_minted - total_value_usd + token_amount = self.dsc.get_token_amount_from_usd(self.weth.address, debt_to_cover) + with boa.env.prank(LIQUIDATOR): + self.mint_and_deposit(token_amount, 0, user) + self.dsc.liquidate(self.weth, user, debt_to_cover) +``` + +This is a good starting point for our fuzz tester. We can run this code using the following command: + +```bash +python test_fuzz.py +``` + +If the invariant doesn't hold, we'll need to adjust our code to make sure that the invariant remains true even after the rules are applied. From 38afe32edc6db48188c75d3714cf6f0e805b380f Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:39:20 -0700 Subject: [PATCH 219/255] Equious updated courses/advanced-moccasin/3-moccasin-stablecoin/19-audit-readiness/+page.md. --- .../19-audit-readiness/+page.md | 90 +++++++++++++++++-- 1 file changed, 85 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/19-audit-readiness/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/19-audit-readiness/+page.md index c3eadc976..4cbca57e6 100644 --- a/courses/advanced-moccasin/3-moccasin-stablecoin/19-audit-readiness/+page.md +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/19-audit-readiness/+page.md @@ -1,5 +1,85 @@ - - --- - title: Audit Readiness - --- - \ No newline at end of file +## Audit Readiness + +We are going to prepare our codebase for an audit, or a competitive audit, or an external security review. We haven't really spoken too much about what these are, what they look like, and the like. So, we're going to go ahead and watch this quick video on what is an audit and what they're for and what to expect. Then, we'll come back and we'll see what we need to do to level up our code base here. + +### What is a Smart Contract Audit? + +A smart contract audit is a time-boxed, security-based code review on your smart contract system. An auditor's goal is to find as many vulnerabilities as possible and educate the protocol on best security and coding practices. + +### Why are Audits Important? + +Why is it critical that you get an audit before deploying your code to a live blockchain? Well, for starters, there are entire websites dedicated to how many hacks happen. Last year, we saw the most value ever stolen from smart contracts, with almost $4 billion dollars stolen. Due to the immutability of the blockchain, once a smart contract is deployed, you can't change it. So, you better get it right. A blockchain is a permissionless, adversarial environment, and your protocol needs to be prepared for malicious users. But even more so than that, an audit can improve your developers' team's understanding of code, improving their speed and effectiveness in implementing features moving forward. It can teach your team the latest tooling in the space. Often, just one smart contract audit isn't even enough. Protocols go on a security journey that includes many audits and many different services, like formal verification, competitive audits, and bug bounty programs. + +### What an Audit Looks Like + +There are a lot of companies that offer smart contract auditing services, like Trail of Bits, Consensus Diligence, OpenZeppelin, Sigma Prime, Spearbit, MixBytes, WatchPug, Trust, and, of course, CyfrIn. Additionally, there's a lot of independent auditors that do great work as well. A typical audit looks like this: + +1. **Price and Timeline** + * First, a protocol needs to reach out. They can reach out before or after their code is finished. Ideally, they reach out sometime before their code is finished so the auditors can have time to slot them in. + * Once they reach out, the protocol and auditors will discuss how long the audit will take based off of scope and code complexity. + +2. **Scope** + * The scope of the audit is going to be the exact files and commit hash that's going to be audited. + * How long the audit usually depends on how many lines of code slash complexity. + +3. **Duration** + * You can see a very rough approximation of how long an audit takes on your screen now. + * Of course, this depends from firm-to-firm, audit-to-audit, and tool-to-tool. So, take these with a very large grain of salt. + +4. **Timeline** + * Additionally, it's the duration that sets the price. And same thing, at the time we're recording, prices range wildly depending on who's doing the audit, how many people are doing the audit, how complex the code is, and more. + * These initial conversations are really just to get a ballpark estimate and slot you in to the auditor's schedule. + +5. **Commit Hash, Down Payment, Start Date** + * Once you have a commit hash, you can finalize the start date and final price. The commit hash is the unique ID of the code base you're working with, so the auditors can know exactly what code they're going to be looking at. + * Some auditors will ask for a down payment in order to schedule you in. + +6. **Audit Begins** + * The audit begins. The auditors will use every tool in their arsenal to find as many vulnerabilities in your code as possible. We'll give you some tricks in a minute to make this a successful step. + +7. **Initial Report** + * After the time period ends, the auditors will give you an initial report, which will list their findings by severity. Usually, categorized into highs, mediums, lows, informational slash non-critical, and gas efficiencies. High, mediums, and low represent the severity of impact and likelihood of each vulnerability. + * Informational, gas, and non-critical are findings to improve the efficiency of your code, code structure, readability, and best practice improvements. These are not necessarily vulnerabilities but more ways to improve your code. + +### The Next Steps + +8. **Mitigation Begins** + * The protocol's team will then have an agreed-upon time to fix the vulnerabilities found in the initial audit report. + * Sometimes, depending on the severity of the findings, you have to start from scratch. But, more times than not, you can just implement the recommendations the auditors give you. + +9. **Final Report** + * After the protocol makes these changes, the audit team will do a final audit report exclusively on the fixes made to address the issues brought up in the initial report. + +10. **Post Audit** + * Hopefully, the protocol and auditors have a great experience together. They can work together in the future to keep Web 3 secure. + +### Making Your Audit Successful + +Now, there are a few key things you can do to make sure your audit is successful. To get the most out of your audit, you should: + +1. Have clear documentation +2. A robust test suite ideally including fuzz tests +3. Code should be commented and readable +4. Modern best practices followed +5. Communication channel between developers and auditors +6. Do an initial video walkthrough of code + + * The most important part of the process is during the audit. You want to think of you and your auditors working together as a team. One of the best ways to do this is to have a dedicated channel where auditors can ask questions to developers. + * The developers will always have more context over the codebase than the auditors ever will, because they have spent more time working on it. + * The more documentation, context, and information you can give to the auditors, the better. This way, it can be easy for anyone to walk through the code and understand what it's supposed to do. + +In fact, 80% of all bugs are actually business logic implementation bugs. This means that these are bugs that have nothing to do with some weird coding error and are just somebody not knowing what the protocol should be doing. It's vitally important that the auditors understand what the code should be doing. Having a modern test suite and tooling can also make auditors spend less time fiddling with your tooling and more time finding issues. + +### Additional Information + +1. **Post Audit** + * We highly encourage you to take the recommendations your auditors give you seriously. Additionally, after an audit, if you make a change to your code base, that new code is now unaudited code. It doesn't matter how small the changes. We've seen a ton of protocols saying, "Oh, I'll just slip in one line of code." And sure enough, that's the line of code that gets exploited. Depending on the seriousness of your protocol and how many users you want to use it, one audit might not even be enough. Working with multiple auditors and getting more eyes on your code will give you a better chance of finding more vulnerabilities. + +2. **What an Audit Isn't** + * An audit doesn't mean that your code is bug-free. An audit is a security journey between the protocol and the auditor, to find as many bugs as possible and teach the protocol different methodologies to stay more secure in the future. Security is a continuous process that is always evolving. No matter how much experience someone has, people at all levels have missed vulnerabilities. On the unfortunate day that that happens, be sure that you and your auditor can jump on a call quickly to try to remedy the situation. Consider getting insurance for your protocol as well. + +### How to Prepare for an Audit + +Let's jump back to our code. Let's go ahead and prepare this code for an audit. +We need to clean up our README. We need to set up a "How to run" section in our documentation. +We need to go through our code. We probably need to add some more docstrings because right now, a lot of this is kind of woosy, right? We're not really sure what these functions are doing. We would need to update docstrings. Additionally, we need to write some docs in our README as to like what this protocol even does, right? Oftentimes, auditing and doing security on our protocol is going to be just making sure that the code matches what it's supposed to do. But if security researchers don't know what this code base is supposed to do, then there's nothing for them to check against. So, we want to write some docs saying, "Hey, here's what the codebase is supposed to do. Here's how the stablecoin works. Here's how the collateralization ratio works." et cetera. Then, we would want to create a scope for this as well. A scope of the project. So, we would say, "Hey, for this audit, we would want you to audit these two contracts: DecentralizedStableCoin.vy and DSCEngine.vy." We could optionally also add our library files from Snyk, but most of the time, those are going to be ignored. We go over security way, way more in depth in the Smart Contract Security section of CyfrIn Updraft. We go into security even more and Assembly and Formal Verification. These are both written with Solidity in mind. However, at this point in your career, pretty much all of the knowledge will transfer over. Pretty much all the examples in the Foundry and Solidity curriculum are the exact same examples you just did in Vyper and Python. So, to get deeper into security, you would want to head over here. But one other thing I always point out is the thing called "The Rekt Test." These are a list of 12 questions you want to ask yourself to make sure you're ready to deploy your smart contracts. Now, there are some more advanced things in here, like "Do you have a team member with security defined in their role?" "Do you require hardware security keys for production systems?" which are things we haven't gone over, but these are some of the things that you really need to consider when you're actually going to deploy your contract. Security is absolutely crucial when it comes to these smart contracts because if you have a bug, there goes all your money, there goes all of your hard work, down the tube. So, this is a good thing to check out before deploying as well. And if you're a little bit confused still on what even is an audit, don't worry. Once you get to a point where you're ready to deploy a smart contract, that's when you're going to want to start thinking about one. Or, if you decide you want to go down the security route, that's when you start thinking about them, too. And in my opinion, some of the best developers on Earth are also security-focused. So, I highly recommend you checking out CodeHawks, where there are competitive audits that you can participate in to actually get better at security yourself. So, a couple of things we wanted to do to get this a little bit better. We would add some docs how to write this, update our docstring, add docs about what this code base even does, include the scope of what our audit looks like. And, there's a couple other things as well. I highly recommend people who want to become either A: Better developers, or B: Get into security, definitely go check out CodeHawks, sign up, try to compete in some competitive audits because even just doing one or two, your skills and your understanding of how audits work and what they look like will skyrocket just by doing one or two. Additionally, CodeHawks has this thing called "First Flights", which are incredibly easy competitive audits. So, it's easy to get in, start doing some code reviews, and the like. From 2f39891ebd4dbad7d9264ecfe66abe4d994106c8 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:39:36 -0700 Subject: [PATCH 220/255] Equious updated courses/advanced-moccasin/3-moccasin-stablecoin/2-what-is-a-stablecoin/+page.md. --- .../2-what-is-a-stablecoin/+page.md | 250 +++++++++++++++++- 1 file changed, 245 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/2-what-is-a-stablecoin/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/2-what-is-a-stablecoin/+page.md index faa9d44a8..29b317abc 100644 --- a/courses/advanced-moccasin/3-moccasin-stablecoin/2-what-is-a-stablecoin/+page.md +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/2-what-is-a-stablecoin/+page.md @@ -1,5 +1,245 @@ - - --- - title: What Is A Stablecoin - --- - \ No newline at end of file +## What is a Stablecoin? (But Actually) + +We are going to learn about stablecoins and why they are important. + +Let's start with the definition of a stablecoin. A stablecoin is a cryptocurrency whose buying power stays relatively stable. It doesn't fluctuate in value compared to the rest of the market. + +Why do we care about stablecoins? Because money is important! In everyday society, we need a stable currency to fulfill the three functions of money. In Web3, we need a crypto version of this. + +The three functions of money are: + +* Storage of value +* Unit of account +* Medium of exchange + +We need a stablecoin that fulfills these three functions. + +Here's where we need to start disagreeing with traditional media. Stablecoins are often categorized into these four categories: + +* Fiat-collateralized +* Crypto-backed +* Commodity-backed +* Algorithmic + +This isn't the worst way to categorize them. It makes it easier for new people to understand, but I think it paints an inaccurate picture. + +Here's what we are going to do. We are going to categorize stablecoins by: + +* **Relative stability** - pegged/anchored or floating. +* **Stability method** - governed or algorithmic. +* **Collateral type** - endogenous or exogenous. + +Let's start with relative stability. + +When we talk about stability, something is only stable relative to something else. + +The most popular type of stablecoin is a pegged or anchored stablecoin. These are stablecoins that are pegged or anchored to another asset like the USD. + +Examples of pegged stablecoins are: + +* Tether +* Dai +* USDC + +They follow the narrative of one of these coins equals $1.00 and that's how they stay stable. They are stable because they track the price of another asset that we think is stable. + +Most of these stablecoins have some type of mechanism to make them almost interchangeable with their pegged assets. + +USDC says for every USDC token printed or minted, there is a dollar or a bunch of assets that equal a dollar in some bank account somewhere. So, the way it keeps its value is that at any time, you should be able to swap your USDC for the dollar. Or at least, hypothetically, so. + +Die, on the other hand, uses a permissionless over-collateralization to maintain its peg. But, we'll get to understanding that a little later. + +However, a stablecoin doesn't have to be pegged to another asset. It can be floating. + +Remember, to be considered a stablecoin, its buying power just has to stay relatively the same over time. + +So, a floating stablecoin is floating because it's buying power stays the same and it's not tied down to any other asset. + +With this mechanism, you could hypothetically have a stablecoin that's even more stable than an anchored or pegged stablecoin. + +Let's look at an example. + +Let's say I can buy 10 apples for $10 today, but in 5 years, I can only buy five apples with $10. That is an example of buying power changing and not being very stable. + +But, someone buying apples with dollars would probably be able to buy the same amount of apples six months ago to now. That's an example of buying power staying relatively the same. + +Since we can buy the same amount of apples today than six months ago, a dollar would be considered a more stable asset whereas Bitcoin would be much less stable. This is what we mean by buying power. + +Now, let's look at the second categorization, stability method. + +The stability method is the mechanism that keeps the coins stable. If it's a pegged stablecoin, what is the pegging mechanism? If it's a floating stablecoin, well, what is the floating mechanism? + +And, it typically revolves around minting and burning the stablecoins in very specific ways. And, usually, it refers to who or what is doing the minting and burning. + +These are on a spectrum of governed to algorithmic. In a governed stablecoin, there is a governing body or a centralized body that is minting and burning the stablecoins. + +Examples of algorithmic stablecoins are: + +* Die +* Frax +* Rai + +And yes, the $40 billion disaster UST. + +Yes, we are going to talk a little bit more about classic UST and Luna. + +Now, a token can have algorithmic and governed properties in the same way that it can be somewhere in the middle of being floating and pegged. + +Die, for example, does have an autonomous set of code that dictates the minting and burning, but it also has a DAO where they can vote on different interest rates and what can be collateral types and different things like that. + +So, technically it is a hybrid system. It has some governance mechanisms and also some algorithmic ones. + +USDC would fall purely in the governed category because it's controlled by a centralized body. + +UST and Luna would fall almost purely in algorithmic. + +The Dirt Roads blog has some amazing takes on these pieces and a wonderful visualization of where in a spectrum of coins that are more algorithmic or governed. + +They use "dumb" as the opposite of "algorithmic" instead of "governed," which probably isn't wrong. Most classically categorized fiat collateralized stablecoins almost all fall into the governed or dumb section since they are dealing with fiat currency and you need a centralized entity to onboard that fiat to the blockchain. + +You'll also notice on this chart, they have anchored versus reflexive on the x-axis. That's referring to how the collateral type affects the stablecoin. Collateral type is what we are going to cover next. + +So, the summary here, though, is algorithmic stablecoins use some sort of autonomous permissionless code to mint and burn tokens, whereas a governed stablecoin has some human interaction that mints and burns the coins and keeps them stable. + +Now, before we go to our final category, let's look at this chart again. + +We could replace the word "anchored" with exogenous, and reflexive with endogenous. And we have a chart that shows collateral type versus stability mechanism, which brings us to number three, collateral type. + +Now, when we say collateral we mean the stuff backing our stablecoins and giving it value. + +USDC has the dollar as its collateral, and it's the dollar that gives the USDC token its value, because you can hypothetically swap one USDC for $1.00. + +Die is collateralized by many assets. For example, you could deposit ETH and get minted Die in return. + +UST was, in a roundabout way, collateralized by Luna. + +Exogenous collateral is collateral that originates from outside the protocol, and endogenous collateral originates from inside the protocol. + +So, one of the easier ways to define what type of collateral a protocol is using is to ask this question: if the stablecoin fails, does the underlying collateral also fail? If yes, it's endogenous. If no, it's exogenous. + +If USDC fails, the protocol does the underlying collateral, the dollar, fail? No, so the protocol has exogenous collateral. If the USDC stablecoin fails, the dollar is going to keep being the dollar. + +If Die, the stablecoin, fails, does the underlying collateral, ETH, also fail? No. So, the Die system is exogenous. The value of ETH isn't dependent on the value of Die. + +If UST fails, does the underlying collateral, Luna slash Terra fail? Yes, absolutely. And, this is exactly what happened that caused the system to lose $40 billion in what seemed like a day. + +Exogenous collateral originates from outside the protocol. Endogenous collateral originates from inside the protocol. + +Two other good tests that you can ask are: was the collateral created with the sole purpose of being collateral, or does the protocol own the issuance of the underlying collateral? + +If the answer is yes to either one of those, then it's endogenous collateral. + +Now, the traditional media usually says that algorithmic stablecoins are to blame. But, I think what they are really referring to is endogenously collateralized stablecoins. It makes sense that they can be scary and potentially dangerous, because their value kind of comes from nothing. Endogenously collateralized stablecoins are typically over-collateralized, meaning there's more value of collateral than there is of the stablecoins. + +Here, we have another image from Dirt Roads comparing different stablecoins. The exogenous versus endogenous collateral of the protocols and how much they have. + +MakerDAO slash Die has almost all exogenous collateral. + +Frax, which is another stablecoin we haven't really spoken about too much, has a mix of exogenous and endogenous collateral. + +And the old Terra Luna and UST system had mainly endogenous collateral, which is how the system was able to crumble so quickly. + +So, yeah, yeah. Endogenously collateralized stablecoins don't have a great track record. So, why would you want to make one? Well, the answer is scale. And, often times people will also say capital efficiency. + +With exogenously collateralized stablecoins, the only way you can mint more stablecoins is by onboarding more collateral. + +You can only have a stablecoin market cap that is as high or higher than that of all your collateral. + +So, if you want to have $68 billion in stablecoins, then that means you need to have $68 billion worth of collateral. And, that's a lot of money that you would need to onboard to your system. + +If you have an endogenously collateralized stablecoin, you can have $0 worth of collateral, meaning it's much easier to become massive faster. + +Now, I agree with the Dirt Roads publication when they say that exogenously collateralized stablecoins can't scale. And, I talked more about that in the blog associated with this video. So, if you are interested, be sure to check that out after the rest of this video. + +But, watch the rest of this video because we are just getting started. + +In the blog, we also talk more about seigniorage shares and shelling coin logic, which, if you are interested in that stuff, definitely check it out. + +Most of these endogenously collateralized coins can be traced back to a paper written by a man named Robert Sams, where he talks about how to build an endogenously collateralized stablecoin using a seigniorage shares model. Which, again, I'm not going to go into, but I wanted to mention it, because it's probably one of the most influential papers when it comes to these endogenously collateralized stablecoins. + +Let's move on to the concept of **reflexive**, which relates to the **collateral type**. + +When we talk about collateral, we mean the stuff backing our stablecoins and giving it value. + +Examples of collateral types include: + +* **USD** +* **ETH** +* **Luna** + +The **exogenous versus endogenous** distinction is important: + +* **Exogenous collateral** originates from outside the protocol. +* **Endogenous collateral** originates from inside the protocol. + +Here are two good tests to determine which category a protocol is using: + +* Was the collateral created with the sole purpose of being collateral? +* Does the protocol own the issuance of the underlying collateral? + +If the answer is **yes** to either one of these, then it's **endogenous collateral**. + +Now, the traditional media usually says that algorithmic stablecoins are to blame. But, I think what they are really referring to is **endogenously collateralized stablecoins**. It makes sense that they can be scary and potentially dangerous, because their value kind of comes from nothing. + +Endogenously collateralized stablecoins are typically **over-collateralized**, meaning there's more value of collateral than there is of the stablecoins. + +If you have an endogenously collateralized stablecoin, you can have $0 worth of collateral, meaning it's much easier to become massive faster. + +Now, I agree with the Dirt Roads publication when they say that exogenously collateralized stablecoins can't scale. And, I talked more about that in the blog associated with this video. So, if you are interested, be sure to check that out after the rest of this video. + +But, watch the rest of this video because we are just getting started. + +In the blog, we also talk more about **seigniorage shares** and **shelling coin logic**, which, if you are interested in that stuff, definitely check it out. + +Most of these endogenously collateralized coins can be traced back to a paper written by a man named Robert Sams, where he talks about how to build an endogenously collateralized stablecoin using a seigniorage shares model. Which, again, I'm not going to go into, but I wanted to mention it, because it's probably one of the most influential papers when it comes to these endogenously collateralized stablecoins. + +Let's move on to **the fourth category, what they actually do.** + +We'll start by asking the question, okay, which one of these is the best stablecoin? And to that, I need to ask, the best stablecoin for who? + +Centralized governed coins obviously have the issue of centrality, which sort of defeats the purpose of being in Web3. So, maybe we want some flavors of algorithmic stablecoins. Maybe that's probably what we want for Web3. But these algorithmic coins might feel untested to non-crypto people, and the fees associated with them might be a little bit scary. + +For me, personally, like I said, I really love the idea of Rai. The idea is to have stable buying power as opposed to being pegged to some other asset and its algorithmic nature as opposed to being centralized. So, it's a decentralized stablecoin. That's what we want. But every coin has their trade-offs. And I would argue there is definitely no best coin right now. The stablecoin that's best for the average person might matter much less. It's a stablecoin that's best for rich whales might be what's more important here. + +Now, for most algorithmic stablecoins, you'll see this: some sort of fee associated with minting the coins. + +Protocols do make money off of these stablecoin systems, which I think is good. Sometimes they need money for maintenance, incentives for the stability of the coin, or money for improvements. So I do think these fees are good. + +We need stablecoins for the three functions of money. Storage of value, unit of account and medium of exchange. But are you going to be the one to pay these fees to mint them and keep them in circulation? + +Someone has to pay to mint these coins and often keep paying. The market cap for some of these stablecoins is in the billions. If there's a 1% fee on these and the market cap is $1 billion, or talking about $10 million. Are average people going to collectively pay $10 million a year to keep these in circulation? No. + +So, average people aren't minting these for the three functions of money, well, then who is minting these? So let's play a little bit of a thought experiment. Let's say I have ETH as an investment and I've bought up all the ETH. I've sold my house. I've sold everything I own, and I've used everything I have to buy Ethereum. But, I want more, what can I do? I can put my ETH into one of these stablecoin protocols, get the minted stablecoin and then sell the stablecoin for more ETH. You might have heard concepts like leverage investing, or margin trading, and this is essentially the Web3 equivalent. It's kind of funny. + +We can get into more depth about **how a stablecoin like Dai works** with an example: + +```text +How DAI/MakerDAO works +$100 in ETH +1 ETH == $2000 +$50 in DAI +Mint +$100 in ETH +2% Stability Fee +1 ETH == $2000 +$50 in DAI +Burn +``` + +The stability fee is used to make sure that the system always has more collateral than minted Die. It's also a sort of punishment if someone doesn't keep their collateral up and a way to save the system from becoming under-collateralized. + +Additionally, MakerDAO has a **Maker token** that is used to vote. + +Now, let's look at **Rai**. + +Rai is one of the few floating stablecoins. It uses a **nearly purely algorithmic** stability mechanism. Its collateral type is ETH. + +The idea is to have stable buying power as opposed to being pegged to some other asset. + +It's **decentralized**, meaning there is no governing body and no one controlling the minting and burning of coins. + +We are going to get better and better at creating stablecoins because they are important. + +In the DeFi Minimal repo, we have some minimal stablecoin contract examples, link in the description. + + From 00f8d03bd86ad86ec094d78c4405dd74feb7b11c Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:39:50 -0700 Subject: [PATCH 221/255] Equious updated courses/advanced-moccasin/3-moccasin-stablecoin/20-recap/+page.md. --- .../3-moccasin-stablecoin/20-recap/+page.md | 38 ++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/20-recap/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/20-recap/+page.md index 520a7c357..33f9013da 100644 --- a/courses/advanced-moccasin/3-moccasin-stablecoin/20-recap/+page.md +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/20-recap/+page.md @@ -1,5 +1,33 @@ - - --- - title: Recap - --- - \ No newline at end of file +We just finished writing a decentralized stablecoin and we should be very proud of ourselves. + +Let's do a quick recap of what we accomplished. + +First, we learned about stablecoins, and different types of stablecoins. We learned about things like: + +- Collateral (Exogenous (WETH, WBTC, etc...), Endogenous, and Collateral Type) +- Minting (Stability Mechanism, Decentralized (Algorithmic) Value (Relative Stability), Anchored (Pegged to USD)) + +We watched that long video of me talking about collateral types. Remember, this is important both as a developer and as someone who may be engaging with DeFi. Now you can go, "okay, is this a collateralized stablecoin?". + +We learned a lot about deploying production code and working with production code. We learned about DeFi in general and how to deploy, redeem, mint, burn, and liquidate collateral. + +We wrote unit tests. We only have two in this lesson. If you go to the GitHub repo you'll find we have a lot more. If you don't write tests, shame on you because that is one of the biggest learning pieces from this entire section. + +We also wrote fuzz tests. Remember, fuzz tests allow us to have an even higher assurance that the code we wrote is good. + +We worked with mocks and interfaces. And we even did a little bit of thinking about audit prep. + +We can format everything in our project a little bit nicer with UV Run Ruff, like this: + +```bash +uv run ruff check --select I --fix +``` + +Let's also run Mamushi to reformat our Vyper files: + +```bash +uv run mamushi src +``` + +Congratulations on completing the Mocassin Stablecoin course! +Now is a great time to take a break, go for a walk, hit the gym, or grab some ice cream. We are almost done! From 496a375da01e3be46fb201042e0bbaf77f01541a Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:40:03 -0700 Subject: [PATCH 222/255] Equious updated courses/advanced-moccasin/3-moccasin-stablecoin/3-setup/+page.md. --- .../3-moccasin-stablecoin/3-setup/+page.md | 151 +++++++++++++++++- 1 file changed, 146 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/3-setup/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/3-setup/+page.md index b8774470f..f18de9949 100644 --- a/courses/advanced-moccasin/3-moccasin-stablecoin/3-setup/+page.md +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/3-setup/+page.md @@ -1,5 +1,146 @@ - - --- - title: Setup - --- - \ No newline at end of file +## Stablecoin Project Setup + +We are going to create a new repo for it. +```bash +mkdir mox-stablecoin-cu +``` + +Then we will open this directory in Visual Studio Code: +```bash +code mox-stablecoin-cu +``` + +Then we will create a new folder called "mox-init." +```bash +mox init --vscode --pyproject +``` + +We will delete everything in the "script" folder. + +Next, we will open "README.md" to define what we are building. +``` +# Stablecoin +## Introduction +1. Users can deposit $200 of ETH +2. They can then mint $50 of Stablecoin + 1. This means they will have a 4/1 ratio of collateral to stablecoin (200/50 = 4/1) + 2. We will set a required collateral ratio of 2/1 + 3. If the price of ETH drops, for example to $50, others should be able to liquidate those users! + +``` +We should use AI to assist us in understanding the finance concepts involved in this lesson. + +Now we are ready to start building our stablecoin. + +We are going to create our actual stablecoin. + +We will call this "decentralized_stable_coin.vy." + +``` +# pragma version 0.4.0 +@license MIT +@author You +@title Decentralized Stable Coin +@dev Follows the ERC20 token standard +``` + +We will use the "snekmate" package to assist us. +```bash +mox install snekmate +``` + +We can now import the necessary functions from "snekmate." +``` +from snekmate.tokens import erc20 +from snekmate.auth import ownable as ow +``` + +We will add the necessary functions. +``` +initializes: ow +initializes: erc20(ownable = ow) + +@deploy +def init(): + ow.init() + erc20.init(name = "Decentralized Stable Coin", symbol = "DSC", decimals = 18) +``` + +We will define the constants for our stablecoin. +``` +NAME: constant(String[25]) = "Decentralized Stable Coin" +SYMBOL: constant(String[5]) = "DSC" +DECIMALS: constant(uint8) = 18 +EIP_712_VERSION: constant(String[20]) = "1" +``` + +We will export our stablecoin using "IERC20" and other functions. +``` +exports: ( + erc20.IERC20, + erc20.burn_from, + erc20.mint, + erc20.set_minter, + ow.owner, + ow.transfer_ownership +) +``` + +The final code is as follows: +``` +# pragma version 0.4.0 +@license MIT +@author You +@title Decentralized Stable Coin +@dev Follows the ERC20 token standard + +from snekmate.tokens import erc20 +from snekmate.auth import ownable as ow + +initializes: ow +initializes: erc20(ownable = ow) + +exports: ( + erc20.IERC20, + erc20.burn_from, + erc20.mint, + erc20.set_minter, + ow.owner, + ow.transfer_ownership +) + +NAME: constant(String[25]) = "Decentralized Stable Coin" +SYMBOL: constant(String[5]) = "DSC" +DECIMALS: constant(uint8) = 18 +EIP_712_VERSION: constant(String[20]) = "1" + +@deploy +def init(): + ow.init() + erc20.init(NAME, SYMBOL, DECIMALS, NAME, EIP_712_VERSION) + +```courses\advanced-moccasin\3-moccasin-stablecoin\3-setup\+page.md + You are a supervisor checking the quality of a written lesson generated by a technical writing system. You are tasked with ensuring the written lesson is high quality and meets certain criteria. Important criteria: + + 1. Include ALL significant topics covered + 2. If something specific such a technique or methodology is mentioned, this is very important to include + 3. ALL code should be formatted on new lines as: + ```javascript + commands + ``` + 4. DO NOT include diagrams or images, but absolutely provide code blocks from the lesson. + 6. ALWAYS format your response in markdown + 7. DO NOT use H1s + 8. ONLY output the written lessons + 9. Use first person plural (we, us) when appropriate + 10. DO NOT transcribe the video verbatim. Written lesson should be bespoke + 11. DO NOT deviate from the video content + 12. ONLY include code being shown or written in the video + 13. Terminal commands being run must be formatted on new lines as: + ```bash + commands + ``` + + Based on the criteria above, ensure the provided lesson matches what's required. Check the major topics in the written lesson vs the video content. If anything in the written lesson ISN'T in the video, remove it. If anything in the video ISN'T in the written lesson, add it. + + From fe7b0bfde819be83a27ed471f98e61ed910c5b1b Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:40:16 -0700 Subject: [PATCH 223/255] Equious updated courses/advanced-moccasin/3-moccasin-stablecoin/4-engine-intro/+page.md. --- .../4-engine-intro/+page.md | 204 +++++++++++++++++- 1 file changed, 199 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/4-engine-intro/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/4-engine-intro/+page.md index 36e0d1a48..0d70ccc9b 100644 --- a/courses/advanced-moccasin/3-moccasin-stablecoin/4-engine-intro/+page.md +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/4-engine-intro/+page.md @@ -1,5 +1,199 @@ - - --- - title: Engine Intro - --- - \ No newline at end of file +## DSC Engine Intro + +This lesson will introduce the DSC Engine, a component of a decentralized stablecoin system. We'll begin by creating a new contract in the _src_ folder named _dsc_engine.vy_. We will be creating an ERC20 standard contract that defines the core functionality of the DSC Engine. + +We'll copy and paste the following code into the new file. + +```python +# pragma version 0.4.0 +@license MIT +@author You +@title DSC Engine +@notice This contract is the engine of the Decentralized Stable Coin. It is responsible for the minting and burning of the stablecoin. +@notice Collateral: Exogenous (WETH, WBTC, etc...) +@notice Minting (Stability) Mechanism: Decentralized (Algorithmic) +@notice Value (Relative Stability): Anchored (Pegged to USD) +@notice Collateral Type: Crypto +# +from snekmate.tokens import erc20 +from snekmate.auth import ownable as ow +# +initializes: ow +initializes: erc20(ownable=ow) +# +exports: ( + erc20.IERC20, + erc20.burn_from, + erc20.mint, + erc20.set_minter, + ow.owner, + ow.owner_set, + ow.transfer_ownership +) +# +NAME: constant(String[25]) = "Decentralized Stable Coin" +SYMBOL: constant(String[5]) = "DSC" +DECIMALS: constant(uint8) = 18 +EIP_712_VERSION: constant(String[20]) = "1" +``` + +We'll create a new header titled _EXTERNAL FUNCTIONS_. We'll also create the _@deploy_ constructor function. + +```python +# +# EXTERNAL FUNCTIONS +# +@deploy +def __init__(): + pass +``` + +In the _@deploy_ constructor function we are going to take in a list of token addresses. + +```python +@deploy +def __init__(): + token_addresses: address[2], +``` + +If we wanted this to be more advanced, we could use a dynamic array or other data structures. However, we are just going to keep things simple. We will only support two types of collateral. + +```python +@deploy +def __init__(): + token_addresses: address[2], + price_feed_addresses: address[2], +``` + +We will also need the address of the DSC token. + +```python +@deploy +def __init__(): + token_addresses: address[2], + price_feed_addresses: address[2], + dsc_address: address +``` + +We'll create a new header titled _STATE VARIABLES_. We'll also define _DSC_ as a public immutable address. + +```python +# +# STATE VARIABLES +# +DSC: public(immutable) i_decentralized_stable_coin, +``` + +Next, we'll define _COLLATERAL_TOKENS_ as a public immutable address array of size 2. + +```python +# +# STATE VARIABLES +# +DSC: public(immutable) i_decentralized_stable_coin, +COLLATERAL_TOKENS: public(immutable) address[2], +``` + +We'll also define _token_to_price_feed_ as a public hashmap that maps token addresses to price feeds. + +```python +# +# STATE VARIABLES +# +DSC: public(immutable) i_decentralized_stable_coin, +COLLATERAL_TOKENS: public(immutable) address[2], +# +# Storage +# +token_to_price_feed: public(HashMap[address, address]) +``` + +Lastly, we'll set our state variables. + +```python +# +# STATE VARIABLES +# +DSC: public(immutable) i_decentralized_stable_coin, +COLLATERAL_TOKENS: public(immutable) address[2], +# +# Storage +# +token_to_price_feed: public(HashMap[address, address]) + +# +# EXTERNAL FUNCTIONS +# +@deploy +def __init__(): + token_addresses: address[2], + price_feed_addresses: address[2], + dsc_address: address + DSC = i_decentralized_stable_coin.dsc_address + COLLATERAL_TOKENS = token_addresses + self.token_to_price_feed[token_addresses[0]] = price_feed_addresses[0] + self.token_to_price_feed[token_addresses[1]] = price_feed_addresses[1] +``` + +We'll create a new file titled _i_decentralized_stable_coin.vy_. We'll copy and paste the following code into this file. + +```python +# pragma version 0.4.0 +@license MIT +@author You +@title i_decentralized_stablecoin +@notice +# +@external +def burn_from(owner: address, amount: uint256): + pass +# +@external +def mint(owner: address, amount: uint256): + pass +``` + +Finally, we'll import the _i_decentralized_stable_coin_ interface. + +```python +# pragma version 0.4.0 +@license MIT +@author You +@title DSC Engine +@notice This contract is the engine of the Decentralized Stable Coin. It is responsible for the minting and burning of the stablecoin. +@notice Collateral: Exogenous (WETH, WBTC, etc...) +@notice Minting (Stability) Mechanism: Decentralized (Algorithmic) +@notice Value (Relative Stability): Anchored (Pegged to USD) +@notice Collateral Type: Crypto +# +from snekmate.tokens import erc20 +from snekmate.auth import ownable as ow +from interfaces import i_decentralized_stable_coin +# +initializes: ow +initializes: erc20(ownable=ow) +implements: i_decentralized_stable_coin +# +exports: ( + erc20.IERC20, + erc20.burn_from, + erc20.mint, + erc20.set_minter, + ow.owner, + ow.owner_set, + ow.transfer_ownership +) +# +NAME: constant(String[25]) = "Decentralized Stable Coin" +SYMBOL: constant(String[5]) = "DSC" +DECIMALS: constant(uint8) = 18 +EIP_712_VERSION: constant(String[20]) = "1" +``` + +Now, we can compile our contract. + +```bash +mox compile +``` + +This concludes the DSC Engine Intro lesson. From 279d2bb4a51d2ce85aefc0f60978cfa40e0c047c Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:40:30 -0700 Subject: [PATCH 224/255] Equious updated courses/advanced-moccasin/3-moccasin-stablecoin/5-deposit-collateral/+page.md. --- .../5-deposit-collateral/+page.md | 81 +++++++++++++++++-- 1 file changed, 76 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/5-deposit-collateral/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/5-deposit-collateral/+page.md index e89d3139a..60f9f9f04 100644 --- a/courses/advanced-moccasin/3-moccasin-stablecoin/5-deposit-collateral/+page.md +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/5-deposit-collateral/+page.md @@ -1,5 +1,76 @@ - - --- - title: Deposit Collateral - --- - \ No newline at end of file +## Deposit Collateral + +We are now going to write some code related to the deposit collateral function in a smart contract. First, we'll write the code for our token addresses, price feed addresses, and DSC token. + +```python +@deploy +def init_(token_addresses: address[2], price_feed_addresses: address[2], dsc_address: address): + """ + Notice we have two collateral token types: ETH and WBTC + """ + DSC = I_decentralized_stable_coin(dsc_address) + COLLATERAL_TOKENS = token_addresses + self.token_to_price_feed[token_addresses[0]] = price_feed_addresses[0] + self.token_to_price_feed[token_addresses[1]] = price_feed_addresses[1] +``` + +Now we can create a deposit collateral function. We will have two versions of this function. First, we'll create an external one: + +```python +@external +def deposit_collateral(): + pass +``` + +We'll also create an internal version: + +```python +@internal +def _deposit_collateral(): + pass +``` + +We'll set up an assertion in our internal function: + +```python +@internal +def _deposit_collateral(token_collateral_address: address, amount_collateral: uint256): + """ + Checks + """ + assert amount_collateral > 0, "DSCEngine: Needs more than zero" + assert self.token_to_price_feed[token_collateral_address] != empty_address, "DSCEngine: InvalidCollateral" +``` + +Finally, we will transfer the collateral from the user to the DSC Engine. + +```python +self.user_to_token_to_amount_deposited[msg.sender][token_collateral_address] += amount_collateral +log.CollateralDeposited(msg.sender, amount_collateral) +success: bool = extcall(IERC20(token_collateral_address).transferFrom(msg.sender, self, amount_collateral)) +assert success, "DSCEngine: Transfer failed" +``` + +We have created the basic code for the deposit collateral function. We need to keep track of how much collateral each user has deposited. We will do this by creating a hashmap of the user to the token to the amount deposited. + +```python +user_to_token_to_amount_deposited: public(HashMap[address, HashMap[address, uint256]]) +``` + +We will use the event keyword to emit an event called "CollateralDeposited" in our deposit collateral function. + +```python +event CollateralDeposited( + user: indexed(address), + token_collateral_address: indexed(address), + amount_collateral: uint256 +) +``` + +To conclude this lesson, we'll use `vheader` to add a header for our internal functions, so that we can organize our code. + +```bash +vheader internal functions +``` + +You should add comments to your code. Comments can help other developers understand your code, and they can be helpful for you as well when you come back to your code later. Adding comments is a great way to make sure your code is well-organized and easy to understand. From b04186358022aba4fc3ca0c3369ed0933bdc51ba Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:40:43 -0700 Subject: [PATCH 225/255] Equious updated courses/advanced-moccasin/3-moccasin-stablecoin/6-health-factor/+page.md. --- .../6-health-factor/+page.md | 104 +++++++++++++++++- 1 file changed, 99 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/6-health-factor/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/6-health-factor/+page.md index defc39586..93c36f726 100644 --- a/courses/advanced-moccasin/3-moccasin-stablecoin/6-health-factor/+page.md +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/6-health-factor/+page.md @@ -1,5 +1,99 @@ - - --- - title: Health Factor - --- - \ No newline at end of file +## Creating a Health Factor to Liquidate Users + +In this lesson, we will create a health factor and liquidation threshold to prevent users from minting an excessive amount of tokens relative to the amount of collateral they have deposited. + +### Minting DSC Tokens + +We will first create an external function called `mintDSC` to allow users to mint tokens: + +```javascript +@external +def mintDSC(amount_dsc_to_mint: uint256, collateral_address: address): + success: bool = extcall IERC20(token_collateral_address).transferFrom(msg.sender, self, amount_collateral) + assert success, "DSCEngine: Transfer failed" + self.user_to_dsc_minted[msg.sender] += amount_dsc_to_mint + log CollateralDeposited(msg.sender, amount_collateral) +``` + +### Creating a Health Factor + +We will now create a new internal function called `health_factor` that takes in a user address as an argument. + +```javascript +@internal +def health_factor(user: address): + total_dsc_minted: uint256 = 0 + total_collateral_value_usd: uint256 = 0 + total_dsc_minted, total_collateral_value_usd = self._get_account_information(user) + return self._calculate_health_factor(total_dsc_minted, total_collateral_value_usd) +``` + +Our `health_factor` function needs to know how many tokens the user has minted and how much collateral they have deposited. We will create two new internal functions to get this information, `_get_account_information` and `_get_account_collateral_value`. + +```javascript +@internal +def _get_account_information(user: address) -> (uint256, uint256): + """@notice returns the total DSC minted, and the total collateral value deposited""" + total_dsc_minted: uint256 = self.user_to_dsc_minted[user] + collateral_value_in_usd: uint256 = 0 + for token: address in COLLATERAL_TOKENS: + amount: uint256 = self.user_to_token_to_amount_deposited[user][token] + collateral_value_in_usd += self._get_usd_value(token, amount) + return total_dsc_minted, collateral_value_in_usd + + +@internal +def _get_account_collateral_value(address: address) -> uint256: + """@notice returns the total collateral value deposited""" + total_collateral_value_usd: uint256 = 0 + for token: address in COLLATERAL_TOKENS: + amount: uint256 = self.user_to_token_to_amount_deposited[user][token] + total_collateral_value_usd += self._get_usd_value(token, amount) + return total_collateral_value_usd +``` + +We will also need a new function called `_get_usd_value` which takes in a token address and an amount and returns the value in USD. + +```javascript +@internal +def _get_usd_value(token: address, amount: uint256) -> uint256: + price_feed: AggregatorV3Interface = AggregatorV3Interface(self.token_to_price_feed[token]) + price: int256 = price_feed.staticcall price_feed.latestAnswer() + return (convert(price, uint256) * ADDITIONAL_FEED_PRECISION * amount) // PRECISION +``` + +### Calculating the Health Factor + +Now we are ready to finish our `health_factor` function. We will first call our `_get_account_information` function to get the `total_dsc_minted` and `total_collateral_value_in_usd`. We will then calculate the health factor based on these values. + +```javascript +@internal +def _calculate_health_factor(total_dsc_minted: uint256, total_collateral_value_usd: uint256) -> uint256: + if total_dsc_minted == 0: + return max_value(uint256) + collateral_adjusted_for_threshold: uint256 = (total_collateral_value_usd * LIQUIDATION_THRESHOLD) // LIQUIDATION_PRECISION + return (collateral_adjusted_for_threshold * PRECISION) // total_dsc_minted +``` + +### Creating a Liquidation Threshold + +We will add a new state variable called `LIQUIDATION_THRESHOLD` at the top of our contract which will be a public constant set to 50. + +```javascript +LIQUIDATION_THRESHOLD: public(constant(uint256)) = 50 +``` + +Now that we have our health factor function, we need to add a function that reverts if the health factor is broken. We will call this function `_revert_if_health_factor_broken` which takes in a user address as an argument. + +```javascript +@internal +def _revert_if_health_factor_broken(user: address): + user_health_factor: uint256 = self.health_factor(user) + assert user_health_factor >= MIN_HEALTH_FACTOR, "DSCEngine: Health factor broken!" +``` + +### Conclusion + +In this lesson, we have successfully created a health factor and a liquidation threshold to prevent users from minting an excessive amount of tokens. This is an important safety feature for any stablecoin system and helps ensure its stability. + +We will build upon these core concepts in later lessons, exploring more complex features and improving the stability of our system. From e728669eeea584f468e0d64ce0936d770a138a53 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:40:57 -0700 Subject: [PATCH 226/255] Equious updated courses/advanced-moccasin/3-moccasin-stablecoin/7-minting-dsc/+page.md. --- .../7-minting-dsc/+page.md | 64 +++++++++++++++++-- 1 file changed, 59 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/7-minting-dsc/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/7-minting-dsc/+page.md index da8cd1d96..9f44154b0 100644 --- a/courses/advanced-moccasin/3-moccasin-stablecoin/7-minting-dsc/+page.md +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/7-minting-dsc/+page.md @@ -1,5 +1,59 @@ - - --- - title: Minting Dsc - --- - \ No newline at end of file +We've just built the ability for a user to deposit collateral, and now we're going to dive into the minting of the Decentralized Stable Coin! It's very important to ensure that there's always at least 2:1 ratio of collateral to the amount of DSC that's being minted. The DSC engine is responsible for managing that ratio, so let's take a look at the code. + +Here's the `mintDSC` function: +```javascript +@external +def mint_dsc(amount: uint256): + pass +``` +This function allows the user to specify the amount of DSC they want to mint. Before the actual minting happens, we need to check the user's collateral. So, let's create a function that calculates the user's health factor: +```javascript +@internal +def health_factor(user: address) -> uint256: + total_dsc_minted: uint256 = 0 + total_collateral_value_usd: uint256 = 0 + (total_dsc_minted, total_collateral_value_usd) = self.get_account_information(user) + return self.calculate_health_factor(total_dsc_minted, total_collateral_value_usd) +``` +The `health_factor` function calculates the user's health factor based on the ratio of their total collateral value in USD and the amount of DSC they've already minted. + +Now, we need a function to calculate the health factor: +```javascript +@internal +def calculate_health_factor(total_dsc_minted: uint256, total_collateral_value_usd: uint256) -> uint256: + if total_dsc_minted == 0: + return MAX_HEALTH_FACTOR + # What's the ratio of DSC minted to collateral value? + collateral_adjusted_for_threshold: uint256 = (total_collateral_value_usd + LIQUIDATION_THRESHOLD) // LIQUIDATION_PRECISION + return (collateral_adjusted_for_threshold * PRECISION) // total_dsc_minted +``` +This function calculates the health factor based on the total DSC minted and the collateral value in USD. + +Finally, let's take a look at how we actually mint the DSC: +```javascript +@internal +def _mint_dsc(amount_dsc_to_mint: uint256): + assert amount_dsc_to_mint > 0, "DSCEngine: Needs more than zero" + self.user_to_dsc_minted[msg.sender] += amount_dsc_to_mint + self.revert_if_health_factor_broken(msg.sender) + extcall dsc.mint(msg.sender, amount_dsc_to_mint) +``` +The `_mint_dsc` function makes sure that the amount of DSC being minted is above 0, it then updates the amount of DSC minted for the user, and finally it calls the DSC's mint function! + +We've now created the code for minting the DSC. Now, we will make sure that only the DSC engine is able to mint our decentralized stablecoin. + +We'll start by going to our decentralized stablecoin contract. +```javascript +@deploy +def init(): + erc20.init() +``` +Right when we deploy, we're going to set the minter to be the DSC engine, and we're going to set the owner to be the DSC engine as well. +```javascript +@deploy +def init(): + erc20.init() + erc20.set_minter(dsc_engine) + erc20.ow_transfer_ownership(dsc_engine) +``` +This ensures that only the DSC engine can mint DSC, and it can also transfer ownership of the DSC to another address! From f24d80aa4a46a0ad74aab74c25cc4124e6534fb3 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:41:10 -0700 Subject: [PATCH 227/255] Equious updated courses/advanced-moccasin/3-moccasin-stablecoin/8-redeem-collateral/+page.md. --- .../8-redeem-collateral/+page.md | 59 +++++++++++++++++-- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/8-redeem-collateral/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/8-redeem-collateral/+page.md index a319758c8..a969a2c7f 100644 --- a/courses/advanced-moccasin/3-moccasin-stablecoin/8-redeem-collateral/+page.md +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/8-redeem-collateral/+page.md @@ -1,5 +1,54 @@ - - --- - title: Redeem Collateral - --- - \ No newline at end of file +## Redeeming Collateral + +We are going to create a way for users to redeem collateral. Let's add a function for this. We will create a function that can redeem collateral and it will take in the token collateral address, the address of the user who will redeem collateral, and the amount to redeem, which will be a uint256. We'll also make sure the user doesn't redeem more collateral than they have. + +```python +@external +def redeem_collateral(token_collateral_address: address, address: address, amount: uint256): + self._redeem_collateral(token_collateral_address, address, amount) + self._revert_if_health_factor_broken(msg.sender) +``` + +We should also have an internal function to actually handle the redemption. We can do that by taking in the token collateral address, address, and amount, and then subtracting the amount from the user's token amount deposited. + +```python +@internal +def _redeem_collateral(token_collateral_address: address, address: address, amount: uint256): + self.user_to_token_amount_deposited[from][token_collateral_address] -= amount + log.CollateralRedeemed(token_collateral_address, amount, from, to) + success: bool = extcall(IERC20(token_collateral_address).transfer(to, amount)) + assert success, "DSCEngine: Transfer failed!" +``` + +Finally, to make sure we have a record of all collateral redeemed, we are going to create an event. + +```python +event CollateralRedeemed: + redeem_from: indexed(address) + amount: indexed(uint256) + to: address +``` + +You could even use test-driven development to write your tests first and then write code to match the tests! But for now, we are going to focus on writing the code and then adding the tests later. + +We can now start creating another function, an external function for depositing collateral and minting DSC. + +```python +@external +def deposit_and_mint(token_collateral_address: address, amount_collateral: uint256, amount_dsc_to_mint: uint256): + self._deposit_collateral(token_collateral_address, amount_collateral) + self._mint_dsc(amount_dsc_to_mint) +``` + +This function will take the token collateral address, the amount of collateral, and the amount of DSC to mint. We'll also create an internal function for this and use the same logic as the other functions. + +```python +@internal +def _deposit_collateral(token_collateral_address: address, amount_collateral: uint256): + self._deposit_collateral(token_collateral_address, amount_collateral) + self._mint_dsc(amount_dsc_to_mint) +``` + +ChatGPT is a very helpful tool for this process. We can start a line, and it will typically be able to predict what you will write next. It's a very helpful co-pilot to have. + +We are getting closer to creating our stable coin engine. From 98c7aff04c0bd5327ed394d9b8572f380f419be3 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:41:23 -0700 Subject: [PATCH 228/255] Equious updated courses/advanced-moccasin/3-moccasin-stablecoin/9-liquidation/+page.md. --- .../9-liquidation/+page.md | 99 ++++++++++++++++++- 1 file changed, 94 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/9-liquidation/+page.md b/courses/advanced-moccasin/3-moccasin-stablecoin/9-liquidation/+page.md index 2bf4f831c..74a75a2db 100644 --- a/courses/advanced-moccasin/3-moccasin-stablecoin/9-liquidation/+page.md +++ b/courses/advanced-moccasin/3-moccasin-stablecoin/9-liquidation/+page.md @@ -1,5 +1,94 @@ - - --- - title: Liquidation - --- - \ No newline at end of file +We're going to implement the main functionality of a stablecoin contract: liquidation. + +We'll begin by creating a new function in our stablecoin contract: + +```javascript +@external +def liquidate(collateral: address, user: address, debt_to_cover: uint256): + pass +``` + +We're going to add a few checks to ensure that we can liquidate someone. + +* **Check if their health factor is bad** + +We need to make sure that we're only liquidating users whose health factor is below the minimum. We can do this with the following code: + +```javascript +assert debt_to_cover > 0, "DSCEngine: Needs more than zero" +starting_health_factor: uint256 = self._health_factor(user) +assert starting_health_factor < MIN_HEALTH_FACTOR, "DSCEngine: Health factor is good" +``` + +* **Cover their debt by US burning our DSC but reducing their DSC minted** + +If a user has a health factor below the minimum, the system needs to cover the debt they owe. We do this by burning our own DSC (which is minted) and reducing their DSC minted. + +We need to calculate how much collateral to give back to the user. We'll call a function we don't have yet called `get_token_amount_from_usd`. + +```javascript +token_amount_from_debt_covered: uint256 = self._get_token_amount_from_usd(collateral, debt_to_cover) +bonus_collateral: uint256 = (token_amount_from_debt_covered * LIQUIDATION_BONUS) // LIQUIDATION_PRECISION +``` + +* **Take their collateral** + +Finally, we're going to take the user's collateral by calling `redeem_collateral`, which we've implemented previously. + +```javascript +self._redeem_collateral(collateral, token_amount_from_debt_covered + bonus_collateral, user, msg.sender) +``` + +Finally, we need to burn the user's DSC. + +```javascript +self._burn_dsc(debt_to_cover, user, msg.sender) +``` + +Let's add a few more checks to make sure that we're doing everything correctly. + +* **Ending health factor is greater than starting health factor** + +```javascript +ending_health_factor: uint256 = self._health_factor(user) +assert ending_health_factor > starting_health_factor, "DSCEngine: Didn't improve health factor" +``` + +* **Revert if health factor is broken** + +```javascript +self._revert_if_health_factor_broken(msg.sender) +``` + +We also need to make sure that we're not accidentally depleting `msg.sender`'s health factor. + +```javascript +self._revert_if_health_factor_broken(msg.sender) +``` + +We'll need to add a new variable for our liquidation bonus. This will be added to the top of the contract. + +```javascript +LIQUIDATION_BONUS: public constant uint256 = 100 +``` + +We need to make sure that we're using the correct `LIQUIDATION_BONUS` in the code. + +Let's make a few more adjustments to our function: + +```javascript +@external +def liquidate(collateral: address, user: address, debt_to_cover: uint256): + assert debt_to_cover > 0, "DSCEngine: Needs more than zero" + starting_health_factor: uint256 = self._health_factor(user) + assert starting_health_factor < MIN_HEALTH_FACTOR, "DSCEngine: Health factor is good" + token_amount_from_debt_covered: uint256 = self._get_token_amount_from_usd(collateral, debt_to_cover) + bonus_collateral: uint256 = (token_amount_from_debt_covered * LIQUIDATION_BONUS) // LIQUIDATION_PRECISION + self._redeem_collateral(collateral, token_amount_from_debt_covered + bonus_collateral, user, msg.sender) + self._burn_dsc(debt_to_cover, user, msg.sender) + ending_health_factor: uint256 = self._health_factor(user) + assert ending_health_factor > starting_health_factor, "DSCEngine: Didn't improve health factor" + self._revert_if_health_factor_broken(msg.sender) +``` + +And that's it! We've successfully implemented liquidation into our stablecoin contract. Now, anyone with a low enough health factor can be liquidated! From 73b906246fbc562cc3a3258206b50247a36ca96a Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:41:37 -0700 Subject: [PATCH 229/255] Equious updated courses/advanced-moccasin/4-moccasin-signatures/1-intro/+page.md. --- .../4-moccasin-signatures/1-intro/+page.md | 253 +++++++++++++++++- 1 file changed, 248 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/4-moccasin-signatures/1-intro/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/1-intro/+page.md index c3de78c13..45cf8dc2c 100644 --- a/courses/advanced-moccasin/4-moccasin-signatures/1-intro/+page.md +++ b/courses/advanced-moccasin/4-moccasin-signatures/1-intro/+page.md @@ -1,5 +1,248 @@ - - --- - title: Intro - --- - \ No newline at end of file +## Mocassin Signatures / Merkle Airdrop + +In this lesson, we'll learn how to build a merkle tree-based airdrop smart contract in Vyper. We will start by creating a script called `make-merkle` and another called `deploy-merkle-airdrop`. + +### The Problem With Traditional Airdrops + +Airdrops are a popular way to get people interested in a new project, but they can be expensive to administer, especially if you have a lot of recipients. We don't want to store a mapping of every recipient, as that would take up too much storage space. + +### A Solution: Merkle Trees + +Merkle Trees are a data structure that can help us to more efficiently track a large number of recipients. We will only need to store the root hash of the tree in storage. + +### The `make-merkle` Script + +The `make-merkle` script will generate the merkle root hash: + +```python +import json +from typing import Dict, List, Tuple +from eth_abi import encode +from eth_utils import keccak + +DEFAULT_AMOUNT = 25000000000000000000 +DEFAULT_INPUT = { + "values": [ + { + "0": "0x537C876313D1F3EF5517a5883788D914369799682", + "1": DEFAULT_AMOUNT, + }, + { + "0": "0xF39F0de51aaD8880F66F4c8a6e27279cf1FF92266", + "1": DEFAULT_AMOUNT, + }, + { + "0": "0x2ea2970ed95D20851b0e3f2F4ADAa733D935964fd", + "1": DEFAULT_AMOUNT, + }, + { + "0": "0x6fd8a68b2C01A4C1aB26579C2577F9774C464091D", + "1": DEFAULT_AMOUNT, + }, + ] +} + + +def hash_pair(a: bytes32, b: bytes32) -> bytes32: + """Sort the two hashes values in order. + # Hash the bytes32 values by concatenating + """ + return keccak(min(a, b) + max(a, b)) + + +def get_merkle_root(leaves: List[bytes32]) -> bytes32: + """Calculate Merkle root from list of leaves. + """ + if not leaves: + return b"" + layer = leaves + next_layer = [] + for i in range(0, len(layer), 2): + if i + 1 == len(layer): + # Add sibling to proof + proof.append(b"0x" + layer[i - 1].hex()) + next_layer.append(hash_pair(layer[i], layer[i + 1])) + layer = next_layer + target_idx = index // 2 + while len(layer) > 1: + if len(layer) % 2 == 1: + layer.append(layer[-1]) + next_layer = [] + for i in range(0, len(layer), 2): + next_layer.append(hash_pair(layer[i], layer[i + 1])) + layer = next_layer + target_idx = target_idx // 2 + return layer[0] + + +def get_proof(leaves: List[bytes32], index: int) -> List[str]: + """Generate Merkle proof for at least given index. + """ + if not leaves: + return [] + proof = [] + layer = leaves + target_idx = index + while len(layer) > 1: + if len(layer) % 2 == 1: + layer.append(layer[-1]) + next_layer = [] + for i in range(0, len(layer), 2): + if i + 1 == len(layer): + # Add sibling to proof + proof.append(b"0x" + layer[i - 1].hex()) + next_layer.append(hash_pair(layer[i], layer[i + 1])) + layer = next_layer + target_idx = target_idx // 2 + return proof + + +def generate_merkle_tree(input_data: Dict = None) -> Tuple[List[Dict], bytes]: + """Generate complete Merkle tree data structure from input data. + """ + if input_data is None: + input_data = DEFAULT_INPUT + # Extract and sort leaves + leaves = [] + inputs = input_data["values"] + for i in range(len(leaves)): + entry = {} + inputs = input_data["values"] + entry["inputs"] = inputs[i] + entry["proof"] = get_proof(leaves.copy(), i) + entry["root"] = root.hex() + entry["leaf"] = "0x" + leaves[i].hex() + output.append(entry) + return output, root + +``` + +### The `deploy-merkle-airdrop` Script + +The `deploy-merkle-airdrop` script will deploy a smart contract that uses the merkle root to verify recipient eligibility: + +```python +from eth_utils import to_wei +from moccasin.boa_tools import VyperContract +from script_make_merkle import generate_merkle_tree +from src.merkle import snek_token + +INITIAL_SUPPLY = to_wei(100, "ether") + +def deploy_merkle_airdrop() -> VyperContract: + """Deploy merkle airdrop contract. + """ + token = snek_token.deploy(INITIAL_SUPPLY) + root = generate_merkle_tree() + airdrop_contract = merkle_airdrop.deploy(root, token.address) + token.transfer(airdrop_contract.address, INITIAL_SUPPLY) + print(f"Merkle airdrop contract deployed at {airdrop_contract.address}") + return airdrop_contract + +def moccasin_main(): + """Main function. + """ + deploy_merkle_airdrop() + +if __name__ == "__main__": + moccasin_main() +``` + +### The `merkle-airdrop` Contract + +The `merkle-airdrop` contract includes the `claim` function: + +```python +#pragma version 0.4.0 + +title Merkle Airdrop +@license MIT + +# Airdrop tokens to users who can prove they are in a merkle tree +@notice - Airdrop tokens to users who can prove they are in a merkle tree + +from ethereum.ercs import ERC20 +from snekmate.utils import merkle_proof_verification +from snekmate.utils import message_hash_utils +from snekmate.utils import signature_checker +from snekmate.utils import ecdsa +from snekmate.utils import eip712_domain_separator as eip712 + +initializes: eip712 + +# TYPES + +struct AirdropClaim: + account: address + amount: uint256 + +# STATE VARIABLES + +# Immutable +MERKLE_ROOT: public(immutable(bytes32)) +AIRDROP_TOKEN: public(immutable(ERC20)) + +# Constant +MESSAGE_TYPEHASH: constant(bytes32) = keccak256( + "AirdropClaim(address account, uint256 amount)" +) + +EIP712_NAME: constant(String[50]) = "MerkleAirdrop" +EIP712_VERSION: constant(String[20]) = "1.0.0" +PROOF_MAX_LENGTH: constant(uint8) = max_value(uint8) + +# Storage +has_claimed: public(HashMap(address, bool)) + +# EVENTS + +event Claimed: + account: indexed(address) + amount: uint256 + +event MerkleRootUpdated: + new_merkle_root: bytes32 + +# EXTERNAL FUNCTIONS + +@deploy +def __init__(merkle_root: bytes32, airdrop_token: address): + eip712.__init__(EIP712_NAME, EIP712_VERSION) + MERKLE_ROOT = merkle_root + AIRDROP_TOKEN = ERC20(airdrop_token) + +@external +def claim( + account: address, + amount: uint256, + merkle_proof: DynArray(bytes32, PROOF_MAX_LENGTH), + v: uint8, + r: bytes32, + s: bytes32, +): + assert not self.has_claimed(account), "Already claimed" + message_hash: bytes32 = self.get_message_hash(account, amount) + assert self.is_valid_signature( + account, message_hash, v, r, s + ), "Invalid signature" + leaf: bytes32 = keccak256( + abi.encode(keccak256(abi.encode(account, amount))) + ) + assert merkle_proof_verification.verify( + merkle_proof, MERKLE_ROOT, leaf + ), "Invalid proof" + self.has_claimed(account) = True + log.Claimed(account, amount) + success: bool = extcall( + AIRDROP_TOKEN, + "transfer(address, uint256)", + account, + amount, + ) + assert success, "Transfer failed" + +``` + +### EIP712 + +The `EIP712` domain separator we've been using will be explained in the next section. \ No newline at end of file From fa0a120951e8fd1c1aee729d606f687b44468d34 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:41:50 -0700 Subject: [PATCH 230/255] Equious updated courses/advanced-moccasin/4-moccasin-signatures/10-transaction-types/+page.md. --- .../10-transaction-types/+page.md | 32 ++++++++++++++++--- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/4-moccasin-signatures/10-transaction-types/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/10-transaction-types/+page.md index 8f6407a9e..77d81d627 100644 --- a/courses/advanced-moccasin/4-moccasin-signatures/10-transaction-types/+page.md +++ b/courses/advanced-moccasin/4-moccasin-signatures/10-transaction-types/+page.md @@ -1,5 +1,27 @@ - - --- - title: Transaction Types - --- - \ No newline at end of file +## Transaction Types (Optional) + +We're going to talk about transaction types, which are an important part of working with zkSync. + +There are four main transaction types in Ethereum and zkSync: + +1. **Transaction Type 0 (Legacy Transactions)**: This was the original transaction type used in Ethereum before transaction types were introduced. When we deploy a smart contract using Foundry zkSync, we can specify `--legacy` which sets the transaction type to zero. + +2. **Transaction Type 1 (0x01 Transactions)**: This transaction type was introduced to address certain contract breakage risks. It includes the same fields as legacy transactions, but adds an access list parameter. This parameter allows us to pre-declare allowed contracts and storage slots, which can save gas on cross-contract calls. + +3. **Transaction Type 2 (0x02 Transactions)**: Introduced by EIP-1559, this transaction type aimed to address high network fees and congestion. It replaced the `gasPrice` parameter with a `baseFee`, which is dynamically adjusted for each block. It also introduced `maxPriorityFeePerGas`, which is the maximum fee the sender is willing to pay for priority processing, and `maxFeePerGas`, which is the maximum total fee the sender is willing to pay. While zkSync supports type two transactions, it doesn't utilize the `maxFee` parameters because its gas mechanism works differently. + +4. **Transaction Type 3 (0x03 Transactions)**: Introduced by EIP-4844, this transaction type is related to Proto-DankSharding and blobs. It adds two new fields: `max_blob_fee_per_gas`, which is the maximum fee the sender is willing to pay for the blob gas, and `blob_versioned_hashes`, which is a list of the versioned blob hashes. This type is a separate market from regular gas. This type of transaction is non-refundable. + +We are going to learn more about blobs and EIP-4844 in a later video. + +zkSync has two more specific transaction types, which are: + +1. **EIP-712 Transactions**: This type of transaction is identified as type 113 or 0x71 and defines typed structured data hashing and signing. It enables us to use zkSync-specific features such as account abstraction and paymasters. This transaction type also requires that smart contracts be deployed with it. The fields are similar to standard Ethereum transactions, but include a couple of additional fields: `gasPerPubData`, which is the maximum gas the sender is willing to pay for a single byte of `pubData`, `customSignature`, which is a field for when the signer's account is not an EOA, `paymasterParams`, which are parameters for configuring a custom paymaster, and `factory_deps`, which contains the bytecode of the smart contract being deployed. + +2. **Priority Transactions**: This type of transaction is identified as type 5 or 0xff and enables us to send transactions directly from the L1 to the L2 in zkSync. + +It's important to understand these transaction types because they are used in different ways by zkSync and other tools. For example, when we run a deployment command with Titanoboa, it defaults to using type two transactions (EIP-1559) because most current tooling automatically defaults to them. However, zkSync doesn't support this type of transaction. As a result, when we deploy our smart contract, we get a warning stating that no EIP-1559 transaction is available and that it is falling back to the legacy transaction. zkSync doesn't need these EIP-1559 transactions because it has its own specific gas mechanisms. It's important to remember that zkSync will always default to using type zero transactions if other transaction types aren't supported. + +```bash +mox run deploy merkle_airdrop --network eravm +``` \ No newline at end of file From 74a5a8d61a1bfd3ddb6e8d4da79288df94263c7a Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:42:04 -0700 Subject: [PATCH 231/255] Equious updated courses/advanced-moccasin/4-moccasin-signatures/11-blobs/+page.md. --- .../4-moccasin-signatures/11-blobs/+page.md | 109 +++++++++++++++++- 1 file changed, 104 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/4-moccasin-signatures/11-blobs/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/11-blobs/+page.md index 25167253a..3ccfd065e 100644 --- a/courses/advanced-moccasin/4-moccasin-signatures/11-blobs/+page.md +++ b/courses/advanced-moccasin/4-moccasin-signatures/11-blobs/+page.md @@ -1,5 +1,104 @@ - - --- - title: Blobs - --- - \ No newline at end of file +## Blob Transactions: An Introduction + +In this lesson, we'll explore the concept of blob transactions on the Ethereum blockchain. Blob transactions are a new type of transaction that allows us to store data on chain for a short period of time. This is an essential step in the process of scaling Ethereum using rollups. + +Let's dive into the details. + +### What is a Blob Transaction? + +We'll start by comparing blob transactions to normal transactions. In a normal transaction, all of your transaction data is stored on chain forever. Blob transactions provide us with an alternative method of storing data on chain, that data is stored as a blob. + +Blob transactions are known as type 03 transactions, whereas normal transactions are known as type 02 transactions. The difference between the two is that blob transactions allow us to store data in a "box" that will be eventually deleted. Once the blob transaction is included in a block, the data will be stored as usual, but will be deleted after a short delay of 20-90 days. + +### Why do we use Blob Transactions? + +Blob transactions were introduced in the Ethereum Dencun upgrade on March 13th, 2024. The reason we have blob transactions is that rollups love them! Blob transactions help rollups solve the "blockchain trilemma" problem. + +Rollups help scale Ethereum by executing a bunch of transactions on their own chain. They then bundle up these transactions into a batch and submit it back to Ethereum. This process can provide us with substantially cheaper transactions than sending them on the Ethereum main chain. + +### How do Rollups Use Blob Transactions? + +But, before the Dencun upgrade, this compressed batch of transactions needed to be stored permanently on every Ethereum node in the world. + +This process is problematic because we only need this data for a short period of time, and every single node has to hold it for the entire time. + +Blob transactions eliminate this problem by allowing rollups to submit their compressed transactions as a blob, which doesn�t get stored permanently on every node on chain, but instead a hash of the blob is stored. + +This was achieved by introducing a new opcode, `BLOBHASH`, to help Ethereum verify the compressed transaction batches. This new opcode works with a new precompile called `POINT_EVALUATION_PRECOMPILE`, and it�s through these two new tools that Ethereum is able to validate the data. + +### Example of a Blob Transaction + +To illustrate the concept further, let's take a look at a blob transaction on Etherscan: + +We can see that a transaction was sent by zkSync Era, and that the transaction was a �Commit EIP-4844 Blob�. By clicking on the �Blobs� section, we can then see the data itself, which is represented as a large sequence of binary numbers. + +Next, on Etherscan, we can see the �Blob As Calldata Gas� metric. This metric shows us how much more expensive it would have been if this data was sent as calldata, which is how data was previously sent to Ethereum. + +It is significantly cheaper to send this data as a blob because the data is not being stored permanently on chain. + +### Blob Transactions in Practice + +We will now try to create and send our own blob transaction. We will start by setting up a connection to the blockchain per usual. + +```python +from eth_abi import abi_encode +from web3 import Web3, HTTPProvider + +w3 = Web3(HTTPProvider('rpc_url')) +``` + +Now, we will encode our blob data. + +```python +text = '("<.o.o>")' +encoded_text = abi_encode(['string'], [text]) +``` + +The important thing to keep in mind is that blobs must be at least 4096 words long. A word is 32 bytes, so we will append a series of zeros to our text to meet the minimum requirement. + +```python +BLOB_DATA = (b'\x00' * 32 * (4096 - len(encoded_text) // 32) + encoded_text) +``` + +Next, we need to create our transaction object. Here, we will change the type to a type 03 transaction. + +```python +tx = { +'type': 3, +'chainId': 31337, +'from': acct.address, +'to': '0x0000000000000000000000000000000000000000', +'value': 0, +'maxFeePerGas': '10**12', +'maxPriorityFeePerGas': '10**12', +'maxFeePerBlobGas': '10**12', +'nonce': w3.eth.get_transaction_count(acct.address), +} +``` + +Then, we need to estimate the gas cost. + +```python +gas_estimate = w3.eth.estimate_gas(tx) +tx['gas'] = gas_estimate +``` + +After we have our transaction object created, we sign it and then add our blob data. + +```python +signed = acct.sign_transaction(tx, blobs=[BLOB_DATA]) +``` + +Finally, we send our transaction. + +```bash +rye run send-blob +``` + +We can then see our transaction receipt, and the blob data we sent to the blockchain. + +### Conclusion + +Blob transactions are a key component of Ethereum's scalability roadmap. They allow rollups to send data more cheaply, and hence achieve cheaper transactions for end users. + +Let us know what you think of blob transactions in the comments below. Thanks for getting froggy with us! From cfcda9ba311eaadf71120bd8712a84bbb0799898 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:42:16 -0700 Subject: [PATCH 232/255] Equious updated courses/advanced-moccasin/4-moccasin-signatures/12-type-113-transactions/+page.md. --- .../12-type-113-transactions/+page.md | 72 +++++++++++++++++-- 1 file changed, 67 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/4-moccasin-signatures/12-type-113-transactions/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/12-type-113-transactions/+page.md index e28fccb87..b20bd5983 100644 --- a/courses/advanced-moccasin/4-moccasin-signatures/12-type-113-transactions/+page.md +++ b/courses/advanced-moccasin/4-moccasin-signatures/12-type-113-transactions/+page.md @@ -1,5 +1,67 @@ - - --- - title: Type 113 Transactions - --- - \ No newline at end of file +## Understanding Type 113 Transactions (Optional) + +In this lesson, we will discuss what a type 113 transaction is and how it's used. + +We'll go over the mechanism, or format, that allows Remix to send a transaction for us by signing a message. The way this works is by utilizing something called *account abstraction*. zkSync has *native* account abstraction, meaning it's built into the blockchain. + +Account abstraction allows users' assets to be stored within smart contracts instead of externally owned accounts. This means we can use smart contracts as our accounts instead of tools like Metamask. + +Ethereum has two main types of accounts: + +- **Externally Owned Accounts (EOAs)**: These accounts are owned by a private key and are used to interact with the blockchain. They are the standard way for users to interact with Ethereum. +- **Smart Contract Accounts**: These accounts are represented by smart contracts, which are programs that execute automatically on the blockchain. They can store assets, perform actions, and interact with other smart contracts. + +In zkSync, all accounts are smart contract accounts. This means that we can utilize account abstraction natively, allowing us to create accounts with custom logic, such as multiple signers or gas payment options. + +Let's look at the code: + +```javascript +pragma solidity ^0.4.16; + +contract SimpleStorage { + + struct Person { + uint favoriteNumber; + string name; + } + + Person person1; + + function SimpleStorage() public { + person1.favoriteNumber = 1; + person1.name = "some name"; + } + + function addPerson(uint favoriteNumber, string name) public { + person1.favoriteNumber = favoriteNumber; + person1.name = name; + } + + function getNameAndFavoriteNumber() public constant returns(string, uint) { + return (person1.name, person1.favoriteNumber); + } + + function store(string name, uint favoriteNumber) public { + person1.name = name; + person1.favoriteNumber = favoriteNumber; + } + + function retrieve() public constant returns(uint) { + return person1.favoriteNumber; + } +} +``` + +The code above shows a simple smart contract that stores a person's name and favorite number. + +In this example, a type 113 transaction is used to call the `addPerson` function and store a new person's name and favorite number. + +zkSync's native account abstraction means that any Ethereum address on zkSync is automatically a smart contract account. This enables Remix to automatically send the transaction by signing an EIP 712 message. + +Let's summarize the key concepts: + +- **Account Abstraction**: A technology that allows users to create custom accounts with programmable logic. +- **Native Account Abstraction**: A feature in zkSync where all accounts are smart contract accounts, providing built-in account abstraction capabilities. +- **EIP 712 Signatures**: A standard for signing messages on Ethereum, allowing Remix to send transactions for us using account abstraction. + +By understanding these concepts, we gain a deeper understanding of how transactions work on zkSync and the advantages of using account abstraction. \ No newline at end of file From aed06d988f590a62cd79a4abbf1effc2bfd43260 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:42:28 -0700 Subject: [PATCH 233/255] Equious updated courses/advanced-moccasin/4-moccasin-signatures/13-adding-signature-verification/+page.md. --- .../13-adding-signature-verification/+page.md | 72 +++++++++++++++++-- 1 file changed, 67 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/4-moccasin-signatures/13-adding-signature-verification/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/13-adding-signature-verification/+page.md index 44dff73cb..5bab54612 100644 --- a/courses/advanced-moccasin/4-moccasin-signatures/13-adding-signature-verification/+page.md +++ b/courses/advanced-moccasin/4-moccasin-signatures/13-adding-signature-verification/+page.md @@ -1,5 +1,67 @@ - - --- - title: Adding Signature Verification - --- - \ No newline at end of file +## Adding Signature Verification to Claim + +We're going to add signature verification to our claim function. We'll do this by creating a new function called `get_message_hash`. This function will take an account address and an amount, and it will return a bytes32. + +```python +def get_message_hash(account: address, amount: uint256) -> bytes32: + return keccak256(abi.encode(MESSAGE_TYPEHASH, AirdropClaim(account=account, amount=amount))) +``` + +We also need to create a new struct called `AirdropClaim` that contains an account address and an amount. + +```python +struct AirdropClaim: + account: address + amount: uint256 +``` + +We'll also need to define a constant called `MESSAGE_TYPEHASH` to be used when hashing the message. + +```python +MESSAGE_TYPEHASH: constant(bytes32) = keccak256("AirdropClaim(address account, uint256 amount)") +``` + +We will initialize EIP712 when our contract is deployed. + +```python +def __init__(merkle_root: bytes32, airdrop_token: address): + eip712.__init__(EIP712_NAME, EIP712_VERSION) + MERKLE_ROOT = merkle_root + AIRDROP_TOKEN = IERC20(airdrop_token) +``` + +Now, in the `claim` function we'll use our `get_message_hash` function to get the message hash and then check that the signature is valid. + +```python +def claim(account: address, amount: uint256, merkle_proof: DynArray[bytes32, PROOF_MAX_LENGTH], v: uint8, r: bytes32, s: bytes32): + """Allows users to claim the airdropped tokens.""" + assert not self.has_claimed(account), "merkle_airdrop: Account has already claimed." + message_hash: bytes32 = self._get_message_hash(account, amount) + assert self.is_valid_signature(account, message_hash, v, r, s, "Invalid Signature") + leaf: bytes32 = keccak256(abi.encode(keccak256(abi.encode(account, amount)))) + assert merkle_proof_verification.verify(merkle_proof, MERKLE_ROOT, leaf), "Invalid Proof" + self.has_claimed(account) = True + log.Claimed(account, amount) + success: bool = extcall(AIRDROP_TOKEN, "transfer(address, uint256)", account, amount) + assert success, "Transfer Failed" +``` + +Finally, we'll add a function called `is_valid_signature` that takes an account, message hash, v, r, and s as input, and returns a bool. + +```python +@internal +def is_valid_signature(account: address, message_hash: bytes32, v: uint8, r: bytes32, s: bytes32) -> bool: + v: uint256 = convert(v, uint256) + r: uint256 = convert(r, uint256) + s: uint256 = convert(s, uint256) + actual_signer: address = ecdssa._try_recover_vr_s(message_hash, v, r, s, account) + return actual_signer == account +``` + +We need to import `ECDSA` from `snekmate.utils` to use the `_try_recover_vr_s` function. + +```python +from snekmate.utils import ECDSA +``` + +We've now added signature verification to our claim function. From 22aa875400126f3491da725537f8a2600ec5aa25 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:42:42 -0700 Subject: [PATCH 234/255] Equious updated courses/advanced-moccasin/4-moccasin-signatures/14-deploy/+page.md. --- .../4-moccasin-signatures/14-deploy/+page.md | 48 +++++++++++++++++-- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/4-moccasin-signatures/14-deploy/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/14-deploy/+page.md index 016761360..16ae8084c 100644 --- a/courses/advanced-moccasin/4-moccasin-signatures/14-deploy/+page.md +++ b/courses/advanced-moccasin/4-moccasin-signatures/14-deploy/+page.md @@ -1,5 +1,43 @@ - - --- - title: Deploy - --- - \ No newline at end of file +## Deploying a Merkle Airdrop Contract + +We've built our Merkle airdrop contract, and now we're going to deploy it to a test network so we can interact with it and experiment with the functionality. + +We will be writing some deployment scripts and tests to ensure that the deployment process works as expected. + +### Deploying the Merkle Airdrop Contract + +Let's create a new file called `deploy_merkle.py`. + +```python +from src import snek_token +from eth_utils import to_wei +from script.make_merkle import generate_merkle_tree + +INITIAL_SUPPLY = to_wei(100, "ether") + +def deploy_merkle(): + token = snek_token.deploy(INITIAL_SUPPLY) + _root = generate_merkle_tree() + airdrop_contract = merkle_airdrop.deploy(root, token.address) + token.transfer(airdrop_contract.address, INITIAL_SUPPLY) + print(f"Deployed airdrop contract at {airdrop_contract.address}") + return airdrop_contract + + +def moccasin_main(): + return deploy_merkle() +``` + +This script will first deploy the token contract with an initial supply of 100 Ether. Then, it will generate the Merkle tree and deploy the Merkle airdrop contract, providing the root of the tree and the token contract address to the deployment function. Lastly, the script will transfer the initial token supply to the airdrop contract's address. + +### Testing the Deployment + +We can now test the deployment script by running the following command in our terminal: + +```bash +mox run deploy_merkle +``` + +This will execute the `deploy_merkle` function and display the address of the deployed airdrop contract. + +This testing process allows us to ensure the functionality of the deployment script and verify that all the necessary steps are completed correctly. From 3bd6629bb2bebd9b2c0d3da1ca490506cdbd7676 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:42:54 -0700 Subject: [PATCH 235/255] Equious updated courses/advanced-moccasin/4-moccasin-signatures/15-testing/+page.md. --- .../4-moccasin-signatures/15-testing/+page.md | 243 +++++++++++++++++- 1 file changed, 238 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/4-moccasin-signatures/15-testing/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/15-testing/+page.md index c1839c795..ddb60606e 100644 --- a/courses/advanced-moccasin/4-moccasin-signatures/15-testing/+page.md +++ b/courses/advanced-moccasin/4-moccasin-signatures/15-testing/+page.md @@ -1,5 +1,238 @@ - - --- - title: Testing - --- - \ No newline at end of file +## Testing + +We'll start by writing some tests so we can finally see all the pieces of this signature thing come together. We'll first create a `conf_test.py` where we will add our fixtures: + +```python +import boa +from script.deploy_merkle import deploy_merkle +import pytest +``` + +We're going to need `pytest`: + +```python +import pytest +``` + +We're going to add `@pytest.fixture`: + +```python +@pytest.fixture +``` + +Then, we'll add a function: + +```python +def merkle(): +``` + +And we'll return `deploy_merkle`: + +```python +return deploy_merkle() +``` + +We'll also get to the token. Let's add `@pytest.fixture`: + +```python +@pytest.fixture +``` + +and `def token`: + +```python +def token(merkle): +``` + +Instead of doing the manifest named, we'll just have this input the merkle and say: + +```python +from src import snek_token +``` + +from `src` import `snek_token`. This is what we call it. We'll return `snek_token`: + +```python +return snek_token.at(merkle.AIRDROP_TOKEN()) +``` + +`@merkle.AIRDROP_TOKEN()`. + +Now we'll create a user. We'll add `@pytest.fixture`: + +```python +@pytest.fixture +``` + +and `def user`: + +```python +def user(): +``` + +We're going to have to work with real keys, so we can't do `boa.env.generate`. We need to use a real key, so we'll run `anvil quick`. We'll grab the top private key and put it into our test: + +```python +ANVIL_KEY = "0xac0974bec39a17e36ba4d4d238ff44d4bac944cbed5efcae784d7f447f2ff808" +``` + +We'll import `Account`: + +```python +from eth_account import Account +``` + +And now we'll say `account equals account.from_key anvil key`: + +```python +account = Account.from_key(ANVIL_KEY) +``` + +We'll look at our `merkle_output.json` to find the address associated with this private key: + +```bash +anvil +``` + +We can see that this key corresponds to the address `0xf39f5e1aad88f8f64c6a888827279cffb992266`. + +We'll add `with boa.env.prank(account.address):` to our `user` fixture: + +```python +with boa.env.prank(account.address): +``` + +And add `yield account` to return the `account` from the `user` fixture. + +```python +yield account +``` + +We'll also add the `anvil address`: + +```python +ANVIL_ADDRESS = "0xf39f5e1aad88f8f64c6a888827279cffb992266" +``` + +Now we'll create `test_merkle.py`: + +```bash +mock test -k +``` + +We'll add a function: + +```python +def test_user_can_claim(merkle, token, user): +``` + +We'll grab the starting balance: + +```python +starting_token_balance = token.balanceOf(user.address) +``` + +To get the message hash, we'll use our `merkle` fixture and pass in the `user.address` and `DEFAULT_AMOUNT`: + +```python +message_hash = merkle.get_message_hash(user.address, DEFAULT_AMOUNT) +``` + +We need to import `sign_message_hash` from `eth_account.utils.signing`: + +```python +from eth_account.utils.signing import sign_message_hash +``` + +We'll also need to import `PrivateKey` from `eth_keys.datatypes`: + +```python +from eth_keys.datatypes import PrivateKey +``` + +Then we'll use `sign_message_hash` to generate our signature: + +```python +v, r, s = sign_message_hash(PrivateKey(user.key), message_hash) +``` + +We'll use our `merkle` fixture to call `claim`: + +```python +merkle.claim(user.address, DEFAULT_AMOUNT, proof, v, bytes(r), bytes(s)) +``` + +We'll grab our ending balance: + +```python +ending_balance = token.balanceOf(user.address) +``` + +And we'll assert that the `ending_balance` is equal to the `starting_token_balance` plus the `DEFAULT_AMOUNT`: + +```python +assert ending_balance == (starting_token_balance + DEFAULT_AMOUNT) +``` + +Now we'll do a couple of things to demonstrate how our tests can fail. + +We'll create a bad user fixture, which is the same as our user fixture, but we'll use `ANVIL_KEY_TWO`: + +```python +@pytest.fixture +def bad_user(): + account = Account.from_key(ANVIL_KEY_TWO) + with boa.env.prank(account.address): + yield account +``` + +We'll run `anvil` again and grab private key two. We'll paste this key into our `conf_test.py`: + +```python +ANVIL_KEY_TWO = "0x59c6995e998f7a5a0044966f094539d9c3e9ddae88c7a8412744603b6b7869d0" +``` + +Then, in our `test_merkle.py`, we'll swap `user` for `bad_user`: + +```python +def test_user_can_claim(merkle, token, bad_user): +``` + +And we'll run the test again: + +```bash +mock test -k +``` + +We can see that the test fails with an invalid signature, because we used the wrong private key to sign the hash. + +Let's update our `test_user_can_claim` function to import `to_bytes` from `eth_utils`: + +```python +from eth_utils import to_bytes +``` + +We'll need to update our `proof` to be a `bytes` object, so we'll use `bytes.fromhex`: + +```python +proof = [ + bytes.fromhex("0xebcc963f0588d1ded0db349946755727e95d1917f9427a2d7d8935e0444b"), + bytes.fromhex("0xe5ebd1e1b5a5478a44eca6ab36a95ac3b66b216875f6524caa7a1d87d96576"), +] +``` + +Now, we'll update the `merkle.claim` call to pass in our signature as bytes: + +```python +merkle.claim( + user.address, DEFAULT_AMOUNT, proof, v, to_bytes(r), to_bytes(s) +) +``` + +We'll run the test again: + +```bash +mock test -k +``` + +This time, the test should be successful. From a6f2073a05a570f24c6aebde8d30e761d18daf98 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:43:07 -0700 Subject: [PATCH 236/255] Equious updated courses/advanced-moccasin/4-moccasin-signatures/16-workshop-1/+page.md. --- .../16-workshop-1/+page.md | 83 +++++++++++++++++-- 1 file changed, 78 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/4-moccasin-signatures/16-workshop-1/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/16-workshop-1/+page.md index c61b71da8..5025eee2a 100644 --- a/courses/advanced-moccasin/4-moccasin-signatures/16-workshop-1/+page.md +++ b/courses/advanced-moccasin/4-moccasin-signatures/16-workshop-1/+page.md @@ -1,5 +1,78 @@ - - --- - title: Workshop 1 - --- - \ No newline at end of file +## Introduction to Merkle Trees + +We will be covering the concept of Merkle Trees. They are a powerful tool that is used in various domains like blockchain technology, cryptography, and more. + +Merkle trees are like a hierarchical data structure that allows for efficient and secure verification of data integrity. It enables us to verify a large amount of data using a compact hash value, known as the root. + +Let's dive into the world of Merkle Trees and understand the key concepts behind them. + +## What are Merkle Trees? + +Merkle trees essentially help us to efficiently verify a large amount of data using a small, compact hash value. They are like a hierarchical data structure that holds data and its hash values. + +We can use Merkle Trees in a variety of ways: + +* **Verification of data integrity:** If we make a change to any data, it will affect all hash values leading up to the root, thus allowing us to easily detect any manipulation or tampering. +* **Efficient data comparison:** By comparing the root hash values of two Merkle Trees, we can quickly determine if the data sets are the same or different. +* **Distributed ledger technology:** Merkle trees are used to verify transactions in blockchains. Each block in a blockchain contains a Merkle tree that represents all the transactions in that block. +* **Secure data sharing:** By providing proof that a specific piece of data is included in a Merkle tree, we can share data securely without revealing the entire dataset. + +## Building a Merkle Tree + +Let's consider a simple scenario where we have a set of data elements, and we want to construct a Merkle tree from them. + +We can build a Merkle Tree by: + +1. **Hashing each data element:** This step involves applying a cryptographic hash function to each data element, producing unique hash values for each element. +2. **Pairing and hashing hash values:** We pair up the hash values, creating a new hash by combining the two hash values. The new hash can be created by sorting the hashes and then combining them using a cryptographic hash function. +3. **Continuing the process:** The newly generated hash values from step 2 are then paired up and hashed again, creating a new level in the tree. This process continues until we reach the root node. + +## Example + +We are going to go over a simple Merkle Tree with four leaf nodes. + +The first step we will take is to create an input for our Merkle Tree. + +```python +DEFAULT_AMOUNT = int(25e18) # 25e18 tokens + +DEFAULT_INPUT = { + "values": { + "0": { + "0": "0x537C8f3d3E18Df5517a58B37809143697996682", + "1": DEFAULT_AMOUNT, + }, + "1": { + "0": "0xF39F0de51aa0d88f6e4c6aB8827279cffb92266", + "1": DEFAULT_AMOUNT, + }, + "2": { + "0": "0x2ea3970e82D8d30b25b08e21FAAD4731035964f7dd", + "1": DEFAULT_AMOUNT, + }, + "3": { + "0": "0xf6d8ab2c0148C14FC92657f937f77c464c40091D", + "1": DEFAULT_AMOUNT, + }, + } +} +``` + +We can now use this input to build a Merkle Tree and print it to a `JSON` file for later use. + +```bash +patrick@kcu:mox-signatures-cu % mox run make_merkle +``` + +This will output a `JSON` file that contains the Merkle Tree data. + +## Workshop + +We are now going to complete a workshop. We will build a Merkle Tree with eight leaf nodes. We will be using the code we've created above as a starting point. + +We can modify the `DEFAULT_INPUT` to include eight leaf nodes. We can also use the command `mox run make_merkle` to create the new Merkle Tree. + +Remember, you can try to complete this workshop without the aid of AI. If you get stuck, take a break and then you can use AI or the discussions to help you solve it. Good luck! + + +This is just a basic introduction to Merkle trees and the concept of building them. There are more advanced topics and applications of Merkle trees that we will cover in later lessons. From cf8b655addf5614c7f285f14cc116e1bd9b53c06 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:43:20 -0700 Subject: [PATCH 237/255] Equious updated courses/advanced-moccasin/4-moccasin-signatures/17-recap/+page.md. --- .../4-moccasin-signatures/17-recap/+page.md | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/4-moccasin-signatures/17-recap/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/17-recap/+page.md index 520a7c357..244965e63 100644 --- a/courses/advanced-moccasin/4-moccasin-signatures/17-recap/+page.md +++ b/courses/advanced-moccasin/4-moccasin-signatures/17-recap/+page.md @@ -1,5 +1,30 @@ - - --- - title: Recap - --- - \ No newline at end of file +## Merkle Trees and Signatures + +We've covered a lot in this section. So before we send you off to the next section, let's do a quick refresher on all the things we've learned so far. + +### Merkle Trees + +First, we learned about **merkle trees**. A Merkle tree is a data structure that allows us to compress a large amount of data into a single hash, known as the **Merkle root**. + +Here's how they work: + +1. We start with a list of data, each piece of data is called a **leaf**. +2. We hash each leaf. +3. We hash sibling leaves to create a **parent node**. +4. We continue this process until only one hash remains, and that's our Merkle root. + +### Signatures + +We also learned about **signatures**, how different types of signatures work, and how to create signatures with ECDSA. + +### EIP-712 + +EIP-712 is a standard for structured data signing on Ethereum. We are adding it to our contracts in order to implement signing capabilities. + +### EIP-191 + +EIP-191 is a standard for recovering the address of the signer from a signature. + +### Conclusion + +You've come a long way and we are proud of you for completing this section. Now is a great time to take a break, get some ice cream, or go to the gym. From 8b0c420cfb2e12d6d83b2baf01963e4619cadf41 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:43:32 -0700 Subject: [PATCH 238/255] Equious updated courses/advanced-moccasin/4-moccasin-signatures/2-setup/+page.md. --- .../4-moccasin-signatures/2-setup/+page.md | 104 +++++++++++++++++- 1 file changed, 99 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/4-moccasin-signatures/2-setup/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/2-setup/+page.md index b8774470f..e1b1e656b 100644 --- a/courses/advanced-moccasin/4-moccasin-signatures/2-setup/+page.md +++ b/courses/advanced-moccasin/4-moccasin-signatures/2-setup/+page.md @@ -1,5 +1,99 @@ - - --- - title: Setup - --- - \ No newline at end of file +## Project Setup + +We'll start by creating a new folder and opening it in Visual Studio Code: + +```bash +mkdir mox-signatures-cu +``` + +```bash +code mox-signatures-cu +``` + +We'll then initialize a Python project in Visual Studio Code: + +```bash +mox init --vscode --pyproject +``` + +Next, we'll navigate to the `src` folder and delete the files we don't need: + +* `deploy.py` +* `Counter.py` +* `test_counter.py` +* `conftest.py` + +After this, we'll go to the `README.md` file to describe the project: + +We want to: + +1. Airdrop tokens to `X` number of people. +2. Let people claim via a `claim` function. +3. Not have to store `X` people in a list or mapping on chain. + +We don't want to store thousands of people in an array or mapping on chain because that will be very gas intensive. + +We'll begin coding by creating a new file called `snek_token.vy`. This will be the token we'll be airdropping: + +```javascript +# pragma version 0.4.0 + +@license MIT +@title snek_token + +#@dev We import and implement the 'IERC20' interface, +#@which is a built-in interface of the Vyper compiler. +from ethereum.erc20 import IERC20 + +implements: IERC20 + +from ethereum.erc20 import IERC20Detailed +implements: IERC20Detailed + +#@dev We import and initialise the 'ownable' module. +from snekmate.auth import ownable as ow + +initializes: ow + +#@dev We import and initialise the 'erc20' module. +from snekmate.tokens import erc20 + +initializes: erc20ownable = ow + +NAME: constant(String[25]) = "snek_token" +SYMBOL: constant(String[5]) = "SNEK" +DECIMALS: constant(uint8) = 18 +EIP712_VERSION: constant(String[20]) = "1" + +@deploy +def __init__(initial_supply: uint256): + ow.__init__() + erc20.__init__(NAME, SYMBOL, DECIMALS, NAME, EIP712_VERSION) + erc20._mint(msg.sender, initial_supply) + +exports: erc20._interface +``` + +We'll need to install `snekmate` before moving on. + +```bash +mox install snekmate +``` + +We'll create a new file called `merkle_airdrop.vy`. + +```javascript +# pragma version 0.4.0 + +@license MIT +@title Merkle Airdrop + +from vyper.interfaces import ERC20 + +@external +def claim(): + """Allows users to claim the airdropped tokens.""" + pass +``` + +In our deploy script, when we deploy the `snek` token, we'll send them to the `merkle_airdrop`. The `merkle_airdrop` will have all the tokens to send. From bd75074794303c3a087475a6dfdfc3796884acf4 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:43:46 -0700 Subject: [PATCH 239/255] Equious updated courses/advanced-moccasin/4-moccasin-signatures/3-merkle-trees/+page.md. --- .../3-merkle-trees/+page.md | 73 +++++++++++++++++-- 1 file changed, 68 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/4-moccasin-signatures/3-merkle-trees/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/3-merkle-trees/+page.md index 1a3f36b7e..370910a4e 100644 --- a/courses/advanced-moccasin/4-moccasin-signatures/3-merkle-trees/+page.md +++ b/courses/advanced-moccasin/4-moccasin-signatures/3-merkle-trees/+page.md @@ -1,5 +1,68 @@ - - --- - title: Merkle Trees - --- - \ No newline at end of file +## Merkle Trees & Merkle Proofs + +Merkle Trees are a data structure in computer science. They are used to encrypt blockchain data more securely and efficiently. + +A Merkle Tree is comprised of nodes. At the base of the tree are leaves. Each leaf represents a hash of some data. At the top of the tree is the root, which is the root hash. This root hash is created by hashing all of the leaf hashes together. + +We can take two adjacent nodes at a time and hash them together. This produces a parent node. We repeat this process up the tree, hashing the parents until we reach the top of the tree and are left with a single hash: the root hash. + +A Merkle Proof is a method of proving that some data is in the tree. For example, if someone wanted to prove they were part of a club, we can provide a Merkle Proof. This proof includes all the hashes from the leaf to the root, except for the leaf hash itself. + +**Example:** + +Let's say we had a club with different tiers, like Bronze, Silver, Gold, and Platinum. For each tier, there is a password to prove you belong to that tier. + +We can create a Merkle Tree that includes each tier's password as a leaf. To prove someone belongs to a particular tier, we need to provide the hashes from that tier's leaf node to the root, except for the tier's leaf. This is called a Merkle Proof. + +**How Merkle Proofs Work:** + +Let's say we wanted to prove someone is a member of the club. We can take a Merkle Proof for the Bronze tier. This proof would include the following hashes: + +* **Hash 1-2:** This is a parent node, which was generated by hashing the Bronze tier's leaf node. +* **Hash 3-4:** This is another parent node that is also part of the proof. +* **Root Hash:** This is the top node in the tree, which is generated by hashing the two parent nodes, Hash 1-2 and Hash 3-4. + +This Merkle Proof gives us the ability to verify membership in the Bronze tier, without requiring the user to provide all of their data. + +We can verify the Merkle Proof by hashing the two parent nodes together, `Hash 1-2` and `Hash 3-4`. The result should match the Root Hash provided in the proof. + +**Advantages of Merkle Trees:** + +* **Efficiency:** Merkle Trees are very efficient in terms of data verification. +* **Security:** Merkle Trees are very secure, making them ideal for use in cryptography. +* **Scalability:** Merkle Trees are scalable and can be used to verify large amounts of data. + +We use Merkle Trees in a variety of use cases, such as: + +* **State changes in Rollups:** When a Rollup executes a transaction, we can use a Merkle Proof to prove the transaction was valid. +* **Airdrops:** We can create an Allow List of addresses for an airdrop and use Merkle Proofs to determine which addresses are eligible. + +**OpenZeppelin:** + +We can use OpenZeppelin's Merkle Proof smart contract to make this even easier. The code includes a `verify` function that takes the Merkle Proof, the Merkle Root, and the leaf that we want to verify. + +```javascript +function verify(bytes32 proof, bytes32 root, bytes32 leaf) internal pure returns (bool) { + return processProof(proof, leaf) == root; +} +``` + +This function starts by taking the leaf and the first hash in the proof and hashing them together. This will update the `computedHash`. This is then used to hash the next element in the proof. We repeat this process until we've iterated through the entire proof array. + +The `computedHash` is returned, which will be compared to the `rootHash` that was provided in the proof. We can then determine if the leaf was actually in the Merkle Tree. + +Let's look at how OpenZeppelin uses Keccak256 in their hashing algorithm: + +```javascript +function efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32) { + return a < b ? efficientHash(a, b) : efficientHash(b, a); +} +``` + +This code shows OpenZeppelin's implementation of Keccak256 using assembly. + +**Merkle Proofs for Our Airdrop:** + +We can now implement Merkle Proofs into our airdrop contract. This can help us eliminate the need for the inefficient loop through a long array of addresses. + +This approach uses the OpenZeppelin Merkle Proof smart contract and is much more efficient than the previous method. From 42a2a759799ff1fc6be34a938fb5eeb3c24b2214 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:43:59 -0700 Subject: [PATCH 240/255] Equious updated courses/advanced-moccasin/4-moccasin-signatures/4-making-a-merkle/+page.md. --- .../4-making-a-merkle/+page.md | 192 +++++++++++++++++- 1 file changed, 187 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/4-moccasin-signatures/4-making-a-merkle/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/4-making-a-merkle/+page.md index b7be47f9f..6d21f2752 100644 --- a/courses/advanced-moccasin/4-moccasin-signatures/4-making-a-merkle/+page.md +++ b/courses/advanced-moccasin/4-moccasin-signatures/4-making-a-merkle/+page.md @@ -1,5 +1,187 @@ - - --- - title: Making A Merkle - --- - \ No newline at end of file +## Making Merkle Proofs in Solidity + +We're now going to learn how to make Merkle proofs in Solidity. We'll go over a simplified example, but this concept is very powerful, and you'll see it used in many other places. + +We can do an at deploy def under init. We'll say under merkle root will be a bytes 32. + +```javascript +at deploy def init: + under_merkle_root bytes32 +``` + +And, what we can do, is we can set this merkle root equals under merkle root and somehow, just by us adding this single bytes 32, we will somehow kind of have a full list of people who can claim the token. That that seems insane, but let's keep going for now, just assuming is the case. + +Next, we're also going to need the airdrop token, which will be an address. + +```javascript + airdrop_token public immutable address +``` + +So, how does this claim thing work? What does this actually look like here? Well, what the user is going to have to pass, and again if this doesn't make total sense right away, that's okay. They're going to have to pass in the account, which is going to be an address, who is going to be doing the claiming. How much they're going to be claiming for. The merkle proof, which is going to be a DynArray of bytes 32. + +```javascript + function claim(address account, uint256 amount, bytes32[] calldata merkleProof) public +``` + +We can even ask cloud or something. What is the max size of a uint8? 255. Okay, there you go. Perfect. + +So, merkle proof will be a bytes 32, max size of 255. And, then finally something that is vaguely familiar, the v, the r, the bytes 32 and the s, which is a bytes 32. And, you may recognize these as the values of a signature. + +```javascript + bytes32 v + bytes32 r + bytes32 s +``` + +So, in order for somebody to call claim here, they have to pass their address, the amount, some weird merkle proof thing that we're not really sure what this is quite yet, and then a signature for this as well. + +We're going to go to the repo, mock-signatures-cu draft, go to script, go to make merkle.py, and we're going to just copy everything. Just copy this whole thing. + +```bash +mox-signatures-cu/script/make_merkle.py +``` + +Yes, I know. It's a lot of code, and this is why I'm not having you do it. But, we're going to do make merkle.py and paste this in here. + +I'm not going to have you write this all out, because there's a lot of code here, and there's a lot to explain. And, if you really want to get in your bones, the process of making this, you can absolutely try to do so yourself, but I'm going to walk you through this and tell you what's going on here, so that we can understand how we're going to use this merkle root to claim the tokens on this contract here. + +So, we have this make merkle.py, and what this contract is going to do, is it's going to make our Merkle tree, aka, it's going to make our merkle root. And, Kira just briefly went over this, but essentially this top merkle root is going to be created by hashing everything together. So, we're going to So, we're going to hash the leaf nodes or the you know, the bottom of the tree together. And, then we're going to hash the result of those hashes together, and then we're going to finally end up with this merkle root. So, you can almost think of it as like just hashing yourself many times until you only have one hash left. + +So, for example what we're going to do is we're going to have these be our different leaves right? So, this first value here, is an address and a default amount. And, you can kind of think of this zero, this you know, this address and this default amount, as this first leaf node, that we're going to hash. + +```javascript +def hash_pair(a: bytes32, b: bytes32) -> bytes32: + """Hash two bytes32 values in order.""" + if a < b: + return keccak256(abi.encodePacked(a, b)) + else: + return keccak256(abi.encodePacked(b, a)) +``` + +So, you can almost think of it is like we're going to hash this whole thing, and that's going to be this bottom one. Then, we're going to hash this whole thing, that's going to be this hash 2. Then, we're going to hash this whole thing, and it's going to be hash 3. Then, we're going to hash this whole thing, and it's going to be hash 4. And, what you can see here obviously, is it's just a list of addresses and amounts. + +```javascript +DEFAULT_AMOUNT = int(25e18) # 25 tokens +DEFAULT_INPUT = { + "0": { + "address": "0x537Cbf73d5E16df8517A588B914909135697c96802", + "amount": DEFAULT_AMOUNT, + }, + "1": { + "address": "0xf39f90e8d8f88888f448cce727d3d92e0a4c9f66", + "amount": DEFAULT_AMOUNT, + }, + "2": { + "address": "0x2ea3970e8d852d8314F82E180A4D7d35564f7d4d", + "amount": DEFAULT_AMOUNT, + }, + "3": { + "address": "0xf6db6a2c1Af48C1b5292E537f7674C6a4c0091D", + "amount": DEFAULT_AMOUNT, + }, +} +``` + +So, this is our our list, right? And, we could put this on chain into our contract, but again, that's going to be huge waste of gas, so what do we do instead? Well, if we run this How do you run Mox? Run make merkle. + +```bash +mox make_merkle +``` + +We're going to get get an output that looks like Merkle tree data written to merkle.out.json. And, we're given a merkle root. + +So, what this actually does, is if we run this, it's going to do Mox and main. It's going to call CLI run, and it's going to run this generate merkle tree. So, this is kind of where the secret sauce is here, and essentially what we do is we loop through all of the entries in our input data, right, which is this, again this dictionary at the top here. We get the address. We get the amount, and we basically create this leaf node by combining the two. So, we have this function called generate leaf. If we click on this, we're basically going to generate a leaf node by encoding and hashing address and amount. + +```javascript +def generate_leaf(address: str, amount: str) -> bytes: + """Generate a leaf node by encoding and hashing address and amount.""" + address_int = int(address, 16) # Convert hex address to int + address_bytes32 = bytes32(int(address_int, 16).to_bytes(32, "big", signed=False)) # Convert hex address to int + data.append(address_bytes32) + + amount_int = int(amount) + amount_bytes32 = bytes32(int(amount_int).to_bytes(32, "big", signed=False)) + data.append(amount_bytes32) + + encoded = encode(["bytes32[2]", []], [data]) + first_hash = keccak256(encoded) + return keccak256(abi.encodePacked(first_hash)) +``` + +So, we we convert the address to an integer. Yes, I know that's very bizarre. We convert that to a byte, and then we add it to this array. We do the same thing with the amount, and then we encode it. + +So, this is almost basically taking the raw address and amount data and encoding it into two hashes here. + +```javascript +def get_merkle_root(leaves: List[bytes]) -> bytes: + """Calculate Merkle root from list of leaves.""" + if not leaves: + return keccak256(b"") + + layer = leaves + while len(layer) > 1: + next_layer = [] + for i in range(0, len(layer), 2): + if i < len(layer) - 1: + next_layer.append(hash_pair(layer[i], layer[i + 1])) + else: + next_layer.append(hash_pair(layer[i], layer[i - 1])) + + layer = next_layer + + return layer[0] +``` + +So, we generate these leaf hashes, if you will, and we append it to this array, called leaves, like so. And, then what we do is we call this generate merkle root with all the leaves. + +```javascript +def generate_merkle_tree(input_data: Dict) -> Tuple[List[Dict], bytes]: + """Generate a Merkle tree by encoding and hashing address and amount.""" + data = [] + inputs = [] + # Handle address + for i in range(len(input_data["values"])): + address = input_data["values"][i]["address"] + address_int = int(address, 16) # Convert hex address to int + address_bytes32 = bytes32(int(address_int, 16).to_bytes(32, "big", signed=False)) # Convert hex address to int + data.append(address_bytes32) + amount = input_data["values"][i]["amount"] + amount_int = int(amount) + amount_bytes32 = bytes32(int(amount_int).to_bytes(32, "big", signed=False)) + data.append(amount_bytes32) + + encoded = encode(["bytes32[2]", []], [data]) + leaf = keccak256(encoded) + leaves.append(leaf) + inputs.append({"address": address, "amount": amount}) + + root = get_merkle_root(leaves) + root_hex = "0x" + root.hex() + + output = [] + for i in range(len(leaves)): + entry = { + "inputs": inputs[i], + "proof": get_proof(leaves, copy(leaves), i, 1), + "root": root_hex, + "leaf": "0x" + leaves[i].hex(), + } + output.append(entry) + + return output, root +``` + +And, then what we do is we call this generate merkle root with all the leaves. + +```javascript +def cli_run(): + output, root = generate_merkle_tree(DEFAULT_INPUT) + + print("Merkle tree data written to merkle.out.json") + + with open("merkle.out.json", "w") as f: + json.dump(output, f, indent=4) + + print(f"Merkle Root: {root}") +``` + From 0406d4db5d9b74eac2ed91a4ca5e847f9542c7d0 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:44:12 -0700 Subject: [PATCH 241/255] Equious updated courses/advanced-moccasin/4-moccasin-signatures/5-merkle-proof/+page.md. --- .../5-merkle-proof/+page.md | 117 +++++++++++++++++- 1 file changed, 112 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/4-moccasin-signatures/5-merkle-proof/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/5-merkle-proof/+page.md index 56c50ef51..22a081ae0 100644 --- a/courses/advanced-moccasin/4-moccasin-signatures/5-merkle-proof/+page.md +++ b/courses/advanced-moccasin/4-moccasin-signatures/5-merkle-proof/+page.md @@ -1,5 +1,112 @@ - - --- - title: Merkle Proof - --- - \ No newline at end of file +Merkle Proofs are a way to prove that you are part of a Merkle Tree without having to share the entire tree. They are often used in airdrops and other blockchain applications. + +We will use the following code in our lesson: + +```python +from typing import Dict, List, Tuple +from eth_abi import encode_abi +from eth_utils import keccak + +DEFAULT_AMOUNT = int(25e18) # 25 # tokens +DEFAULT_INPUT = { + "values": { + "0": { + "0": "0x537C8f3d3E18dEF5517a58B3f8D9143697996682", + "1": DEFAULT_AMOUNT, + }, + "1": { + "0": "0xf39fDg6e51aad88fF4ce6a6B8827279cfff92266", + "1": DEFAULT_AMOUNT, + }, + "2": { + "0": "0x2ea397BE8d2d5d30bE21b0F4ADa731D35964F7dd", + "1": DEFAULT_AMOUNT, + }, + "3": { + "0": "0xf6d6ba2c01a48C14f9c2657b977f8f7f4c640091D", + "1": DEFAULT_AMOUNT, + }, + } +} + +def generate_merkle_tree(input_data: Dict = None) -> Tuple[List[Dict], bytes]: + """Generate complete Merkle tree data structure from input data.""" + if input_data is None: + input_data = DEFAULT_INPUT + + # Extract and sort leaves + leaves = [] + inputs = [] + for i in range(len(input_data["values"])): + address = input_data["values"][str(i)]["0"] + amount = input_data["values"][str(i)]["1"] + leaf = generate_leaf(address, amount) + leaves.append(leaf) + inputs.append((address, amount)) + + # Calculate root + root = get_merkle_root(leaves) + root_hex = "0x" + root.hex() + + # Generate output for each leaf + output = [] + for i in range(len(leaves)): + entry = { + "inputs": inputs[i], + "proof": get_proof(leaves.copy(), i), + "root": root_hex, + "leaf": "0x" + leaves[i].hex(), + } + output.append(entry) + + return output, root + +def get_merkle_root(leaves: List[bytes]) -> bytes: + """Calculate Merkle root.""" + next_layer = [] + for i in range(0, len(leaves), 2): + next_layer.append(hash_pair(leaves[i], leaves[i + 1])) + layer = next_layer + while len(layer) > 1: + next_layer = [] + for i in range(0, len(layer), 2): + next_layer.append(hash_pair(layer[i], layer[i + 1])) + layer = next_layer + return layer[0] + +def get_proof(leaves: List[bytes], index: int) -> List[str]: + """Generate Merkle proof for leaf at given index.""" + if not leaves: + return [] + proof = [] + layer = leaves + target_idx = index + while len(layer) > 1: + if len(layer) % 2 == 1: + layer.append(layer[-1]) + next_layer = [] + for i in range(0, len(layer), 2): + if i == target_idx - target_idx % 2: + # Add sibling to proof + proof.append("0x" + layer[i + 1 - (target_idx % 2)].hex()) + next_layer.append(hash_pair(layer[i], layer[i + 1])) + layer = next_layer + target_idx = target_idx // 2 + return proof + +def hash_pair(left: bytes, right: bytes) -> bytes: + """Hash a pair of values.""" + return keccak(encode_abi(["bytes", "bytes"], [left, right])) + +output, root = generate_merkle_tree() +print(output) +print(root) +``` + +We can run the following code to generate a Merkle Tree and its associated Merkle Proofs: + +```bash +mox-signatures-cu % mox run make_merkle +``` + +This will output the Merkle Tree data to a JSON file called `merkle_output.json`. From f7d82d95fa2df32e5036443ecb78cca9213e9573 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:44:25 -0700 Subject: [PATCH 242/255] Equious updated courses/advanced-moccasin/4-moccasin-signatures/6-claiming-a-proof/+page.md. --- .../6-claiming-a-proof/+page.md | 91 ++++++++++++++++++- 1 file changed, 86 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/4-moccasin-signatures/6-claiming-a-proof/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/6-claiming-a-proof/+page.md index 3d6602a5f..d3f662696 100644 --- a/courses/advanced-moccasin/4-moccasin-signatures/6-claiming-a-proof/+page.md +++ b/courses/advanced-moccasin/4-moccasin-signatures/6-claiming-a-proof/+page.md @@ -1,5 +1,86 @@ - - --- - title: Claiming A Proof - --- - \ No newline at end of file +## Claiming using a Merkle Proof + +Merkle Trees are a data structure which provide a mechanism to efficiently verify data, in our case, if someone is eligible to claim tokens in a given airdrop. + +We start with a Merkle Tree which is a tree structure where the leaves are data items or hashes of data items, and the nodes higher up in the tree are hashes of the nodes below them. The root of the tree is the hash of all the data items. + +Let's say someone is claiming tokens in an airdrop, and they provide their address, the amount of tokens they are entitled to, and a Merkle Proof. The Merkle Proof is a list of hashes from the tree, which are used to prove that the leaf node containing the address and amount is indeed in the Merkle Tree. + +Let's get started with creating a contract that can process a Merkle Proof and claim tokens! + +We need to define a few variables for our contract: + +```javascript +# Immutables +MERKLE_ROOT: public(immutable(bytes32)) +AIRDROP_TOKEN: public(immutable(address)) +``` + +We also want to establish a max length for the Merkle Proof: + +```javascript +# Constants +PROOF_MAX_LENGTH: constant(uint8) = max_value(uint8) # 255 +``` + +Now we can write an `init` function which is used to initialize our contract: + +```javascript +@deploy +def init(_merkle_root: bytes32, _airdrop_token: address): + MERKLE_ROOT = _merkle_root + AIRDROP_TOKEN = _airdrop_token +``` + +Let's create a function called `claim` which will be responsible for processing the Merkle Proof: + +```javascript +@external +def claim( + account: address, + amount: uint256, + merkle_proof: DynArray[bytes32, PROOF_MAX_LENGTH], # list of other hashes from the tree + v: uint8, + r: bytes32, + s: bytes32 +): + """Allows users to claim the airdropped tokens.""" + assert not self.has_claimed[account], "merkle_airdrop: Account has already claimed" + leaf: bytes32 = keccak256(abi.encode(keccak256(abi.encode(account, amount)))) + assert merkle_proof_verification.verify_proof(MERKLE_ROOT, leaf, merkle_proof), "merkle_airdrop: Invalid Proof" + self.has_claimed[account] = True + log.Claimed(account, amount) + success: bool = extcall(AIRDROP_TOKEN.transfer(account, amount, v, r, s)) + assert success, "Transfer Failed" +``` + +We want to import the `ERC20` library from `ethereum` so that we can use it to transfer the tokens. + +```javascript +from ethereum.erc2s import IERC20 +``` + +Now, we can define our `AIRDROP_TOKEN` variable as a public immutable `IERC20`: + +```javascript +AIRDROP_TOKEN: public(immutable(IERC20)) +``` + +Let's add an event that will be emitted when an account claims their tokens: + +```javascript +event Claimed( + account: indexed(address), + amount: indexed(uint256) +) +``` + +And finally, we need to make sure we wrap the `AIRDROP_TOKEN` within our `init` function: + +```javascript +AIRDROP_TOKEN = IERC20(_airdrop_token) +``` + +Now, if we deploy this contract, people can use it to claim their tokens using a Merkle Proof. This is a powerful and secure mechanism for airdrops. + +We've introduced the core concepts and functions of a contract that handles a Merkle Proof for claiming tokens. This sets the foundation for exploring more intricate scenarios and advanced concepts surrounding Merkle Trees in airdrops. From 912fefd64416edaba8b1480739238aca8ec63ec5 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:44:38 -0700 Subject: [PATCH 243/255] Equious updated courses/advanced-moccasin/4-moccasin-signatures/7-signature-standards/+page.md. --- .../7-signature-standards/+page.md | 214 +++++++++++++++++- 1 file changed, 209 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/4-moccasin-signatures/7-signature-standards/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/7-signature-standards/+page.md index 05e42f97d..c38da6b92 100644 --- a/courses/advanced-moccasin/4-moccasin-signatures/7-signature-standards/+page.md +++ b/courses/advanced-moccasin/4-moccasin-signatures/7-signature-standards/+page.md @@ -1,5 +1,209 @@ - - --- - title: Signature Standards - --- - \ No newline at end of file +## Signatures & Verification + +We're going to talk about signature standards and how they are implemented in smart contracts. We'll look at the different types of signatures and how they work. + +First, we're going to cover the basics of signature verification in Solidity. We'll create a simple Solidity smart contract to demonstrate signature verification: + +```javascript +contract SignatureVerifier { + function getSignerSimple(uint256 message, uint8 v, bytes32 r, bytes32 s) public pure returns (address) { + bytes32 hashedMessage = bytes32(message); // if string, we'd use keccak256(abi.encodePacked(string)) + address signer = ecrecover(hashedMessage, v, r, s); + return signer; + } + + function verifySignerSimple( + uint256 message, + uint8 v, + bytes32 r, + bytes32 s, + address signer + ) public pure returns (bool) { + address actualSigner = getSignerSimple(message, v, r, s); + require(signer == actualSigner); + return true; + } +} +``` + +In this contract, we have two functions. The first, `getSignerSimple` hashes the message using the `bytes32` data type, and then recovers the signer using the pre-compiled `ecrecover`. The second function, `verifySignerSimple`, retrieves the signer from the message using the `getSignerSimple` function and then compares that address to the expected signer address. It reverts if they aren't the same. + +We'll then dive into EIP 191 and 712 and how they are used to improve signature verification. EIP 191 standardizes the format for signed data. Let's look at the structure for an EIP 191 signature: + +``` +0x19 <1 byte version> +``` + +This signature starts with a 0x19 prefix, followed by the one-byte version, which indicates which version of the standard is being used. Next is the version-specific data, which will vary depending on the version. Lastly, the data to sign is appended. + +EIP 712 uses a version of this format that is a little more complex to prevent replay attacks. It does this by hashing the data in a structured way: + +``` +0x19 0x01 +``` + +The main difference between the EIP 712 and the simple EIP 191 signature is the inclusion of the `domainSeparator`. The domain separator is a hash struct that defines the domain of the message being signed. + +The hash struct is defined as follows: + +```javascript +struct EIP712Domain { + string name; + string version; + uint256 chainId; + address verifyingContract; + bytes32 salt; +} +``` + +The domain separator is created by hashing the name, version, chain ID, verifying contract, and salt. + +Let's demonstrate this in Solidity: + +```javascript +contract SignatureVerifier { + bytes32 public constant MESSAGE_TYPEHASH = keccak256( + "Message(uint256 message)" + ); + + function getMessageHash(string message) public view returns (bytes32) { + return keccak256( + abi.encodePacked( + MESSAGE_TYPEHASH, + Message(message: message) + ) + ); + } + + function getSignerEIP712( + uint256 message, + uint8 v, + bytes32 r, + bytes32 s + ) public view returns (address) { + bytes1 prefix = bytes1(0x19); // 0x19 is version 1 of EIP-191 + bytes1 eip712Version = bytes1(0x01); // EIP-712 is version 1 of EIP-191 + bytes32 hashStructOfDomainSeparator = _domain_separator; + bytes32 hashedMessage = keccak256(abi.encodePacked(MESSAGE_TYPEHASH, Message(number: message))); + bytes32 digest = keccak256(abi.encodePacked(prefix, eip712Version, hashStructOfDomainSeparator, hashedMessage)); + return ecrecover(digest, v, r, s); + } + + function verifySignerEIP712( + uint256 message, + uint8 v, + bytes32 r, + bytes32 s, + address signer + ) public view returns (bool) { + address actualSigner = getSignerEIP712(message, v, r, s); + require(signer == actualSigner); + return true; + } +} +``` + +In this code, we first define the `getMessageHash` function that takes a message and calculates its hash using `keccak256`. We then create a `getSignerEIP712` function. This function follows the EIP 712 format, which means it also takes the domain separator as an argument, as well as the prefix and version. + +The `verifySignerEIP712` function then retrieves the signer from the message, using the `getSignerEIP712` function, and compares it to the expected signer address. It reverts if they are not the same. + +We can also use OpenZeppelin to easily verify signatures: + +```javascript +import { SignatureChecker } from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol"; +import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; + +contract SignatureVerifier { + bytes32 public constant MESSAGE_TYPEHASH = keccak256( + "Message(uint256 message)" + ); + + function getMessageHash(string message) public view returns (bytes32) { + return keccak256( + abi.encodePacked( + MESSAGE_TYPEHASH, + Message(message: message) + ) + ); + } + + function getSignerEIP712(uint256 digest, uint8 v, bytes32 r, bytes32 s) public pure returns (address) { + (address signer, ECDSA.RecoverError recoverError) = ECDSA.tryRecover(digest, bytes32(signatureLength), v, r, s); + //address signer = ECDSA.recover(hashedMessage, packedSignature); + // address signer = ecrecover(hashedMessage, v, r, s); + // address signer = ecrecover(prefixedHashedMessage, v, r, s); + return signer; + } + + function verifySignerEIP712( + uint256 message, + uint8 v, + bytes32 r, + bytes32 s, + address signer + ) public pure returns (bool) { + address actualSigner = getSignerEIP712(getMessageHash(message), v, r, s); + require(actualSigner == signer); + return true; + } +} +``` + +This code demonstrates how to use OpenZeppelin's `SignatureChecker` and `ECDSA` libraries for signature verification. + +As we saw in the previous example, EIP 712 utilizes a `domainSeparator`. Let's look at how we can define the domain separator and hash it together with the other data: + +```javascript +contract SignatureVerifier { + bytes32 public constant EIP712DOMAIN_TYPEHASH = keccak256( + "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" + ); + bytes32 public immutable _domain_separator; + + constructor() { + _domain_separator = keccak256( + abi.encode( + EIP712DOMAIN_TYPEHASH, + keccak256("SignatureVerifier"), + keccak256("1"), + 1, + address(this) + ) + ); + } + + bytes32 public constant MESSAGE_TYPEHASH = keccak256( + "Message(uint256 message)" + ); + + function getMessageHash(string message) public view returns (bytes32) { + return keccak256( + abi.encodePacked( + MESSAGE_TYPEHASH, + Message(message: message) + ) + ); + } + + function getSignerEIP712(uint256 digest, uint8 v, bytes32 r, bytes32 s) public pure returns (address) { + (address signer, ECDSA.RecoverError recoverError) = ECDSA.tryRecover(digest, bytes32(signatureLength), v, r, s); + return signer; + } + + function verifySignerEIP712( + uint256 message, + uint8 v, + bytes32 r, + bytes32 s, + address signer + ) public pure returns (bool) { + address actualSigner = getSignerEIP712(getMessageHash(message), v, r, s); + require(actualSigner == signer); + return true; + } +} +``` + +In this code, we define the `EIP712Domain` struct and then calculate the `_domain_separator` in the constructor. This helps ensure that signatures can only be used with our contract on our chain, along with our application. + +This code helps make our smart contract more secure by preventing replay attacks. Replay attacks are where the same transaction can be sent multiple times. The extra data in the EIP 712 structure prevents this by ensuring that signatures are unique to that specific domain. From 5d5e85c4e556cef7d58a335928b0b46ceec4786e Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:44:51 -0700 Subject: [PATCH 244/255] Equious updated courses/advanced-moccasin/4-moccasin-signatures/8-eip-712-in-vyper/+page.md. --- .../8-eip-712-in-vyper/+page.md | 38 ++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/4-moccasin-signatures/8-eip-712-in-vyper/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/8-eip-712-in-vyper/+page.md index 4d49f70ad..d90453c69 100644 --- a/courses/advanced-moccasin/4-moccasin-signatures/8-eip-712-in-vyper/+page.md +++ b/courses/advanced-moccasin/4-moccasin-signatures/8-eip-712-in-vyper/+page.md @@ -1,5 +1,33 @@ - - --- - title: Eip 712 In Vyper - --- - \ No newline at end of file +We are going to understand the concept of the EIP-712 version thing we keep seeing. + +As Kira just spoke about, this EIP-712 version is going to be the version of EIP-712 that we're working with, which we're working with number one. We can look up EIP-712 in the Ethereum uh in the Ethereum Improvement Proposals website, which is this typed structured data hashing and signing. This is what Kira just went over and if we scroll down, we can see in here we see version. Where is version? Version. We can finally see what these EIP-712 things are for. So, right, anytime we create a token, we usually add this name and this version thing for some reason. So, if we go to the ERC20, we see it's the name EIP-712 and the version EIP-712. So, the name EIP-712 is going to be the maximum 50 character user-readable string name of the signing domain and then the version is the maximum 20 character current version of the signing domain. Signatures from different versions are not compatible. + +If we scroll down, all we really do with these two is we do this EIP-712 domain separator .init. So, we can look that up as well in the utils. Scroll down, EIP-712 domain separator. We can look at the init here. + +```javascript +function signMessageEIP712(uint256 message) internal view returns (uint8, bytes32, bytes32) { + // to encode this, we need to know the domain separator! + bytes32 prefix = bytes32(hex"19"); + // EIP-712 is version 1 of EIP-191 + bytes32 eip191Version = bytes32(hex"01"); + bytes32 hashedMessageStruct = keccak256(abi.encodePacked(signatureVerifier.TYPEHASH(), SignatureVerifier.number(message, number))); + bytes32 digest = keccak256(abi.encodePacked(prefix, eip191Version, signatureVerifier.domain_separator(), hashedMessageStruct)); + return vm.signUser.key, digest; +} +``` + +All this is doing is it's making is it's setting this contract up so that it can do these signatures without running into security issues like signature replays or chain replays etc. So, there's just a ton of stuff in here, a ton of boilerplate in here that has to do with the different versions of EIP-712 domain separator's, getting hash data, etc. So, everything in here is just making doing signatures much better. + +Now, one of the questions is, okay, cool Patrick, but like why is this why is this here? Like, what what do we care about signatures? Does this ERC20 have any signature functionality? And the answer is absolutely. So, on here, there's this function called permit and if you look here, you can see this looks pretty similar to approve except it has a v r and s at the end here. + +```javascript +function permit(uint256 message, uint8 v, bytes32 r, bytes32 s) public { + // Sign a message + (uint8 v, bytes32 r, bytes32 s) = signMessageEIP712(message); + // Verify the message + bool verifiedOnce = signatureVerifier.verifySignerEIP712(messageStruct, v, r, s, userAddr); + assertEq(verifiedOnce, true); +} +``` + +So, as you've seen by now having done many different tests, anytime you want to interact with a smart contract, you need to send two transactions, right? You need to first do an approve and then you need to call the transfer from. Now, this is incredibly annoying for a lot of people, for a lot of reasons because the user has to call this approve every single time. So, what a lot of people in the Ethereum community did was they said hey, it would be great if the approver could just sign something somebody else could pay the gas cost of approving that way I could just roll up and call my single function and have a much better experience. There's this EIP-2612 which talks a lot about this permit extension to EIP-20 signed approvals and so, a lot of tokens have taken on this permit functionality to make people's lives with working with tokens a lot easier. So, it's a bit of a mouthful but essentially, this name and EIP-712 version this makes signing and working with this permit functionality much easier. Prevents replay attacks and prevents a lot of attacks like that. So, it's incredibly powerful and we're going to be using some of it here. From 277d2b45eade5fb7b1bbc29ebf2fcf59cbb0cd44 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:45:04 -0700 Subject: [PATCH 245/255] Equious updated courses/advanced-moccasin/4-moccasin-signatures/9-ecdsa/+page.md. --- .../4-moccasin-signatures/9-ecdsa/+page.md | 86 +++++++++++++++++-- 1 file changed, 81 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/4-moccasin-signatures/9-ecdsa/+page.md b/courses/advanced-moccasin/4-moccasin-signatures/9-ecdsa/+page.md index 65f4879b0..d0c18b453 100644 --- a/courses/advanced-moccasin/4-moccasin-signatures/9-ecdsa/+page.md +++ b/courses/advanced-moccasin/4-moccasin-signatures/9-ecdsa/+page.md @@ -1,5 +1,81 @@ - - --- - title: Ecdsa - --- - \ No newline at end of file +## ECDSA Signatures + +We are going to continue our exploration of digital signatures with something called ECDSA recover, which was mentioned in the last video. This is a process that will be incredibly important to what we are doing here with our Merkle airdrop. Let's dive in. + +### What are ECDSA Signatures? + +ECDSA stands for Elliptic Curve Digital Signature Algorithm. It's a mouthful, but it's based on Elliptic Curve Cryptography. Don't worry, we'll get into what that means in a second. ECDSA is used to: +- generate key pairs +- create signatures +- verify signatures. + +But first, what are signatures in the context of blockchain? + +Blockchain signatures are a means for authentication in blockchain technology. They allow operations such as sending transactions to be verified, ensuring they originated from the intended sender. + +Proof of ownership on Ethereum is achieved using public and private key pairs. These key pairs are used to create digital signatures. + +Think of signatures as an analog to needing ID to withdraw money from a bank, or a digital fingerprint. + +### What is Public Key Cryptography? + +The public-private key pair is used to verify that the sender is the owner of the account. This is known as public key cryptography, and it involves asymmetric encryption. Asymmetric encryption, while sounding confusing, is a pretty straightforward process. + +A private key is used to sign a message, and that private key is used to derive the public key. The public key is then used to verify the signature, and confirm that the person who owns the private key created the signature. + +You should never share your private key, as anyone who has it can access your account. But, sharing your public key is completely safe. If you share your public key, someone cannot steal your funds. + +This public-private key pair defines your Ethereum externally owned account, or EOA. These EOAs interact with the blockchain by signing data and sending transactions without others being able to access accounts they do not own. + +An Ethereum address is used as identification, and is the last 20 bytes of the hash of the public key. + +### How are Public and Private Keys Generated? + +How do we create public and private keys? How are signatures generated? + +Public and private keys are generated using a process that involves two important constants. + +- **Generator Point G** is a constant point on the Elliptic Curve, and can be thought of as a random point. +- **Order n** is a prime number, and defines the length of the private key. It is generated using the generator point G. + +We only really need to remember that these constants are, in fact, constants. They will be used in subsequent calculations. + +### What is a Signature in ECDSA? + +ECDSA signatures are made up of three integers: +- V +- R +- S. + +They might look familiar. +- **R** is the x coordinate of a random point, denoted as R on the curve. +- **S** serves as proof that the signer knows the private key, and is calculated using the nonce k, the hash of the message, the private key, the R part of the signature, and the order n. +- **V** is used to recover the public key from R, and denotes the index of the point on the curve, whether the point is in positive or negative y. This is known as the polarity. + +### How are Signatures Verified? + +Now we've discussed how public and private keys are generated, and how the signature is constructed. Let's take a look at how ECDSA signatures are verified. + +The ECDSA verification algorithm takes the signed message, the signature from the signing algorithm, and the public key, and outputs a boolean representing whether the signature is valid. This is essentially the reverse of the signing process. + +The EVM pre-compiler does this verification for us. It checks to see if the signature is valid. If it is not valid, the pre-compiler will return the zero address, and the smart contract will revert. + +### ECDSA Recover + +ECDSA recover is a function used in smart contracts. It retrieves the signer's address of a message that has been signed using a private key with ECDSA. It uses the signature to do this. + +However, using ECDSA recover directly can lead to some security issues. + +The first issue we discussed is signature malleability. Because the curve is symmetrical about the x-axis, there are two valid signatures for each value of R. Therefore, if an attacker knows one signature, they can calculate the other one. + +We can mitigate this issue by restricting the value of S to one half of the curve. If S is not restricted, then the two valid signatures exist. The smart contract can be vulnerable to signature malleability attacks. + +We should always use the OpenZeppelin ECDSA library to verify signatures. This library has built-in checks to protect against signature malleability attacks. + +We also discussed another issue with using ECDSA recover directly. If the signature is invalid, the ECDSA recover function will return the zero address. The smart contract should have a check in place to ensure it reverts if the zero address is returned from the ECDSA recover function. Again, the OpenZeppelin ECDSA library already has this check in place. + +### Conclusion + +Well done, we covered a lot of information, and it can be overwhelming. You should be proud of yourself for making it through. If anything was confusing, or you need to go over this again, you can always read some other articles, or dive into the math. It's very complex stuff and it's unlikely you'll get your head around it the first time. + +But, you should be proud because now you understand ECDSA Signatures. From 5b69f969a42cce34fa254539837b5d266b6fdc43 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:45:17 -0700 Subject: [PATCH 246/255] Equious updated courses/advanced-moccasin/5-moccasin-upgrades/1-intro/+page.md. --- .../5-moccasin-upgrades/1-intro/+page.md | 126 +++++++++++++++++- 1 file changed, 121 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/5-moccasin-upgrades/1-intro/+page.md b/courses/advanced-moccasin/5-moccasin-upgrades/1-intro/+page.md index c3de78c13..67005a1c7 100644 --- a/courses/advanced-moccasin/5-moccasin-upgrades/1-intro/+page.md +++ b/courses/advanced-moccasin/5-moccasin-upgrades/1-intro/+page.md @@ -1,5 +1,121 @@ - - --- - title: Intro - --- - \ No newline at end of file +## Mox Upgrades: Introduction + +We're going to be covering one of the final but most important concepts in smart contract development: proxies. + +We'll be working with the code in this repo: + +```bash +https://github.com/Cyfrin/mox-upgrades-cu +``` + +At the end of the lesson we'll have two contracts: *counter_one* and *counter_two*. They look nearly identical except for a few minor changes. We're going to deploy this ERC1967 contract in Vyper. This contract isn't 100% compliant, but that's a different conversation. + +We're only going to make calls to this contract and not to the *counter* contracts yet. This proxy contract will be able to set a number, increment a number, get a version, and decrement. It does not have any of these functions nor does it inherit them from the *counter* contracts. + +Let's get started learning about proxies and learning about upgradable contracts. Let's watch this video. + +Now a quick note about this video. I made this a few years ago and I thought a couple jokes were a lot funnier back then than they are now. So um uh, bear with the bad jokes. Thank you. + +## Upgradable Contracts & Proxies: Introduction + +Now I'm editing this video much later after I filmed it, hence why I have a beard. So, I'll be jumping in from time to time, updating some of the sections. + +When deploying your smart contracts on chain, we all know those smart contracts are immutable or unchangeable. But, what if I told you that they were mutable? + +Well technically I wouldn't be correct, however smart contracts actually can change all the time. When people transfer tokens, when people stake in a contract, or really do any type of functionality, those smart contracts have to update their balances and update their mappings and update their variables to reflect this. + +The reason that they are immutable is that the logic itself never changes and will be on chain like that forever. So technically, yes, once they are deployed, they are immutable and this is actually one of the major benefits of smart contracts in the first place. That nobody can tamper with or screw with our smart contracts once we deploy them. + +However, this can be an issue if, for example, we want to upgrade our smart contracts or protocol to do more things, or we want to fix some glaring bug or issue that we have. + +Now, even though we can't change the specific code that's been deployed to an address, we can actually do a lot more than you think. And in this video, we're going to explain the different methodologies behind upgrading your smart contracts. And then, we're going to show you how to do it with Hardhat and Open Zeppelin. + +Huge shout out to a lot of Open Zeppelin and Trail of Bits articles that helped me put this video together, and a number of other sources as well. Links in the description. So, let's get to it. + +Now at first glance, you might be thinking, "If you can upgrade your smart contracts then they're not really immutable then." And in a way you'd be right. So, when explaining kind of the different philosophies and patterns that we can use here we do need to keep in mind the philosophies and decentralization implications that each one of these patterns have, as they do all have different advantages and disadvantages. And yes, some of the disadvantages here are going to affect decentralization. So, we need to keep that in mind. And, this is why it's so important that before you go ahead and jump in and start deploying upgradable smart contracts, you understand the trade-offs. + +So, we're going to talk about three different ways to upgrade your smart contracts. The first one being the *not really* / parameterize way to upgrade your smart contracts. The social migration method and then the method that you probably have heard about which is proxies, which have a ton of sub-categories like metamorphic contracts, transparent upgradeable proxies and universal upgradeable proxies. + +So, let's talk about the *not really* upgrading method, or the parameterization method, or whatever you want to call it. This is the simplest way to think about upgrading your smart contracts. And, it really isn't upgrading our smart contracts because we can't really change the logic of the smart contract. Whatever logic that we've written is there. We also can't add new storage or state variables. So, this is really not really upgrading, but it is something to think about. Upgrades is just parameterizing everything. Whatever logic that we've deployed is there and that's what we're interacting with. This function means we just have a whole bunch of setter functions and we can update certain parameters, like maybe we have a reward parameter that gives out a token at 1% every year or something like that. Maybe we have a setter function that says, hey, update that to 2% or update that to 4%. It's just a setter function that changes some variable. + +Now, the advantages here obviously this is really simple to implement. The disadvantage is that, if you didn't think of some logic or some functionality the first time you deployed your smart contract, that's too bad. You're stuck with it. You can't update the logic or really update anything, with the parameterization a.k.a. *not really* method. And the other thing you have to think about is who the admins are. Who has access to these setter functions to these updating functions? If it's a single person, guess what? You have a centralized smart contract. + +Now, of course, you're going to add a governance contract to be the admin contract of your protocol, and that would be a decentralized way of doing this. So, just keep that in mind. You can do this method, just need a governance protocol to do so. + +Another example of this might be a contract registry and this is something that actually that early versions of Aave used. Before you call a function, you actually check some contract registry that is updated as a parameter by somebody, and you get routed to that contract and you do your call there. Again, this really doesn't allow us to have the full functionality of upgrades here. You can argue that this registry is a mix of one of the later versions, but for all intents and purposes, it doesn't really give us that flexibility that we want for our upgrades. + +But, some people might even think that upgrading your smart contract is ruining the decentralization. And, one of the things that makes smart contracts so potent is that they are immutable and that this is one of the benefits that they have. + +So, there are some people who think that you shouldn't add any customization, or any upgrade ability. You should deploy your contract and then that's it. Trail of Bits has actually argued that, if you deploy your contract knowing that it can't be changed later, you take a little bit extra time making sure you get everything right, and there are often less security vulnerabilities because you're just setting it, forgetting it, and not looking at it again. + +Now if I wanted to upgrade a smart contract with this philosophy in mind, the philosophy that I did want to keep my smart contracts immutable, we can instead use the social migration method, which I previously called the *yeet* method and now I think it's less funny, so we're just going to stick with social migration. + +The *social yeet* method, or the migration method, is just when you deploy your new contract, not connected to the old contract in any way, and by social convention, you tell everybody, hey this new contract, this new one that we just deployed, yeah, this is the real one now and it's just by convention of people migrating and over into using this new one that the upgrade is done. Hence my slang name of *social yeet* because you yeet the first one out of the way and you move to the second one. + +I think I'm funny. Yay! This has the advantage of truly always saying, hey this is our immutable smart contract and this is our new one. This is really the truest definition of immutable because since you give it no way of being upgraded in place, then if somebody calls that contract in 50,000 years in the future, it'll respond exactly the same. + +Another huge disadvantage here is that you have to have a totally new contract address. So, if you're an ERC20 token, for example, you have to go convince all the exchanges to list your new contract address as the actual address. Keep in mind that, when we do this, we do have to move the state of the first one over to the second one. So, for example, if you're an ERC token, moving to a new version of that ERC token, you do have to have a way to take all those mappings from the first contract and move it to the second one. Obviously, there are ways to do this since everything is on chain, but if you have a million transfer calls, I don't want to have to write the script that updates everyone's balance and figures out what everyone's balances is just so I can migrate to my new version of the contract. + +So, there is a ton of social convention work here to do. Trail of Bits has actually written a fantastic blog on upgrading from a V1 to a V2 or et cetera with this *yeet* methodology. And they give a lot of steps for moving your storage and your state variables over to the new contract. So, link in the description if you want to read that. + +Now let's get to our big ticket item. So, in order to have a really robust upgrading mentality or philosophy, we need to have some type of methodology or framework that can update our state, keep our contract address and allow us to update any type of logic in our smart contracts in an easy way. Which leads us to our big ticket item: the proxies. + +## Proxies + +Proxies are the truest form of upgrades since a user can keep interacting with the protocols through these proxies and not even notice that anything changed or even got updated. + +Now, these are also the places where you can screw up the easiest. + +Proxies use a lot of low level functionality, and the main one being the *delegate call* functionality. *Delegate call* is a low level function where the code in the target contract is executed in the context of the calling contract, and *msg.sender* and *msg.value* also don't change. + +So, you understand what *delegate call* means now, right? Great, and in English this means if I delegate call a function in contract B from contract A, I will do contract B's logic in contract A. So, if contract B has a function that says hey, store this value in a variable up top, I'm going to store that variable in contract A. + +This is the powerhouse, and this combined with the *fallback* function allows us to delegate all calls through a proxy contract address to some other contract. This means that I can have one proxy contract that will have the same address forever and I can just point and route people to the correct implementation contract that has the logic. Whenever I want to upgrade I just deploy a new implementation contract and point my proxy to that new implementation. + +Now, whenever a user calls a function on the proxy contract, I'm going to *delegate call* it to the new contract. I can just call an admin only function on my proxy contract, let's call it *upgrade* or something, and I make all the contract calls go to this new contract. + +When we're talking about proxies, there are four pieces of terminology that we want to keep in mind. First is the implementation contract. The implementation contract has all of our logic and all the pieces of our protocol. Whenever we upgrade, we actually launch a brand new implementation contract. The proxy contract. Proxy points to which implementation is the *correct* one, and routes everyone's function calls to that contract. The user. The user is going to be making contract and function calls through the proxy contract. And then some type of admin. The admin is the one who's going to decide when to upgrade and which contract to point to. + +In this scenario, the other cool thing about the proxy and *delegate call* is that all my storage variables are going to be stored in the proxy contract and not in the implementation contract. This way, when I upgrade to a new logic contract, all of my data will stay on the proxy contract. So, whenever I want to update my logic, just point to a new implementation contract. If I want to add a new storage variable or a new type of storage, I just add it in my logic contract and the proxy contract will pick it up. + +Now, using proxies has a couple of gotchas, and we're going to talk about the gotchas and then we're going to talk about the different proxy contract methodologies, because yes, there are many proxy contract methodologies as well. And this is why Trail of Bits doesn't really recommend using upgradable proxies for your smart contracts because they're fraught with a lot of these potential issues. + +Not to mention, again you do still have some type of admin who's going to be upgrading your smart contracts. + +Now, if this is a governance protocol, then great, you're decentralized. But if this is a single group or entity, then we have a problem. + +The two biggest gotchas are storage clashes and function selector clashes. + +Now, what does this mean? When we use *delegate call*, remember we do the logic of contract B inside contract A. So, if contract B says we need to set value to two, we go ahead and set value to two, but these smart contracts are actually kind of dumb. We actually set the value of whatever is in the same storage location on contract A as contract B. So, if our contract looks like this and we have two variables in contract A, we're still going to set the first storage spot on contract A to the new value. This is really important to know because this means we can only pretend new storage variables and new implementation contracts, and we can't reorder or change old ones. This is called *storage clashing*. And in the implementations we're going to talk about, they all address this issue. + +The next one is called *function selector clashes*. When we tell our proxies to *delegate call* to one of these implementations, it uses what's called a function selector to find a function. The function selector is a four byte hash of the function name and the function signature. Don't worry about the function signature for now. + +Now it's possible that a function in the implementation contract has the same function selector as an admin function in the proxy contract, which may cause you to do accidentally a whole bunch of weird stuff. For example, in this sample code in front of you, even though these functions are totally different, they actually have the same function selector. So, yes, we can run into an issue where some harmless function like get price has the same function selector as upgrade proxy or destroy proxy or something like that. + +This leads to our first out of the three implementations of the proxy contracts. + +## Transparent Proxy Pattern + +This is called the transparent proxy pattern. + +In this methodology, admins are only allowed to call admin functions, and they can't call any functions in the implementation contract. And users can only call functions in the implementation contract and not any admin contracts. This way, you can't ever accidentally have one of the two swapping and having a function selector clash and you're running into a big issue where you call a function you probably shouldn't have. + +If you're an admin you're calling admin functions. If you're a user you're calling implementation functions. So, if you're an admin and you build some crazy awesome DeFi protocol, you better come up with a new wallet address because you can't participate. + +## Universal Upgradeable Proxies + +The second type of proxy we're going to talk about is the universal upgradeable proxy, or the UUPS. + +This version of upgradable contracts actually puts all the logic of upgrading in the implementation itself. This way the solidity compiler will actually kick out and say, hey, we got two functions in here that have the same function selector. + +## Gotchas + +This is also advantageous because we have one less read that we have to do. We no longer have to check in the proxy contract if someone is an admin or not. This saves on gas, of course. And, the proxy is also a little bit smaller because of this. The issue is that if you deploy an implementation contract without any upgradeable functionality, you're stuck. And it's back to the *yeet* method with you. + +And, the last pattern or methodology that we're going to talk about is the diamond pattern. Which does a number of things, but one of the biggest things that it does is, it actually allows for multiple implementation contracts. + +This addresses a couple different issues. For example, if your contract is so big and it doesn't fit into the one contract maximum size, you can just have multiple contracts through this multi-implementation method. It also allows you to make more granular upgrades. Like, you don't have to always deploy and upgrade your entire smart contract. You can just upgrade little pieces of it if you've chunked them out. + +All the proxies mentioned here have some type of Ethereum Improvement Proposal, and most of them are in the draft phase. + +And, at the end of this explainer, we will do a demo of showing you how the *delegate call* function works. From 482fa344a691aad8768ce5a4c0417e83554b54c7 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:45:30 -0700 Subject: [PATCH 247/255] Equious updated courses/advanced-moccasin/5-moccasin-upgrades/2-erc-1967-and-delegatecall/+page.md. --- .../2-erc-1967-and-delegatecall/+page.md | 79 +++++++++++++++++-- 1 file changed, 74 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/5-moccasin-upgrades/2-erc-1967-and-delegatecall/+page.md b/courses/advanced-moccasin/5-moccasin-upgrades/2-erc-1967-and-delegatecall/+page.md index bb2fdb9cb..9c23601b8 100644 --- a/courses/advanced-moccasin/5-moccasin-upgrades/2-erc-1967-and-delegatecall/+page.md +++ b/courses/advanced-moccasin/5-moccasin-upgrades/2-erc-1967-and-delegatecall/+page.md @@ -1,5 +1,74 @@ - - --- - title: Erc 1967 And Delegatecall - --- - \ No newline at end of file +## ERC-1967 and Delegate Call + +We will create our own proxy contract ourselves and see first-hand how this works. + +We will start with a blank contract. Open your terminal and use the following commands: + +```bash +mkdir mox-upgrades-cu +code mox-upgrades-cu +``` + +Next, we will delete everything in our _src_ folder. + +Now, we will grab the ERC-1967.vy file from our GitHub repository. Open your browser and navigate to your GitHub repository. Click on _mox-upgrades-cu_ and _src_, then grab the code from the _ERC1967.vy_ file. + +Paste this code into a new file called _ERC1967.vy_ in your _src_ folder. + +```javascript +gap_0: uint256; # 244400534053805366564022568114969544909752651517672968839296883920ac459d9512 +implementation: public(address); # 0x3c680994a13ba1a321d667c8249d22b0d9ca2076c3735a2c45a5920ac459d9512 +gap_1: uint256; # 575156741210777536643407599865508318857449273161256368323712657080424561478 +admin: public(address); # 0x05512766a568b3173aeb9a016e78a6f1cc2436e24e3ee6ee1178d6a7178d5b75805d61d3 + +def default() -> uint256: + """@notice Fallback function that delegates all calls to the implementation""" + assert self.implementation != empty(address), "Implementation not set" + """# Delegate call to the implementation""" + result: uint256 = convert(raw_call( + self.implementation, + msg.data, + max_outsize=32, + is_delegate_call=True, + revert_on_failure=True + ), uint256) + return result +``` + +We will cover some of the highlights from the ERC-1967 contract code. +First, you will see that the contract has a giant fixed-size array of uint256s. + +The reason we have this massive array is because we want this implementation slot to be at this specific slot in storage. Remember, since we learned a lot about storage, we learned that since this is a uint256 array, it is going to initialize all these storage slots to zero, and this implementation address will be set to the storage slot after all of this. + +If you go to the documentation here for the ERC-1967, the storage slot for the implementation, or the logic contract address, is this address here. + +So, the implementation still might be a little bit hazy to you right now. That's okay, no worries. We will explain it as we go along here. So, essentially, we're doing some weird storage stuff. So, we are creating kind of this gap in storage, so the storage has a ton of empty slots, then it has this implementation, then it has a ton more empty slots, and then it has some admin address. + +The reason for this is if we scroll down and we look at this default function. Remember how the default function works? It's the fallback function. If somebody calls, you know, a function that doesn't exist, like they call like, Hello World, there's no Hello World on here. It'll automatically kick all the data to this default function. + +In our default function here, we have it set up where we're going to assert that the implementation isn't empty. Then we're going to send everything to that implementation slot. + +However, it's going to do this thing is delegate call. It's going to be set to True. + +So, let me show you a little bit of a diagram of kind of what this looks like. + +In a normal raw call, it would kind of look like this. Somebody would call the ERC-1967.vy. It would hit the default function, the default function would look in its storage. It would see the implementation and then would kick all the data over to some contract, like Counter one. Counter one would do it. + +But, with delegate call, what it's going to do instead, you can almost think of it as it kind of going over to Counter one, saying Hey, do you have this function that they are asking for, and then take it for itself? + +I know that that sounds kind of bizarre, but you can almost think of this delegate call as a borrowing feature. So, let's say Counter one has a function that looks like this. + +```javascript +def set_number(new_number): + number = new_number +``` + +If we were to just do a regular call, well, this would get called on our Counter one contract, and Counter one's storage would get changed. But, instead, with delegate call, we are actually going to borrow this function, and bring it over here. Bring it to ourselves. And now we're going to almost run this function on our contract itself. But, instead of saying def set_number, new_number, well, actually, excuse me, it would be self.number = new_number. But, our contract is going to say, okay, what storage slot was your self.number in? Okay, that was storage slot zero. So, I am just going to say my storage slot zero is going to be the new number, and on the ERC-1967 contract, the number, the storage slot zero, would get populated, and nothing would happen to Counter one. + +So, I like to think of the delegate call functionality as like a function borrower. Like, hey, I am going to send all this data to you, I am going to send all this data to this Counter one, but all the results, and everything that happens, I am going to keep it. You are not going to keep any of it, which is pretty cool. + +We also have an upgrade to function which allows us to upgrade. And we have a change admin function as well. This means, though, what's kind of scary, is if our Counter one had like a def change admin, we would never be able to call it, because it would trigger our change admin function being called. And, this is actually an issue when it comes to using these type of proxy contracts, is you want to look out for function selector collisions where the function selectors are the same, which we learned a little bit about function selectors before. + +This setup that we are using here is some type of It is kind of a version of what's known as the transparent proxy pattern. A lot of the modern Solidity contracts use this thing called a UUPS Proxy pattern. And, as you get more advanced, you can decide what type of proxies that you want to use. + +This code is for educational purposes only. I do not endorse this as production grade proxy. I have not audited this. So, just a rule of thumb here if you are going to use proxies in Vyper, be sure to get them audited and security reviewed. From ab3e00c407db056cc9b4bf426398aa418668e6ab Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:45:42 -0700 Subject: [PATCH 248/255] Equious updated courses/advanced-moccasin/5-moccasin-upgrades/3-delegatecall/+page.md. --- .../3-delegatecall/+page.md | 101 +++++++++++++++++- 1 file changed, 96 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/5-moccasin-upgrades/3-delegatecall/+page.md b/courses/advanced-moccasin/5-moccasin-upgrades/3-delegatecall/+page.md index 01bcfe675..4fb74d616 100644 --- a/courses/advanced-moccasin/5-moccasin-upgrades/3-delegatecall/+page.md +++ b/courses/advanced-moccasin/5-moccasin-upgrades/3-delegatecall/+page.md @@ -1,5 +1,96 @@ - - --- - title: Delegatecall - --- - \ No newline at end of file +## DelegateCall in Action + +In this lesson, we'll take a look at the implementation of delegate call, a powerful tool that lets us upgrade our contracts without having to change their addresses. + +Let's get started. We'll copy and paste these contracts into our project: + +```javascript +#counter_one.vy +# SPDX-License-Identifier: MIT +pragma version 0.4.0 + +number: public(uint256) + +@external +def set_number(new_number: uint256): + self.number = new_number + +@external +def increment(): + self.number += 1 + +@external +def version() -> uint256: + return 1 + +``` + +```javascript +#counter_two.vy +# SPDX-License-Identifier: MIT +pragma version 0.4.0 + +number: public(uint256) + +@external +def set_number(new_number: uint256): + self.number = new_number + +@external +def increment(): + self.number += 2 + +@external +def decrement(): + self.number -= 1 + +@external +def version() -> uint256: + return 2 +``` + +Next, we'll update our deploy script to include these contracts: + +```javascript +#deploy.py + +from src import ERC1967, counter_one, counter_two +import boa +import warnings + +def deploy(): + implementation = counter_one.deploy() + proxy = ERC1967.deploy(implementation.address, boa.env.eoa) + proxy_with_abi = counter_one.at(proxy.address) + proxy_with_abi.set_number(77) + print(proxy_with_abi.number()) + print(implementation.number()) + +def moccasin_main(): + deploy() + +``` + +Here's what this script does: + +1. We deploy our implementation contract. +2. Then, we deploy the proxy contract with the implementation address and the admin address, which is set to boa.env.eoa. +3. We assign the ABI to the proxy contract. +4. We call the set_number function on the proxy, setting the number value to 77. +5. We print the value of `number` from both the proxy contract and the implementation contract. + +You'll notice that the `number` value was updated in the proxy contract but not the implementation contract. + +Remember, the delegate call implementation is likely to throw warnings. We'll ignore these warnings by including this snippet in our script: + +```javascript +with warnings.catch_warnings(): + warnings.simplefilter("ignore") +``` +Finally, we can run our script with this command: + +```bash +mox run deploy +``` + +This will run the deploy script, and you'll see that our `set_number` function call was applied to the proxy contract and not the implementation contract. From 2139682345d4bd36ad12d4737cd7446fb0930155 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:45:54 -0700 Subject: [PATCH 249/255] Equious updated courses/advanced-moccasin/5-moccasin-upgrades/4-how-proxies-upgrade/+page.md. --- .../4-how-proxies-upgrade/+page.md | 85 +++++++++++++++++-- 1 file changed, 80 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/5-moccasin-upgrades/4-how-proxies-upgrade/+page.md b/courses/advanced-moccasin/5-moccasin-upgrades/4-how-proxies-upgrade/+page.md index 758dc1d74..86297386b 100644 --- a/courses/advanced-moccasin/5-moccasin-upgrades/4-how-proxies-upgrade/+page.md +++ b/courses/advanced-moccasin/5-moccasin-upgrades/4-how-proxies-upgrade/+page.md @@ -1,5 +1,80 @@ - - --- - title: How Proxies Upgrade - --- - \ No newline at end of file +Proxies are very useful in smart contract development. They allow us to upgrade the logic of our contract without changing the address of the contract. This is helpful for several reasons: + +* When we need to fix bugs +* When we need to add new functionality +* When we want to change the logic of the contract without affecting the users who have already interacted with it. + +Here's an example of how proxies work: + +1. We deploy a proxy contract, which is a special contract that acts as a middleman between the users and the actual logic of our contract. +2. We deploy a logic contract, which contains the actual logic of our contract. +3. We set the proxy contract to point to the logic contract. +4. When users interact with the proxy contract, the proxy contract will forward the call to the logic contract. +5. To upgrade the logic of our contract, we simply deploy a new logic contract with the updated logic and then update the proxy contract to point to the new logic contract. + +We'll use the `counter` contract as an example. + +We'll show how to upgrade from version 1 to version 2: + +**Code:** + +```python +def deploy(): + implementation = counter_one.deploy() + proxy = ERC1967.vy_deploy(implementation.address, boa.env.eoa) + + with warnings.catch_warnings(): + warnings.simplefilter('ignore') + proxy_with_abi = counter_one.at(proxy.address) + proxy_with_abi.set_number(77) + + print(proxy_with_abi.number()) + print(implementation.number()) + + print(proxy_with_abi.version()) + + # Let's upgrade! + implementation_two = counter_two.deploy() + proxy.upgrade_to(implementation_two.address) + + with warnings.catch_warnings(): + warnings.simplefilter('ignore') + proxy_with_abi = counter_two.at(proxy.address) + + print(proxy_with_abi.number()) + + proxy_with_abi.decrement() + + print(proxy_with_abi.number()) + print(proxy_with_abi.version()) + +def moccasin_main(): + deploy() + +moccasin_main() + +``` + +This code will: + +1. Deploy a `counter_one` contract +2. Deploy a proxy contract `ERC1967.vy` pointing to `counter_one` +3. Set a number `77` +4. Print the version of `counter_one` +5. Deploy a `counter_two` contract +6. Upgrade the proxy to point to `counter_two` +7. Print the current number +8. Decrement the number using `counter_two` and print the number again +9. Print the version of `counter_two` + +**Running the Code:** + +```bash +mox run deploy +``` + +**Output:** + +The terminal output will show the current number, which will be `77`, followed by the decremented number, which will be `76`, and the version of the contract, which will be `2`. + +This example shows how we can upgrade the logic of our contract without affecting the users who have already interacted with it. Proxies are a powerful tool that can be used to make smart contracts more flexible and maintainable. From d75752d83a39ce54800d6f4a91fc21d67040b99c Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:46:08 -0700 Subject: [PATCH 250/255] Equious updated courses/advanced-moccasin/5-moccasin-upgrades/5-workshop/+page.md. --- .../5-moccasin-upgrades/5-workshop/+page.md | 73 +++++++++++++++++-- 1 file changed, 68 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/5-moccasin-upgrades/5-workshop/+page.md b/courses/advanced-moccasin/5-moccasin-upgrades/5-workshop/+page.md index d8fee3739..fbeb93cca 100644 --- a/courses/advanced-moccasin/5-moccasin-upgrades/5-workshop/+page.md +++ b/courses/advanced-moccasin/5-moccasin-upgrades/5-workshop/+page.md @@ -1,5 +1,68 @@ - - --- - title: Workshop - --- - \ No newline at end of file +## Proxies Workshop + +We know this was a quick session, but that's it! You now understand proxies and how they work. But before we go, we should, of course, have you do a little workshop. + +For our workshop here, we have two workshops: + +**Spend at most 25 minutes on all of these prompts without the aide of AI. If you're unable to solve them after 25 minutes, stop, take a break, and then work with an AI or the discussions to help you solve them. Good luck!** + +1. Try to write a contract that has a function selector collision with the proxy. +2. Write a contract where the storage variables change order! + +Let's take a look at our existing code: + +```javascript +from src import ERC1967, counter_one, counter_two +import boa +import warnings +``` + +```javascript +def deploy(): + implementation = counter_one.deploy() + proxy = ERC1967.deploy(implementation.address, boa.env.eoa) + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + proxy_with_abi = counter_one.at(proxy.address) + proxy_with_abi.set_number(77) + print(proxy_with_abi.number()) + print(proxy_with_abi.decrement()) + print(proxy_with_abi.number()) + print(proxy_with_abi.version()) + +# Let's upgrade! +implementation = counter_two.deploy() +proxy.upgrade_to(new_implementation=implementation.address) +``` + +What does that mean? Well, remember we learned about function selectors, right? So in my counter one, the function selector for `set_number`, I can figure out by running: + +```bash +patrick@cu moz-upgrades-cu % cast sig "set_number(uint256)" +0xd6d1ee14 +``` + +And this is the function selector. So when we call our proxy, when we call `set_number` on our proxy, the codebase goes, "Okay, I'm looking for this function selector." No, that's not right! No, that's not right! No, that's not right! No, that's not right! Okay, I'm going to go with the default then because I can't find the function selector. What this means, though, is you can have a function with the same selector, even though it's a different function. So for example, if I do: + +```bash +patrick@cu moz-upgrades-cu % cast sig "upgrade_to(address)" +0x3c436f25 +``` + +This is the function selector here. And when we call `upgrade_to`, we would call it on the proxy here. But what could happen is, let me let's take this function selector and I'll go look up a function selector database. We can use this one. Punch this in. Okay, it looks like nobody else has used this function selector. But what could happen is we could have a similar function selector on our implementation and this would be a collision. So we can do: + +```bash +patrick@cu moz-upgrades-cu % cast sig "transfer(address,uint256)" +0xa9059cbb +``` + +I'm pretty sure there's a well-known function collision with this. Actually there's a ton of them. So, so all of these all of these functions have the same function signature. + +`workMyDirefulOwnerUint256Uint256` +`join_tg_invmmru_haha_f006797(address,bool)` +`func020893253501(bytes)` +`transfer(bytes4)bytes(bytes[64](int14811))` +`many_msg_babbage(bytes)` +`transfer(address,uint256)` + +This weird thing here this weird thing here this very bizarre transfer, many message babbage bytes one. These all have the exact same function selector. So your first workshop is kind of hard. Well, I guess I kind of gave you a bit of the answer here. Um, your first workshop is to try to write a contract that has a function selector collision with the proxy. And then number two, write a contract where the storage variables change order, and look at how that affects it. So for example, in our counter one, maybe we'll have a number public uint256 and we'll have a my bool public bool or bull, excuse me. And then in counter two in counter two switch the order, and see what happens then. Do you get what you expect? Why do you see the results that you see? So these are your two workshops. Take some time, tinker around, play with this and I'll see you very soon. From 4bb2bca20dca32ac0ce49a3f2f0f7a7853c8942e Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:46:21 -0700 Subject: [PATCH 251/255] Equious updated courses/advanced-moccasin/5-moccasin-upgrades/6-recap/+page.md. --- .../5-moccasin-upgrades/6-recap/+page.md | 47 +++++++++++++++++-- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/5-moccasin-upgrades/6-recap/+page.md b/courses/advanced-moccasin/5-moccasin-upgrades/6-recap/+page.md index 520a7c357..f13c4f693 100644 --- a/courses/advanced-moccasin/5-moccasin-upgrades/6-recap/+page.md +++ b/courses/advanced-moccasin/5-moccasin-upgrades/6-recap/+page.md @@ -1,5 +1,42 @@ - - --- - title: Recap - --- - \ No newline at end of file +## Recap of the Section + +We've learned a lot about proxies and the delegate call functionality of EVM smart contracts in this section. We've learned that you can have a contract whose fallback function will always raw call or reach out to another contract, but kind of borrow its functionality for itself. + +We learned that there's a very specific implementation slot that we need to use if we want to follow the EIP 1967 guidelines. We learned that we made some gaps in our smart contract in order to reach that specific slot. + +We learned how to upgrade to a new implementation slot. We didn't work with change admin, but this one is pretty self-explanatory. We were able to see with our little deploy script what deploying and upgrading a contract with a proxy looks like. + +```python +from src import ERC1967, counter_one, counter_two +import boa +import warnings + +def deploy(): + implementation = counter_one.deploy() + proxy = ERC1967.deploy_implementation(implementation.address, boa.env.eoa) + + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + proxy_with_abi = counter_one.at(proxy.address) + + proxy_with_abi.set_number(77) + print(proxy_with_abi.number()) + print(implementation.number()) + print(proxy_with_abi.version()) + + # Let's upgrade! + implementation_two = counter_two.deploy() + proxy.upgrade_to(implementation_two.address) + + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + proxy_with_abi = counter_two.at(proxy.address) + + print(proxy_with_abi.number()) + proxy_with_abi.decrement() + print(proxy_with_abi.number()) + print(proxy_with_abi.version()) + +def moccasin_main(): + deploy() +``` \ No newline at end of file From f0c42bee7fa129e1910e3ff395ee23f29fb4b1a6 Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:46:34 -0700 Subject: [PATCH 252/255] Equious updated courses/advanced-moccasin/5-moccasin-upgrades/7-what-do-i-do-now_/+page.md. --- .../7-what-do-i-do-now_/+page.md | 51 +++++++++++++++++-- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/5-moccasin-upgrades/7-what-do-i-do-now_/+page.md b/courses/advanced-moccasin/5-moccasin-upgrades/7-what-do-i-do-now_/+page.md index d5f0bb35b..5fe03fdfd 100644 --- a/courses/advanced-moccasin/5-moccasin-upgrades/7-what-do-i-do-now_/+page.md +++ b/courses/advanced-moccasin/5-moccasin-upgrades/7-what-do-i-do-now_/+page.md @@ -1,5 +1,46 @@ - - --- - title: What Do I Do Now_ - --- - \ No newline at end of file +## What Do I Do Now? + +We've finished the advanced Mochassin curriculum here. You should be proud of yourself! Now, we're going to scroll all the way down to the bottom because there's more to learn. + +The most common question we get asked after these courses is "What do I do now?". There's always more to learn, so here are some resources on where to go next. + +### Learning More + +- Top 10 learning resources +- Patrick Collins +- CryptoZombies +- Alchemy University +- Speed Run Ethereum +- Ethereum.org + +### Community + +- Twitter +- Ethereum Discord +- Reddit ethdev + +### Hackathons + +- ETH Global +- CL Hackathon +- ETH India + +This is where we need to go and apply our knowledge. + +We've already talked about how to get hired; now it's time to put your knowledge into practice. You definitely want to join the community. If you haven't said hi to me on Twitter, you should say hi! We've had thousands of developers reach out to us who now have full-time jobs in Web3. They've won competitive audits, bug bounties, and have been awarded grants and hackathon wins. You can do it too! + +Hackathons are one of the best places to get started. Projects will literally pay you to build stuff for them. It's like being paid to learn; it's a win-win situation! ETH Global is one of our favorites. + +### Competitive Audits + +Another great option is competitive audits. These are a great way to become a powerful security-minded researcher and a better developer. We recommend checking out CodeHawks. + +### First Flights + +CodeHawks also has a thing called "First Flights", which are beginner-friendly audit competitions. We've specifically placed some bugs in there that you should be able to find. + +If you're looking at Cyfirn Updraft, they have a lot of curriculum, including one of our favorites, the Python and Vyper course. There are also more advanced courses, like Assembly and Formal Verification, Smart Contract DevOps, and Smart Contract Security. + +We also have a course on Curve StableSwap, which is all in Vyper, which you've just learned. Curve is a multi-billion dollar protocol, and the codebase is used and forked by tons of other projects, so learning Curve will teach you more about other protocols. + +In general, be sure to subscribe to anything Cyfirn puts out. We're dedicated to making the lives of developers and security researchers better! From e7f7ff68bfb4b2f2b91b45d03e2f1afd47693d5e Mon Sep 17 00:00:00 2001 From: Equious <76449140+Equious@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:46:47 -0700 Subject: [PATCH 253/255] Equious updated courses/advanced-moccasin/5-moccasin-upgrades/8-finale/+page.md. --- .../5-moccasin-upgrades/8-finale/+page.md | 38 ++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/courses/advanced-moccasin/5-moccasin-upgrades/8-finale/+page.md b/courses/advanced-moccasin/5-moccasin-upgrades/8-finale/+page.md index cd8892b05..0d0ec129e 100644 --- a/courses/advanced-moccasin/5-moccasin-upgrades/8-finale/+page.md +++ b/courses/advanced-moccasin/5-moccasin-upgrades/8-finale/+page.md @@ -1,5 +1,33 @@ - - --- - title: Finale - --- - \ No newline at end of file +## Congratulations, You've Made it! + +Congratulations, you've made it through the Vyper and Python course! We're so proud of you for all the hard work you've put in, and we're excited to see you put these new skills to use. + +You've learned about the core concepts of smart contract development, and you've even built some projects. At this point, we're confident that you have the fundamentals to move forward. But, we're just getting started. + +There's so much more to explore in the world of Web3, and you have the skills to do it. Now, it's your time to be a part of the community and build something great. + +So, go out there and make a difference, and don't forget to celebrate your successes along the way! + +## Next Steps + +Think about what you're passionate about and what you want to create. There are many different areas to focus on, such as: + +* **Security:** You can help make the Web3 world safer by working on security audits or building tools to prevent exploits. +* **Infrastructure:** You can improve the scalability and performance of the blockchain by working on infrastructure projects. +* **Protocols:** You can build new protocols that solve real-world problems, such as decentralized finance or supply chain management. + +The possibilities are endless! + +## Keep Learning + +Web3 is constantly evolving, so it's important to stay up-to-date. Here are a few ways to do that: + +* **Follow the latest news:** Subscribe to Web3 newsletters or follow industry leaders on social media. +* **Join online communities:** Connect with other Web3 developers and learn from their experiences. +* **Contribute to open-source projects:** Help improve existing projects and build your portfolio. + +## A Big Thank You + +We want to thank you for joining us on this journey. We're so grateful for your dedication and enthusiasm. You're a part of something big, and we're excited to see what you do next. + +We hope that you'll continue to learn, grow, and contribute to the Web3 world. From 5070bc767c4f4a5c9a57b22292c75a74c7566c65 Mon Sep 17 00:00:00 2001 From: hunter <104146303+solhosty@users.noreply.github.com> Date: Tue, 10 Dec 2024 06:04:06 -0500 Subject: [PATCH 254/255] hunter/rename --- .../1-moccasin-nft/1-intro/+page.md | 0 .../10-note-what-happens-when-we-stop-anvil/+page.md | 0 .../1-moccasin-nft/11-workshop-1/+page.md | 0 .../1-moccasin-nft/12-what-is-an-svg/+page.md | 0 .../1-moccasin-nft/13-mood-nft/+page.md | 0 .../1-moccasin-nft/14-base-64-encoding-images/+page.md | 0 .../1-moccasin-nft/15-base-64-encoding-json/+page.md | 0 .../1-moccasin-nft/16-abi-encoding/+page.md | 0 .../1-moccasin-nft/17-function-selectors-and-signatures/+page.md | 0 .../1-moccasin-nft/18-calling-functions-raw/+page.md | 0 .../1-moccasin-nft/19-manually-crafting-calldata/+page.md | 0 .../1-moccasin-nft/2-setup/+page.md | 0 .../1-moccasin-nft/20-mid-section-recap/+page.md | 0 .../1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md | 0 .../1-moccasin-nft/22-finishing-the-mood-nft/+page.md | 0 .../1-moccasin-nft/23-workshop-2/+page.md | 0 .../1-moccasin-nft/24-recap/+page.md | 0 .../1-moccasin-nft/3-what-is-an-nft/+page.md | 0 .../1-moccasin-nft/4-building-an-erc721-contract/+page.md | 0 .../1-moccasin-nft/5-tokenuri/+page.md | 0 .../1-moccasin-nft/6-deploy/+page.md | 0 .../1-moccasin-nft/7-what-is-ipfs/+page.md | 0 .../1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md | 0 .../1-moccasin-nft/9-deploying-to-zksync/+page.md | 0 .../2-moccasin-portfolio-rebalance/1-intro/+page.md | 0 .../2-moccasin-portfolio-rebalance/10-atokens/+page.md | 0 .../11-portfolio-allocations/+page.md | 0 .../12-withdrawing-from-aave/+page.md | 0 .../2-moccasin-portfolio-rebalance/13-uniswap/+page.md | 0 .../2-moccasin-portfolio-rebalance/14-finish-rebalance/+page.md | 0 .../2-moccasin-portfolio-rebalance/15-zksync-demo/+page.md | 0 .../2-moccasin-portfolio-rebalance/16-workshop/+page.md | 0 .../2-moccasin-portfolio-rebalance/17-recap/+page.md | 0 .../2-moccasin-portfolio-rebalance/2-real-demo/+page.md | 0 .../2-moccasin-portfolio-rebalance/3-setup/+page.md | 0 .../4-forked-network-setup/+page.md | 0 .../2-moccasin-portfolio-rebalance/5-minting-weth/+page.md | 0 .../6-getting-abis-from-the-explorer/+page.md | 0 .../2-moccasin-portfolio-rebalance/7-minting-usdc/+page.md | 0 .../2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md | 0 .../9-depositing-into-aave/+page.md | 0 .../3-moccasin-stablecoin/1-intro/+page.md | 0 .../3-moccasin-stablecoin/10-deployment/+page.md | 0 .../3-moccasin-stablecoin/11-testing/+page.md | 0 .../3-moccasin-stablecoin/12-workshop-1/+page.md | 0 .../3-moccasin-stablecoin/13-fuzz-setup/+page.md | 0 .../3-moccasin-stablecoin/14-invariant/+page.md | 0 .../3-moccasin-stablecoin/15-rules-deposit-and-redeem/+page.md | 0 .../3-moccasin-stablecoin/16-rules-mint-dsc/+page.md | 0 .../3-moccasin-stablecoin/17-rules-update-price/+page.md | 0 .../3-moccasin-stablecoin/18-workshop-2/+page.md | 0 .../3-moccasin-stablecoin/19-audit-readiness/+page.md | 0 .../3-moccasin-stablecoin/2-what-is-a-stablecoin/+page.md | 0 .../3-moccasin-stablecoin/20-recap/+page.md | 0 .../3-moccasin-stablecoin/3-setup/+page.md | 0 .../3-moccasin-stablecoin/4-engine-intro/+page.md | 0 .../3-moccasin-stablecoin/5-deposit-collateral/+page.md | 0 .../3-moccasin-stablecoin/6-health-factor/+page.md | 0 .../3-moccasin-stablecoin/7-minting-dsc/+page.md | 0 .../3-moccasin-stablecoin/8-redeem-collateral/+page.md | 0 .../3-moccasin-stablecoin/9-liquidation/+page.md | 0 .../4-moccasin-signatures/1-intro/+page.md | 0 .../4-moccasin-signatures/10-transaction-types/+page.md | 0 .../4-moccasin-signatures/11-blobs/+page.md | 0 .../4-moccasin-signatures/12-type-113-transactions/+page.md | 0 .../13-adding-signature-verification/+page.md | 0 .../4-moccasin-signatures/14-deploy/+page.md | 0 .../4-moccasin-signatures/15-testing/+page.md | 0 .../4-moccasin-signatures/16-workshop-1/+page.md | 0 .../4-moccasin-signatures/17-recap/+page.md | 0 .../4-moccasin-signatures/2-setup/+page.md | 0 .../4-moccasin-signatures/3-merkle-trees/+page.md | 0 .../4-moccasin-signatures/4-making-a-merkle/+page.md | 0 .../4-moccasin-signatures/5-merkle-proof/+page.md | 0 .../4-moccasin-signatures/6-claiming-a-proof/+page.md | 0 .../4-moccasin-signatures/7-signature-standards/+page.md | 0 .../4-moccasin-signatures/8-eip-712-in-vyper/+page.md | 0 .../4-moccasin-signatures/9-ecdsa/+page.md | 0 .../5-moccasin-upgrades/1-intro/+page.md | 0 .../5-moccasin-upgrades/2-erc-1967-and-delegatecall/+page.md | 0 .../5-moccasin-upgrades/3-delegatecall/+page.md | 0 .../5-moccasin-upgrades/4-how-proxies-upgrade/+page.md | 0 .../5-moccasin-upgrades/5-workshop/+page.md | 0 .../5-moccasin-upgrades/6-recap/+page.md | 0 .../5-moccasin-upgrades/7-what-do-i-do-now_/+page.md | 0 .../5-moccasin-upgrades/8-finale/+page.md | 0 .../1-python-in-updraft/1-intro/+page.md | 0 .../1-python-in-updraft/10-types/+page.md | 0 .../1-python-in-updraft/11-math/+page.md | 0 .../1-python-in-updraft/12-more-math/+page.md | 0 .../1-python-in-updraft/13-funcs/+page.md | 0 .../1-python-in-updraft/14-conditionals/+page.md | 0 .../1-python-in-updraft/15-while-loops/+page.md | 0 .../1-python-in-updraft/16-loops-2/+page.md | 0 .../1-python-in-updraft/17-loops-3/+page.md | 0 .../1-python-in-updraft/18-workshop/+page.md | 0 .../1-python-in-updraft/19-recap/+page.md | 0 .../1-python-in-updraft/2-google-collab/+page.md | 0 .../1-python-in-updraft/20-dev-env-setup/+page.md | 0 .../1-python-in-updraft/21-install-vscode-macos-linux/+page.md | 0 .../1-python-in-updraft/22-install-wsl/+page.md | 0 .../1-python-in-updraft/23-vscode-windows-install/+page.md | 0 .../1-python-in-updraft/24-vscode-windows-wsl-extension/+page.md | 0 .../1-python-in-updraft/25-vscode-quickstart/+page.md | 0 .../1-python-in-updraft/26-install-python-macos/+page.md | 0 .../1-python-in-updraft/27-install-python-wsl-linux/+page.md | 0 .../1-python-in-updraft/28-vscode-quickstart-2/+page.md | 0 .../1-python-in-updraft/29-mental-prep/+page.md | 0 .../1-python-in-updraft/3-setup/+page.md | 0 .../1-python-in-updraft/30-local-py/+page.md | 0 .../1-python-in-updraft/31-python-shell/+page.md | 0 .../1-python-in-updraft/32-python-extensions-vscode/+page.md | 0 .../1-python-in-updraft/33-our-first-python/+page.md | 0 .../1-python-in-updraft/34-python-imports/+page.md | 0 .../1-python-in-updraft/35-installing-uv/+page.md | 0 .../1-python-in-updraft/36-uv-python-version/+page.md | 0 .../1-python-in-updraft/37-adding-packages-uv/+page.md | 0 .../1-python-in-updraft/38-virtual-envs/+page.md | 0 .../1-python-in-updraft/39-recap-pt-2/+page.md | 0 .../1-python-in-updraft/4-notebook/+page.md | 0 .../1-python-in-updraft/5-google-ai/+page.md | 0 .../1-python-in-updraft/6-python-vars/+page.md | 0 .../1-python-in-updraft/7-type-hints/+page.md | 0 .../1-python-in-updraft/8-arrays/+page.md | 0 .../1-python-in-updraft/9-inputs/+page.md | 0 .../2-web3py/1-intro/+page.md | 0 .../2-web3py/10-breakpoint/+page.md | 0 .../2-web3py/11-anvil/+page.md | 0 .../2-web3py/12-anvil2/+page.md | 0 .../2-web3py/13-tx/+page.md | 0 .../2-web3py/14-tx-pt-2/+page.md | 0 .../2-web3py/15-tx-pt-3/+page.md | 0 .../2-web3py/16-nonce/+page.md | 0 .../2-web3py/17-sign-tx/+page.md | 0 .../2-web3py/18-pkey-promise/+page.md | 0 .../2-web3py/19-env-vars/+page.md | 0 .../2-web3py/2-setup/+page.md | 0 .../2-web3py/20-send-tx/+page.md | 0 .../2-web3py/21-encrypt/+page.md | 0 .../2-web3py/22-pledge/+page.md | 0 .../2-web3py/23-workshop/+page.md | 0 .../2-web3py/24-recap/+page.md | 0 .../2-web3py/3-vyper-extension/+page.md | 0 .../2-web3py/4-compile-python/+page.md | 0 .../2-web3py/5-idk/+page.md | 0 .../2-web3py/6-__nam__/+page.md | 0 .../2-web3py/7-vyper-package/+page.md | 0 .../2-web3py/8-vscode-py/+page.md | 0 .../2-web3py/9-web3-py/+page.md | 0 .../3-boa-favs/1-intro/+page.md | 0 .../3-boa-favs/10-add-person/+page.md | 0 .../3-boa-favs/11-workshop/+page.md | 0 .../3-boa-favs/12-recap/+page.md | 0 .../3-boa-favs/2-setup/+page.md | 0 .../3-boa-favs/3-pyevm/+page.md | 0 .../3-boa-favs/4-vypercontract/+page.md | 0 .../3-boa-favs/5-debug/+page.md | 0 .../3-boa-favs/6-pyevm_/+page.md | 0 .../3-boa-favs/7-anvil/+page.md | 0 .../3-boa-favs/8-interacting-anvil/+page.md | 0 .../3-boa-favs/9-interact-prevs/+page.md | 0 .../4-mox-favs/1-intro/+page.md | 0 .../4-mox-favs/10-account-cli/+page.md | 0 .../4-mox-favs/11-mox-testing/+page.md | 0 .../4-mox-favs/12-testing-deploy-script/+page.md | 0 .../4-mox-favs/13-aaa/+page.md | 0 .../4-mox-favs/14-fixtures/+page.md | 0 .../4-mox-favs/15-conftest/+page.md | 0 .../4-mox-favs/16-type-hints/+page.md | 0 .../4-mox-favs/17-sepolia-deploy/+page.md | 0 .../4-mox-favs/18-verify/+page.md | 0 .../4-mox-favs/19-zksync-setup/+page.md | 0 .../4-mox-favs/2-install-mox/+page.md | 0 .../4-mox-favs/20-eravm/+page.md | 0 .../4-mox-favs/21-setting-up-zksync/+page.md | 0 .../4-mox-favs/22-bridging/+page.md | 0 .../4-mox-favs/23-zksync-deploy/+page.md | 0 .../4-mox-favs/24-zksync-contract-deployment/+page.md | 0 .../4-mox-favs/25-tx-types/+page.md | 0 .../4-mox-favs/26-workshop/+page.md | 0 .../4-mox-favs/27-recap/+page.md | 0 .../4-mox-favs/3-create-mox/+page.md | 0 .../4-mox-favs/4-mox-something/+page.md | 0 .../4-mox-favs/5-mox-script/+page.md | 0 .../4-mox-favs/6-other-net/+page.md | 0 .../4-mox-favs/7-encrypt-key/+page.md | 0 .../4-mox-favs/8-shell/+page.md | 0 .../4-mox-favs/9-using-key/+page.md | 0 .../5-mox-five/1-intro/+page.md | 0 .../5-mox-five/10-vyper-modules/+page.md | 0 .../5-mox-five/11-initializes-module-state/+page.md | 0 .../5-mox-five/12-exports/+page.md | 0 .../5-mox-five/13-workshop/+page.md | 0 .../5-mox-five/14-recap/+page.md | 0 .../5-mox-five/3-create-copy-of/+page.md | 0 .../5-mox-five/4-static-ext-call/+page.md | 0 .../5-mox-five/5-vyi/+page.md | 0 .../5-mox-five/6-idk/+page.md | 0 .../5-mox-five/7-extcall/+page.md | 0 .../5-mox-five/8-store-contract-by-interface/+page.md | 0 .../5-mox-five/9-method-chaining/+page.md | 0 .../6-mox-coffee/1-intro/+page.md | 0 .../6-mox-coffee/10-kinds/+page.md | 0 .../6-mox-coffee/11-unit/+page.md | 0 .../6-mox-coffee/12-test-revert/+page.md | 0 .../6-mox-coffee/13-set-balance/+page.md | 0 .../6-mox-coffee/14-prank/+page.md | 0 .../6-mox-coffee/15-mid-sec-work/+page.md | 0 .../6-mox-coffee/16-more-fixtures/+page.md | 0 .../6-mox-coffee/17-test-coverage/+page.md | 0 .../6-mox-coffee/18-gas-profile/+page.md | 0 .../6-mox-coffee/19-fork-tests/+page.md | 0 .../6-mox-coffee/2-setup/+page.md | 0 .../6-mox-coffee/20-staging/+page.md | 0 .../6-mox-coffee/21-deployments-db/+page.md | 0 .../6-mox-coffee/22-zksync-testing/+page.md | 0 .../6-mox-coffee/23-github/+page.md | 0 .../6-mox-coffee/24-clone/+page.md | 0 .../6-mox-coffee/25-workshop/+page.md | 0 .../6-mox-coffee/26-recap/+page.md | 0 .../6-mox-coffee/3-refactor/+page.md | 0 .../6-mox-coffee/4-storage/+page.md | 0 .../6-mox-coffee/5-refactor-2/+page.md | 0 .../6-mox-coffee/6-script/+page.md | 0 .../6-mox-coffee/7-mocks/+page.md | 0 .../6-mox-coffee/8-manifest/+page.md | 0 .../6-mox-coffee/9-top-level/+page.md | 0 .../7-mox-html/1-mox-intro/+page.md | 0 .../7-mox-html/2-introduction/+page.md | 0 .../7-mox-html/3-setup/+page.md | 0 .../7-mox-html/4-metamask/+page.md | 0 .../7-mox-html/5-function-selectors/+page.md | 0 .../7-mox-html/6-summary/+page.md | 0 .../8-mox-erc20/1-intro/+page.md | 0 .../8-mox-erc20/10-built-in-interfaces/+page.md | 0 .../8-mox-erc20/11-deploy-scripts/+page.md | 0 .../8-mox-erc20/12-tests/+page.md | 0 .../8-mox-erc20/13-events/+page.md | 0 .../8-mox-erc20/14-testing-events/+page.md | 0 .../8-mox-erc20/15-formatting/+page.md | 0 .../8-mox-erc20/16-justfile/+page.md | 0 .../8-mox-erc20/17-vheaders/+page.md | 0 .../8-mox-erc20/18-fuzzing/+page.md | 0 .../8-mox-erc20/19-stateless-fuzz/+page.md | 0 .../8-mox-erc20/2-setup/+page.md | 0 .../8-mox-erc20/20-stateful-fuzz/+page.md | 0 .../8-mox-erc20/21-workshop/+page.md | 0 .../8-mox-erc20/22-rng/+page.md | 0 .../8-mox-erc20/23-cei/+page.md | 0 .../8-mox-erc20/24-mox-console/+page.md | 0 .../8-mox-erc20/25-recap/+page.md | 0 .../8-mox-erc20/3-custom-pyproject/+page.md | 0 .../8-mox-erc20/4-what-is-erc20/+page.md | 0 .../8-mox-erc20/5-build-it/+page.md | 0 .../8-mox-erc20/6-mox-libs-git/+page.md | 0 .../8-mox-erc20/7-mox-libs-pypi/+page.md | 0 .../8-mox-erc20/8-mox-idk/+page.md | 0 .../8-mox-erc20/9-init-supply/+page.md | 0 .../9-how-to-get-hired/1-intro/+page.md | 0 .../9-how-to-get-hired/2-workshop/+page.md | 0 .../1-favorites/1-welcome/+page.md | 0 .../1-favorites/10-contract-design/+page.md | 0 .../1-favorites/11-vyper-types/+page.md | 0 .../1-favorites/12-visibilitiy/+page.md | 0 .../1-favorites/13-functions/+page.md | 0 .../1-favorites/14-func-visibility/+page.md | 0 .../1-favorites/15-view-and-pure/+page.md | 0 .../1-favorites/16-constructor/+page.md | 0 .../1-favorites/17-advanced-funcs/+page.md | 0 .../1-favorites/18-ref-types/+page.md | 0 .../1-favorites/19-claude/+page.md | 0 .../1-favorites/2-best-practices/+page.md | 0 .../1-favorites/20-arrays-lists/+page.md | 0 .../1-favorites/21-idk/+page.md | 0 .../1-favorites/22-workshop/+page.md | 0 .../1-favorites/23-hash-map/+page.md | 0 .../1-favorites/24-recap/+page.md | 0 .../1-favorites/25-tenderly/+page.md | 0 .../1-favorites/26-zksync/+page.md | 0 .../1-favorites/27-share/+page.md | 0 .../1-favorites/28-evm/+page.md | 0 .../1-favorites/29-pure-and-view/+page.md | 0 .../1-favorites/3-mox-best-practices/+page.md | 0 .../1-favorites/30-conditionals/+page.md | 0 .../1-favorites/31-workshop-pt-2/+page.md | 0 .../1-favorites/32-recap-pt-2/+page.md | 0 .../1-favorites/4-walkthrough/+page.md | 0 .../1-favorites/5-welcome-to-remix/+page.md | 0 .../1-favorites/6-pragma-version/+page.md | 0 .../1-favorites/7-comments/+page.md | 0 .../1-favorites/8-license/+page.md | 0 .../1-favorites/9-compiling/+page.md | 0 .../2-remix-coffee/1-introduction/+page.md | 0 .../2-remix-coffee/10-chainlink-in-vyper/+page.md | 0 .../2-remix-coffee/11-abi/+page.md | 0 .../2-remix-coffee/12-in-line-inter/+page.md | 0 .../2-remix-coffee/13-staticcall/+page.md | 0 .../2-remix-coffee/14-tenderly/+page.md | 0 .../2-remix-coffee/15-ai/+page.md | 0 .../2-remix-coffee/16-deploy-parameter/+page.md | 0 .../2-remix-coffee/17-integer-precision/+page.md | 0 .../2-remix-coffee/18-converting-types/+page.md | 0 .../2-remix-coffee/19-integer-division/+page.md | 0 .../2-remix-coffee/2-setup/+page.md | 0 .../2-remix-coffee/20-as-wei-value/+page.md | 0 .../2-remix-coffee/21-send-eth-in-tx/+page.md | 0 .../2-remix-coffee/22-contract-to-contract/+page.md | 0 .../2-remix-coffee/23-getting-revert/+page.md | 0 .../2-remix-coffee/24-msg-sender/+page.md | 0 .../2-remix-coffee/25-withdraw-eth/+page.md | 0 .../2-remix-coffee/26-dynamic-vs-fixed-array/+page.md | 0 .../2-remix-coffee/27-resetting-array/+page.md | 0 .../2-remix-coffee/28-plus-equals/+page.md | 0 .../2-remix-coffee/29-for-loops/+page.md | 0 .../2-remix-coffee/3-doc-strings/+page.md | 0 .../2-remix-coffee/30-tenderly_/+page.md | 0 .../2-remix-coffee/31-idk/+page.md | 0 .../2-remix-coffee/32-natspec/+page.md | 0 .../2-remix-coffee/33-update-immute/+page.md | 0 .../2-remix-coffee/34-magic/+page.md | 0 .../2-remix-coffee/35-gas/+page.md | 0 .../2-remix-coffee/36-fallback/+page.md | 0 .../2-remix-coffee/37-better-way-to-send/+page.md | 0 .../2-remix-coffee/38-recap/+page.md | 0 .../2-remix-coffee/4-sending-eth/+page.md | 0 .../2-remix-coffee/5-gwei-wei-eth/+page.md | 0 .../2-remix-coffee/6-send-tx/+page.md | 0 .../2-remix-coffee/7-reverts/+page.md | 0 .../2-remix-coffee/8-chainlink/+page.md | 0 .../2-remix-coffee/9-mid-recap/+page.md | 0 .../3-ai/1-intro/+page.md | 0 .../3-ai/2-vid/+page.md | 0 .../3-ai/3-triage/+page.md | 0 .../3-ai/4-formatting-qs/+page.md | 0 .../3-ai/5-workshop/+page.md | 0 335 files changed, 0 insertions(+), 0 deletions(-) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/1-moccasin-nft/1-intro/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/1-moccasin-nft/11-workshop-1/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/1-moccasin-nft/12-what-is-an-svg/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/1-moccasin-nft/13-mood-nft/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/1-moccasin-nft/14-base-64-encoding-images/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/1-moccasin-nft/15-base-64-encoding-json/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/1-moccasin-nft/16-abi-encoding/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/1-moccasin-nft/17-function-selectors-and-signatures/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/1-moccasin-nft/18-calling-functions-raw/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/1-moccasin-nft/19-manually-crafting-calldata/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/1-moccasin-nft/2-setup/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/1-moccasin-nft/20-mid-section-recap/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/1-moccasin-nft/22-finishing-the-mood-nft/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/1-moccasin-nft/23-workshop-2/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/1-moccasin-nft/24-recap/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/1-moccasin-nft/3-what-is-an-nft/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/1-moccasin-nft/4-building-an-erc721-contract/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/1-moccasin-nft/5-tokenuri/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/1-moccasin-nft/6-deploy/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/1-moccasin-nft/7-what-is-ipfs/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/1-moccasin-nft/9-deploying-to-zksync/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/2-moccasin-portfolio-rebalance/1-intro/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/2-moccasin-portfolio-rebalance/10-atokens/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/2-moccasin-portfolio-rebalance/11-portfolio-allocations/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/2-moccasin-portfolio-rebalance/12-withdrawing-from-aave/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/2-moccasin-portfolio-rebalance/13-uniswap/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/2-moccasin-portfolio-rebalance/14-finish-rebalance/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/2-moccasin-portfolio-rebalance/15-zksync-demo/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/2-moccasin-portfolio-rebalance/16-workshop/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/2-moccasin-portfolio-rebalance/17-recap/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/2-moccasin-portfolio-rebalance/2-real-demo/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/2-moccasin-portfolio-rebalance/3-setup/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/2-moccasin-portfolio-rebalance/4-forked-network-setup/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/2-moccasin-portfolio-rebalance/5-minting-weth/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/2-moccasin-portfolio-rebalance/6-getting-abis-from-the-explorer/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/2-moccasin-portfolio-rebalance/7-minting-usdc/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/2-moccasin-portfolio-rebalance/9-depositing-into-aave/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/3-moccasin-stablecoin/1-intro/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/3-moccasin-stablecoin/10-deployment/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/3-moccasin-stablecoin/11-testing/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/3-moccasin-stablecoin/12-workshop-1/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/3-moccasin-stablecoin/13-fuzz-setup/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/3-moccasin-stablecoin/14-invariant/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/3-moccasin-stablecoin/15-rules-deposit-and-redeem/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/3-moccasin-stablecoin/16-rules-mint-dsc/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/3-moccasin-stablecoin/17-rules-update-price/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/3-moccasin-stablecoin/18-workshop-2/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/3-moccasin-stablecoin/19-audit-readiness/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/3-moccasin-stablecoin/2-what-is-a-stablecoin/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/3-moccasin-stablecoin/20-recap/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/3-moccasin-stablecoin/3-setup/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/3-moccasin-stablecoin/4-engine-intro/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/3-moccasin-stablecoin/5-deposit-collateral/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/3-moccasin-stablecoin/6-health-factor/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/3-moccasin-stablecoin/7-minting-dsc/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/3-moccasin-stablecoin/8-redeem-collateral/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/3-moccasin-stablecoin/9-liquidation/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/4-moccasin-signatures/1-intro/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/4-moccasin-signatures/10-transaction-types/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/4-moccasin-signatures/11-blobs/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/4-moccasin-signatures/12-type-113-transactions/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/4-moccasin-signatures/13-adding-signature-verification/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/4-moccasin-signatures/14-deploy/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/4-moccasin-signatures/15-testing/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/4-moccasin-signatures/16-workshop-1/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/4-moccasin-signatures/17-recap/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/4-moccasin-signatures/2-setup/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/4-moccasin-signatures/3-merkle-trees/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/4-moccasin-signatures/4-making-a-merkle/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/4-moccasin-signatures/5-merkle-proof/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/4-moccasin-signatures/6-claiming-a-proof/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/4-moccasin-signatures/7-signature-standards/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/4-moccasin-signatures/8-eip-712-in-vyper/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/4-moccasin-signatures/9-ecdsa/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/5-moccasin-upgrades/1-intro/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/5-moccasin-upgrades/2-erc-1967-and-delegatecall/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/5-moccasin-upgrades/3-delegatecall/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/5-moccasin-upgrades/4-how-proxies-upgrade/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/5-moccasin-upgrades/5-workshop/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/5-moccasin-upgrades/6-recap/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/5-moccasin-upgrades/7-what-do-i-do-now_/+page.md (100%) rename courses/{advanced-moccasin => advanced-python-vyper-smart-contract-development}/5-moccasin-upgrades/8-finale/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/1-intro/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/10-types/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/11-math/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/12-more-math/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/13-funcs/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/14-conditionals/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/15-while-loops/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/16-loops-2/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/17-loops-3/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/18-workshop/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/19-recap/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/2-google-collab/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/20-dev-env-setup/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/21-install-vscode-macos-linux/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/22-install-wsl/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/23-vscode-windows-install/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/24-vscode-windows-wsl-extension/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/25-vscode-quickstart/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/26-install-python-macos/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/27-install-python-wsl-linux/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/28-vscode-quickstart-2/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/29-mental-prep/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/3-setup/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/30-local-py/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/31-python-shell/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/32-python-extensions-vscode/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/33-our-first-python/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/34-python-imports/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/35-installing-uv/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/36-uv-python-version/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/37-adding-packages-uv/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/38-virtual-envs/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/39-recap-pt-2/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/4-notebook/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/5-google-ai/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/6-python-vars/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/7-type-hints/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/8-arrays/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/1-python-in-updraft/9-inputs/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/2-web3py/1-intro/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/2-web3py/10-breakpoint/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/2-web3py/11-anvil/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/2-web3py/12-anvil2/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/2-web3py/13-tx/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/2-web3py/14-tx-pt-2/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/2-web3py/15-tx-pt-3/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/2-web3py/16-nonce/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/2-web3py/17-sign-tx/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/2-web3py/18-pkey-promise/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/2-web3py/19-env-vars/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/2-web3py/2-setup/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/2-web3py/20-send-tx/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/2-web3py/21-encrypt/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/2-web3py/22-pledge/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/2-web3py/23-workshop/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/2-web3py/24-recap/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/2-web3py/3-vyper-extension/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/2-web3py/4-compile-python/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/2-web3py/5-idk/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/2-web3py/6-__nam__/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/2-web3py/7-vyper-package/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/2-web3py/8-vscode-py/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/2-web3py/9-web3-py/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/3-boa-favs/1-intro/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/3-boa-favs/10-add-person/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/3-boa-favs/11-workshop/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/3-boa-favs/12-recap/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/3-boa-favs/2-setup/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/3-boa-favs/3-pyevm/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/3-boa-favs/4-vypercontract/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/3-boa-favs/5-debug/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/3-boa-favs/6-pyevm_/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/3-boa-favs/7-anvil/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/3-boa-favs/8-interacting-anvil/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/3-boa-favs/9-interact-prevs/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/4-mox-favs/1-intro/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/4-mox-favs/10-account-cli/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/4-mox-favs/11-mox-testing/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/4-mox-favs/12-testing-deploy-script/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/4-mox-favs/13-aaa/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/4-mox-favs/14-fixtures/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/4-mox-favs/15-conftest/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/4-mox-favs/16-type-hints/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/4-mox-favs/17-sepolia-deploy/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/4-mox-favs/18-verify/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/4-mox-favs/19-zksync-setup/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/4-mox-favs/2-install-mox/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/4-mox-favs/20-eravm/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/4-mox-favs/21-setting-up-zksync/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/4-mox-favs/22-bridging/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/4-mox-favs/23-zksync-deploy/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/4-mox-favs/24-zksync-contract-deployment/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/4-mox-favs/25-tx-types/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/4-mox-favs/26-workshop/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/4-mox-favs/27-recap/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/4-mox-favs/3-create-mox/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/4-mox-favs/4-mox-something/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/4-mox-favs/5-mox-script/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/4-mox-favs/6-other-net/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/4-mox-favs/7-encrypt-key/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/4-mox-favs/8-shell/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/4-mox-favs/9-using-key/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/5-mox-five/1-intro/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/5-mox-five/10-vyper-modules/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/5-mox-five/11-initializes-module-state/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/5-mox-five/12-exports/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/5-mox-five/13-workshop/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/5-mox-five/14-recap/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/5-mox-five/3-create-copy-of/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/5-mox-five/4-static-ext-call/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/5-mox-five/5-vyi/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/5-mox-five/6-idk/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/5-mox-five/7-extcall/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/5-mox-five/8-store-contract-by-interface/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/5-mox-five/9-method-chaining/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/6-mox-coffee/1-intro/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/6-mox-coffee/10-kinds/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/6-mox-coffee/11-unit/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/6-mox-coffee/12-test-revert/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/6-mox-coffee/13-set-balance/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/6-mox-coffee/14-prank/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/6-mox-coffee/15-mid-sec-work/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/6-mox-coffee/16-more-fixtures/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/6-mox-coffee/17-test-coverage/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/6-mox-coffee/18-gas-profile/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/6-mox-coffee/19-fork-tests/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/6-mox-coffee/2-setup/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/6-mox-coffee/20-staging/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/6-mox-coffee/21-deployments-db/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/6-mox-coffee/22-zksync-testing/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/6-mox-coffee/23-github/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/6-mox-coffee/24-clone/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/6-mox-coffee/25-workshop/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/6-mox-coffee/26-recap/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/6-mox-coffee/3-refactor/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/6-mox-coffee/4-storage/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/6-mox-coffee/5-refactor-2/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/6-mox-coffee/6-script/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/6-mox-coffee/7-mocks/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/6-mox-coffee/8-manifest/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/6-mox-coffee/9-top-level/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/7-mox-html/1-mox-intro/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/7-mox-html/2-introduction/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/7-mox-html/3-setup/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/7-mox-html/4-metamask/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/7-mox-html/5-function-selectors/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/7-mox-html/6-summary/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/8-mox-erc20/1-intro/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/8-mox-erc20/10-built-in-interfaces/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/8-mox-erc20/11-deploy-scripts/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/8-mox-erc20/12-tests/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/8-mox-erc20/13-events/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/8-mox-erc20/14-testing-events/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/8-mox-erc20/15-formatting/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/8-mox-erc20/16-justfile/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/8-mox-erc20/17-vheaders/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/8-mox-erc20/18-fuzzing/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/8-mox-erc20/19-stateless-fuzz/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/8-mox-erc20/2-setup/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/8-mox-erc20/20-stateful-fuzz/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/8-mox-erc20/21-workshop/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/8-mox-erc20/22-rng/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/8-mox-erc20/23-cei/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/8-mox-erc20/24-mox-console/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/8-mox-erc20/25-recap/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/8-mox-erc20/3-custom-pyproject/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/8-mox-erc20/4-what-is-erc20/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/8-mox-erc20/5-build-it/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/8-mox-erc20/6-mox-libs-git/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/8-mox-erc20/7-mox-libs-pypi/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/8-mox-erc20/8-mox-idk/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/8-mox-erc20/9-init-supply/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/9-how-to-get-hired/1-intro/+page.md (100%) rename courses/{moccasin-101 => intermediate-python-vyper-smart-contract-development}/9-how-to-get-hired/2-workshop/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/1-welcome/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/10-contract-design/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/11-vyper-types/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/12-visibilitiy/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/13-functions/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/14-func-visibility/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/15-view-and-pure/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/16-constructor/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/17-advanced-funcs/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/18-ref-types/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/19-claude/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/2-best-practices/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/20-arrays-lists/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/21-idk/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/22-workshop/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/23-hash-map/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/24-recap/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/25-tenderly/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/26-zksync/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/27-share/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/28-evm/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/29-pure-and-view/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/3-mox-best-practices/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/30-conditionals/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/31-workshop-pt-2/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/32-recap-pt-2/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/4-walkthrough/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/5-welcome-to-remix/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/6-pragma-version/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/7-comments/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/8-license/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/1-favorites/9-compiling/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/1-introduction/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/10-chainlink-in-vyper/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/11-abi/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/12-in-line-inter/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/13-staticcall/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/14-tenderly/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/15-ai/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/16-deploy-parameter/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/17-integer-precision/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/18-converting-types/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/19-integer-division/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/2-setup/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/20-as-wei-value/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/21-send-eth-in-tx/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/22-contract-to-contract/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/23-getting-revert/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/24-msg-sender/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/25-withdraw-eth/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/26-dynamic-vs-fixed-array/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/27-resetting-array/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/28-plus-equals/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/29-for-loops/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/3-doc-strings/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/30-tenderly_/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/31-idk/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/32-natspec/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/33-update-immute/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/34-magic/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/35-gas/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/36-fallback/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/37-better-way-to-send/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/38-recap/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/4-sending-eth/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/5-gwei-wei-eth/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/6-send-tx/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/7-reverts/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/8-chainlink/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/2-remix-coffee/9-mid-recap/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/3-ai/1-intro/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/3-ai/2-vid/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/3-ai/3-triage/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/3-ai/4-formatting-qs/+page.md (100%) rename courses/{vyper-101 => intro-python-vyper-smart-contract-development}/3-ai/5-workshop/+page.md (100%) diff --git a/courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md b/courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/1-intro/+page.md similarity index 100% rename from courses/advanced-moccasin/1-moccasin-nft/1-intro/+page.md rename to courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/1-intro/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md b/courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md similarity index 100% rename from courses/advanced-moccasin/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md rename to courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/10-note-what-happens-when-we-stop-anvil/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md b/courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/11-workshop-1/+page.md similarity index 100% rename from courses/advanced-moccasin/1-moccasin-nft/11-workshop-1/+page.md rename to courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/11-workshop-1/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md b/courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/12-what-is-an-svg/+page.md similarity index 100% rename from courses/advanced-moccasin/1-moccasin-nft/12-what-is-an-svg/+page.md rename to courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/12-what-is-an-svg/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md b/courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/13-mood-nft/+page.md similarity index 100% rename from courses/advanced-moccasin/1-moccasin-nft/13-mood-nft/+page.md rename to courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/13-mood-nft/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md b/courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/14-base-64-encoding-images/+page.md similarity index 100% rename from courses/advanced-moccasin/1-moccasin-nft/14-base-64-encoding-images/+page.md rename to courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/14-base-64-encoding-images/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md b/courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/15-base-64-encoding-json/+page.md similarity index 100% rename from courses/advanced-moccasin/1-moccasin-nft/15-base-64-encoding-json/+page.md rename to courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/15-base-64-encoding-json/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md b/courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/16-abi-encoding/+page.md similarity index 100% rename from courses/advanced-moccasin/1-moccasin-nft/16-abi-encoding/+page.md rename to courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/16-abi-encoding/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md b/courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/17-function-selectors-and-signatures/+page.md similarity index 100% rename from courses/advanced-moccasin/1-moccasin-nft/17-function-selectors-and-signatures/+page.md rename to courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/17-function-selectors-and-signatures/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md b/courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/18-calling-functions-raw/+page.md similarity index 100% rename from courses/advanced-moccasin/1-moccasin-nft/18-calling-functions-raw/+page.md rename to courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/18-calling-functions-raw/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md b/courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/19-manually-crafting-calldata/+page.md similarity index 100% rename from courses/advanced-moccasin/1-moccasin-nft/19-manually-crafting-calldata/+page.md rename to courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/19-manually-crafting-calldata/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md b/courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/2-setup/+page.md similarity index 100% rename from courses/advanced-moccasin/1-moccasin-nft/2-setup/+page.md rename to courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/2-setup/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md b/courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/20-mid-section-recap/+page.md similarity index 100% rename from courses/advanced-moccasin/1-moccasin-nft/20-mid-section-recap/+page.md rename to courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/20-mid-section-recap/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md b/courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md similarity index 100% rename from courses/advanced-moccasin/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md rename to courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/21-verifying-calldata-in-metamask/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md b/courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/22-finishing-the-mood-nft/+page.md similarity index 100% rename from courses/advanced-moccasin/1-moccasin-nft/22-finishing-the-mood-nft/+page.md rename to courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/22-finishing-the-mood-nft/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/23-workshop-2/+page.md b/courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/23-workshop-2/+page.md similarity index 100% rename from courses/advanced-moccasin/1-moccasin-nft/23-workshop-2/+page.md rename to courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/23-workshop-2/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/24-recap/+page.md b/courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/24-recap/+page.md similarity index 100% rename from courses/advanced-moccasin/1-moccasin-nft/24-recap/+page.md rename to courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/24-recap/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md b/courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/3-what-is-an-nft/+page.md similarity index 100% rename from courses/advanced-moccasin/1-moccasin-nft/3-what-is-an-nft/+page.md rename to courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/3-what-is-an-nft/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md b/courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/4-building-an-erc721-contract/+page.md similarity index 100% rename from courses/advanced-moccasin/1-moccasin-nft/4-building-an-erc721-contract/+page.md rename to courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/4-building-an-erc721-contract/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md b/courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/5-tokenuri/+page.md similarity index 100% rename from courses/advanced-moccasin/1-moccasin-nft/5-tokenuri/+page.md rename to courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/5-tokenuri/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md b/courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/6-deploy/+page.md similarity index 100% rename from courses/advanced-moccasin/1-moccasin-nft/6-deploy/+page.md rename to courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/6-deploy/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md b/courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/7-what-is-ipfs/+page.md similarity index 100% rename from courses/advanced-moccasin/1-moccasin-nft/7-what-is-ipfs/+page.md rename to courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/7-what-is-ipfs/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md b/courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md similarity index 100% rename from courses/advanced-moccasin/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md rename to courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/8-viewing-an-nft-in-metamask/+page.md diff --git a/courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md b/courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/9-deploying-to-zksync/+page.md similarity index 100% rename from courses/advanced-moccasin/1-moccasin-nft/9-deploying-to-zksync/+page.md rename to courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/9-deploying-to-zksync/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/1-intro/+page.md b/courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/1-intro/+page.md similarity index 100% rename from courses/advanced-moccasin/2-moccasin-portfolio-rebalance/1-intro/+page.md rename to courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/1-intro/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/10-atokens/+page.md b/courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/10-atokens/+page.md similarity index 100% rename from courses/advanced-moccasin/2-moccasin-portfolio-rebalance/10-atokens/+page.md rename to courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/10-atokens/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/11-portfolio-allocations/+page.md b/courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/11-portfolio-allocations/+page.md similarity index 100% rename from courses/advanced-moccasin/2-moccasin-portfolio-rebalance/11-portfolio-allocations/+page.md rename to courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/11-portfolio-allocations/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/12-withdrawing-from-aave/+page.md b/courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/12-withdrawing-from-aave/+page.md similarity index 100% rename from courses/advanced-moccasin/2-moccasin-portfolio-rebalance/12-withdrawing-from-aave/+page.md rename to courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/12-withdrawing-from-aave/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/13-uniswap/+page.md b/courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/13-uniswap/+page.md similarity index 100% rename from courses/advanced-moccasin/2-moccasin-portfolio-rebalance/13-uniswap/+page.md rename to courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/13-uniswap/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/14-finish-rebalance/+page.md b/courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/14-finish-rebalance/+page.md similarity index 100% rename from courses/advanced-moccasin/2-moccasin-portfolio-rebalance/14-finish-rebalance/+page.md rename to courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/14-finish-rebalance/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/15-zksync-demo/+page.md b/courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/15-zksync-demo/+page.md similarity index 100% rename from courses/advanced-moccasin/2-moccasin-portfolio-rebalance/15-zksync-demo/+page.md rename to courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/15-zksync-demo/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/16-workshop/+page.md b/courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/16-workshop/+page.md similarity index 100% rename from courses/advanced-moccasin/2-moccasin-portfolio-rebalance/16-workshop/+page.md rename to courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/16-workshop/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/17-recap/+page.md b/courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/17-recap/+page.md similarity index 100% rename from courses/advanced-moccasin/2-moccasin-portfolio-rebalance/17-recap/+page.md rename to courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/17-recap/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/2-real-demo/+page.md b/courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/2-real-demo/+page.md similarity index 100% rename from courses/advanced-moccasin/2-moccasin-portfolio-rebalance/2-real-demo/+page.md rename to courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/2-real-demo/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/3-setup/+page.md b/courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/3-setup/+page.md similarity index 100% rename from courses/advanced-moccasin/2-moccasin-portfolio-rebalance/3-setup/+page.md rename to courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/3-setup/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/4-forked-network-setup/+page.md b/courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/4-forked-network-setup/+page.md similarity index 100% rename from courses/advanced-moccasin/2-moccasin-portfolio-rebalance/4-forked-network-setup/+page.md rename to courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/4-forked-network-setup/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/5-minting-weth/+page.md b/courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/5-minting-weth/+page.md similarity index 100% rename from courses/advanced-moccasin/2-moccasin-portfolio-rebalance/5-minting-weth/+page.md rename to courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/5-minting-weth/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/6-getting-abis-from-the-explorer/+page.md b/courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/6-getting-abis-from-the-explorer/+page.md similarity index 100% rename from courses/advanced-moccasin/2-moccasin-portfolio-rebalance/6-getting-abis-from-the-explorer/+page.md rename to courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/6-getting-abis-from-the-explorer/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/7-minting-usdc/+page.md b/courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/7-minting-usdc/+page.md similarity index 100% rename from courses/advanced-moccasin/2-moccasin-portfolio-rebalance/7-minting-usdc/+page.md rename to courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/7-minting-usdc/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md b/courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md similarity index 100% rename from courses/advanced-moccasin/2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md rename to courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md diff --git a/courses/advanced-moccasin/2-moccasin-portfolio-rebalance/9-depositing-into-aave/+page.md b/courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/9-depositing-into-aave/+page.md similarity index 100% rename from courses/advanced-moccasin/2-moccasin-portfolio-rebalance/9-depositing-into-aave/+page.md rename to courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/9-depositing-into-aave/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/1-intro/+page.md b/courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/1-intro/+page.md similarity index 100% rename from courses/advanced-moccasin/3-moccasin-stablecoin/1-intro/+page.md rename to courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/1-intro/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/10-deployment/+page.md b/courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/10-deployment/+page.md similarity index 100% rename from courses/advanced-moccasin/3-moccasin-stablecoin/10-deployment/+page.md rename to courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/10-deployment/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/11-testing/+page.md b/courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/11-testing/+page.md similarity index 100% rename from courses/advanced-moccasin/3-moccasin-stablecoin/11-testing/+page.md rename to courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/11-testing/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/12-workshop-1/+page.md b/courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/12-workshop-1/+page.md similarity index 100% rename from courses/advanced-moccasin/3-moccasin-stablecoin/12-workshop-1/+page.md rename to courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/12-workshop-1/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/13-fuzz-setup/+page.md b/courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/13-fuzz-setup/+page.md similarity index 100% rename from courses/advanced-moccasin/3-moccasin-stablecoin/13-fuzz-setup/+page.md rename to courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/13-fuzz-setup/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/14-invariant/+page.md b/courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/14-invariant/+page.md similarity index 100% rename from courses/advanced-moccasin/3-moccasin-stablecoin/14-invariant/+page.md rename to courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/14-invariant/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/15-rules-deposit-and-redeem/+page.md b/courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/15-rules-deposit-and-redeem/+page.md similarity index 100% rename from courses/advanced-moccasin/3-moccasin-stablecoin/15-rules-deposit-and-redeem/+page.md rename to courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/15-rules-deposit-and-redeem/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/16-rules-mint-dsc/+page.md b/courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/16-rules-mint-dsc/+page.md similarity index 100% rename from courses/advanced-moccasin/3-moccasin-stablecoin/16-rules-mint-dsc/+page.md rename to courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/16-rules-mint-dsc/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/17-rules-update-price/+page.md b/courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/17-rules-update-price/+page.md similarity index 100% rename from courses/advanced-moccasin/3-moccasin-stablecoin/17-rules-update-price/+page.md rename to courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/17-rules-update-price/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/18-workshop-2/+page.md b/courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/18-workshop-2/+page.md similarity index 100% rename from courses/advanced-moccasin/3-moccasin-stablecoin/18-workshop-2/+page.md rename to courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/18-workshop-2/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/19-audit-readiness/+page.md b/courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/19-audit-readiness/+page.md similarity index 100% rename from courses/advanced-moccasin/3-moccasin-stablecoin/19-audit-readiness/+page.md rename to courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/19-audit-readiness/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/2-what-is-a-stablecoin/+page.md b/courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/2-what-is-a-stablecoin/+page.md similarity index 100% rename from courses/advanced-moccasin/3-moccasin-stablecoin/2-what-is-a-stablecoin/+page.md rename to courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/2-what-is-a-stablecoin/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/20-recap/+page.md b/courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/20-recap/+page.md similarity index 100% rename from courses/advanced-moccasin/3-moccasin-stablecoin/20-recap/+page.md rename to courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/20-recap/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/3-setup/+page.md b/courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/3-setup/+page.md similarity index 100% rename from courses/advanced-moccasin/3-moccasin-stablecoin/3-setup/+page.md rename to courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/3-setup/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/4-engine-intro/+page.md b/courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/4-engine-intro/+page.md similarity index 100% rename from courses/advanced-moccasin/3-moccasin-stablecoin/4-engine-intro/+page.md rename to courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/4-engine-intro/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/5-deposit-collateral/+page.md b/courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/5-deposit-collateral/+page.md similarity index 100% rename from courses/advanced-moccasin/3-moccasin-stablecoin/5-deposit-collateral/+page.md rename to courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/5-deposit-collateral/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/6-health-factor/+page.md b/courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/6-health-factor/+page.md similarity index 100% rename from courses/advanced-moccasin/3-moccasin-stablecoin/6-health-factor/+page.md rename to courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/6-health-factor/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/7-minting-dsc/+page.md b/courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/7-minting-dsc/+page.md similarity index 100% rename from courses/advanced-moccasin/3-moccasin-stablecoin/7-minting-dsc/+page.md rename to courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/7-minting-dsc/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/8-redeem-collateral/+page.md b/courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/8-redeem-collateral/+page.md similarity index 100% rename from courses/advanced-moccasin/3-moccasin-stablecoin/8-redeem-collateral/+page.md rename to courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/8-redeem-collateral/+page.md diff --git a/courses/advanced-moccasin/3-moccasin-stablecoin/9-liquidation/+page.md b/courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/9-liquidation/+page.md similarity index 100% rename from courses/advanced-moccasin/3-moccasin-stablecoin/9-liquidation/+page.md rename to courses/advanced-python-vyper-smart-contract-development/3-moccasin-stablecoin/9-liquidation/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/1-intro/+page.md b/courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/1-intro/+page.md similarity index 100% rename from courses/advanced-moccasin/4-moccasin-signatures/1-intro/+page.md rename to courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/1-intro/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/10-transaction-types/+page.md b/courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/10-transaction-types/+page.md similarity index 100% rename from courses/advanced-moccasin/4-moccasin-signatures/10-transaction-types/+page.md rename to courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/10-transaction-types/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/11-blobs/+page.md b/courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/11-blobs/+page.md similarity index 100% rename from courses/advanced-moccasin/4-moccasin-signatures/11-blobs/+page.md rename to courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/11-blobs/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/12-type-113-transactions/+page.md b/courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/12-type-113-transactions/+page.md similarity index 100% rename from courses/advanced-moccasin/4-moccasin-signatures/12-type-113-transactions/+page.md rename to courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/12-type-113-transactions/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/13-adding-signature-verification/+page.md b/courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/13-adding-signature-verification/+page.md similarity index 100% rename from courses/advanced-moccasin/4-moccasin-signatures/13-adding-signature-verification/+page.md rename to courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/13-adding-signature-verification/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/14-deploy/+page.md b/courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/14-deploy/+page.md similarity index 100% rename from courses/advanced-moccasin/4-moccasin-signatures/14-deploy/+page.md rename to courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/14-deploy/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/15-testing/+page.md b/courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/15-testing/+page.md similarity index 100% rename from courses/advanced-moccasin/4-moccasin-signatures/15-testing/+page.md rename to courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/15-testing/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/16-workshop-1/+page.md b/courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/16-workshop-1/+page.md similarity index 100% rename from courses/advanced-moccasin/4-moccasin-signatures/16-workshop-1/+page.md rename to courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/16-workshop-1/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/17-recap/+page.md b/courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/17-recap/+page.md similarity index 100% rename from courses/advanced-moccasin/4-moccasin-signatures/17-recap/+page.md rename to courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/17-recap/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/2-setup/+page.md b/courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/2-setup/+page.md similarity index 100% rename from courses/advanced-moccasin/4-moccasin-signatures/2-setup/+page.md rename to courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/2-setup/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/3-merkle-trees/+page.md b/courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/3-merkle-trees/+page.md similarity index 100% rename from courses/advanced-moccasin/4-moccasin-signatures/3-merkle-trees/+page.md rename to courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/3-merkle-trees/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/4-making-a-merkle/+page.md b/courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/4-making-a-merkle/+page.md similarity index 100% rename from courses/advanced-moccasin/4-moccasin-signatures/4-making-a-merkle/+page.md rename to courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/4-making-a-merkle/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/5-merkle-proof/+page.md b/courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/5-merkle-proof/+page.md similarity index 100% rename from courses/advanced-moccasin/4-moccasin-signatures/5-merkle-proof/+page.md rename to courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/5-merkle-proof/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/6-claiming-a-proof/+page.md b/courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/6-claiming-a-proof/+page.md similarity index 100% rename from courses/advanced-moccasin/4-moccasin-signatures/6-claiming-a-proof/+page.md rename to courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/6-claiming-a-proof/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/7-signature-standards/+page.md b/courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/7-signature-standards/+page.md similarity index 100% rename from courses/advanced-moccasin/4-moccasin-signatures/7-signature-standards/+page.md rename to courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/7-signature-standards/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/8-eip-712-in-vyper/+page.md b/courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/8-eip-712-in-vyper/+page.md similarity index 100% rename from courses/advanced-moccasin/4-moccasin-signatures/8-eip-712-in-vyper/+page.md rename to courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/8-eip-712-in-vyper/+page.md diff --git a/courses/advanced-moccasin/4-moccasin-signatures/9-ecdsa/+page.md b/courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/9-ecdsa/+page.md similarity index 100% rename from courses/advanced-moccasin/4-moccasin-signatures/9-ecdsa/+page.md rename to courses/advanced-python-vyper-smart-contract-development/4-moccasin-signatures/9-ecdsa/+page.md diff --git a/courses/advanced-moccasin/5-moccasin-upgrades/1-intro/+page.md b/courses/advanced-python-vyper-smart-contract-development/5-moccasin-upgrades/1-intro/+page.md similarity index 100% rename from courses/advanced-moccasin/5-moccasin-upgrades/1-intro/+page.md rename to courses/advanced-python-vyper-smart-contract-development/5-moccasin-upgrades/1-intro/+page.md diff --git a/courses/advanced-moccasin/5-moccasin-upgrades/2-erc-1967-and-delegatecall/+page.md b/courses/advanced-python-vyper-smart-contract-development/5-moccasin-upgrades/2-erc-1967-and-delegatecall/+page.md similarity index 100% rename from courses/advanced-moccasin/5-moccasin-upgrades/2-erc-1967-and-delegatecall/+page.md rename to courses/advanced-python-vyper-smart-contract-development/5-moccasin-upgrades/2-erc-1967-and-delegatecall/+page.md diff --git a/courses/advanced-moccasin/5-moccasin-upgrades/3-delegatecall/+page.md b/courses/advanced-python-vyper-smart-contract-development/5-moccasin-upgrades/3-delegatecall/+page.md similarity index 100% rename from courses/advanced-moccasin/5-moccasin-upgrades/3-delegatecall/+page.md rename to courses/advanced-python-vyper-smart-contract-development/5-moccasin-upgrades/3-delegatecall/+page.md diff --git a/courses/advanced-moccasin/5-moccasin-upgrades/4-how-proxies-upgrade/+page.md b/courses/advanced-python-vyper-smart-contract-development/5-moccasin-upgrades/4-how-proxies-upgrade/+page.md similarity index 100% rename from courses/advanced-moccasin/5-moccasin-upgrades/4-how-proxies-upgrade/+page.md rename to courses/advanced-python-vyper-smart-contract-development/5-moccasin-upgrades/4-how-proxies-upgrade/+page.md diff --git a/courses/advanced-moccasin/5-moccasin-upgrades/5-workshop/+page.md b/courses/advanced-python-vyper-smart-contract-development/5-moccasin-upgrades/5-workshop/+page.md similarity index 100% rename from courses/advanced-moccasin/5-moccasin-upgrades/5-workshop/+page.md rename to courses/advanced-python-vyper-smart-contract-development/5-moccasin-upgrades/5-workshop/+page.md diff --git a/courses/advanced-moccasin/5-moccasin-upgrades/6-recap/+page.md b/courses/advanced-python-vyper-smart-contract-development/5-moccasin-upgrades/6-recap/+page.md similarity index 100% rename from courses/advanced-moccasin/5-moccasin-upgrades/6-recap/+page.md rename to courses/advanced-python-vyper-smart-contract-development/5-moccasin-upgrades/6-recap/+page.md diff --git a/courses/advanced-moccasin/5-moccasin-upgrades/7-what-do-i-do-now_/+page.md b/courses/advanced-python-vyper-smart-contract-development/5-moccasin-upgrades/7-what-do-i-do-now_/+page.md similarity index 100% rename from courses/advanced-moccasin/5-moccasin-upgrades/7-what-do-i-do-now_/+page.md rename to courses/advanced-python-vyper-smart-contract-development/5-moccasin-upgrades/7-what-do-i-do-now_/+page.md diff --git a/courses/advanced-moccasin/5-moccasin-upgrades/8-finale/+page.md b/courses/advanced-python-vyper-smart-contract-development/5-moccasin-upgrades/8-finale/+page.md similarity index 100% rename from courses/advanced-moccasin/5-moccasin-upgrades/8-finale/+page.md rename to courses/advanced-python-vyper-smart-contract-development/5-moccasin-upgrades/8-finale/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/1-intro/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/1-intro/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/1-intro/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/1-intro/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/10-types/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/10-types/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/10-types/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/10-types/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/11-math/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/11-math/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/11-math/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/11-math/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/12-more-math/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/12-more-math/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/12-more-math/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/12-more-math/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/13-funcs/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/13-funcs/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/13-funcs/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/13-funcs/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/14-conditionals/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/14-conditionals/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/14-conditionals/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/14-conditionals/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/15-while-loops/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/15-while-loops/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/15-while-loops/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/15-while-loops/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/16-loops-2/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/16-loops-2/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/16-loops-2/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/16-loops-2/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/17-loops-3/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/17-loops-3/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/17-loops-3/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/17-loops-3/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/18-workshop/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/18-workshop/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/18-workshop/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/18-workshop/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/19-recap/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/19-recap/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/19-recap/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/19-recap/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/2-google-collab/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/2-google-collab/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/2-google-collab/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/2-google-collab/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/20-dev-env-setup/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/20-dev-env-setup/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/20-dev-env-setup/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/20-dev-env-setup/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/21-install-vscode-macos-linux/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/21-install-vscode-macos-linux/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/21-install-vscode-macos-linux/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/21-install-vscode-macos-linux/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/22-install-wsl/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/22-install-wsl/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/22-install-wsl/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/22-install-wsl/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/23-vscode-windows-install/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/23-vscode-windows-install/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/23-vscode-windows-install/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/23-vscode-windows-install/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/24-vscode-windows-wsl-extension/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/24-vscode-windows-wsl-extension/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/24-vscode-windows-wsl-extension/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/24-vscode-windows-wsl-extension/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/25-vscode-quickstart/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/25-vscode-quickstart/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/25-vscode-quickstart/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/25-vscode-quickstart/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/26-install-python-macos/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/26-install-python-macos/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/26-install-python-macos/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/26-install-python-macos/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/27-install-python-wsl-linux/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/27-install-python-wsl-linux/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/27-install-python-wsl-linux/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/27-install-python-wsl-linux/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/28-vscode-quickstart-2/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/28-vscode-quickstart-2/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/28-vscode-quickstart-2/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/28-vscode-quickstart-2/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/29-mental-prep/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/29-mental-prep/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/29-mental-prep/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/29-mental-prep/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/3-setup/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/3-setup/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/3-setup/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/3-setup/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/30-local-py/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/30-local-py/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/30-local-py/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/30-local-py/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/31-python-shell/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/31-python-shell/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/31-python-shell/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/31-python-shell/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/32-python-extensions-vscode/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/32-python-extensions-vscode/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/32-python-extensions-vscode/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/32-python-extensions-vscode/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/33-our-first-python/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/33-our-first-python/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/33-our-first-python/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/33-our-first-python/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/34-python-imports/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/34-python-imports/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/34-python-imports/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/34-python-imports/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/35-installing-uv/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/35-installing-uv/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/35-installing-uv/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/35-installing-uv/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/36-uv-python-version/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/36-uv-python-version/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/36-uv-python-version/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/36-uv-python-version/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/37-adding-packages-uv/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/37-adding-packages-uv/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/37-adding-packages-uv/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/37-adding-packages-uv/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/38-virtual-envs/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/38-virtual-envs/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/38-virtual-envs/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/38-virtual-envs/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/39-recap-pt-2/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/39-recap-pt-2/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/39-recap-pt-2/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/39-recap-pt-2/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/4-notebook/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/4-notebook/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/4-notebook/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/4-notebook/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/5-google-ai/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/5-google-ai/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/5-google-ai/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/5-google-ai/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/6-python-vars/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/6-python-vars/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/6-python-vars/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/6-python-vars/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/7-type-hints/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/7-type-hints/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/7-type-hints/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/7-type-hints/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/8-arrays/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/8-arrays/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/8-arrays/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/8-arrays/+page.md diff --git a/courses/moccasin-101/1-python-in-updraft/9-inputs/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/9-inputs/+page.md similarity index 100% rename from courses/moccasin-101/1-python-in-updraft/9-inputs/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/9-inputs/+page.md diff --git a/courses/moccasin-101/2-web3py/1-intro/+page.md b/courses/intermediate-python-vyper-smart-contract-development/2-web3py/1-intro/+page.md similarity index 100% rename from courses/moccasin-101/2-web3py/1-intro/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/2-web3py/1-intro/+page.md diff --git a/courses/moccasin-101/2-web3py/10-breakpoint/+page.md b/courses/intermediate-python-vyper-smart-contract-development/2-web3py/10-breakpoint/+page.md similarity index 100% rename from courses/moccasin-101/2-web3py/10-breakpoint/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/2-web3py/10-breakpoint/+page.md diff --git a/courses/moccasin-101/2-web3py/11-anvil/+page.md b/courses/intermediate-python-vyper-smart-contract-development/2-web3py/11-anvil/+page.md similarity index 100% rename from courses/moccasin-101/2-web3py/11-anvil/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/2-web3py/11-anvil/+page.md diff --git a/courses/moccasin-101/2-web3py/12-anvil2/+page.md b/courses/intermediate-python-vyper-smart-contract-development/2-web3py/12-anvil2/+page.md similarity index 100% rename from courses/moccasin-101/2-web3py/12-anvil2/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/2-web3py/12-anvil2/+page.md diff --git a/courses/moccasin-101/2-web3py/13-tx/+page.md b/courses/intermediate-python-vyper-smart-contract-development/2-web3py/13-tx/+page.md similarity index 100% rename from courses/moccasin-101/2-web3py/13-tx/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/2-web3py/13-tx/+page.md diff --git a/courses/moccasin-101/2-web3py/14-tx-pt-2/+page.md b/courses/intermediate-python-vyper-smart-contract-development/2-web3py/14-tx-pt-2/+page.md similarity index 100% rename from courses/moccasin-101/2-web3py/14-tx-pt-2/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/2-web3py/14-tx-pt-2/+page.md diff --git a/courses/moccasin-101/2-web3py/15-tx-pt-3/+page.md b/courses/intermediate-python-vyper-smart-contract-development/2-web3py/15-tx-pt-3/+page.md similarity index 100% rename from courses/moccasin-101/2-web3py/15-tx-pt-3/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/2-web3py/15-tx-pt-3/+page.md diff --git a/courses/moccasin-101/2-web3py/16-nonce/+page.md b/courses/intermediate-python-vyper-smart-contract-development/2-web3py/16-nonce/+page.md similarity index 100% rename from courses/moccasin-101/2-web3py/16-nonce/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/2-web3py/16-nonce/+page.md diff --git a/courses/moccasin-101/2-web3py/17-sign-tx/+page.md b/courses/intermediate-python-vyper-smart-contract-development/2-web3py/17-sign-tx/+page.md similarity index 100% rename from courses/moccasin-101/2-web3py/17-sign-tx/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/2-web3py/17-sign-tx/+page.md diff --git a/courses/moccasin-101/2-web3py/18-pkey-promise/+page.md b/courses/intermediate-python-vyper-smart-contract-development/2-web3py/18-pkey-promise/+page.md similarity index 100% rename from courses/moccasin-101/2-web3py/18-pkey-promise/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/2-web3py/18-pkey-promise/+page.md diff --git a/courses/moccasin-101/2-web3py/19-env-vars/+page.md b/courses/intermediate-python-vyper-smart-contract-development/2-web3py/19-env-vars/+page.md similarity index 100% rename from courses/moccasin-101/2-web3py/19-env-vars/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/2-web3py/19-env-vars/+page.md diff --git a/courses/moccasin-101/2-web3py/2-setup/+page.md b/courses/intermediate-python-vyper-smart-contract-development/2-web3py/2-setup/+page.md similarity index 100% rename from courses/moccasin-101/2-web3py/2-setup/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/2-web3py/2-setup/+page.md diff --git a/courses/moccasin-101/2-web3py/20-send-tx/+page.md b/courses/intermediate-python-vyper-smart-contract-development/2-web3py/20-send-tx/+page.md similarity index 100% rename from courses/moccasin-101/2-web3py/20-send-tx/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/2-web3py/20-send-tx/+page.md diff --git a/courses/moccasin-101/2-web3py/21-encrypt/+page.md b/courses/intermediate-python-vyper-smart-contract-development/2-web3py/21-encrypt/+page.md similarity index 100% rename from courses/moccasin-101/2-web3py/21-encrypt/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/2-web3py/21-encrypt/+page.md diff --git a/courses/moccasin-101/2-web3py/22-pledge/+page.md b/courses/intermediate-python-vyper-smart-contract-development/2-web3py/22-pledge/+page.md similarity index 100% rename from courses/moccasin-101/2-web3py/22-pledge/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/2-web3py/22-pledge/+page.md diff --git a/courses/moccasin-101/2-web3py/23-workshop/+page.md b/courses/intermediate-python-vyper-smart-contract-development/2-web3py/23-workshop/+page.md similarity index 100% rename from courses/moccasin-101/2-web3py/23-workshop/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/2-web3py/23-workshop/+page.md diff --git a/courses/moccasin-101/2-web3py/24-recap/+page.md b/courses/intermediate-python-vyper-smart-contract-development/2-web3py/24-recap/+page.md similarity index 100% rename from courses/moccasin-101/2-web3py/24-recap/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/2-web3py/24-recap/+page.md diff --git a/courses/moccasin-101/2-web3py/3-vyper-extension/+page.md b/courses/intermediate-python-vyper-smart-contract-development/2-web3py/3-vyper-extension/+page.md similarity index 100% rename from courses/moccasin-101/2-web3py/3-vyper-extension/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/2-web3py/3-vyper-extension/+page.md diff --git a/courses/moccasin-101/2-web3py/4-compile-python/+page.md b/courses/intermediate-python-vyper-smart-contract-development/2-web3py/4-compile-python/+page.md similarity index 100% rename from courses/moccasin-101/2-web3py/4-compile-python/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/2-web3py/4-compile-python/+page.md diff --git a/courses/moccasin-101/2-web3py/5-idk/+page.md b/courses/intermediate-python-vyper-smart-contract-development/2-web3py/5-idk/+page.md similarity index 100% rename from courses/moccasin-101/2-web3py/5-idk/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/2-web3py/5-idk/+page.md diff --git a/courses/moccasin-101/2-web3py/6-__nam__/+page.md b/courses/intermediate-python-vyper-smart-contract-development/2-web3py/6-__nam__/+page.md similarity index 100% rename from courses/moccasin-101/2-web3py/6-__nam__/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/2-web3py/6-__nam__/+page.md diff --git a/courses/moccasin-101/2-web3py/7-vyper-package/+page.md b/courses/intermediate-python-vyper-smart-contract-development/2-web3py/7-vyper-package/+page.md similarity index 100% rename from courses/moccasin-101/2-web3py/7-vyper-package/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/2-web3py/7-vyper-package/+page.md diff --git a/courses/moccasin-101/2-web3py/8-vscode-py/+page.md b/courses/intermediate-python-vyper-smart-contract-development/2-web3py/8-vscode-py/+page.md similarity index 100% rename from courses/moccasin-101/2-web3py/8-vscode-py/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/2-web3py/8-vscode-py/+page.md diff --git a/courses/moccasin-101/2-web3py/9-web3-py/+page.md b/courses/intermediate-python-vyper-smart-contract-development/2-web3py/9-web3-py/+page.md similarity index 100% rename from courses/moccasin-101/2-web3py/9-web3-py/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/2-web3py/9-web3-py/+page.md diff --git a/courses/moccasin-101/3-boa-favs/1-intro/+page.md b/courses/intermediate-python-vyper-smart-contract-development/3-boa-favs/1-intro/+page.md similarity index 100% rename from courses/moccasin-101/3-boa-favs/1-intro/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/3-boa-favs/1-intro/+page.md diff --git a/courses/moccasin-101/3-boa-favs/10-add-person/+page.md b/courses/intermediate-python-vyper-smart-contract-development/3-boa-favs/10-add-person/+page.md similarity index 100% rename from courses/moccasin-101/3-boa-favs/10-add-person/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/3-boa-favs/10-add-person/+page.md diff --git a/courses/moccasin-101/3-boa-favs/11-workshop/+page.md b/courses/intermediate-python-vyper-smart-contract-development/3-boa-favs/11-workshop/+page.md similarity index 100% rename from courses/moccasin-101/3-boa-favs/11-workshop/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/3-boa-favs/11-workshop/+page.md diff --git a/courses/moccasin-101/3-boa-favs/12-recap/+page.md b/courses/intermediate-python-vyper-smart-contract-development/3-boa-favs/12-recap/+page.md similarity index 100% rename from courses/moccasin-101/3-boa-favs/12-recap/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/3-boa-favs/12-recap/+page.md diff --git a/courses/moccasin-101/3-boa-favs/2-setup/+page.md b/courses/intermediate-python-vyper-smart-contract-development/3-boa-favs/2-setup/+page.md similarity index 100% rename from courses/moccasin-101/3-boa-favs/2-setup/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/3-boa-favs/2-setup/+page.md diff --git a/courses/moccasin-101/3-boa-favs/3-pyevm/+page.md b/courses/intermediate-python-vyper-smart-contract-development/3-boa-favs/3-pyevm/+page.md similarity index 100% rename from courses/moccasin-101/3-boa-favs/3-pyevm/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/3-boa-favs/3-pyevm/+page.md diff --git a/courses/moccasin-101/3-boa-favs/4-vypercontract/+page.md b/courses/intermediate-python-vyper-smart-contract-development/3-boa-favs/4-vypercontract/+page.md similarity index 100% rename from courses/moccasin-101/3-boa-favs/4-vypercontract/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/3-boa-favs/4-vypercontract/+page.md diff --git a/courses/moccasin-101/3-boa-favs/5-debug/+page.md b/courses/intermediate-python-vyper-smart-contract-development/3-boa-favs/5-debug/+page.md similarity index 100% rename from courses/moccasin-101/3-boa-favs/5-debug/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/3-boa-favs/5-debug/+page.md diff --git a/courses/moccasin-101/3-boa-favs/6-pyevm_/+page.md b/courses/intermediate-python-vyper-smart-contract-development/3-boa-favs/6-pyevm_/+page.md similarity index 100% rename from courses/moccasin-101/3-boa-favs/6-pyevm_/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/3-boa-favs/6-pyevm_/+page.md diff --git a/courses/moccasin-101/3-boa-favs/7-anvil/+page.md b/courses/intermediate-python-vyper-smart-contract-development/3-boa-favs/7-anvil/+page.md similarity index 100% rename from courses/moccasin-101/3-boa-favs/7-anvil/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/3-boa-favs/7-anvil/+page.md diff --git a/courses/moccasin-101/3-boa-favs/8-interacting-anvil/+page.md b/courses/intermediate-python-vyper-smart-contract-development/3-boa-favs/8-interacting-anvil/+page.md similarity index 100% rename from courses/moccasin-101/3-boa-favs/8-interacting-anvil/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/3-boa-favs/8-interacting-anvil/+page.md diff --git a/courses/moccasin-101/3-boa-favs/9-interact-prevs/+page.md b/courses/intermediate-python-vyper-smart-contract-development/3-boa-favs/9-interact-prevs/+page.md similarity index 100% rename from courses/moccasin-101/3-boa-favs/9-interact-prevs/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/3-boa-favs/9-interact-prevs/+page.md diff --git a/courses/moccasin-101/4-mox-favs/1-intro/+page.md b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/1-intro/+page.md similarity index 100% rename from courses/moccasin-101/4-mox-favs/1-intro/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/1-intro/+page.md diff --git a/courses/moccasin-101/4-mox-favs/10-account-cli/+page.md b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/10-account-cli/+page.md similarity index 100% rename from courses/moccasin-101/4-mox-favs/10-account-cli/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/10-account-cli/+page.md diff --git a/courses/moccasin-101/4-mox-favs/11-mox-testing/+page.md b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/11-mox-testing/+page.md similarity index 100% rename from courses/moccasin-101/4-mox-favs/11-mox-testing/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/11-mox-testing/+page.md diff --git a/courses/moccasin-101/4-mox-favs/12-testing-deploy-script/+page.md b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/12-testing-deploy-script/+page.md similarity index 100% rename from courses/moccasin-101/4-mox-favs/12-testing-deploy-script/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/12-testing-deploy-script/+page.md diff --git a/courses/moccasin-101/4-mox-favs/13-aaa/+page.md b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/13-aaa/+page.md similarity index 100% rename from courses/moccasin-101/4-mox-favs/13-aaa/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/13-aaa/+page.md diff --git a/courses/moccasin-101/4-mox-favs/14-fixtures/+page.md b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/14-fixtures/+page.md similarity index 100% rename from courses/moccasin-101/4-mox-favs/14-fixtures/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/14-fixtures/+page.md diff --git a/courses/moccasin-101/4-mox-favs/15-conftest/+page.md b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/15-conftest/+page.md similarity index 100% rename from courses/moccasin-101/4-mox-favs/15-conftest/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/15-conftest/+page.md diff --git a/courses/moccasin-101/4-mox-favs/16-type-hints/+page.md b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/16-type-hints/+page.md similarity index 100% rename from courses/moccasin-101/4-mox-favs/16-type-hints/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/16-type-hints/+page.md diff --git a/courses/moccasin-101/4-mox-favs/17-sepolia-deploy/+page.md b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/17-sepolia-deploy/+page.md similarity index 100% rename from courses/moccasin-101/4-mox-favs/17-sepolia-deploy/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/17-sepolia-deploy/+page.md diff --git a/courses/moccasin-101/4-mox-favs/18-verify/+page.md b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/18-verify/+page.md similarity index 100% rename from courses/moccasin-101/4-mox-favs/18-verify/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/18-verify/+page.md diff --git a/courses/moccasin-101/4-mox-favs/19-zksync-setup/+page.md b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/19-zksync-setup/+page.md similarity index 100% rename from courses/moccasin-101/4-mox-favs/19-zksync-setup/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/19-zksync-setup/+page.md diff --git a/courses/moccasin-101/4-mox-favs/2-install-mox/+page.md b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/2-install-mox/+page.md similarity index 100% rename from courses/moccasin-101/4-mox-favs/2-install-mox/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/2-install-mox/+page.md diff --git a/courses/moccasin-101/4-mox-favs/20-eravm/+page.md b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/20-eravm/+page.md similarity index 100% rename from courses/moccasin-101/4-mox-favs/20-eravm/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/20-eravm/+page.md diff --git a/courses/moccasin-101/4-mox-favs/21-setting-up-zksync/+page.md b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/21-setting-up-zksync/+page.md similarity index 100% rename from courses/moccasin-101/4-mox-favs/21-setting-up-zksync/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/21-setting-up-zksync/+page.md diff --git a/courses/moccasin-101/4-mox-favs/22-bridging/+page.md b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/22-bridging/+page.md similarity index 100% rename from courses/moccasin-101/4-mox-favs/22-bridging/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/22-bridging/+page.md diff --git a/courses/moccasin-101/4-mox-favs/23-zksync-deploy/+page.md b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/23-zksync-deploy/+page.md similarity index 100% rename from courses/moccasin-101/4-mox-favs/23-zksync-deploy/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/23-zksync-deploy/+page.md diff --git a/courses/moccasin-101/4-mox-favs/24-zksync-contract-deployment/+page.md b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/24-zksync-contract-deployment/+page.md similarity index 100% rename from courses/moccasin-101/4-mox-favs/24-zksync-contract-deployment/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/24-zksync-contract-deployment/+page.md diff --git a/courses/moccasin-101/4-mox-favs/25-tx-types/+page.md b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/25-tx-types/+page.md similarity index 100% rename from courses/moccasin-101/4-mox-favs/25-tx-types/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/25-tx-types/+page.md diff --git a/courses/moccasin-101/4-mox-favs/26-workshop/+page.md b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/26-workshop/+page.md similarity index 100% rename from courses/moccasin-101/4-mox-favs/26-workshop/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/26-workshop/+page.md diff --git a/courses/moccasin-101/4-mox-favs/27-recap/+page.md b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/27-recap/+page.md similarity index 100% rename from courses/moccasin-101/4-mox-favs/27-recap/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/27-recap/+page.md diff --git a/courses/moccasin-101/4-mox-favs/3-create-mox/+page.md b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/3-create-mox/+page.md similarity index 100% rename from courses/moccasin-101/4-mox-favs/3-create-mox/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/3-create-mox/+page.md diff --git a/courses/moccasin-101/4-mox-favs/4-mox-something/+page.md b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/4-mox-something/+page.md similarity index 100% rename from courses/moccasin-101/4-mox-favs/4-mox-something/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/4-mox-something/+page.md diff --git a/courses/moccasin-101/4-mox-favs/5-mox-script/+page.md b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/5-mox-script/+page.md similarity index 100% rename from courses/moccasin-101/4-mox-favs/5-mox-script/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/5-mox-script/+page.md diff --git a/courses/moccasin-101/4-mox-favs/6-other-net/+page.md b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/6-other-net/+page.md similarity index 100% rename from courses/moccasin-101/4-mox-favs/6-other-net/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/6-other-net/+page.md diff --git a/courses/moccasin-101/4-mox-favs/7-encrypt-key/+page.md b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/7-encrypt-key/+page.md similarity index 100% rename from courses/moccasin-101/4-mox-favs/7-encrypt-key/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/7-encrypt-key/+page.md diff --git a/courses/moccasin-101/4-mox-favs/8-shell/+page.md b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/8-shell/+page.md similarity index 100% rename from courses/moccasin-101/4-mox-favs/8-shell/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/8-shell/+page.md diff --git a/courses/moccasin-101/4-mox-favs/9-using-key/+page.md b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/9-using-key/+page.md similarity index 100% rename from courses/moccasin-101/4-mox-favs/9-using-key/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/9-using-key/+page.md diff --git a/courses/moccasin-101/5-mox-five/1-intro/+page.md b/courses/intermediate-python-vyper-smart-contract-development/5-mox-five/1-intro/+page.md similarity index 100% rename from courses/moccasin-101/5-mox-five/1-intro/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/5-mox-five/1-intro/+page.md diff --git a/courses/moccasin-101/5-mox-five/10-vyper-modules/+page.md b/courses/intermediate-python-vyper-smart-contract-development/5-mox-five/10-vyper-modules/+page.md similarity index 100% rename from courses/moccasin-101/5-mox-five/10-vyper-modules/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/5-mox-five/10-vyper-modules/+page.md diff --git a/courses/moccasin-101/5-mox-five/11-initializes-module-state/+page.md b/courses/intermediate-python-vyper-smart-contract-development/5-mox-five/11-initializes-module-state/+page.md similarity index 100% rename from courses/moccasin-101/5-mox-five/11-initializes-module-state/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/5-mox-five/11-initializes-module-state/+page.md diff --git a/courses/moccasin-101/5-mox-five/12-exports/+page.md b/courses/intermediate-python-vyper-smart-contract-development/5-mox-five/12-exports/+page.md similarity index 100% rename from courses/moccasin-101/5-mox-five/12-exports/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/5-mox-five/12-exports/+page.md diff --git a/courses/moccasin-101/5-mox-five/13-workshop/+page.md b/courses/intermediate-python-vyper-smart-contract-development/5-mox-five/13-workshop/+page.md similarity index 100% rename from courses/moccasin-101/5-mox-five/13-workshop/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/5-mox-five/13-workshop/+page.md diff --git a/courses/moccasin-101/5-mox-five/14-recap/+page.md b/courses/intermediate-python-vyper-smart-contract-development/5-mox-five/14-recap/+page.md similarity index 100% rename from courses/moccasin-101/5-mox-five/14-recap/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/5-mox-five/14-recap/+page.md diff --git a/courses/moccasin-101/5-mox-five/3-create-copy-of/+page.md b/courses/intermediate-python-vyper-smart-contract-development/5-mox-five/3-create-copy-of/+page.md similarity index 100% rename from courses/moccasin-101/5-mox-five/3-create-copy-of/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/5-mox-five/3-create-copy-of/+page.md diff --git a/courses/moccasin-101/5-mox-five/4-static-ext-call/+page.md b/courses/intermediate-python-vyper-smart-contract-development/5-mox-five/4-static-ext-call/+page.md similarity index 100% rename from courses/moccasin-101/5-mox-five/4-static-ext-call/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/5-mox-five/4-static-ext-call/+page.md diff --git a/courses/moccasin-101/5-mox-five/5-vyi/+page.md b/courses/intermediate-python-vyper-smart-contract-development/5-mox-five/5-vyi/+page.md similarity index 100% rename from courses/moccasin-101/5-mox-five/5-vyi/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/5-mox-five/5-vyi/+page.md diff --git a/courses/moccasin-101/5-mox-five/6-idk/+page.md b/courses/intermediate-python-vyper-smart-contract-development/5-mox-five/6-idk/+page.md similarity index 100% rename from courses/moccasin-101/5-mox-five/6-idk/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/5-mox-five/6-idk/+page.md diff --git a/courses/moccasin-101/5-mox-five/7-extcall/+page.md b/courses/intermediate-python-vyper-smart-contract-development/5-mox-five/7-extcall/+page.md similarity index 100% rename from courses/moccasin-101/5-mox-five/7-extcall/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/5-mox-five/7-extcall/+page.md diff --git a/courses/moccasin-101/5-mox-five/8-store-contract-by-interface/+page.md b/courses/intermediate-python-vyper-smart-contract-development/5-mox-five/8-store-contract-by-interface/+page.md similarity index 100% rename from courses/moccasin-101/5-mox-five/8-store-contract-by-interface/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/5-mox-five/8-store-contract-by-interface/+page.md diff --git a/courses/moccasin-101/5-mox-five/9-method-chaining/+page.md b/courses/intermediate-python-vyper-smart-contract-development/5-mox-five/9-method-chaining/+page.md similarity index 100% rename from courses/moccasin-101/5-mox-five/9-method-chaining/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/5-mox-five/9-method-chaining/+page.md diff --git a/courses/moccasin-101/6-mox-coffee/1-intro/+page.md b/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/1-intro/+page.md similarity index 100% rename from courses/moccasin-101/6-mox-coffee/1-intro/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/1-intro/+page.md diff --git a/courses/moccasin-101/6-mox-coffee/10-kinds/+page.md b/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/10-kinds/+page.md similarity index 100% rename from courses/moccasin-101/6-mox-coffee/10-kinds/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/10-kinds/+page.md diff --git a/courses/moccasin-101/6-mox-coffee/11-unit/+page.md b/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/11-unit/+page.md similarity index 100% rename from courses/moccasin-101/6-mox-coffee/11-unit/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/11-unit/+page.md diff --git a/courses/moccasin-101/6-mox-coffee/12-test-revert/+page.md b/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/12-test-revert/+page.md similarity index 100% rename from courses/moccasin-101/6-mox-coffee/12-test-revert/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/12-test-revert/+page.md diff --git a/courses/moccasin-101/6-mox-coffee/13-set-balance/+page.md b/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/13-set-balance/+page.md similarity index 100% rename from courses/moccasin-101/6-mox-coffee/13-set-balance/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/13-set-balance/+page.md diff --git a/courses/moccasin-101/6-mox-coffee/14-prank/+page.md b/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/14-prank/+page.md similarity index 100% rename from courses/moccasin-101/6-mox-coffee/14-prank/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/14-prank/+page.md diff --git a/courses/moccasin-101/6-mox-coffee/15-mid-sec-work/+page.md b/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/15-mid-sec-work/+page.md similarity index 100% rename from courses/moccasin-101/6-mox-coffee/15-mid-sec-work/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/15-mid-sec-work/+page.md diff --git a/courses/moccasin-101/6-mox-coffee/16-more-fixtures/+page.md b/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/16-more-fixtures/+page.md similarity index 100% rename from courses/moccasin-101/6-mox-coffee/16-more-fixtures/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/16-more-fixtures/+page.md diff --git a/courses/moccasin-101/6-mox-coffee/17-test-coverage/+page.md b/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/17-test-coverage/+page.md similarity index 100% rename from courses/moccasin-101/6-mox-coffee/17-test-coverage/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/17-test-coverage/+page.md diff --git a/courses/moccasin-101/6-mox-coffee/18-gas-profile/+page.md b/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/18-gas-profile/+page.md similarity index 100% rename from courses/moccasin-101/6-mox-coffee/18-gas-profile/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/18-gas-profile/+page.md diff --git a/courses/moccasin-101/6-mox-coffee/19-fork-tests/+page.md b/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/19-fork-tests/+page.md similarity index 100% rename from courses/moccasin-101/6-mox-coffee/19-fork-tests/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/19-fork-tests/+page.md diff --git a/courses/moccasin-101/6-mox-coffee/2-setup/+page.md b/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/2-setup/+page.md similarity index 100% rename from courses/moccasin-101/6-mox-coffee/2-setup/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/2-setup/+page.md diff --git a/courses/moccasin-101/6-mox-coffee/20-staging/+page.md b/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/20-staging/+page.md similarity index 100% rename from courses/moccasin-101/6-mox-coffee/20-staging/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/20-staging/+page.md diff --git a/courses/moccasin-101/6-mox-coffee/21-deployments-db/+page.md b/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/21-deployments-db/+page.md similarity index 100% rename from courses/moccasin-101/6-mox-coffee/21-deployments-db/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/21-deployments-db/+page.md diff --git a/courses/moccasin-101/6-mox-coffee/22-zksync-testing/+page.md b/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/22-zksync-testing/+page.md similarity index 100% rename from courses/moccasin-101/6-mox-coffee/22-zksync-testing/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/22-zksync-testing/+page.md diff --git a/courses/moccasin-101/6-mox-coffee/23-github/+page.md b/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/23-github/+page.md similarity index 100% rename from courses/moccasin-101/6-mox-coffee/23-github/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/23-github/+page.md diff --git a/courses/moccasin-101/6-mox-coffee/24-clone/+page.md b/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/24-clone/+page.md similarity index 100% rename from courses/moccasin-101/6-mox-coffee/24-clone/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/24-clone/+page.md diff --git a/courses/moccasin-101/6-mox-coffee/25-workshop/+page.md b/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/25-workshop/+page.md similarity index 100% rename from courses/moccasin-101/6-mox-coffee/25-workshop/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/25-workshop/+page.md diff --git a/courses/moccasin-101/6-mox-coffee/26-recap/+page.md b/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/26-recap/+page.md similarity index 100% rename from courses/moccasin-101/6-mox-coffee/26-recap/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/26-recap/+page.md diff --git a/courses/moccasin-101/6-mox-coffee/3-refactor/+page.md b/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/3-refactor/+page.md similarity index 100% rename from courses/moccasin-101/6-mox-coffee/3-refactor/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/3-refactor/+page.md diff --git a/courses/moccasin-101/6-mox-coffee/4-storage/+page.md b/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/4-storage/+page.md similarity index 100% rename from courses/moccasin-101/6-mox-coffee/4-storage/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/4-storage/+page.md diff --git a/courses/moccasin-101/6-mox-coffee/5-refactor-2/+page.md b/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/5-refactor-2/+page.md similarity index 100% rename from courses/moccasin-101/6-mox-coffee/5-refactor-2/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/5-refactor-2/+page.md diff --git a/courses/moccasin-101/6-mox-coffee/6-script/+page.md b/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/6-script/+page.md similarity index 100% rename from courses/moccasin-101/6-mox-coffee/6-script/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/6-script/+page.md diff --git a/courses/moccasin-101/6-mox-coffee/7-mocks/+page.md b/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/7-mocks/+page.md similarity index 100% rename from courses/moccasin-101/6-mox-coffee/7-mocks/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/7-mocks/+page.md diff --git a/courses/moccasin-101/6-mox-coffee/8-manifest/+page.md b/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/8-manifest/+page.md similarity index 100% rename from courses/moccasin-101/6-mox-coffee/8-manifest/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/8-manifest/+page.md diff --git a/courses/moccasin-101/6-mox-coffee/9-top-level/+page.md b/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/9-top-level/+page.md similarity index 100% rename from courses/moccasin-101/6-mox-coffee/9-top-level/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/9-top-level/+page.md diff --git a/courses/moccasin-101/7-mox-html/1-mox-intro/+page.md b/courses/intermediate-python-vyper-smart-contract-development/7-mox-html/1-mox-intro/+page.md similarity index 100% rename from courses/moccasin-101/7-mox-html/1-mox-intro/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/7-mox-html/1-mox-intro/+page.md diff --git a/courses/moccasin-101/7-mox-html/2-introduction/+page.md b/courses/intermediate-python-vyper-smart-contract-development/7-mox-html/2-introduction/+page.md similarity index 100% rename from courses/moccasin-101/7-mox-html/2-introduction/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/7-mox-html/2-introduction/+page.md diff --git a/courses/moccasin-101/7-mox-html/3-setup/+page.md b/courses/intermediate-python-vyper-smart-contract-development/7-mox-html/3-setup/+page.md similarity index 100% rename from courses/moccasin-101/7-mox-html/3-setup/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/7-mox-html/3-setup/+page.md diff --git a/courses/moccasin-101/7-mox-html/4-metamask/+page.md b/courses/intermediate-python-vyper-smart-contract-development/7-mox-html/4-metamask/+page.md similarity index 100% rename from courses/moccasin-101/7-mox-html/4-metamask/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/7-mox-html/4-metamask/+page.md diff --git a/courses/moccasin-101/7-mox-html/5-function-selectors/+page.md b/courses/intermediate-python-vyper-smart-contract-development/7-mox-html/5-function-selectors/+page.md similarity index 100% rename from courses/moccasin-101/7-mox-html/5-function-selectors/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/7-mox-html/5-function-selectors/+page.md diff --git a/courses/moccasin-101/7-mox-html/6-summary/+page.md b/courses/intermediate-python-vyper-smart-contract-development/7-mox-html/6-summary/+page.md similarity index 100% rename from courses/moccasin-101/7-mox-html/6-summary/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/7-mox-html/6-summary/+page.md diff --git a/courses/moccasin-101/8-mox-erc20/1-intro/+page.md b/courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/1-intro/+page.md similarity index 100% rename from courses/moccasin-101/8-mox-erc20/1-intro/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/1-intro/+page.md diff --git a/courses/moccasin-101/8-mox-erc20/10-built-in-interfaces/+page.md b/courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/10-built-in-interfaces/+page.md similarity index 100% rename from courses/moccasin-101/8-mox-erc20/10-built-in-interfaces/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/10-built-in-interfaces/+page.md diff --git a/courses/moccasin-101/8-mox-erc20/11-deploy-scripts/+page.md b/courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/11-deploy-scripts/+page.md similarity index 100% rename from courses/moccasin-101/8-mox-erc20/11-deploy-scripts/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/11-deploy-scripts/+page.md diff --git a/courses/moccasin-101/8-mox-erc20/12-tests/+page.md b/courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/12-tests/+page.md similarity index 100% rename from courses/moccasin-101/8-mox-erc20/12-tests/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/12-tests/+page.md diff --git a/courses/moccasin-101/8-mox-erc20/13-events/+page.md b/courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/13-events/+page.md similarity index 100% rename from courses/moccasin-101/8-mox-erc20/13-events/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/13-events/+page.md diff --git a/courses/moccasin-101/8-mox-erc20/14-testing-events/+page.md b/courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/14-testing-events/+page.md similarity index 100% rename from courses/moccasin-101/8-mox-erc20/14-testing-events/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/14-testing-events/+page.md diff --git a/courses/moccasin-101/8-mox-erc20/15-formatting/+page.md b/courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/15-formatting/+page.md similarity index 100% rename from courses/moccasin-101/8-mox-erc20/15-formatting/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/15-formatting/+page.md diff --git a/courses/moccasin-101/8-mox-erc20/16-justfile/+page.md b/courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/16-justfile/+page.md similarity index 100% rename from courses/moccasin-101/8-mox-erc20/16-justfile/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/16-justfile/+page.md diff --git a/courses/moccasin-101/8-mox-erc20/17-vheaders/+page.md b/courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/17-vheaders/+page.md similarity index 100% rename from courses/moccasin-101/8-mox-erc20/17-vheaders/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/17-vheaders/+page.md diff --git a/courses/moccasin-101/8-mox-erc20/18-fuzzing/+page.md b/courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/18-fuzzing/+page.md similarity index 100% rename from courses/moccasin-101/8-mox-erc20/18-fuzzing/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/18-fuzzing/+page.md diff --git a/courses/moccasin-101/8-mox-erc20/19-stateless-fuzz/+page.md b/courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/19-stateless-fuzz/+page.md similarity index 100% rename from courses/moccasin-101/8-mox-erc20/19-stateless-fuzz/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/19-stateless-fuzz/+page.md diff --git a/courses/moccasin-101/8-mox-erc20/2-setup/+page.md b/courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/2-setup/+page.md similarity index 100% rename from courses/moccasin-101/8-mox-erc20/2-setup/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/2-setup/+page.md diff --git a/courses/moccasin-101/8-mox-erc20/20-stateful-fuzz/+page.md b/courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/20-stateful-fuzz/+page.md similarity index 100% rename from courses/moccasin-101/8-mox-erc20/20-stateful-fuzz/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/20-stateful-fuzz/+page.md diff --git a/courses/moccasin-101/8-mox-erc20/21-workshop/+page.md b/courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/21-workshop/+page.md similarity index 100% rename from courses/moccasin-101/8-mox-erc20/21-workshop/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/21-workshop/+page.md diff --git a/courses/moccasin-101/8-mox-erc20/22-rng/+page.md b/courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/22-rng/+page.md similarity index 100% rename from courses/moccasin-101/8-mox-erc20/22-rng/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/22-rng/+page.md diff --git a/courses/moccasin-101/8-mox-erc20/23-cei/+page.md b/courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/23-cei/+page.md similarity index 100% rename from courses/moccasin-101/8-mox-erc20/23-cei/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/23-cei/+page.md diff --git a/courses/moccasin-101/8-mox-erc20/24-mox-console/+page.md b/courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/24-mox-console/+page.md similarity index 100% rename from courses/moccasin-101/8-mox-erc20/24-mox-console/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/24-mox-console/+page.md diff --git a/courses/moccasin-101/8-mox-erc20/25-recap/+page.md b/courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/25-recap/+page.md similarity index 100% rename from courses/moccasin-101/8-mox-erc20/25-recap/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/25-recap/+page.md diff --git a/courses/moccasin-101/8-mox-erc20/3-custom-pyproject/+page.md b/courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/3-custom-pyproject/+page.md similarity index 100% rename from courses/moccasin-101/8-mox-erc20/3-custom-pyproject/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/3-custom-pyproject/+page.md diff --git a/courses/moccasin-101/8-mox-erc20/4-what-is-erc20/+page.md b/courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/4-what-is-erc20/+page.md similarity index 100% rename from courses/moccasin-101/8-mox-erc20/4-what-is-erc20/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/4-what-is-erc20/+page.md diff --git a/courses/moccasin-101/8-mox-erc20/5-build-it/+page.md b/courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/5-build-it/+page.md similarity index 100% rename from courses/moccasin-101/8-mox-erc20/5-build-it/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/5-build-it/+page.md diff --git a/courses/moccasin-101/8-mox-erc20/6-mox-libs-git/+page.md b/courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/6-mox-libs-git/+page.md similarity index 100% rename from courses/moccasin-101/8-mox-erc20/6-mox-libs-git/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/6-mox-libs-git/+page.md diff --git a/courses/moccasin-101/8-mox-erc20/7-mox-libs-pypi/+page.md b/courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/7-mox-libs-pypi/+page.md similarity index 100% rename from courses/moccasin-101/8-mox-erc20/7-mox-libs-pypi/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/7-mox-libs-pypi/+page.md diff --git a/courses/moccasin-101/8-mox-erc20/8-mox-idk/+page.md b/courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/8-mox-idk/+page.md similarity index 100% rename from courses/moccasin-101/8-mox-erc20/8-mox-idk/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/8-mox-idk/+page.md diff --git a/courses/moccasin-101/8-mox-erc20/9-init-supply/+page.md b/courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/9-init-supply/+page.md similarity index 100% rename from courses/moccasin-101/8-mox-erc20/9-init-supply/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/9-init-supply/+page.md diff --git a/courses/moccasin-101/9-how-to-get-hired/1-intro/+page.md b/courses/intermediate-python-vyper-smart-contract-development/9-how-to-get-hired/1-intro/+page.md similarity index 100% rename from courses/moccasin-101/9-how-to-get-hired/1-intro/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/9-how-to-get-hired/1-intro/+page.md diff --git a/courses/moccasin-101/9-how-to-get-hired/2-workshop/+page.md b/courses/intermediate-python-vyper-smart-contract-development/9-how-to-get-hired/2-workshop/+page.md similarity index 100% rename from courses/moccasin-101/9-how-to-get-hired/2-workshop/+page.md rename to courses/intermediate-python-vyper-smart-contract-development/9-how-to-get-hired/2-workshop/+page.md diff --git a/courses/vyper-101/1-favorites/1-welcome/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/1-welcome/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/1-welcome/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/1-welcome/+page.md diff --git a/courses/vyper-101/1-favorites/10-contract-design/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/10-contract-design/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/10-contract-design/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/10-contract-design/+page.md diff --git a/courses/vyper-101/1-favorites/11-vyper-types/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/11-vyper-types/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/11-vyper-types/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/11-vyper-types/+page.md diff --git a/courses/vyper-101/1-favorites/12-visibilitiy/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/12-visibilitiy/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/12-visibilitiy/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/12-visibilitiy/+page.md diff --git a/courses/vyper-101/1-favorites/13-functions/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/13-functions/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/13-functions/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/13-functions/+page.md diff --git a/courses/vyper-101/1-favorites/14-func-visibility/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/14-func-visibility/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/14-func-visibility/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/14-func-visibility/+page.md diff --git a/courses/vyper-101/1-favorites/15-view-and-pure/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/15-view-and-pure/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/15-view-and-pure/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/15-view-and-pure/+page.md diff --git a/courses/vyper-101/1-favorites/16-constructor/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/16-constructor/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/16-constructor/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/16-constructor/+page.md diff --git a/courses/vyper-101/1-favorites/17-advanced-funcs/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/17-advanced-funcs/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/17-advanced-funcs/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/17-advanced-funcs/+page.md diff --git a/courses/vyper-101/1-favorites/18-ref-types/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/18-ref-types/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/18-ref-types/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/18-ref-types/+page.md diff --git a/courses/vyper-101/1-favorites/19-claude/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/19-claude/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/19-claude/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/19-claude/+page.md diff --git a/courses/vyper-101/1-favorites/2-best-practices/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/2-best-practices/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/2-best-practices/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/2-best-practices/+page.md diff --git a/courses/vyper-101/1-favorites/20-arrays-lists/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/20-arrays-lists/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/20-arrays-lists/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/20-arrays-lists/+page.md diff --git a/courses/vyper-101/1-favorites/21-idk/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/21-idk/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/21-idk/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/21-idk/+page.md diff --git a/courses/vyper-101/1-favorites/22-workshop/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/22-workshop/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/22-workshop/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/22-workshop/+page.md diff --git a/courses/vyper-101/1-favorites/23-hash-map/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/23-hash-map/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/23-hash-map/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/23-hash-map/+page.md diff --git a/courses/vyper-101/1-favorites/24-recap/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/24-recap/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/24-recap/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/24-recap/+page.md diff --git a/courses/vyper-101/1-favorites/25-tenderly/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/25-tenderly/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/25-tenderly/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/25-tenderly/+page.md diff --git a/courses/vyper-101/1-favorites/26-zksync/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/26-zksync/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/26-zksync/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/26-zksync/+page.md diff --git a/courses/vyper-101/1-favorites/27-share/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/27-share/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/27-share/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/27-share/+page.md diff --git a/courses/vyper-101/1-favorites/28-evm/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/28-evm/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/28-evm/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/28-evm/+page.md diff --git a/courses/vyper-101/1-favorites/29-pure-and-view/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/29-pure-and-view/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/29-pure-and-view/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/29-pure-and-view/+page.md diff --git a/courses/vyper-101/1-favorites/3-mox-best-practices/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/3-mox-best-practices/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/3-mox-best-practices/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/3-mox-best-practices/+page.md diff --git a/courses/vyper-101/1-favorites/30-conditionals/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/30-conditionals/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/30-conditionals/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/30-conditionals/+page.md diff --git a/courses/vyper-101/1-favorites/31-workshop-pt-2/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/31-workshop-pt-2/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/31-workshop-pt-2/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/31-workshop-pt-2/+page.md diff --git a/courses/vyper-101/1-favorites/32-recap-pt-2/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/32-recap-pt-2/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/32-recap-pt-2/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/32-recap-pt-2/+page.md diff --git a/courses/vyper-101/1-favorites/4-walkthrough/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/4-walkthrough/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/4-walkthrough/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/4-walkthrough/+page.md diff --git a/courses/vyper-101/1-favorites/5-welcome-to-remix/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/5-welcome-to-remix/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/5-welcome-to-remix/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/5-welcome-to-remix/+page.md diff --git a/courses/vyper-101/1-favorites/6-pragma-version/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/6-pragma-version/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/6-pragma-version/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/6-pragma-version/+page.md diff --git a/courses/vyper-101/1-favorites/7-comments/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/7-comments/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/7-comments/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/7-comments/+page.md diff --git a/courses/vyper-101/1-favorites/8-license/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/8-license/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/8-license/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/8-license/+page.md diff --git a/courses/vyper-101/1-favorites/9-compiling/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/9-compiling/+page.md similarity index 100% rename from courses/vyper-101/1-favorites/9-compiling/+page.md rename to courses/intro-python-vyper-smart-contract-development/1-favorites/9-compiling/+page.md diff --git a/courses/vyper-101/2-remix-coffee/1-introduction/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/1-introduction/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/1-introduction/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/1-introduction/+page.md diff --git a/courses/vyper-101/2-remix-coffee/10-chainlink-in-vyper/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/10-chainlink-in-vyper/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/10-chainlink-in-vyper/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/10-chainlink-in-vyper/+page.md diff --git a/courses/vyper-101/2-remix-coffee/11-abi/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/11-abi/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/11-abi/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/11-abi/+page.md diff --git a/courses/vyper-101/2-remix-coffee/12-in-line-inter/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/12-in-line-inter/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/12-in-line-inter/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/12-in-line-inter/+page.md diff --git a/courses/vyper-101/2-remix-coffee/13-staticcall/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/13-staticcall/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/13-staticcall/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/13-staticcall/+page.md diff --git a/courses/vyper-101/2-remix-coffee/14-tenderly/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/14-tenderly/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/14-tenderly/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/14-tenderly/+page.md diff --git a/courses/vyper-101/2-remix-coffee/15-ai/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/15-ai/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/15-ai/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/15-ai/+page.md diff --git a/courses/vyper-101/2-remix-coffee/16-deploy-parameter/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/16-deploy-parameter/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/16-deploy-parameter/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/16-deploy-parameter/+page.md diff --git a/courses/vyper-101/2-remix-coffee/17-integer-precision/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/17-integer-precision/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/17-integer-precision/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/17-integer-precision/+page.md diff --git a/courses/vyper-101/2-remix-coffee/18-converting-types/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/18-converting-types/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/18-converting-types/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/18-converting-types/+page.md diff --git a/courses/vyper-101/2-remix-coffee/19-integer-division/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/19-integer-division/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/19-integer-division/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/19-integer-division/+page.md diff --git a/courses/vyper-101/2-remix-coffee/2-setup/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/2-setup/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/2-setup/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/2-setup/+page.md diff --git a/courses/vyper-101/2-remix-coffee/20-as-wei-value/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/20-as-wei-value/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/20-as-wei-value/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/20-as-wei-value/+page.md diff --git a/courses/vyper-101/2-remix-coffee/21-send-eth-in-tx/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/21-send-eth-in-tx/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/21-send-eth-in-tx/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/21-send-eth-in-tx/+page.md diff --git a/courses/vyper-101/2-remix-coffee/22-contract-to-contract/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/22-contract-to-contract/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/22-contract-to-contract/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/22-contract-to-contract/+page.md diff --git a/courses/vyper-101/2-remix-coffee/23-getting-revert/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/23-getting-revert/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/23-getting-revert/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/23-getting-revert/+page.md diff --git a/courses/vyper-101/2-remix-coffee/24-msg-sender/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/24-msg-sender/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/24-msg-sender/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/24-msg-sender/+page.md diff --git a/courses/vyper-101/2-remix-coffee/25-withdraw-eth/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/25-withdraw-eth/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/25-withdraw-eth/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/25-withdraw-eth/+page.md diff --git a/courses/vyper-101/2-remix-coffee/26-dynamic-vs-fixed-array/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/26-dynamic-vs-fixed-array/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/26-dynamic-vs-fixed-array/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/26-dynamic-vs-fixed-array/+page.md diff --git a/courses/vyper-101/2-remix-coffee/27-resetting-array/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/27-resetting-array/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/27-resetting-array/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/27-resetting-array/+page.md diff --git a/courses/vyper-101/2-remix-coffee/28-plus-equals/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/28-plus-equals/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/28-plus-equals/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/28-plus-equals/+page.md diff --git a/courses/vyper-101/2-remix-coffee/29-for-loops/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/29-for-loops/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/29-for-loops/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/29-for-loops/+page.md diff --git a/courses/vyper-101/2-remix-coffee/3-doc-strings/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/3-doc-strings/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/3-doc-strings/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/3-doc-strings/+page.md diff --git a/courses/vyper-101/2-remix-coffee/30-tenderly_/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/30-tenderly_/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/30-tenderly_/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/30-tenderly_/+page.md diff --git a/courses/vyper-101/2-remix-coffee/31-idk/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/31-idk/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/31-idk/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/31-idk/+page.md diff --git a/courses/vyper-101/2-remix-coffee/32-natspec/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/32-natspec/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/32-natspec/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/32-natspec/+page.md diff --git a/courses/vyper-101/2-remix-coffee/33-update-immute/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/33-update-immute/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/33-update-immute/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/33-update-immute/+page.md diff --git a/courses/vyper-101/2-remix-coffee/34-magic/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/34-magic/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/34-magic/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/34-magic/+page.md diff --git a/courses/vyper-101/2-remix-coffee/35-gas/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/35-gas/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/35-gas/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/35-gas/+page.md diff --git a/courses/vyper-101/2-remix-coffee/36-fallback/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/36-fallback/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/36-fallback/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/36-fallback/+page.md diff --git a/courses/vyper-101/2-remix-coffee/37-better-way-to-send/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/37-better-way-to-send/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/37-better-way-to-send/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/37-better-way-to-send/+page.md diff --git a/courses/vyper-101/2-remix-coffee/38-recap/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/38-recap/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/38-recap/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/38-recap/+page.md diff --git a/courses/vyper-101/2-remix-coffee/4-sending-eth/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/4-sending-eth/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/4-sending-eth/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/4-sending-eth/+page.md diff --git a/courses/vyper-101/2-remix-coffee/5-gwei-wei-eth/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/5-gwei-wei-eth/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/5-gwei-wei-eth/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/5-gwei-wei-eth/+page.md diff --git a/courses/vyper-101/2-remix-coffee/6-send-tx/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/6-send-tx/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/6-send-tx/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/6-send-tx/+page.md diff --git a/courses/vyper-101/2-remix-coffee/7-reverts/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/7-reverts/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/7-reverts/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/7-reverts/+page.md diff --git a/courses/vyper-101/2-remix-coffee/8-chainlink/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/8-chainlink/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/8-chainlink/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/8-chainlink/+page.md diff --git a/courses/vyper-101/2-remix-coffee/9-mid-recap/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/9-mid-recap/+page.md similarity index 100% rename from courses/vyper-101/2-remix-coffee/9-mid-recap/+page.md rename to courses/intro-python-vyper-smart-contract-development/2-remix-coffee/9-mid-recap/+page.md diff --git a/courses/vyper-101/3-ai/1-intro/+page.md b/courses/intro-python-vyper-smart-contract-development/3-ai/1-intro/+page.md similarity index 100% rename from courses/vyper-101/3-ai/1-intro/+page.md rename to courses/intro-python-vyper-smart-contract-development/3-ai/1-intro/+page.md diff --git a/courses/vyper-101/3-ai/2-vid/+page.md b/courses/intro-python-vyper-smart-contract-development/3-ai/2-vid/+page.md similarity index 100% rename from courses/vyper-101/3-ai/2-vid/+page.md rename to courses/intro-python-vyper-smart-contract-development/3-ai/2-vid/+page.md diff --git a/courses/vyper-101/3-ai/3-triage/+page.md b/courses/intro-python-vyper-smart-contract-development/3-ai/3-triage/+page.md similarity index 100% rename from courses/vyper-101/3-ai/3-triage/+page.md rename to courses/intro-python-vyper-smart-contract-development/3-ai/3-triage/+page.md diff --git a/courses/vyper-101/3-ai/4-formatting-qs/+page.md b/courses/intro-python-vyper-smart-contract-development/3-ai/4-formatting-qs/+page.md similarity index 100% rename from courses/vyper-101/3-ai/4-formatting-qs/+page.md rename to courses/intro-python-vyper-smart-contract-development/3-ai/4-formatting-qs/+page.md diff --git a/courses/vyper-101/3-ai/5-workshop/+page.md b/courses/intro-python-vyper-smart-contract-development/3-ai/5-workshop/+page.md similarity index 100% rename from courses/vyper-101/3-ai/5-workshop/+page.md rename to courses/intro-python-vyper-smart-contract-development/3-ai/5-workshop/+page.md From 703e7c5e40fa9818e52a0792d123c7a868ccc1b1 Mon Sep 17 00:00:00 2001 From: hunter <104146303+solhosty@users.noreply.github.com> Date: Tue, 10 Dec 2024 14:12:18 -0500 Subject: [PATCH 255/255] hunter/remove-32-33 --- .../32-alchemy-mempool/+page.md | 82 ------------------- .../33-summary-congratulations/+page.md | 47 ----------- 2 files changed, 129 deletions(-) delete mode 100644 courses/foundry/1-foundry-simple-storage/32-alchemy-mempool/+page.md delete mode 100644 courses/foundry/1-foundry-simple-storage/33-summary-congratulations/+page.md diff --git a/courses/foundry/1-foundry-simple-storage/32-alchemy-mempool/+page.md b/courses/foundry/1-foundry-simple-storage/32-alchemy-mempool/+page.md deleted file mode 100644 index 03a1dcb3b..000000000 --- a/courses/foundry/1-foundry-simple-storage/32-alchemy-mempool/+page.md +++ /dev/null @@ -1,82 +0,0 @@ ---- -title: Alchemy & The Mempool ---- - -_Follow along the course with this video._ - - - ---- - -## Alchemy: A Game Changer for Decentralized Application Development - -Innovation in the blockchain industry has come a long way, with powerful tools making their way into the ecosystem to support developers and bring efficiency to their workflows. Among these tools is Alchemy, and today we have Vito, the lead developer experience at Alchemy, to walk us through the platform, its features, and how you can leverage it to exponentially increase your productivity. - -## What is Alchemy? - -Alchemy is a platform equipped with APIs, SDKs, and libraries to enhance your developer experience while working on Web3 projects. Think of Alchemy as the AWS of Web3. It functions as a node provider and developer tooling platform predominantly used in thousands of Web3 and Web2 applications, including large Web2 corporations like Adobe, Shopify, and Stripe. - -The need for platforms such as Alchemy arises from the fact that, as a developer, you don't usually have to worry about running the servers your code operates on or developing the deployment and integration pipelines for your application. Instead, you use services such as AWS, Azure, and Google Cloud for that—Alchemy does the same but for Web3. - -## How Does Alchemy Work? - -Alchemy enhances your developer experience through a combination of features. The platform's primary component is the _Supernode_, a proprietary blockchain engine that works as a load balancer on top of your node. - -Like its name suggests, the Supernode ensures data from the blockchain is always up-to-date and readily available. Using the Supernode as a foundation, Alchemy has built the _Enhanced APIs_—a set of APIs that makes pulling data from the blockchain a breeze. - -To put it simply, the Alchemy Supernode sits at the core of its ecosystem, powering up functionalities like Enhanced APIs and monitoring tools while supporting multiple chains. - -What follows is a step-by-step guide on how to create a new account on Alchemy and leverage this platform to its full extent: - -## Creating a New Account on Alchemy - -Creating an account on Alchemy is not only easy but also completely free. You can also freely scale your applications up using the platform's generous premium plans. - -#### Step 1: Navigate to Alchemy.com - -Head over to [Alchemy.com](https://www.alchemy.com/) and create a new account. - -#### Step 2: Create a New Application - -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 -- Polygon zkEVM -- Optimism -- Arbitrum -- Solana (non-EVM chain) - -## The Application-Specific Dashboard - -Once your application is up and running, you will have access to the application-specific dashboard. This dashboard provides crucial insights into your application and infrastructure health, such as latency, compute units, and transaction success rate, which can be valuable for debugging and identifying issues. - -If you observe a lower success rate for your transactions, go to the "Recent Invalid Request" tab. This will list all unsuccessful requests along with the reasons for their failure, making it easier for you to debug and fix issues. - -::image{src='/foundry/22-alchemy/alchemy1.png' style='width: 100%; height: auto;'} - -## Mempool Watcher - -Another powerful tool provided by Alchemy is the Mempool watcher. Picture it as Ethereum's mempool, where all pending transactions reside waiting for validation or mining. - -The Mempool watcher provides extensive details about your transactions, such as: - -- Transaction status (mined, pending, dropped, replaced) -- Gas used -- Time taken for validation -- Transaction value -- Sender's and receiver's address - -This detailed transaction tracking allows you to have a better understanding of each transaction and aids immensely in debugging specific issues related to individual transactions. - -## Wrapping Up - -To sum up, Alchemy is a revolutionary platform that brings a plethora of tools to aid your Web3 development experience. From Supernode to Enhanced APIs and crucial troubleshooting tools, Alchemy is undeniably a game changer in the world of decentralized applications. - -"Alchemy can be a powerful asset to any blockchain developer, offering a simplified experience in an inherently complicated Web3 environment." – Vito, Lead Developer Experience at Alchemy. - -Vito suggests that you check out Alchemy's [documentation](https://docs.alchemy.com/) to explore more about the platform, its APIs, SDKs, libraries, and tools. Also, don't forget to follow them on Twitter at [@AlchemyPlatform](https://twitter.com/alchemyplatform) and [@AlchemyLearn](https://twitter.com/alchemyLearn). And if you want to connect directly with Vito, feel free to reach out to him on Twitter at [@VitoStack](https://twitter.com/VittoStack). - -Alchemy is revolutionizing the landscape of blockchain development and making it more accessible and efficient for everyone involved. Happy building with Alchemy! diff --git a/courses/foundry/1-foundry-simple-storage/33-summary-congratulations/+page.md b/courses/foundry/1-foundry-simple-storage/33-summary-congratulations/+page.md deleted file mode 100644 index fdffe8891..000000000 --- a/courses/foundry/1-foundry-simple-storage/33-summary-congratulations/+page.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -title: Summary & Congratulations ---- - -_Follow along the course with this video._ - - - ---- - -## Celebrating Milestones in Foundry: A Complete Walkthrough of Our Recent Project - -You should feel a warm sense of accomplishment envelop you. Completing an entire project in Foundry is no mean feat. A hearty congratulation is in order for such an indomitable effort. This article serves as a quick, yet comprehensive, recap of everything we learnt in our project, proceeding into our next engagement. From the onset, rest assured, we are set to advance our Foundry skills, push upcoming projects on GitHub, and familiarize ourselves with advanced tooling. - -## A Quick Trip Down Memory Lane: Key Takeaways from the Project - -Firstly, we journeyed through the process of creating a new Foundry project using Forge and Knit. These essential tools afforded us a structured, professional environment complete with folders to keep our work organized. - -We not only learnt about Foundry’s basic commands but also their specific functionalities such as: - -- **Cast**: interacts with contracts that have been previously deployed. -- **Forge**: compiles and interacts with our contracts. -- **Anvil**: deploys a local blockchain, similar to another tool we used, Ganache. - -A pivotal part of our learning process was comprehending that sending a transaction via our MetaMask is tantamount to making an HTTP post request to a particular RPC URL. A similar RPC URL can be obtained from a node-as-a-service provider like [Alchemy](https://www.alchemyapi.io/) and used to send transactions directly from our Foundry projects. - -We obtained practical knowledge on how to compile code in Foundry and write a Solidity script for its subsequent deployment. We also find it critical to ensure the security of our private keys. Hence, throughout this course, we will be using an `.env` file. But be warned when dealing with real money, having your private key in plain text is not advisable. - -## 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. - -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. - -```bash -forge format my_contract.sol -``` - -::image{src='/foundry/23-summary/summary1.png' style='width: 100%; height: auto;'} - -## Looking Ahead - -With these tools in your web development arsenal, you've performed exceptionally well – and yes, you should be incredibly proud. Remember, even something as small as installing tools like `Vs code` and `Foundry` can pose great difficulties, so, you're doing fantastic. - -Take a breather. Remember, breaks enhance productivity. Till next time, continue to strive for greatness in every line of code you write! - -::image{src='/foundry/23-summary/summary2.png' style='width: 100%; height: auto;'}