Skip to content

Commit 4668e01

Browse files
7201 receipt vault
1 parent d4783b8 commit 4668e01

File tree

2 files changed

+46
-24
lines changed

2 files changed

+46
-24
lines changed

src/abstract/OwnerFreezable.sol

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ pragma solidity ^0.8.25;
55
import {OwnableUpgradeable} from "openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol";
66
import {IOwnerFreezableV1, IERC5313} from "../interface/IOwnerFreezableV1.sol";
77

8-
/// @dev String ID for the OwnerFreezableV1 storage location.
8+
/// @dev String ID for the OwnerFreezableV1 storage location v1.
99
string constant OWNER_FREEZABLE_V1_STORAGE_ID = "rain.storage.owner-freezable.1";
1010

1111
/// @dev "rain.storage.owner-freezable.1" with the erc7201 formula.
@@ -65,8 +65,9 @@ abstract contract OwnerFreezable is IOwnerFreezableV1, OwnableUpgradeable {
6565
mapping(address to => uint256 protectedUntil) alwaysAllowedTos;
6666
}
6767

68-
function getStorage() private pure returns (OwnerFreezableV17201Storage storage s) {
69-
assembly {
68+
/// @dev Accessor for the owner freezable storage.
69+
function getStorageOwnerFreezable() private pure returns (OwnerFreezableV17201Storage storage s) {
70+
assembly ("memory-safe") {
7071
s.slot := OWNER_FREEZABLE_V1_STORAGE_LOCATION
7172
}
7273
}
@@ -78,25 +79,25 @@ abstract contract OwnerFreezable is IOwnerFreezableV1, OwnableUpgradeable {
7879

7980
/// @inheritdoc IOwnerFreezableV1
8081
function ownerFrozenUntil() external view returns (uint256) {
81-
OwnerFreezableV17201Storage storage s = getStorage();
82+
OwnerFreezableV17201Storage storage s = getStorageOwnerFreezable();
8283
return s.ownerFrozenUntil;
8384
}
8485

8586
/// @inheritdoc IOwnerFreezableV1
8687
function ownerFreezeAlwaysAllowedFrom(address from) external view returns (uint256) {
87-
OwnerFreezableV17201Storage storage s = getStorage();
88+
OwnerFreezableV17201Storage storage s = getStorageOwnerFreezable();
8889
return s.alwaysAllowedFroms[from];
8990
}
9091

9192
/// @inheritdoc IOwnerFreezableV1
9293
function ownerFreezeAlwaysAllowedTo(address to) external view returns (uint256) {
93-
OwnerFreezableV17201Storage storage s = getStorage();
94+
OwnerFreezableV17201Storage storage s = getStorageOwnerFreezable();
9495
return s.alwaysAllowedTos[to];
9596
}
9697

9798
/// @inheritdoc IOwnerFreezableV1
9899
function ownerFreezeUntil(uint256 freezeUntil) external onlyOwner {
99-
OwnerFreezableV17201Storage storage s = getStorage();
100+
OwnerFreezableV17201Storage storage s = getStorageOwnerFreezable();
100101
// Freezing is additive so we can only increase the freeze time.
101102
// It is a no-op on the state if the new freeze time is less than the
102103
// current one.
@@ -118,7 +119,7 @@ abstract contract OwnerFreezable is IOwnerFreezableV1, OwnableUpgradeable {
118119
revert OwnerFreezeAlwaysAllowedFromZero(from);
119120
}
120121

121-
OwnerFreezableV17201Storage storage s = getStorage();
122+
OwnerFreezableV17201Storage storage s = getStorageOwnerFreezable();
122123

123124
// Adding a `from` is additive so we can only increase the protected
124125
// time. It is a no-op on the state if the new protected time is less
@@ -134,7 +135,7 @@ abstract contract OwnerFreezable is IOwnerFreezableV1, OwnableUpgradeable {
134135

135136
/// @inheritdoc IOwnerFreezableV1
136137
function ownerFreezeStopAlwaysAllowingFrom(address from) external onlyOwner {
137-
OwnerFreezableV17201Storage storage s = getStorage();
138+
OwnerFreezableV17201Storage storage s = getStorageOwnerFreezable();
138139

139140
// If the current time is after the protection for this `from` then
140141
// we can remove it. Otherwise we revert to respect the protection.
@@ -154,7 +155,7 @@ abstract contract OwnerFreezable is IOwnerFreezableV1, OwnableUpgradeable {
154155
revert IOwnerFreezableV1.OwnerFreezeAlwaysAllowedToZero(to);
155156
}
156157

157-
OwnerFreezableV17201Storage storage s = getStorage();
158+
OwnerFreezableV17201Storage storage s = getStorageOwnerFreezable();
158159

159160
// Adding a `to` is additive so we can only increase the protected time.
160161
// It is a no-op on the state if the new protected time is less than the
@@ -170,7 +171,7 @@ abstract contract OwnerFreezable is IOwnerFreezableV1, OwnableUpgradeable {
170171

171172
/// @inheritdoc IOwnerFreezableV1
172173
function ownerFreezeStopAlwaysAllowingTo(address to) external onlyOwner {
173-
OwnerFreezableV17201Storage storage s = getStorage();
174+
OwnerFreezableV17201Storage storage s = getStorageOwnerFreezable();
174175

175176
// If the current time is after the protection for this `to` then
176177
// we can remove it. Otherwise we revert to respect the protection.
@@ -187,7 +188,7 @@ abstract contract OwnerFreezable is IOwnerFreezableV1, OwnableUpgradeable {
187188
/// @param from The address that tokens are being sent from.
188189
/// @param to The address that tokens are being sent to.
189190
function ownerFreezeCheckTransaction(address from, address to) internal view {
190-
OwnerFreezableV17201Storage storage s = getStorage();
191+
OwnerFreezableV17201Storage storage s = getStorageOwnerFreezable();
191192

192193
// We either simply revert or no-op for this check.
193194
// Revert if the contract is frozen and neither the `from` nor `to` are

src/abstract/ReceiptVault.sol

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ import {ERC165Upgradeable as ERC165} from
3232
"openzeppelin-contracts-upgradeable/contracts/utils/introspection/ERC165Upgradeable.sol";
3333
import {IERC20Metadata} from "openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol";
3434

35+
/// @dev String ID for the ReceiptVault storage location v1.
36+
string constant RECEIPT_VAULT_V1_STORAGE_ID = "rain.storage.receipt-vault.1";
37+
38+
/// @dev "rain.storage.receipt-vault.1" with the erc7201 formula.
39+
bytes32 constant RECEIPT_VAULT_V1_STORAGE_LOCATION = 0x04485615b1da6633eec3daf54aadca2a89ef8b155744e223a046f4a6e38be700;
40+
3541
/// Represents the action being taken on shares, ostensibly for calculating a
3642
/// ratio.
3743
enum ShareAction {
@@ -108,11 +114,11 @@ struct ReceiptVaultConfig {
108114
/// free market layer.
109115
abstract contract ReceiptVault is
110116
IReceiptManagerV2,
117+
IReceiptVaultV3,
118+
ICloneableV2,
111119
Multicall,
112120
ReentrancyGuard,
113121
ERC20,
114-
IReceiptVaultV3,
115-
ICloneableV2,
116122
ERC165
117123
{
118124
using LibFixedPointDecimalArithmeticOpenZeppelin for uint256;
@@ -123,11 +129,21 @@ abstract contract ReceiptVault is
123129
//slither-disable-next-line naming-convention
124130
IReceiptV3 internal immutable I_RECEIPT_IMPLEMENTATION;
125131

126-
/// Underlying ERC4626 asset.
127-
IERC20 internal sAsset;
128-
/// ERC1155 Receipt owned by this receipt vault for the purpose of tracking
129-
/// mints and enforcing integrity of subsequent burns.
130-
IReceiptV3 internal sReceipt;
132+
/// @param asset Underlying ERC4626 asset.
133+
/// @param receipt ERC1155 Receipt owned by this receipt vault for the
134+
/// purpose of tracking mints and enforcing integrity of subsequent burns.
135+
/// @custom:storage-location erc7201:rain.storage.receipt-vault.1
136+
struct ReceiptVaultV17201Storage {
137+
IERC20 asset;
138+
IReceiptV3 receipt;
139+
}
140+
141+
/// @dev Accessor to the receipt vault storage.
142+
function getStorageReceiptVault() private pure returns (ReceiptVaultV17201Storage storage s) {
143+
assembly ("memory-safe") {
144+
s.slot := RECEIPT_VAULT_V1_STORAGE_LOCATION
145+
}
146+
}
131147

132148
/// `ReceiptVault` is intended to be cloned and initialized by a
133149
/// `ReceiptVaultFactory` so is an implementation contract that can't itself
@@ -153,14 +169,16 @@ abstract contract ReceiptVault is
153169
function __ReceiptVault_init(VaultConfig memory config) internal virtual {
154170
__Multicall_init();
155171
__ERC20_init(config.name, config.symbol);
156-
sAsset = IERC20(config.asset);
157172

158173
// Slither false positive here due to it being impossible to set the
159174
// receipt before it has been deployed.
160175
// slither-disable-next-line reentrancy-benign
161176
IReceiptV3 managedReceipt =
162177
IReceiptV3(I_FACTORY.clone(address(I_RECEIPT_IMPLEMENTATION), abi.encode(address(this))));
163-
sReceipt = managedReceipt;
178+
179+
ReceiptVaultV17201Storage storage s = getStorageReceiptVault();
180+
s.asset = IERC20(config.asset);
181+
s.receipt = managedReceipt;
164182

165183
// Sanity check here. Should always be true as we cloned the receipt
166184
// from the factory ourselves just above.
@@ -179,12 +197,14 @@ abstract contract ReceiptVault is
179197

180198
/// @inheritdoc IReceiptVaultV1
181199
function asset() public view virtual returns (address) {
182-
return address(sAsset);
200+
ReceiptVaultV17201Storage storage s = getStorageReceiptVault();
201+
return address(s.asset);
183202
}
184203

185204
/// @inheritdoc IERC20Metadata
186205
function decimals() public view virtual override returns (uint8) {
187-
address lAsset = address(sAsset);
206+
ReceiptVaultV17201Storage storage s = getStorageReceiptVault();
207+
address lAsset = address(s.asset);
188208
uint256 lAssetCodeSize;
189209
assembly ("memory-safe") {
190210
lAssetCodeSize := extcodesize(lAsset)
@@ -365,7 +385,8 @@ abstract contract ReceiptVault is
365385

366386
/// @inheritdoc IReceiptVaultV3
367387
function receipt() public view virtual returns (IReceiptV3) {
368-
return sReceipt;
388+
ReceiptVaultV17201Storage storage s = getStorageReceiptVault();
389+
return s.receipt;
369390
}
370391

371392
/// Similar to `receiptInformation` on the underlying receipt but for this

0 commit comments

Comments
 (0)