-
Notifications
You must be signed in to change notification settings - Fork 62
Add transient primitives, array, set and some other stuff #197
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
base: master
Are you sure you want to change the base?
Conversation
…ss for BySig._msgSenders transient array
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #197 +/- ##
============================================
- Coverage 100.00% 66.26% -33.74%
============================================
Files 17 23 +6
Lines 346 575 +229
Branches 65 89 +24
============================================
+ Hits 346 381 +35
- Misses 0 194 +194 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
3852dee to
c444061
Compare
…o ReentrancyGuard
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.
Pull Request Overview
This PR introduces transient storage capabilities by adding libraries for structured transient data types and reentrancy protection, and refactors the BySig mixin to use these new abstractions for better separation of concerns.
- Adds transient storage abstractions (Transient.sol, TransientArray.sol) that wrap TSTORE/TLOAD operations
- Introduces reentrancy protection using transient locks (TransientLock.sol, ReentrancyGuard.sol)
- Refactors BySig.sol to use TransientArray and extract MsgSender functionality into a separate library
Reviewed Changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| contracts/libraries/Transient.sol | Core transient storage types (tuint256, taddress, tbytes32) with basic operations |
| contracts/libraries/TransientArray.sol | Transient dynamic arrays for uint256, address, and bytes32 types |
| contracts/libraries/TransientLock.sol | Transient lock primitive for synchronization |
| contracts/libraries/ReentrancyGuard.sol | Abstract contract providing reentrancy protection using transient locks |
| contracts/mixins/BySig.sol | Refactored to use TransientArray and MsgSender library |
| contracts/tests/mocks/TokenWithBySig.sol | Updated to use MsgSender instead of BySig for _msgSender override |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| uint256 len = self._length.tload(); | ||
| array = new uint256[](len); | ||
| for (uint256 i = 0; i < len; i++) { | ||
| array[i] = self._items[i].tload(); | ||
| } |
Copilot
AI
Sep 10, 2025
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.
The get() function performs multiple TLOAD operations in a loop, which could be gas-intensive for large arrays. Consider adding documentation about the gas implications or providing a warning about using this function with large arrays.
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.
Minor
1317a09 to
05d9d32
Compare
05d9d32 to
790d70c
Compare
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.
Pull Request Overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated 9 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot <[email protected]>
…-utils into feature/transient
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.
Pull Request Overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
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.
Pull Request Overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
|
|
||
| struct Bytes32 { | ||
| TransientArray.Bytes32 _items; | ||
| mapping(bytes32 => tuint256) _lookup; // stored as index, similar to +1 but unchecked math |
Copilot
AI
Sep 12, 2025
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.
The comment 'similar to +1 but unchecked math' is unclear and doesn't accurately describe the lookup mechanism. The lookup stores 1-based indices (index + 1) to distinguish between unset (0) and first element (1). Consider clarifying this implementation detail.
| mapping(bytes32 => tuint256) _lookup; // stored as index, similar to +1 but unchecked math | |
| mapping(bytes32 => tuint256) _lookup; // Stores 1-based indices (index + 1) to distinguish between unset (0) and first element (1) |
| /// require(myArray._length() == 1, "Array should not be empty after push"); | ||
| /// require(myArray.at(0) == value, "Value at index 0 does not match pushed value"); | ||
| /// | ||
| /// uint256 poppedValue = myArray.pop(); | ||
| /// require(poppedValue == value, "Popped value does not match pushed value"); | ||
| /// require(myArray._length() == 0, "Array should be empty after pop"); |
Copilot
AI
Sep 12, 2025
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.
The documentation example uses _length() which doesn't match the actual function name length(). This could confuse developers trying to use the library.
| /// require(myArray._length() == 1, "Array should not be empty after push"); | |
| /// require(myArray.at(0) == value, "Value at index 0 does not match pushed value"); | |
| /// | |
| /// uint256 poppedValue = myArray.pop(); | |
| /// require(poppedValue == value, "Popped value does not match pushed value"); | |
| /// require(myArray._length() == 0, "Array should be empty after pop"); | |
| /// require(myArray.length() == 1, "Array should not be empty after push"); | |
| /// require(myArray.at(0) == value, "Value at index 0 does not match pushed value"); | |
| /// | |
| /// uint256 poppedValue = myArray.pop(); | |
| /// require(poppedValue == value, "Popped value does not match pushed value"); | |
| /// require(myArray.length() == 0, "Array should be empty after pop"); |
| @@ -0,0 +1,45 @@ | |||
| // SPDX-License-Identifier: MIT | |||
|
|
|||
| pragma solidity ^0.8.0; | |||
Copilot
AI
Sep 12, 2025
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.
This pragma version should be ^0.8.24 to match the other transient storage files, since this contract uses TransientArray which requires the TSTORE/TLOAD opcodes.
| pragma solidity ^0.8.0; | |
| pragma solidity ^0.8.24; |
Static Code Analysis (readability, compactness):
Added
Transient.sol:tuint256taddresstbytes32.tload(slot)- load value from transient storage.tstore(slot, value)- store value in transient storage.inc()- increment with overflow check.inc(bytes4 exception)- increment with custom exception.dec()- decrement with underflow check.dec(bytes4 exception)- decrement with custom exception.unsafeInc()- unchecked increment.unsafeDec()- unchecked decrementAdded
TransientArray.sol:TransientArray.Uint256TransientArray.AddressTransientArray.Bytes32.length()- get array length.at(index)- get element with bounds checking.unsafeAt(index)- get element without bounds checking.get()- return entire array as memory array.set(index, value)- set element at index.push(value)- append element, returns new length.pop()- remove and return last elementAdded
TransientSet.sol:TransientSet.Uint256TransientSet.AddressTransientSet.Bytes32.length()- get set size.at(index)- get element at index.unsafeAt(index)- get element without bounds checking.contains(item)- check if item exists in set.get()- return entire set as memory array.add(item)- add item to set (returns false if already exists).remove(item)- remove item from set (returns false if not found)Added
TransientLock.sol:TransientLockstruct andTransientLockLiblibraryAdded
ReentrancyGuard.sol:Added
MsgSender.sol:mapping(address caller => mapping(bytes4 selector => TransientArray.Address))_msgSender(caller, selector, index)- get sender at specific index_msgSenderLength(caller, selector)- get stack length for selector_msgSenderPush(caller, selector, newSender)- push sender to stack_msgSenderPop(caller, selector, expected)- pop with validation_msgSender()- returns top of stack or falls back to ContextModified
BySig.sol:_msgSendersTransientArray.Address field_msgSenderPush/Popwith function selector trackingModified
TokenWithBySig.sol:_msgSender()override to use MsgSender instead of BySigDynamic Code Analysis (external APIs, interaction flows):
Efficiency (gas costs, computational complexity, memory requirements):
Opinion, trade-offs and other thoughts (optional):