Skip to content
This repository has been archived by the owner on Dec 3, 2024. It is now read-only.

Namespace storage #191

Merged
merged 33 commits into from
Jul 18, 2024
Merged

Conversation

minghinmatthewlam
Copy link

@minghinmatthewlam minghinmatthewlam commented Jul 11, 2024

Why this should be merged

Fixes #185

How this works

Adds namespace storage to all contracts according to ERC7201. Namespace storage helps prevent collision between storage of different logic contracts when used in the context of upgradeable contracts and proxies.

Changes:

  • all state variables are added to the contract's storage struct
  • the storage struct is specified a specific storage slot with @custom:storage-location according to erc7201
  • private variable for getting back the storage location
  • private getter function and assembly to save storage struct inside $ struct

How this was tested

CI
TODO: should ideally have unit tests to make sure that the storage location are computed correctly.

How is this documented

TBD

@minghinmatthewlam minghinmatthewlam marked this pull request as ready for review July 11, 2024 21:40
@minghinmatthewlam minghinmatthewlam requested a review from a team as a code owner July 11, 2024 21:40
}

// solhint-disable-next-line func-name-mixedcase
function __ERC20TokenRemote_init(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also just for my own understanding: is the only benefit of creating the __ERC20TokenRemote_init internal function and calling it from initialize to support contracts that may inherit from this contract in the future?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup mostly it, and also to keep a convention for upgradeable contracts

struct TokenRemoteStorage {
/// @notice The blockchain ID of the chain this contract is deployed on.
bytes32 _blockchainID;
/// @notice The blockchain ID of the TokenHome instance this contract receives tokens from.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also spacing nit here, what do think of including the empty newline between these state variables like we had before? Makes it a bit easier to read IMO

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's getting autoformatted being the types are in a struct, going to leave it for now.

// solhint-disable no-console
import {console2} from "forge-std/console2.sol";

contract ComputeSlotTest is Test {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thoughts on making the storage slot variables public for the sake of both making them easy to unit test?

@@ -205,6 +227,41 @@ abstract contract TokenRemote is ITokenRemote, TeleporterOwnerUpgradeable, SendR
// Right-shift by 5 bits to divide by 32.
return (payloadSize + 31) >> 5;
}

function getIsCollateralized() public view returns (bool) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thoughts on remove the "get" prefix on some/all of these public getters? isCollateralized() in particular seems fully descriptive already. Removing "get" may make them feel a bit closer to standard public state variable getters, but I don't have strong feelings either way.

Copy link
Collaborator

@michaelkaplan13 michaelkaplan13 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super excited to have this place.

I had a few questions and minor nits. Only high level question I have is if using namespace storage has any significant impact on the gas costs of the function calls? I wouldn't expect so, but I'm not 100% sure if those lookups/writes are handled differently under the hood.

Update: Thinking through it a bit more, it seems like state lookups will have one additional read (first read the STORAGE_SLOT variable value, then read the intended variable, rather than just reading the intended variable directly). Writes now require an additional read first also (need to lookup STORAGE_SLOT) prior to knowing where to write the value. These additional reads should hopefully be somewhat limited by the fact that the STORAGE_SLOT value can be reused for future reads/writes once it has been read into memory once in a function call.

Copy link
Contributor

@bernard-avalabs bernard-avalabs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally makes sense to me. It is interesting to learn about how ERC7201 works. Does this change affect any of our existing smart contract analysis tools?

@minghinmatthewlam minghinmatthewlam merged commit 80cb00e into upgradeable-poc-merge Jul 18, 2024
6 of 9 checks passed
@minghinmatthewlam minghinmatthewlam deleted the namespace-storage branch July 18, 2024 18:35
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

4 participants