arnaucube
arnaucube/poseidon-solidity-examplePublic Self-hosted repository
poseidon-solidity-example/lib/forge-std/src/StdStorage.sol
lib/forge-std/src/StdStorage.solRaw
  1// SPDX-License-Identifier: MIT
  2pragma solidity >=0.6.2 <0.9.0;
  3
  4import {Vm} from "./Vm.sol";
  5
  6struct StdStorage {
  7    mapping(address => mapping(bytes4 => mapping(bytes32 => uint256))) slots;
  8    mapping(address => mapping(bytes4 => mapping(bytes32 => bool))) finds;
  9    bytes32[] _keys;
 10    bytes4 _sig;
 11    uint256 _depth;
 12    address _target;
 13    bytes32 _set;
 14}
 15
 16library stdStorageSafe {
 17    event SlotFound(address who, bytes4 fsig, bytes32 keysHash, uint256 slot);
 18    event WARNING_UninitedSlot(address who, uint256 slot);
 19
 20    Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
 21
 22    function sigs(string memory sigStr) internal pure returns (bytes4) {
 23        return bytes4(keccak256(bytes(sigStr)));
 24    }
 25
 26    /// @notice find an arbitrary storage slot given a function sig, input data, address of the contract and a value to check against
 27    // slot complexity:
 28    //  if flat, will be bytes32(uint256(uint));
 29    //  if map, will be keccak256(abi.encode(key, uint(slot)));
 30    //  if deep map, will be keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot)))));
 31    //  if map struct, will be bytes32(uint256(keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot)))))) + structFieldDepth);
 32    function find(StdStorage storage self) internal returns (uint256) {
 33        address who = self._target;
 34        bytes4 fsig = self._sig;
 35        uint256 field_depth = self._depth;
 36        bytes32[] memory ins = self._keys;
 37
 38        // calldata to test against
 39        if (self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]) {
 40            return self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))];
 41        }
 42        bytes memory cald = abi.encodePacked(fsig, flatten(ins));
 43        vm.record();
 44        bytes32 fdat;
 45        {
 46            (, bytes memory rdat) = who.staticcall(cald);
 47            fdat = bytesToBytes32(rdat, 32 * field_depth);
 48        }
 49
 50        (bytes32[] memory reads,) = vm.accesses(address(who));
 51        if (reads.length == 1) {
 52            bytes32 curr = vm.load(who, reads[0]);
 53            if (curr == bytes32(0)) {
 54                emit WARNING_UninitedSlot(who, uint256(reads[0]));
 55            }
 56            if (fdat != curr) {
 57                require(
 58                    false,
 59                    "stdStorage find(StdStorage): Packed slot. This would cause dangerous overwriting and currently isn't supported."
 60                );
 61            }
 62            emit SlotFound(who, fsig, keccak256(abi.encodePacked(ins, field_depth)), uint256(reads[0]));
 63            self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = uint256(reads[0]);
 64            self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = true;
 65        } else if (reads.length > 1) {
 66            for (uint256 i = 0; i < reads.length; i++) {
 67                bytes32 prev = vm.load(who, reads[i]);
 68                if (prev == bytes32(0)) {
 69                    emit WARNING_UninitedSlot(who, uint256(reads[i]));
 70                }
 71                // store
 72                vm.store(who, reads[i], bytes32(hex"1337"));
 73                bool success;
 74                bytes memory rdat;
 75                {
 76                    (success, rdat) = who.staticcall(cald);
 77                    fdat = bytesToBytes32(rdat, 32 * field_depth);
 78                }
 79
 80                if (success && fdat == bytes32(hex"1337")) {
 81                    // we found which of the slots is the actual one
 82                    emit SlotFound(who, fsig, keccak256(abi.encodePacked(ins, field_depth)), uint256(reads[i]));
 83                    self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = uint256(reads[i]);
 84                    self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = true;
 85                    vm.store(who, reads[i], prev);
 86                    break;
 87                }
 88                vm.store(who, reads[i], prev);
 89            }
 90        } else {
 91            revert("stdStorage find(StdStorage): No storage use detected for target.");
 92        }
 93
 94        require(
 95            self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))],
 96            "stdStorage find(StdStorage): Slot(s) not found."
 97        );
 98
 99        delete self._target;
