Skip to content

Commit 1317a09

Browse files
committed
Transients refinement
1 parent b54387f commit 1317a09

File tree

6 files changed

+77
-50
lines changed

6 files changed

+77
-50
lines changed

contracts/libraries/ReentrancyGuard.sol

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// SPDX-License-Identifier: MIT
22

3-
pragma solidity ^0.8.0;
3+
pragma solidity ^0.8.24; // tload/tstore are available since 0.8.24
44

55
import { TransientLock, TransientLockLib } from "./TransientLock.sol";
66

@@ -22,7 +22,7 @@ import { TransientLock, TransientLockLib } from "./TransientLock.sol";
2222
abstract contract ReentrancyGuard {
2323
using TransientLockLib for TransientLock;
2424

25-
error MissingNonReentrantModifier();
25+
error MissingNonReentrantModifier(bytes4 selector);
2626

2727
TransientLock private _lock;
2828

@@ -33,7 +33,7 @@ abstract contract ReentrancyGuard {
3333
}
3434

3535
modifier onlyNonReentrantCall {
36-
if (!_inNonReentrantCall()) revert MissingNonReentrantModifier();
36+
if (!_inNonReentrantCall()) revert MissingNonReentrantModifier(msg.sig);
3737
_;
3838
}
3939

@@ -44,7 +44,7 @@ abstract contract ReentrancyGuard {
4444
}
4545

4646
modifier onlyNonReentrantCallLock(TransientLock storage lock) {
47-
if (!lock.isLocked()) revert MissingNonReentrantModifier();
47+
if (!lock.isLocked()) revert MissingNonReentrantModifier(msg.sig);
4848
_;
4949
}
5050

contracts/libraries/Transient.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// SPDX-License-Identifier: MIT
22

3-
pragma solidity ^0.8.0;
3+
pragma solidity ^0.8.24; // tload/tstore are available since 0.8.24
44

55
struct tuint256 { // solhint-disable-line contract-name-camelcase
66
uint256 _raw;

contracts/libraries/TransientArray.sol

Lines changed: 60 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
// SPDX-License-Identifier: MIT
22

3-
pragma solidity ^0.8.0;
3+
pragma solidity ^0.8.24; // tload/tstore are available since 0.8.24
44

5+
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
56
import { TransientLib, tuint256, taddress, tbytes32 } from "./Transient.sol";
67

78
/// @dev Library for managing transient dynamic arrays (TSTORE, TLOAD) of different types (uint256, address, bytes32).
@@ -23,6 +24,7 @@ import { TransientLib, tuint256, taddress, tbytes32 } from "./Transient.sol";
2324
/// }
2425
/// ```
2526
library TransientArray {
27+
using Math for uint256;
2628
using TransientLib for tuint256;
2729
using TransientLib for taddress;
2830
using TransientLib for tbytes32;
@@ -60,21 +62,32 @@ library TransientArray {
6062
return self._items[index].tload();
6163
}
6264

63-
function push(Uint256 storage self, uint256 value) internal {
65+
function get(Uint256 storage self) internal view returns (uint256[] memory array) {
66+
uint256 len = self._length.tload();
67+
array = new uint256[](len);
68+
for (uint256 i = 0; i < len; i++) {
69+
array[i] = self._items[i].tload();
70+
}
71+
}
72+
73+
function set(Uint256 storage self, uint256 index, uint256 value) internal {
74+
if (index >= self._length.tload()) revert TransientArray_IndexOutOfBounds();
75+
self._items[index].tstore(value);
76+
}
77+
78+
function push(Uint256 storage self, uint256 value) internal returns (uint256 newLength) {
6479
uint256 nextElementIndex = self._length.tload();
6580
self._items[nextElementIndex].tstore(value);
6681
unchecked {
67-
self._length.tstore(nextElementIndex + 1);
82+
newLength = nextElementIndex + 1;
83+
self._length.tstore(newLength);
6884
}
6985
}
7086

7187
function pop(Uint256 storage self) internal returns (uint256 ret) {
72-
uint256 currentLength = self._length.tload();
73-
if (currentLength == 0) revert TransientArray_EmptyArrayPop();
74-
uint256 newLength;
75-
unchecked {
76-
newLength = currentLength - 1;
77-
}
88+
(bool success, uint256 newLength) = self._length.tload().trySub(1);
89+
if (!success) revert TransientArray_EmptyArrayPop();
90+
7891
ret = self._items[newLength].tload();
7992
delete self._items[newLength];
8093
self._length.tstore(newLength);
@@ -95,21 +108,32 @@ library TransientArray {
95108
return self._items[index].tload();
96109
}
97110

98-
function push(Address storage self, address value) internal {
111+
function get(Address storage self) internal view returns (address[] memory array) {
112+
uint256 len = self._length.tload();
113+
array = new address[](len);
114+
for (uint256 i = 0; i < len; i++) {
115+
array[i] = self._items[i].tload();
116+
}
117+
}
118+
119+
function set(Address storage self, uint256 index, address value) internal {
120+
if (index >= self._length.tload()) revert TransientArray_IndexOutOfBounds();
121+
self._items[index].tstore(value);
122+
}
123+
124+
function push(Address storage self, address value) internal returns (uint256 newLength) {
99125
uint256 nextElementIndex = self._length.tload();
100126
self._items[nextElementIndex].tstore(value);
101127
unchecked {
102-
self._length.tstore(nextElementIndex + 1);
128+
newLength = nextElementIndex + 1;
129+
self._length.tstore(newLength);
103130
}
104131
}
105132

106133
function pop(Address storage self) internal returns (address ret) {
107-
uint256 currentLength = self._length.tload();
108-
if (currentLength == 0) revert TransientArray_EmptyArrayPop();
109-
uint256 newLength;
110-
unchecked {
111-
newLength = currentLength - 1;
112-
}
134+
(bool success, uint256 newLength) = self._length.tload().trySub(1);
135+
if (!success) revert TransientArray_EmptyArrayPop();
136+
113137
ret = self._items[newLength].tload();
114138
delete self._items[newLength];
115139
self._length.tstore(newLength);
@@ -130,21 +154,32 @@ library TransientArray {
130154
return self._items[index].tload();
131155
}
132156

133-
function push(Bytes32 storage self, bytes32 value) internal {
157+
function get(Bytes32 storage self) internal view returns (bytes32[] memory array) {
158+
uint256 len = self._length.tload();
159+
array = new bytes32[](len);
160+
for (uint256 i = 0; i < len; i++) {
161+
array[i] = self._items[i].tload();
162+
}
163+
}
164+
165+
function set(Bytes32 storage self, uint256 index, bytes32 value) internal {
166+
if (index >= self._length.tload()) revert TransientArray_IndexOutOfBounds();
167+
self._items[index].tstore(value);
168+
}
169+
170+
function push(Bytes32 storage self, bytes32 value) internal returns (uint256 newLength) {
134171
uint256 nextElementIndex = self._length.tload();
135172
self._items[nextElementIndex].tstore(value);
136173
unchecked {
137-
self._length.tstore(nextElementIndex + 1);
174+
newLength = nextElementIndex + 1;
175+
self._length.tstore(newLength);
138176
}
139177
}
140178

141179
function pop(Bytes32 storage self) internal returns (bytes32 ret) {
142-
uint256 currentLength = self._length.tload();
143-
if (currentLength == 0) revert TransientArray_EmptyArrayPop();
144-
uint256 newLength;
145-
unchecked {
146-
newLength = currentLength - 1;
147-
}
180+
(bool success, uint256 newLength) = self._length.tload().trySub(1);
181+
if (!success) revert TransientArray_EmptyArrayPop();
182+
148183
ret = self._items[newLength].tload();
149184
delete self._items[newLength];
150185
self._length.tstore(newLength);

contracts/libraries/TransientLock.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// SPDX-License-Identifier: MIT
22

3-
pragma solidity ^0.8.0;
3+
pragma solidity ^0.8.24; // tload/tstore are available since 0.8.24
44

55
import { TransientLib, tuint256 } from "./Transient.sol";
66

contracts/mixins/BySig.sol

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,19 @@
22

33
pragma solidity ^0.8.0;
44

5-
import { Context } from "@openzeppelin/contracts/utils/Context.sol";
65
import { Address } from "@openzeppelin/contracts/utils/Address.sol";
76
import { EIP712 } from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
87
import { ECDSA } from "../libraries/ECDSA.sol";
98
import { BySigTraits } from "../libraries/BySigTraits.sol";
109
import { TransientArray } from "../libraries/TransientArray.sol";
10+
import { MsgSender } from "../libraries/MsgSender.sol";
1111

1212
/**
1313
* @title BySig
1414
* @notice Mixin that provides signature-based accessibility to every external method of the smart contract.
1515
* @dev Inherit your contract from this mixin and use `_msgSender()` instead of `msg.sender` everywhere.
1616
*/
17-
abstract contract BySig is Context, EIP712 {
17+
abstract contract BySig is MsgSender, EIP712 {
1818
using Address for address;
1919
using BySigTraits for BySigTraits.Value;
2020
using TransientArray for TransientArray.Address;
@@ -47,7 +47,6 @@ abstract contract BySig is Context, EIP712 {
4747
bytes32 constant public SIGNED_CALL_TYPEHASH = keccak256("SignedCall(uint256 traits,bytes data)");
4848

4949
// Various nonces used for signature verification and replay protection.
50-
TransientArray.Address /* transient */ private _msgSenders;
5150
mapping(address => uint256) private _bySigAccountNonces;
5251
mapping(address => mapping(bytes4 => uint256)) private _bySigSelectorNonces;
5352
mapping(address => mapping(uint256 => uint256)) private _bySigUniqueNonces;
@@ -124,9 +123,10 @@ abstract contract BySig is Context, EIP712 {
124123
if (!_useNonce(signer, sig.traits, sig.data)) revert WrongNonce();
125124
if (!ECDSA.recoverOrIsValidSignature(signer, hashBySig(sig), signature)) revert WrongSignature();
126125

127-
_msgSenders.push(signer);
126+
bytes4 selector = bytes4(sig.data);
127+
_msgSenderPush(msg.sender, selector, signer);
128128
ret = address(this).functionDelegateCall(sig.data);
129-
_msgSenders.pop();
129+
_msgSenderPop(msg.sender, selector, signer);
130130
}
131131

132132
/**
@@ -141,7 +141,10 @@ abstract contract BySig is Context, EIP712 {
141141
* @return ret Result of the executed call.
142142
*/
143143
function sponsoredCall(address token, uint256 amount, bytes calldata data, bytes calldata extraData) public payable returns(bytes memory ret) {
144+
_msgSenderPush(msg.sender, bytes4(data), _msgSender());
144145
ret = address(this).functionDelegateCall(data);
146+
_msgSenderPop(msg.sender, bytes4(data), _msgSender());
147+
145148
_chargeSigner(_msgSender(), msg.sender, token, amount, extraData);
146149
}
147150

@@ -188,18 +191,6 @@ abstract contract BySig is Context, EIP712 {
188191
_bySigUniqueNonces[_msgSender()][nonce >> 8] |= 1 << (nonce & 0xff);
189192
}
190193

191-
/**
192-
* @dev Returns the address of the message sender, replacing the traditional `msg.sender` with a potentially signed sender.
193-
* @return The address of the message sender.
194-
*/
195-
function _msgSender() internal view override virtual returns (address) {
196-
uint256 length = _msgSenders.length();
197-
if (length == 0) {
198-
return super._msgSender();
199-
}
200-
return _msgSenders.unsafeAt(length - 1);
201-
}
202-
203194
function _useNonce(address signer, BySigTraits.Value traits, bytes calldata data) private returns(bool) {
204195
BySigTraits.NonceType nonceType = traits.nonceType();
205196
uint256 nonce = traits.nonce();

contracts/tests/mocks/TokenWithBySig.sol

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { Context } from "@openzeppelin/contracts/utils/Context.sol";
66
import { EIP712 } from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
77
import { TokenMock } from "../../mocks/TokenMock.sol";
88
import { BySig } from "../../mixins/BySig.sol";
9+
import { MsgSender } from "../../libraries/MsgSender.sol";
910

1011
contract TokenWithBySig is TokenMock, BySig {
1112
error WrongToken();
@@ -15,8 +16,8 @@ contract TokenWithBySig is TokenMock, BySig {
1516
// solhint-disable-next-line no-empty-blocks
1617
constructor(string memory name, string memory symbol, string memory version) TokenMock(name, symbol) EIP712(name, version) {}
1718

18-
function _msgSender() internal view override(Context, BySig) returns (address) {
19-
return BySig._msgSender();
19+
function _msgSender() internal view override(Context, MsgSender) returns (address) {
20+
return MsgSender._msgSender();
2021
}
2122

2223
function getChainId() external view returns (uint256) {

0 commit comments

Comments
 (0)