Skip to content

Commit

Permalink
📝 4-2 done.
Browse files Browse the repository at this point in the history
  • Loading branch information
0xfps committed May 16, 2024
1 parent 93c8f36 commit df61707
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# `uint8`, `uint128`, `uint256`

Unsigned integers are stored in memory based on the size of bytes they have. While sm all uint values like uint8 have 1 byte, uint256 has 32 bytes. Solidity's storage is designed in such a way that it can contain up to 32 bytes of value in one slot. In a situation where a variable doesn't contain up to 32 bytes, the value is stored and the next variable will be **packed** into the same slot, on the condition that when the bytes are added to the slot, it doesn't exceed 32 bytes.
Unsigned integers are stored in memory based on the size of bytes they have. The size of `uint[n]` bytes can be realized by dividing `[n]` by 8, meaning that, while small `uint[n]` values like `uint8` have 1 byte, `uint256` has 32 bytes. Solidity's storage is designed in such a way that it can contain up to 32 bytes of value in one slot. In a situation where a variable doesn't contain up to 32 bytes, the value is stored and the next variable will be **packed** into the same slot, on the condition that when the bytes are added to the slot, it doesn't exceed 32 bytes.


`uint256` => 32 bytes => Slot 0. <br>
`uint256` => 32 bytes => Slot 0.

This is the maximum, hence it occupies an entire slot of its own. Whatever bytes we are going to add will exceed 32 and hence, will pick up the next slot, slot 1.

`uint128` => 16 bytes => Slot 1. We still have 16 bytes left to be filled. <br>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Custom Types