100        delete self._sig;
101        delete self._keys;
102        delete self._depth;
103
104        return self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))];
105    }
106
107    function target(StdStorage storage self, address _target) internal returns (StdStorage storage) {
108        self._target = _target;
109        return self;
110    }
111
112    function sig(StdStorage storage self, bytes4 _sig) internal returns (StdStorage storage) {
113        self._sig = _sig;
114        return self;
115    }
116
117    function sig(StdStorage storage self, string memory _sig) internal returns (StdStorage storage) {
118        self._sig = sigs(_sig);
119        return self;
120    }
121
122    function with_key(StdStorage storage self, address who) internal returns (StdStorage storage) {
123        self._keys.push(bytes32(uint256(uint160(who))));
124        return self;
125    }
126
127    function with_key(StdStorage storage self, uint256 amt) internal returns (StdStorage storage) {
128        self._keys.push(bytes32(amt));
129        return self;
130    }
131
132    function with_key(StdStorage storage self, bytes32 key) internal returns (StdStorage storage) {
133        self._keys.push(key);
134        return self;
135    }
136
137    function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) {
138        self._depth = _depth;
139        return self;
140    }
141
142    function read(StdStorage storage self) private returns (bytes memory) {
143        address t = self._target;
144        uint256 s = find(self);
145        return abi.encode(vm.load(t, bytes32(s)));
146    }
147
148    function read_bytes32(StdStorage storage self) internal returns (bytes32) {
149        return abi.decode(read(self), (bytes32));
150    }
151
152    function read_bool(StdStorage storage self) internal returns (bool) {
153        int256 v = read_int(self);
154        if (v == 0) return false;
155        if (v == 1) return true;
156        revert("stdStorage read_bool(StdStorage): Cannot decode. Make sure you are reading a bool.");
157    }
158
159    function read_address(StdStorage storage self) internal returns (address) {
160        return abi.decode(read(self), (address));
161    }
162
163    function read_uint(StdStorage storage self) internal returns (uint256) {
164        return abi.decode(read(self), (uint256));
165    }
166
167    function read_int(StdStorage storage self) internal returns (int256) {
168        return abi.decode(read(self), (int256));
169    }
170
171    function bytesToBytes32(bytes memory b, uint256 offset) private pure returns (bytes32) {
172        bytes32 out;
173
174        uint256 max = b.length > 32 ? 32 : b.length;
175        for (uint256 i = 0; i < max; i++) {
176            out |= bytes32(b[offset + i] & 0xFF) >> (i * 8);
177        }
178        return out;
179    }
180
181    function flatten(bytes32[] memory b) private pure returns (bytes memory) {
182        bytes memory result = new bytes(b.length * 32);
183        for (uint256 i = 0; i < b.length; i++) {
184            bytes32 k = b[i];
185            /// @solidity memory-safe-assembly
186            assembly {
187                mstore(add(result, add(32, mul(32, i))), k)
188            }
189        }
190
191        return result;
192    }
193}
194
195library stdStorage {
196    Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
197
198    function sigs(string memory sigStr) internal pure returns (bytes4) {
199        return stdStorageSafe.sigs(sigStr);
200    }
201
202    function find(StdStorage storage self) internal returns (uint256) {
203        return stdStorageSafe.find(self);
204    }
205
206    function target(StdStorage storage self, address _target) internal returns (StdStorage storage) {
207        return stdStorageSafe.target(self, _target);
208    }
209
210    function sig(StdStorage storage self, bytes4 _sig) internal returns (StdStorage storage) {
211        return stdStorageSafe.sig(self, _sig);
212    }
213
214    function sig(StdStorage storage self, string memory _sig) internal returns (StdStorage storage) {
215        return stdStorageSafe.sig(self, _sig);
216    }
217
218    function with_key(StdStorage storage self, address who) internal returns (StdStorage storage) {
219        return stdStorageSafe.with_key(self, who);
220    }
221
222    function with_key(StdStorage storage self, uint256 amt) internal returns (StdStorage storage) {
223        return stdStorageSafe.with_key(self, amt);
224    }
225
226    function with_key(StdStorage storage self, bytes32 key) internal returns (StdStorage storage) {
227        return stdStorageSafe.with_key(self, key);
228    }
229
230    function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) {
231        return stdStorageSafe.depth(self, _depth);
232    }
233
234    function checked_write(StdStorage storage self, address who) internal {
235        checked_write(self, bytes32(uint256(uint160(who))));
236    }
237
238    function checked_write(StdStorage storage self, uint256 amt) internal {
239        checked_write(self, bytes32(amt));
240    }
241
242    function checked_write(StdStorage storage self, bool write) internal {
243        bytes32 t;
244        /// @solidity memory-safe-assembly
245        assembly {
246            t := write
247        }
248        checked_write(self, t);
249    }
250
251    function checked_write(StdStorage storage self, bytes32 set) internal {
252        address who = self._target;
253        bytes4 fsig = self._sig;
254        uint256 field_depth = self._depth;
255        bytes32[] memory ins = self._keys;
256
257        bytes memory cald = abi.encodePacked(fsig, flatten(ins));
258        if (!self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]) {
259            find(self);
260        }
261        bytes32 slot = bytes32(self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]);
262
263        bytes32 fdat;
264        {
265            (, bytes memory rdat) = who.staticcall(cald);
266            fdat = bytesToBytes32(rdat, 32 * field_depth);
267        }
268        bytes32 curr = vm.load(who, slot);
269
270        if (fdat != curr) {
271            require(
272                false,
273                "stdStorage find(StdStorage): Packed slot. This would cause dangerous overwriting and currently isn't supported."
274            );
275        }
276        vm.store(who, slot, set);
277        delete self._target;
278        delete self._sig;
279        delete self._keys;
280        delete self._depth;
281    }
282
283    function read_bytes32(StdStorage storage self) internal returns (bytes32) {
284        return stdStorageSafe.read_bytes32(self);
285    }
286
287    function read_bool(StdStorage storage self) internal returns (bool) {
288        return stdStorageSafe.read_bool(self);
289    }
290
291    function read_address(StdStorage storage self) internal returns (address) {
292        return stdStorageSafe.read_address(self);
293    }
294
295    function read_uint(StdStorage storage self) internal returns (uint256) {
296        return stdStorageSafe.read_uint(self);
297    }
298
299    function read_int(StdStorage storage self) internal returns (int256) {
300        return stdStorageSafe.read_int(self);
301    }
302
303    // Private function so needs to be copied over
304    function bytesToBytes32(bytes memory b, uint256 offset) private pure returns (bytes32) {
305        bytes32 out;
306
307        uint256 max = b.length > 32 ? 32 : b.length;
308        for (uint256 i = 0; i < max; i++) {
309            out |= bytes32(b[offset + i] & 0xFF) >> (i * 8);
310        }
311        return out;
312    }
313
314    // Private function so needs to be copied over
315    function flatten(bytes32[] memory b) private pure returns (bytes memory) {
316        bytes memory result = new bytes(b.length * 32);
317        for (uint256 i = 0; i < b.length; i++) {
318            bytes32 k = b[i];
319            /// @solidity memory-safe-assembly
320            assembly {
321                mstore(add(result, add(32, mul(32, i))), k)
322            }
323        }
324
325        return result;
326    }
327}