22// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd
33pragma solidity ^ 0.8.25 ;
44
5- import {OwnableUpgradeable as Ownable } from "openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol " ;
5+ import {OwnableUpgradeable} from "openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol " ;
66import {IOwnerFreezableV1, IERC5313 } from "../interface/IOwnerFreezableV1.sol " ;
77
8+ /// @dev String ID for the OwnerFreezableV1 storage location.
9+ string constant OWNER_FREEZABLE_V1_STORAGE_ID = "rain.storage.owner-freezable.1 " ;
10+
11+ /// @dev "rain.storage.owner-freezable.1" with the erc7201 formula.
12+ bytes32 constant OWNER_FREEZABLE_V1_STORAGE_LOCATION =
13+ 0x04485615b1da6633eec3daf54aadca2a89ef8b155744e223a046f4a6e38be700 ;
14+
815/// @title OwnerFreezable
916/// This abstract contract inherits from Ownable and adds the ability for the
1017/// owner to freeze the contract until a given timestamp. The owner cannot
@@ -39,58 +46,68 @@ import {IOwnerFreezableV1, IERC5313} from "../interface/IOwnerFreezableV1.sol";
3946/// allow adding `from` addresses to the always allowed list, but not `to`
4047/// addresses, to mitigate the risk that the attacker opens up the ability to
4148/// dump on the LPs en masse after the snapshot.
42- abstract contract OwnerFreezable is Ownable , IOwnerFreezableV1 {
43- /// Contract is frozen until this time.
44- /// Explicitly initialized to `0` for clarity.
45- uint256 private sOwnerFrozenUntil = 0 ;
46-
47- /// @dev Mapping of `from` addresses that are always allowed to send.
48- /// If the protected time is any non-zero value then the `from` address is
49- /// always allowed to send. While the current time is less than the
50- /// protected time the `from` address cannot be removed from the always
51- /// allowed list.
52- mapping (address from = > uint256 protectedUntil ) private sAlwaysAllowedFroms;
53-
54- /// @dev Mapping of `to` addresses that are always allowed to receive.
55- /// If the protected time is any non-zero value then the `to` address is
56- /// always allowed to receive. While the current time is less than the
57- /// protected time the `to` address cannot be removed from the always
58- /// allowed list.
59- mapping (address to = > uint256 protectedUntil ) private sAlwaysAllowedTos;
49+ abstract contract OwnerFreezable is IOwnerFreezableV1 , OwnableUpgradeable {
50+ /// @param ownerFrozenUntil Contract is frozen until this time.
51+ /// @param alwaysAllowedFroms Mapping of `from` addresses that are always
52+ /// allowed to send. If the protected time is any non-zero value then the
53+ /// `from` address is always allowed to send. While the current time is less
54+ /// than the protected time the `from` address cannot be removed from the
55+ /// always allowed list.
56+ /// @param alwaysAllowedTos Mapping of `to` addresses that are always
57+ /// allowed to receive. If the protected time is any non-zero value then the
58+ /// `to` address is always allowed to receive. While the current time is less
59+ /// than the protected time the `to` address cannot be removed from the
60+ /// always allowed list.
61+ /// @custom:storage-location erc7201:rain.storage.owner-freezable.1
62+ struct OwnerFreezableV1Storage {
63+ uint256 ownerFrozenUntil;
64+ mapping (address from = > uint256 protectedUntil ) alwaysAllowedFroms;
65+ mapping (address to = > uint256 protectedUntil ) alwaysAllowedTos;
66+ }
67+
68+ function getStorage () private pure returns (OwnerFreezableV1Storage storage s ) {
69+ assembly {
70+ s.slot := OWNER_FREEZABLE_V1_STORAGE_LOCATION
71+ }
72+ }
6073
6174 /// @inheritdoc IERC5313
62- function owner () public view virtual override (IERC5313 , Ownable ) returns (address ) {
75+ function owner () public view virtual override (IERC5313 , OwnableUpgradeable ) returns (address ) {
6376 return super .owner ();
6477 }
6578
6679 /// @inheritdoc IOwnerFreezableV1
6780 function ownerFrozenUntil () external view returns (uint256 ) {
68- return sOwnerFrozenUntil;
81+ OwnerFreezableV1Storage storage s = getStorage ();
82+ return s.ownerFrozenUntil;
6983 }
7084
7185 /// @inheritdoc IOwnerFreezableV1
7286 function ownerFreezeAlwaysAllowedFrom (address from ) external view returns (uint256 ) {
73- return sAlwaysAllowedFroms[from];
87+ OwnerFreezableV1Storage storage s = getStorage ();
88+ return s.alwaysAllowedFroms[from];
7489 }
7590
7691 /// @inheritdoc IOwnerFreezableV1
7792 function ownerFreezeAlwaysAllowedTo (address to ) external view returns (uint256 ) {
78- return sAlwaysAllowedTos[to];
93+ OwnerFreezableV1Storage storage s = getStorage ();
94+ return s.alwaysAllowedTos[to];
7995 }
8096
8197 /// @inheritdoc IOwnerFreezableV1
8298 function ownerFreezeUntil (uint256 freezeUntil ) external onlyOwner {
99+ OwnerFreezableV1Storage storage s = getStorage ();
83100 // Freezing is additive so we can only increase the freeze time.
84101 // It is a no-op on the state if the new freeze time is less than the
85102 // current one.
86- if (freezeUntil > sOwnerFrozenUntil ) {
87- sOwnerFrozenUntil = freezeUntil;
103+ if (freezeUntil > s.ownerFrozenUntil ) {
104+ s.ownerFrozenUntil = freezeUntil;
88105 }
89106
90107 // Emit the event with the new freeze time. We do this even if the
91108 // freeze time is unchanged so that we can track the history of
92109 // freeze calls offchain.
93- emit OwnerFrozenUntil (owner (), freezeUntil, sOwnerFrozenUntil );
110+ emit OwnerFrozenUntil (owner (), freezeUntil, s.ownerFrozenUntil );
94111 }
95112
96113 /// @inheritdoc IOwnerFreezableV1
@@ -101,27 +118,31 @@ abstract contract OwnerFreezable is Ownable, IOwnerFreezableV1 {
101118 revert OwnerFreezeAlwaysAllowedFromZero (from);
102119 }
103120
121+ OwnerFreezableV1Storage storage s = getStorage ();
122+
104123 // Adding a `from` is additive so we can only increase the protected
105124 // time. It is a no-op on the state if the new protected time is less
106125 // than the current one.
107- if (protectUntil > sAlwaysAllowedFroms [from]) {
108- sAlwaysAllowedFroms [from] = protectUntil;
126+ if (protectUntil > s.alwaysAllowedFroms [from]) {
127+ s.alwaysAllowedFroms [from] = protectUntil;
109128 }
110129 // Emit the event with the new protected time. We do this even if the
111130 // protected time is unchanged so that we can track the history of
112131 // protections offchain.
113- emit OwnerFreezeAlwaysAllowedFrom (owner (), from, protectUntil, sAlwaysAllowedFroms [from]);
132+ emit OwnerFreezeAlwaysAllowedFrom (owner (), from, protectUntil, s.alwaysAllowedFroms [from]);
114133 }
115134
116135 /// @inheritdoc IOwnerFreezableV1
117136 function ownerFreezeStopAlwaysAllowingFrom (address from ) external onlyOwner {
137+ OwnerFreezableV1Storage storage s = getStorage ();
138+
118139 // If the current time is after the protection for this `from` then
119140 // we can remove it. Otherwise we revert to respect the protection.
120- if (block .timestamp < sAlwaysAllowedFroms [from]) {
121- revert OwnerFreezeAlwaysAllowedFromProtected (from, sAlwaysAllowedFroms [from]);
141+ if (block .timestamp < s.alwaysAllowedFroms [from]) {
142+ revert OwnerFreezeAlwaysAllowedFromProtected (from, s.alwaysAllowedFroms [from]);
122143 }
123144
124- delete sAlwaysAllowedFroms [from];
145+ delete s.alwaysAllowedFroms [from];
125146 emit OwnerFreezeAlwaysAllowedFrom (owner (), from, 0 , 0 );
126147 }
127148
@@ -133,27 +154,31 @@ abstract contract OwnerFreezable is Ownable, IOwnerFreezableV1 {
133154 revert IOwnerFreezableV1.OwnerFreezeAlwaysAllowedToZero (to);
134155 }
135156
157+ OwnerFreezableV1Storage storage s = getStorage ();
158+
136159 // Adding a `to` is additive so we can only increase the protected time.
137160 // It is a no-op on the state if the new protected time is less than the
138161 // current one.
139- if (protectUntil > sAlwaysAllowedTos [to]) {
140- sAlwaysAllowedTos [to] = protectUntil;
162+ if (protectUntil > s.alwaysAllowedTos [to]) {
163+ s.alwaysAllowedTos [to] = protectUntil;
141164 }
142165 // Emit the event with the new protected time. We do this even if the
143166 // protected time is unchanged so that we can track the history of
144167 // protections offchain.
145- emit OwnerFreezeAlwaysAllowedTo (owner (), to, protectUntil, sAlwaysAllowedTos [to]);
168+ emit OwnerFreezeAlwaysAllowedTo (owner (), to, protectUntil, s.alwaysAllowedTos [to]);
146169 }
147170
148171 /// @inheritdoc IOwnerFreezableV1
149172 function ownerFreezeStopAlwaysAllowingTo (address to ) external onlyOwner {
173+ OwnerFreezableV1Storage storage s = getStorage ();
174+
150175 // If the current time is after the protection for this `to` then
151176 // we can remove it. Otherwise we revert to respect the protection.
152- if (block .timestamp < sAlwaysAllowedTos [to]) {
153- revert IOwnerFreezableV1.OwnerFreezeAlwaysAllowedToProtected (to, sAlwaysAllowedTos [to]);
177+ if (block .timestamp < s.alwaysAllowedTos [to]) {
178+ revert IOwnerFreezableV1.OwnerFreezeAlwaysAllowedToProtected (to, s.alwaysAllowedTos [to]);
154179 }
155180
156- delete sAlwaysAllowedTos [to];
181+ delete s.alwaysAllowedTos [to];
157182 emit OwnerFreezeAlwaysAllowedTo (owner (), to, 0 , 0 );
158183 }
159184
@@ -162,11 +187,13 @@ abstract contract OwnerFreezable is Ownable, IOwnerFreezableV1 {
162187 /// @param from The address that tokens are being sent from.
163188 /// @param to The address that tokens are being sent to.
164189 function ownerFreezeCheckTransaction (address from , address to ) internal view {
190+ OwnerFreezableV1Storage storage s = getStorage ();
191+
165192 // We either simply revert or no-op for this check.
166193 // Revert if the contract is frozen and neither the `from` nor `to` are
167194 // in their respective always allowed lists.
168- if (block .timestamp < sOwnerFrozenUntil && sAlwaysAllowedFroms [from] == 0 && sAlwaysAllowedTos [to] == 0 ) {
169- revert IOwnerFreezableV1.OwnerFrozen (sOwnerFrozenUntil , from, to);
195+ if (block .timestamp < s.ownerFrozenUntil && s.alwaysAllowedFroms [from] == 0 && s.alwaysAllowedTos [to] == 0 ) {
196+ revert IOwnerFreezableV1.OwnerFrozen (s.ownerFrozenUntil , from, to);
170197 }
171198 }
172199}
0 commit comments