A custom type or a user-defined value type allows you to create an alias of a native type in Solidity. This alias, will inherit and act as if it is the original type. It is defined by using the `type C is V syntax`, where `C` is the custom type, and `V` is the native type. To convert from the underlying type to the custom type, `C.wrap(<value>)` is used, and to convert from the custom type to the native underlying type, `C.unwrap(<value>)` is used [[6](https://docs.soliditylang.org/en/latest/types.html#user-defined-value-types)].

Custom types behave like their underlying types.

```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
contract Yul {
type CustomTypeUint8 is uint8; // Will behave like uint8.
type CustomTypeUint256 is uint256; // Will behave like uint256.
type CustomTypeInt128 is int128; // Will behave like int128.
type CustomTypeAddress is address; // Will behave like address.
type CustomTypeBytes4 is bytes4; // Will behave like bytes4.
type CustomTypeBytes32 is bytes32; // Will behave like bytes32.
// Slot 0.
CustomTypeUint256 public customType = CustomTypeUint256.wrap(12000);
// Slot 1.
uint256 public underlyingType = CustomTypeUint256.unwrap(customType);
function getCustomType() public view returns (bytes32) {
assembly {
mstore(0x80, sload(0x00))
return(0x80, 0x20)
}
}
function getUnderlyingType() public view returns (bytes32) {
assembly {
mstore(0x80, sload(0x01))
return(0x80, 0x20)
}
}
}
```

> 🚨 You cannot define custom types for `bytes` and `string`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# `uint8[]`, `uint128[]`, `uint256[]`

Up till now, we've learnt about individual data types in Solidity and how they are stored in storage. Before we proceed to their array counterparts, we would want to go over how arrays are viewed in Solidity storage generally. This view is applied to all other types.

Solidity recognizes two types of arrays, the fixed length array and the dynamic array. These two array types are
treated differently by Solidity.

## Fixed Arrays, `<type>[n]`

Solidity views `<type>[n]` array elements as individual values. Which means that, these values are treated as if they
were
not in an array. If a `uint256[5]` array has 5 elements, they will occupy 5 slots, in their correct places.

```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
contract Yul {
// Slots 0 - 4.
uint256[5] public fixedArray;
// Slot 5.
uint8[6] public fixedSmallArray;
}
```
In the code above, the `fixedArray` variable occupies 5 slots. This is because, it contains 5 `uint256` values. In
Solidity, because the length of the array is fixed (in this case, 5), Solidity knows how much in storage to allocate
for the storage of each individual value. It is seen as if they're 5 `uint256` values kept side by side.

The `fixedSmallArray` occupies one slot, because, as explained, it will be seen as 6 `uint8` values kept side by
side and they, like we have already discussed, will be packed into one slot.

## Dynamic Arrays, `<type>[]`

Dynamic arrays are stored just like fixed arrays, when it comes to packing, but in terms of knowing **where** in
storage to store the array, a little bit of calculation is done. Because the length is dynamic, Solidity does not
know how much space to allocate for the storage, therefore, the storage of a dynamic array starts at `keccak256(slot)
`. Meaning that, if a dynamic array is declared at slot 0, the first element will be found `keccak256(0)`.

To read the value of the other array elements from storage, they will be obtained by loading the storage at
`keccak256(slot) + elementIndex`. Meaning that, if we had the above dynamic array that grew to 10 elements, and we
would
like to retrieve the value of the 9th element, it would be found at `keccak256(0) + 9`.

```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
contract Yul {
// Slot 0.
uint256[] public dynamicArray;
// Slot 1.
uint8[] public dynamicSmallArray;
}
```

The values of the elements in the dynamicArray variable can be found at `keccak256(0) + elementIndex`. While the
values for the `dynamicSmallArray` will be found at `keccak256(1)`, we didn't add any `elementIndex` here because
the elements of `dynamicSmallArray` will be packed in one slot because they're `uint8` and will be packed. If they are
more than enough to fit into the next slot, then, we can load the next storage location.

## General `<type>[]` Deduction.

Once the concept of type storages is understood, you can use that to figure out how the array versions of that type
will be stored.

You can use the knowledge of arrays to write to any array index, or read from an array index.

To retrieve an element from a packed array is quite trick and is not readily advised.

> 🚨 The use of Yul to read and write arrays is not advised. It is a very tricky business.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# `int8[]`, `int128[]`, `int256[]`

Combine the knowledge of [int8, int128 and int256](4-2-2-int8-int128-int256.md) with [arrays](4-2-11-uint8%5B%5D-uint128%5B%5D-uint256%5B%5D.md).
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# `bytes1[]`, `bytes16[]`, `bytes32[]`

Combine the knowledge of [bytes1, bytes16, bytes32](4-2-3-bytes1-bytes16-bytes32.md) with [arrays](4-2-11-uint8%5B%5D-uint128%5B%5D-uint256%5B%5D.md).
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# `bytes[]`

Combine the knowledge of [bytes](4-2-4-bytes.md) with [arrays](4-2-11-uint8%5B%5D-uint128%5B%5D-uint256%5B%5D.md).
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# `string[]`

Combine the knowledge of [string](4-2-5-string.md) with [arrays](4-2-11-uint8%5B%5D-uint128%5B%5D-uint256%5B%5D.md).
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# `address[]`

Combine the knowledge of [address](4-2-6-address.md) with [arrays](4-2-11-uint8%5B%5D-uint128%5B%5D-uint256%5B%5D.md).
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# `Custom Types[]`

Combine the knowledge of [Custom Types](4-2-10-custom-types.md) with [arrays](4-2-11-uint8%5B%5D-uint128%5B%5D-uint256%5B%5D.md).
10 changes: 9 additions & 1 deletion book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,12 @@
- [address](4-yul-implementations/4-2-variable-storage-in-storage/4-2-6-address.md)
- [struct](4-yul-implementations/4-2-variable-storage-in-storage/4-2-7-struct.md)
- [mapping](4-yul-implementations/4-2-variable-storage-in-storage/4-2-8-mapping.md)
- [enum](4-yul-implementations/4-2-variable-storage-in-storage/4-2-9-enum.md)
- [enum](4-yul-implementations/4-2-variable-storage-in-storage/4-2-9-enum.md)
- [Custom Types](4-yul-implementations/4-2-variable-storage-in-storage/4-2-10-custom-types.md)
- [uint8[], uint128[], uint256[]](4-yul-implementations/4-2-variable-storage-in-storage/4-2-11-uint8%5B%5D-uint128%5B%5D-uint256%5B%5D.md)
- [int8[], int128[], int256[]](4-yul-implementations/4-2-variable-storage-in-storage/4-2-12-int8%5B%5D-int128%5B%5D-int256%5B%5D.md)
- [bytes1[], bytes16[], bytes32[]](4-yul-implementations/4-2-variable-storage-in-storage/4-2-13-bytes1%5B%5D-bytes16%5B%5D-bytes32%5B%5D.md)
- [bytes[]](4-yul-implementations/4-2-variable-storage-in-storage/4-2-14-bytes%5B%5D.md)
- [string[]](4-yul-implementations/4-2-variable-storage-in-storage/4-2-15-string%5B%5D.md)
- [address[]](4-yul-implementations/4-2-variable-storage-in-storage/4-2-16-address%5B%5D.md)
- [Custom Types[]](4-yul-implementations/4-2-variable-storage-in-storage/4-2-17-custom-types%5B%5D.md)

0 comments on commit df61707

Please sign in to comment.