-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: remediations #6
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,18 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
// Sentinel address | ||
address constant SENTINEL = address(0x1); | ||
// Zero address | ||
address constant ZERO_ADDRESS = address(0x0); | ||
|
||
/** | ||
* @title SentinelListLib | ||
* @dev Library for managing a linked list of addresses | ||
* @author Rhinestone | ||
*/ | ||
library SentinelListLib { | ||
// Struct to hold the linked list | ||
struct SentinelList { | ||
mapping(address => address) entries; | ||
} | ||
|
@@ -14,22 +22,48 @@ | |
error LinkedList_InvalidEntry(address entry); | ||
error LinkedList_EntryAlreadyInList(address entry); | ||
|
||
/** | ||
* Initialize the linked list | ||
* | ||
* @param self The linked list | ||
*/ | ||
function init(SentinelList storage self) internal { | ||
if (alreadyInitialized(self)) revert LinkedList_AlreadyInitialized(); | ||
self.entries[SENTINEL] = SENTINEL; | ||
} | ||
|
||
/** | ||
* Check if the linked list is already initialized | ||
* | ||
* @param self The linked list | ||
* | ||
* @return bool True if the linked list is already initialized | ||
*/ | ||
function alreadyInitialized(SentinelList storage self) internal view returns (bool) { | ||
return self.entries[SENTINEL] != ZERO_ADDRESS; | ||
} | ||
|
||
/** | ||
* Get the next entry in the linked list | ||
* | ||
* @param self The linked list | ||
* @param entry The current entry | ||
* | ||
* @return address The next entry | ||
*/ | ||
function getNext(SentinelList storage self, address entry) internal view returns (address) { | ||
if (entry == ZERO_ADDRESS) { | ||
revert LinkedList_InvalidEntry(entry); | ||
} | ||
return self.entries[entry]; | ||
} | ||
|
||
/** | ||
* Push a new entry to the linked list | ||
* | ||
* @param self The linked list | ||
* @param newEntry The new entry | ||
*/ | ||
function push(SentinelList storage self, address newEntry) internal { | ||
if (newEntry == ZERO_ADDRESS || newEntry == SENTINEL) { | ||
revert LinkedList_InvalidEntry(newEntry); | ||
|
@@ -39,6 +73,27 @@ | |
self.entries[SENTINEL] = newEntry; | ||
} | ||
|
||
/** | ||
* Safe push a new entry to the linked list | ||
* @dev This ensures that the linked list is initialized and initializes it if it is not | ||
* | ||
* @param self The linked list | ||
* @param newEntry The new entry | ||
*/ | ||
function safePush(SentinelList storage self, address newEntry) internal { | ||
if (!alreadyInitialized({ self: self })) { | ||
init({ self: self }); | ||
} | ||
push({ self: self, newEntry: newEntry }); | ||
} | ||
|
||
/** | ||
* Pop an entry from the linked list | ||
* | ||
* @param self The linked list | ||
* @param prevEntry The entry before the entry to pop | ||
* @param popEntry The entry to pop | ||
*/ | ||
function pop(SentinelList storage self, address prevEntry, address popEntry) internal { | ||
if (popEntry == ZERO_ADDRESS || popEntry == SENTINEL) { | ||
revert LinkedList_InvalidEntry(prevEntry); | ||
|
@@ -48,20 +103,42 @@ | |
self.entries[popEntry] = ZERO_ADDRESS; | ||
} | ||
|
||
/** | ||
* Pop all entries from the linked list | ||
* | ||
* @param self The linked list | ||
*/ | ||
function popAll(SentinelList storage self) internal { | ||
address next = self.entries[SENTINEL]; | ||
while (next != ZERO_ADDRESS) { | ||
address current = next; | ||
next = self.entries[next]; | ||
self.entries[current] = ZERO_ADDRESS; | ||
} | ||
self.entries[SENTINEL] = ZERO_ADDRESS; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NOTE: fixes I7 |
||
} | ||
|
||
/** | ||
* Check if the linked list contains an entry | ||
* | ||
* @param self The linked list | ||
* @param entry The entry to check | ||
* | ||
* @return bool True if the linked list contains the entry | ||
*/ | ||
function contains(SentinelList storage self, address entry) internal view returns (bool) { | ||
return SENTINEL != entry && self.entries[entry] != ZERO_ADDRESS; | ||
} | ||
|
||
/** | ||
* Get all entries in the linked list | ||
* | ||
* @param self The linked list | ||
* @param start The start entry | ||
* @param pageSize The page size | ||
* | ||
* @return array All entries in the linked list | ||
* @return next The next entry | ||
*/ | ||
function getEntriesPaginated( | ||
SentinelList storage self, | ||
address start, | ||
|
@@ -104,7 +181,7 @@ | |
// Set correct size of returned array | ||
// solhint-disable-next-line no-inline-assembly | ||
/// @solidity memory-safe-assembly | ||
assembly { | ||
mstore(array, entryCount) | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,20 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
// Sentinel address | ||
address constant SENTINEL = address(0x1); | ||
// Zero address | ||
address constant ZERO_ADDRESS = address(0x0); | ||
|
||
/** | ||
* Implements a linked list, but adheres to ERC-4337 storage restrictions. | ||
* Intended use: validator modules for modular ERC-4337 smart accounts | ||
* @author kopy-kat | rhinestone.wtf | ||
* @title SentinelListLib | ||
* @dev Library for managing a linked list of addresses that is compliant with the ERC-4337 | ||
* validation rules | ||
* @author Rhinestone | ||
*/ | ||
library SentinelList4337Lib { | ||
// Struct to hold the linked list | ||
// This linked list has the account address as the inner key so it is ERC-4337 compliant | ||
struct SentinelList { | ||
mapping(address key => mapping(address account => address entry)) entries; | ||
} | ||
|
@@ -19,11 +24,25 @@ | |
error LinkedList_InvalidEntry(address entry); | ||
error LinkedList_EntryAlreadyInList(address entry); | ||
|
||
/** | ||
* Initialize the linked list | ||
* | ||
* @param self The linked list | ||
* @param account The account to initialize the linked list for | ||
*/ | ||
function init(SentinelList storage self, address account) internal { | ||
if (alreadyInitialized(self, account)) revert LinkedList_AlreadyInitialized(); | ||
self.entries[SENTINEL][account] = SENTINEL; | ||
} | ||
|
||
/** | ||
* Check if the linked list is already initialized | ||
* | ||
* @param self The linked list | ||
* @param account The account to check if the linked list is initialized for | ||
* | ||
* @return bool True if the linked list is already initialized | ||
*/ | ||
function alreadyInitialized( | ||
SentinelList storage self, | ||
address account | ||
|
@@ -35,6 +54,15 @@ | |
return self.entries[SENTINEL][account] != ZERO_ADDRESS; | ||
} | ||
|
||
/** | ||
* Get the next entry in the linked list | ||
* | ||
* @param self The linked list | ||
* @param account The account to get the next entry for | ||
* @param entry The current entry | ||
* | ||
* @return address The next entry | ||
*/ | ||
function getNext( | ||
SentinelList storage self, | ||
address account, | ||
|
@@ -50,6 +78,13 @@ | |
return self.entries[entry][account]; | ||
} | ||
|
||
/** | ||
* Push a new entry to the linked list | ||
* | ||
* @param self The linked list | ||
* @param account The account to push the new entry for | ||
* @param newEntry The new entry | ||
*/ | ||
function push(SentinelList storage self, address account, address newEntry) internal { | ||
if (newEntry == ZERO_ADDRESS || newEntry == SENTINEL) { | ||
revert LinkedList_InvalidEntry(newEntry); | ||
|
@@ -61,6 +96,29 @@ | |
self.entries[SENTINEL][account] = newEntry; | ||
} | ||
|
||
/** | ||
* Safe push a new entry to the linked list | ||
* @dev This ensures that the linked list is initialized and initializes it if it is not | ||
* | ||
* @param self The linked list | ||
* @param account The account to push the new entry for | ||
* @param newEntry The new entry | ||
*/ | ||
function safePush(SentinelList storage self, address account, address newEntry) internal { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NOTE: fixes L4 |
||
if (!alreadyInitialized(self, account)) { | ||
init({ self: self, account: account }); | ||
} | ||
push({ self: self, account: account, newEntry: newEntry }); | ||
} | ||
|
||
/** | ||
* Pop an entry from the linked list | ||
* | ||
* @param self The linked list | ||
* @param account The account to pop the entry for | ||
* @param prevEntry The entry before the entry to pop | ||
* @param popEntry The entry to pop | ||
*/ | ||
function pop( | ||
SentinelList storage self, | ||
address account, | ||
|
@@ -79,16 +137,30 @@ | |
self.entries[popEntry][account] = ZERO_ADDRESS; | ||
} | ||
|
||
/** | ||
* Pop all entries from the linked list | ||
* | ||
* @param self The linked list | ||
* @param account The account to pop all entries for | ||
*/ | ||
function popAll(SentinelList storage self, address account) internal { | ||
address next = self.entries[SENTINEL][account]; | ||
while (next != ZERO_ADDRESS) { | ||
address current = next; | ||
next = self.entries[next][account]; | ||
self.entries[current][account] = ZERO_ADDRESS; | ||
} | ||
self.entries[SENTINEL][account] = ZERO_ADDRESS; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NOTE: fixes I7 |
||
} | ||
|
||
/** | ||
* Check if the linked list contains an entry | ||
* | ||
* @param self The linked list | ||
* @param account The account to check if the entry is in the linked list for | ||
* @param entry The entry to check for | ||
* | ||
* @return bool True if the linked list contains the entry | ||
*/ | ||
function contains( | ||
SentinelList storage self, | ||
address account, | ||
|
@@ -101,6 +173,17 @@ | |
return SENTINEL != entry && self.entries[entry][account] != ZERO_ADDRESS; | ||
} | ||
|
||
/** | ||
* Get all entries in the linked list | ||
* | ||
* @param self The linked list | ||
* @param account The account to get the entries for | ||
* @param start The start entry | ||
* @param pageSize The page size | ||
* | ||
* @return array All entries in the linked list | ||
* @return next The next entry | ||
*/ | ||
function getEntriesPaginated( | ||
SentinelList storage self, | ||
address account, | ||
|
@@ -146,7 +229,7 @@ | |
// Set correct size of returned array | ||
// solhint-disable-next-line no-inline-assembly | ||
/// @solidity memory-safe-assembly | ||
assembly { | ||
mstore(array, entryCount) | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NOTE: fixes L4