Last active
July 17, 2022 04:08
-
-
Save PedroCailleret/e95ce73a9c2f6b9df2768feb15d0fe5b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // SPDX-License-Identifier: AGPL-3.0-only | |
| pragma solidity 0.8.4; | |
| /// @author 0xtr4um4 | |
| /// @notice This is a quick demo on how to read custom types (enum) of a struct | |
| /// nested in a mapping from storage using assembly when considering read value | |
| /// to be fetched through not tightly packed/optimized storage slots. | |
| contract AssemblySructGetter { | |
| enum ERC721Type // uint8 => max value: 255 bits = (2^8 - 1) | |
| { | |
| ERC721Minimal, // == 0 | |
| ERC721Basic, // == 1 | |
| ERC721Whitelist, // == 2 | |
| ERC721Lazy // == 3 | |
| } | |
| // Ideally we should pack the storage slots to leave last 20 bytes (address) for last; | |
| // but since we are reaching for irregular struct storage reads (i.e., assymetric storage | |
| // slot distribution), we `shr` by 160 bits (20 bytes for the type) and 1 (`uint8` value | |
| // returned from enum type) should follow next. With regularly distributed struct | |
| // storage slots (32 bytes delimited), adding the storage location to itself | |
| // up to the desired point with `and(sload(add(col.slot, 2))` is possible. | |
| struct Collection { | |
| address creator; // 20 bytes = 160 bits | |
| ERC721Type colType; // 32 bytes = 256 bits | |
| bytes32 colSalt; // {...} | |
| uint256 blocknumber; // {...} | |
| } | |
| // passing in uint256 to fill an entire 32 bytes slot | |
| mapping(uint256 => Collection) private colInfo; | |
| constructor() { | |
| bytes32 tokenSalt = keccak256(bytes("string")); | |
| colInfo[255] = Collection( | |
| msg.sender, | |
| ERC721Type.ERC721Basic, // 8 bit value | |
| tokenSalt, | |
| block.number | |
| ); | |
| } | |
| /// @dev Cost: 23756 gas | |
| function yulTypeCheck() external view returns(address creator, uint8 pointer /* ERC721Type pointer*/) { | |
| Collection storage col = colInfo[255]; | |
| assembly { | |
| let x := sload(col.slot) | |
| creator := and(x, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) | |
| pointer := shr(160, x) | |
| } | |
| } | |
| /// @dev Cost: 24021 gas | |
| function saneTypeCheck() external view returns(address creator, uint8 pointer) { | |
| Collection storage col = colInfo[255]; | |
| creator = address(col.creator); | |
| pointer = uint8(col.colType); | |
| return (creator, pointer); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment