Skip to content

Commit

Permalink
📝 Finalize first review.
Browse files Browse the repository at this point in the history
  • Loading branch information
0xfps committed Jun 9, 2024
1 parent bbdff4b commit 9fc146f
Show file tree
Hide file tree
Showing 22 changed files with 72 additions and 118 deletions.
90 changes: 23 additions & 67 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,79 +1,35 @@
## Yul By Example
# Yul By Example

Basically, we made [Solidity by example](https://solidity-by-example.org/) but for Yul :)<br><br>
**Required Solidity Version**: v0.8.17.<br>
**Required SPDX-License-Identifier**: MIT
---

```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
To see the book change live run:

```sh
mdbook serve
contract Yul {
function yulFunction() public {
assembly {
mstore(0x40, "Yul By Example.")
}
}
}
```

To run the book with docker, run:
## Source Code
book/src

## Book URL
🔗 https://yul-by-example.vercel.app/

## Run Book Locally
To run a copy of this book locally on your device, clone the repo and install `mdbook` via cargo (that comes with Rust). If you don't have Rust installed in your PC, you can download and setup Rust [here](https://www.rust-lang.org/).

### Contracts Implemented so far
- [Array](/src/Array.sol)
- [Bitwise](/src/Bitwise.sol)
- [Call](/src/Call.sol)
- [Calldata](/src/Calldata.sol)
- [Conditionals](/src/Conditionals.sol)
- [Counter](/src/Counter.sol)
- [Enums](/src/Enums.sol)
- [Errors](/src/Errors.sol)
- [Ether Wallet](/src/EtherWallet.sol)
- [Events](/src/Events.sol)
- [FallBack](/src/Fallback.sol)
- [For Loop](src/ForLoop.sol)
- [Functions](src/Functions.sol)
- [Hash](src/Hash.sol)
- [Hello World](/src/HelloWorld.sol)
- [IsContract](/src/IsContract.sol)
- [Mapping](/src/Mapping.sol)
- [Send Ether](/src/SendEther.sol)
- [Signature Verification](/src/SignatureVerification.sol)
- [Simple Storage](/src/SimpleStorage.sol)
- [Structs](/src/Structs.sol)
- [Types](/src/Types.sol)
- [Unchecked](/src/Unchecked.sol)
- [ERC20](/src/YulERC20.sol)
To install `mdbook`, you can refer to [this](https://rust-lang.github.io/mdBook/guide/installation.html).

### Docs
- [Array](/book/src/Array.md)
- [Bitwise](/book/src/Bitwise.md)
- [Call](/book/src/Call.md)
- [Calldata](/book/src/Calldata.md)
- [Conditionals](/book/src/Conditionals.md)
- [Counter](/book/src/Counter.md)
- [Enums](/book/src/Enums.md)
- [Errors](/book/src/Errors.md)
- [Ether Wallet](/book/src/EtherWallet.md)
- [Events](/book/src/Events.md)
- [Fallback](/book/src/Fallback.md)
- [For Loop](/book/src/ForLoop.md)
- [Functions](/book/src/Functions.md)
- [Hash](/book/src/Hash.md)
- [Hello World](/book/src/HelloWorld.md)
- [Is Contract](/book/src/IsContract.md)
- [Mapping](/book/src/Mapping.md)
- [Safe Operations](/book/src/SafeOperations.md)
- [Send Ether](/book/src/SendEther.md)
- [Signature Verification](/book/src/SignarureVerification.md)
- [Simple Storage](/book/src/SimpleStorage.md)
- [Structs](/book/src/Structs.md)
- [Types](/book/src/Types.md)
- [Unchecked](/book/src/Unchecked.md)
- [Yul ERC20](/book/src/YulERC20.md)
To display the book on your browser, run `mdbook serve book/ -o` from the base directory.

## Contributors ✨

<a href="https://github.com/Perelyn-sama/yul_by_example/graphs/contributors">
<img src="https://contrib.rocks/image?repo=Perelyn-sama/yul_by_example" />
</a>

### Acknowledgements

These contracts were inspired by or directly modified from many sources, primarily:
- [RareSkills](https://github.com/RareSkills/Udemy-Yul-Code)
- [Solidity By Example](https://solidity-by-example.org/)
</a>
2 changes: 1 addition & 1 deletion book/book/1-introduction/1-1-introduction.html
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ <h1 id="introduction"><a class="header" href="#introduction">Introduction</a></h
<p>Hello there!</p>
<p>This is a book about Yul, a low-level, intermediate language written alongside Solidity that can be compiled to bytecode for different backends [<a href="https://docs.soliditylang.org/en/latest/yul.html#yul">1</a>].</p>
<p>Over the course of this book, we are going to go through what Yul is, why it is important, its advantage and disadvantage over Solidity and its implementations in a smart contract.</p>
<p>Also, we will see how storage and memory are laid out in Solidity and how we would harness the power of Yul to infiltrate and modify to our taste.</p>
<p>Also, we will see how storage and memory are laid out in Solidity and how we would harness the power of Yul to infiltrate and modify these to our taste.</p>
<p>Enjoy!</p>

</main>
Expand Down
2 changes: 1 addition & 1 deletion book/book/1-introduction/1-2-what-is-yul.html
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ <h1 id="what-is-yul"><a class="header" href="#what-is-yul">What Is Yul?</a></h1>
low-level language that gives developers a high degree of control over the execution of their smart contracts. It is
similar in many ways to Assembly but with higher-level features that make it easier to work with [<a href="https://www.quicknode.com/guides/ethereum-development/smart-contracts/what-is-yul#what-is-yul">2</a>].</p>
<p>Yul was previously called <strong>Julia</strong> or <strong>Iulia</strong>.</p>
<p>Within the context of smart contract development, Yul is usually referred to as <strong>Inline Assembly</strong>. As it is very
<p>Within the context of smart contract development, Yul is usually referred to as <strong>Inline Assembly</strong>, as it is very
similar to Assembly and is written within functions in smart contract code.</p>

</main>
Expand Down
4 changes: 2 additions & 2 deletions book/book/1-introduction/1-3-why-is-yul-important.html
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,9 @@ <h1 class="menu-title">Yul By Example</h1>
<main>
<h1 id="why-is-yul-important"><a class="header" href="#why-is-yul-important">Why Is Yul Important?</a></h1>
<hr />
<p>During smart contract development process, there are actions, or manipulations which are not feasible for the
<p>During the smart contract development process, there are actions, or manipulations which are not feasible for the
programmer from the high-level Solidity code. Using Yul, the programmer is given much more fine-grained control over
the storage, memory and in some cases calldata layout of the EVM. This control also allows for much more gas efficient code to be written.</p>
the storage, memory and in some cases <code>calldata</code> layout of the EVM. This control also allows for much more gas efficient code to be written.</p>
<p>The flexibility and gas optimization of Yul are what makes it important.</p>

</main>
Expand Down
2 changes: 1 addition & 1 deletion book/book/1-introduction/1-4-yul's-advantages.html
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ <h1 class="menu-title">Yul By Example</h1>
<main>
<h1 id="yuls-advantage"><a class="header" href="#yuls-advantage">Yul's Advantage</a></h1>
<hr />
<p>As stated in the <a href="1-3-why-is-yul-important.html">previous chapter</a>, the ability to manipulate the storage, memory or calldata layout to the programmer's taste with an extra benefit of much more gas optimized code is Yul's major advantage over Solidity.</p>
<p>As stated in the <a href="1-3-why-is-yul-important.html">previous chapter</a>, the ability to manipulate the storage, memory or <code>calldata</code> layout to the programmer's taste with an extra benefit of much more gas optimized code is Yul's major advantage over high-level Solidity.</p>

</main>

Expand Down
2 changes: 1 addition & 1 deletion book/book/1-introduction/1-6-code-layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ <h1 id="code-layout"><a class="header" href="#code-layout">Code Layout</a></h1>
<hr />
<p>Every piece of Yul code written here can be rerun on <a href="https://remix.ethereum.org/">Remix</a>.</p>
<p>Remix is an online smart contract development suite. It also offers a way of observing the process of EVM layouts and storage. It will be used over the course of this book, and you can replicate whatever we have done here on the suite.</p>
<p>It is also recommended that you keep <a href="https://evm.codes">evm.codes</a> handy over your course of learning and practising Yul, and even after you've understood. It is a magnificent resource.</p>
<p>It is also recommended that you keep <a href="https://evm.codes">evm.codes</a> handy over your course of learning and practising Yul, and even after you've understood the language. It is a magnificent resource.</p>

</main>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,23 +177,23 @@ <h1 id="soliditys-storage-and-memory-layout"><a class="header" href="#soliditys-
<hr />
<p>We have understood what the storage and memory are. Persistent and temporary, respectively. Now we are going to take a look at how these two data storage locations are laid out.</p>
<h3 id="storage"><a class="header" href="#storage">Storage</a></h3>
<p>Solidity's storage layout has a finite amount of space, which is broken down into 32-byte groups called <code>slots</code>, and each slot can hold a 256-bit value. These slots start from index 0 and can stretch to a theoretical index limit of somewhere around <code>(2^256) - 1</code>. It is safe to say that the storage can never get full. Cool, isn't it?</p>
<p>Solidity's storage layout has a finite amount of space, which is broken down into 32-byte groups called <code>slots</code>, and each slot can hold a 256-bit value. These slots start from index 0 and can stretch to an index limit of <code>(2^256) - 1</code>. It is safe to say that the storage can never get full. Cool, isn't it?</p>
<p>Values stored in storage slots are stored as <code>bytes32</code> values, and sometimes, can be packed, as we will see later on in this book. To retrieve the value of a Solidity storage variable, the 32-byte value stored in the corresponding slot is retrieved. In some cases - when the value in the slot has been packed -, the value retrieved is worked on by methods of shifting or masking to retrieve the desired value.</p>
<blockquote>
<p>💡 Remember when we said one should know how the EVM works before moving on with Yul? Yeah, that's one of the reasons why. You cannot retrieve what you do not know how it was stored.</p>
</blockquote>
<h3 id="memory"><a class="header" href="#memory">Memory</a></h3>
<p>Solidity's memory layout, unlike the storage layout is quite tricky. While the storage has a defined maximum slot
index of
<code>(2 **256) - 1</code> that can hold 32-byte values, the memory is a large group of 32-byte slots that their data can not
<code>(2^256) - 1</code> that can hold 32-byte values, the memory is a large group of 32-byte slots that their data can not
be retrieved by passing a slot index. But instead, data stored in the memory are retrieved by picking
a particular location and returning a specific number of bytes from that point in the memory.</p>
<p>"Why?", you may ask, it is because the default number of bytes returned from any point in memory is <code>32</code> and in
cases where the point started from is the middle of a particular 32-byte slot, it will encroach into the next slot.</p>
<p>You can imagine memory slots as laid out end to end, in a way that data retrieval can be started from any point and
stopped at any point. Unlike storage that returns only the 32-bytes stored at an index, nothing more, nothing less.</p>
<p>If you do not understand that, do not
sweat it. You will get a better grasp of it when we talk about <a href="">variable storage in memory</a>.</p>
sweat it. You will get a better grasp of it when we talk about <a href="../4-yul-implementations/4-3-variable-storage-in-memory/4-3-0-variable-storage-in-memory.html">variable storage in memory</a> section.</p>
<p>These positions in memory start from <code>0x00</code> and are in groups of 32-bytes, meaning that the slots are in th is way:</p>
<p><code>0x00</code> - <code>0x1f</code> <br>
<code>0x20</code> - <code>0x3f</code> <br>
Expand All @@ -216,9 +216,8 @@ <h3 id="memory"><a class="header" href="#memory">Memory</a></h3>
storing in a memory location with existing data overwrites that location.</p>
</blockquote>
<blockquote>
<p>💡 The positions we will use over the course of this book to access memory points will be written in hexadecimals
(<code>0x**</code>)
as it's easier to read, since the EVM already deals in hexadecimals.</p>
<p>💡 The positions and values in memory that we will use over the course of this book to access memory points will be written in hexadecimals
(<code>0x**</code>) as they are easier to read, since the EVM already deals in hexadecimals.</p>
</blockquote>

</main>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ <h1 id="starting-yul-in-a-solidity-contract"><a class="header" href="#starting-y
}
</code></pre>
<blockquote>
<p>🚨 Yul does not recognize global variables, it only recognized local variables within functions, function parameters and named <code>return</code> variables.</p>
<p>🚨 Yul does not recognize Solidity global or state variables, it only recognized local variables within functions, function parameters and named <code>return</code> variables.</p>
</blockquote>

</main>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ <h1 class="menu-title">Yul By Example</h1>
<main>
<h1 id="variable-storage-in-storage"><a class="header" href="#variable-storage-in-storage">Variable Storage In Storage</a></h1>
<hr />
<p>Solidity stores variables declared globally in storage. The storage is made up of slots, as we've discussed earlier. In this section we will look at how different data types are stored in Solidity's storage. Some are packed and some are greedy enough to take up a full slot without sharing.</p>
<p>Solidity stores variables declared globally, otherwise known as state variables in storage. The storage is made up of slots, as we have discussed earlier. In this section we will look at how different data types are stored in Solidity's storage. Some are packed and some are greedy enough to take up a full slot without sharing.</p>
<p>You can head into the start of the section at <a href="4-2-1-uint8-uint128-uint256.html">uint8, uint128, uint256</a>.</p>

</main>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ <h3 id="single-uint8-value"><a class="header" href="#single-uint8-value">Single
<blockquote>
<p><code>return(position, size)</code></p>
</blockquote>
<p>If we called the <code>getUint8</code> function to return a <code>uint8</code>, Solidity will handle the conversion for us and we will see <code>16</code> returned. However, we will be returning in bytes32 over the course of this book to understand the actual storage and memory layouts of the EVM.</p>
<p>If we called the <code>getUint8</code> function to return a <code>uint8</code>, Solidity will handle the conversion for us and we will see <code>16</code> returned. However, we will be returning in <code>bytes32</code> over the course of this book to understand the actual storage and memory layouts of the EVM.</p>
<p>Calling the <code>getUint8</code> function will return <code>0x0000000000000000000000000000000000000000000000000000000000000010</code>, which when converted to decimal, equals to <code>16</code>, the value we stored.</p>
<p>To get a glimpse of Solidity doing the automatic conversion of <code>bytes32</code> to <code>uint8</code>, we can rewrite the code to this:</p>
<pre><code class="language-solidity">// SPDX-License-Identifier: GPL-3.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ <h1 class="menu-title">Yul By Example</h1>
<main>
<h1 id="int8-int128-int256"><a class="header" href="#int8-int128-int256"><code>int8</code>, <code>int128</code>, <code>int256</code></a></h1>
<hr />
<p>While <code>uint[n]</code> types can only contain positive integers, the <code>int[n]</code> types can contain both positive and negative numbers. As you know, <code>int[n]</code> variables store numbers ranging from <code>-1 -&gt; -(2 ^ (n-1))</code> on the negative side, and <code>0 -&gt; (2^n) - 1</code> on the positive side. This means that for the three <code>int[n]</code> types specified above, this would be their minimum and maximum values.</p>
<p>While <code>uint[n]</code> types can only contain positive integers, the <code>int[n]</code> types can contain both positive and negative numbers. As you know, <code>int[n]</code> variables store numbers ranging from <code>-1 -&gt; -(2 ^ (n-1))</code> on the negative side, and <code>0 -&gt; ((2^n) - 1)</code> on the positive side. This means that for the three <code>int[n]</code> types specified above, this would be their minimum and maximum values.</p>
<div class="table-wrapper"><table><thead><tr><th><strong><code>int[n]</code> type</strong></th><th><strong>Minimum Value</strong></th><th><strong>Maximum Value</strong></th></tr></thead><tbody>
<tr><td><code>int8</code></td><td>-128</td><td>127</td></tr>
<tr><td><code>int128</code></td><td>-2^127</td><td>(2^127) - 1</td></tr>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ <h1 id="bytes1-bytes16-bytes32"><a class="header" href="#bytes1-bytes16-bytes32"
</code></pre>
<p>This will return <code>0x00000000000000000000000000000000000000000000000000000000aabbccdd</code>.</p>
<p>Setting a <code>bytes[n]</code> variable in a function will right-pad it to 32 bytes. Whereas, directly assigning the variable in a Yul block or in storage will handle it normally by left padding it.</p>
<p>To get a knowledge of which type of <code>bytes[n]</code> does what, refer to <a href="../4-3-variable-storage-in-memory/4-3-3-bytes1-bytes16-bytes32.html#padding">this part of the book</a>.</p>
<h3 id="bytes16"><a class="header" href="#bytes16">bytes16</a></h3>
<pre><code class="language-solidity">// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,6 @@ <h3 id="storage-for-bytes-with-length-from-32-and-above"><a class="header" href=
32 bytes of the entire thing, while the remaining 8 bytes would be in the next slot, <code>keccak256(0) + 1</code></p>
<p>We're going to store a pretty long <code>bytes</code> value now.</p>
<pre><code class="language-solidity">// SPDX-License-Identifier: GPL-3.0
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;

contract MyContract {
Expand Down Expand Up @@ -332,7 +331,7 @@ <h3 id="storage-for-bytes-with-length-from-32-and-above"><a class="header" href=
it only contains values for the first 8 bytes. Using both data, we can see that our <code>bytes</code> value was spread out
across two storage slots. We can try to concatenate them and return all the bytes, but that would involve moving
them into memory, and then returning the proper ABI encoded memory data for the <code>bytes</code>. We would look at that when
we get to the <a href="">Variable Storage In Memory</a> section of this book.</p>
we get to the <a href="../4-3-variable-storage-in-memory/4-3-0-variable-storage-in-memory.html">Variable Storage In Memory</a> section of this book.</p>
<blockquote>
<p>💡 <code>bytes</code> and <code>string</code> share the same characteristics in storage and memory. The same way <code>bytes</code> are stored in
storage and memory, that is the same way <code>string</code> are stored. The only differences are that each <code>string</code> character is
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ <h1 class="menu-title">Yul By Example</h1>
<main>
<h1 id="struct"><a class="header" href="#struct"><code>struct</code></a></h1>
<hr />
<p>A <code>struct</code> is a group of data. The layout of a <code>struct</code> is identical to the layout of the data within a <code>struct</code>. The slots a <code>struct</code> would occupy is dependent on the types of variables within the struct. A struct with two uint256 types would occupy two slots.</p>
<p>A <code>struct</code> is a group of data. The layout of a <code>struct</code> is identical to the layout of the data within a <code>struct</code>. The slots a <code>struct</code> would occupy is dependent on the types of variables within the struct. A struct with two <code>uint256</code> types would occupy two slots.</p>
<pre><code class="language-solidity">// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ <h1 class="menu-title">Yul By Example</h1>
<main>
<h1 id="staticcall"><a class="header" href="#staticcall"><code>staticcall</code></a></h1>
<hr />
<p>The difference between <code>staticcall</code> and <code>delegatecall</code> is that <code>staticcall</code> makes calls to only <code>view</code> or <code>pure</code> functions.</p>
<p>The difference between <code>staticcall</code> and <code>delegatecall</code> is that <code>staticcall</code> makes calls to only <code>view</code> or <code>pure</code> functions. A <code>staticcall</code> will revert if it makes a call to a function in a smart contract that changes the state of that smart contract.</p>
<pre><code class="language-solidity">// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;

Expand Down
Loading

0 comments on commit 9fc146f

Please sign in to comment.