284 lines
10 KiB
Solidity
284 lines
10 KiB
Solidity
|
// SPDX-License-Identifier: MIT
|
||
|
pragma solidity >=0.7.0 <0.9.0;
|
||
|
|
||
|
import "../src/StdStorage.sol";
|
||
|
import "../src/Test.sol";
|
||
|
|
||
|
contract StdStorageTest is Test {
|
||
|
using stdStorage for StdStorage;
|
||
|
|
||
|
StorageTest internal test;
|
||
|
|
||
|
function setUp() public {
|
||
|
test = new StorageTest();
|
||
|
}
|
||
|
|
||
|
function testStorageHidden() public {
|
||
|
assertEq(uint256(keccak256("my.random.var")), stdstore.target(address(test)).sig("hidden()").find());
|
||
|
}
|
||
|
|
||
|
function testStorageObvious() public {
|
||
|
assertEq(uint256(0), stdstore.target(address(test)).sig("exists()").find());
|
||
|
}
|
||
|
|
||
|
function testStorageCheckedWriteHidden() public {
|
||
|
stdstore.target(address(test)).sig(test.hidden.selector).checked_write(100);
|
||
|
assertEq(uint256(test.hidden()), 100);
|
||
|
}
|
||
|
|
||
|
function testStorageCheckedWriteObvious() public {
|
||
|
stdstore.target(address(test)).sig(test.exists.selector).checked_write(100);
|
||
|
assertEq(test.exists(), 100);
|
||
|
}
|
||
|
|
||
|
function testStorageMapStructA() public {
|
||
|
uint256 slot =
|
||
|
stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(0).find();
|
||
|
assertEq(uint256(keccak256(abi.encode(address(this), 4))), slot);
|
||
|
}
|
||
|
|
||
|
function testStorageMapStructB() public {
|
||
|
uint256 slot =
|
||
|
stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(1).find();
|
||
|
assertEq(uint256(keccak256(abi.encode(address(this), 4))) + 1, slot);
|
||
|
}
|
||
|
|
||
|
function testStorageDeepMap() public {
|
||
|
uint256 slot = stdstore.target(address(test)).sig(test.deep_map.selector).with_key(address(this)).with_key(
|
||
|
address(this)
|
||
|
).find();
|
||
|
assertEq(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint256(5)))))), slot);
|
||
|
}
|
||
|
|
||
|
function testStorageCheckedWriteDeepMap() public {
|
||
|
stdstore.target(address(test)).sig(test.deep_map.selector).with_key(address(this)).with_key(address(this))
|
||
|
.checked_write(100);
|
||
|
assertEq(100, test.deep_map(address(this), address(this)));
|
||
|
}
|
||
|
|
||
|
function testStorageDeepMapStructA() public {
|
||
|
uint256 slot = stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this))
|
||
|
.with_key(address(this)).depth(0).find();
|
||
|
assertEq(
|
||
|
bytes32(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint256(6)))))) + 0),
|
||
|
bytes32(slot)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
function testStorageDeepMapStructB() public {
|
||
|
uint256 slot = stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this))
|
||
|
.with_key(address(this)).depth(1).find();
|
||
|
assertEq(
|
||
|
bytes32(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint256(6)))))) + 1),
|
||
|
bytes32(slot)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
function testStorageCheckedWriteDeepMapStructA() public {
|
||
|
stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)).with_key(
|
||
|
address(this)
|
||
|
).depth(0).checked_write(100);
|
||
|
(uint256 a, uint256 b) = test.deep_map_struct(address(this), address(this));
|
||
|
assertEq(100, a);
|
||
|
assertEq(0, b);
|
||
|
}
|
||
|
|
||
|
function testStorageCheckedWriteDeepMapStructB() public {
|
||
|
stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)).with_key(
|
||
|
address(this)
|
||
|
).depth(1).checked_write(100);
|
||
|
(uint256 a, uint256 b) = test.deep_map_struct(address(this), address(this));
|
||
|
assertEq(0, a);
|
||
|
assertEq(100, b);
|
||
|
}
|
||
|
|
||
|
function testStorageCheckedWriteMapStructA() public {
|
||
|
stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(0).checked_write(100);
|
||
|
(uint256 a, uint256 b) = test.map_struct(address(this));
|
||
|
assertEq(a, 100);
|
||
|
assertEq(b, 0);
|
||
|
}
|
||
|
|
||
|
function testStorageCheckedWriteMapStructB() public {
|
||
|
stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(1).checked_write(100);
|
||
|
(uint256 a, uint256 b) = test.map_struct(address(this));
|
||
|
assertEq(a, 0);
|
||
|
assertEq(b, 100);
|
||
|
}
|
||
|
|
||
|
function testStorageStructA() public {
|
||
|
uint256 slot = stdstore.target(address(test)).sig(test.basic.selector).depth(0).find();
|
||
|
assertEq(uint256(7), slot);
|
||
|
}
|
||
|
|
||
|
function testStorageStructB() public {
|
||
|
uint256 slot = stdstore.target(address(test)).sig(test.basic.selector).depth(1).find();
|
||
|
assertEq(uint256(7) + 1, slot);
|
||
|
}
|
||
|
|
||
|
function testStorageCheckedWriteStructA() public {
|
||
|
stdstore.target(address(test)).sig(test.basic.selector).depth(0).checked_write(100);
|
||
|
(uint256 a, uint256 b) = test.basic();
|
||
|
assertEq(a, 100);
|
||
|
assertEq(b, 1337);
|
||
|
}
|
||
|
|
||
|
function testStorageCheckedWriteStructB() public {
|
||
|
stdstore.target(address(test)).sig(test.basic.selector).depth(1).checked_write(100);
|
||
|
(uint256 a, uint256 b) = test.basic();
|
||
|
assertEq(a, 1337);
|
||
|
assertEq(b, 100);
|
||
|
}
|
||
|
|
||
|
function testStorageMapAddrFound() public {
|
||
|
uint256 slot = stdstore.target(address(test)).sig(test.map_addr.selector).with_key(address(this)).find();
|
||
|
assertEq(uint256(keccak256(abi.encode(address(this), uint256(1)))), slot);
|
||
|
}
|
||
|
|
||
|
function testStorageMapUintFound() public {
|
||
|
uint256 slot = stdstore.target(address(test)).sig(test.map_uint.selector).with_key(100).find();
|
||
|
assertEq(uint256(keccak256(abi.encode(100, uint256(2)))), slot);
|
||
|
}
|
||
|
|
||
|
function testStorageCheckedWriteMapUint() public {
|
||
|
stdstore.target(address(test)).sig(test.map_uint.selector).with_key(100).checked_write(100);
|
||
|
assertEq(100, test.map_uint(100));
|
||
|
}
|
||
|
|
||
|
function testStorageCheckedWriteMapAddr() public {
|
||
|
stdstore.target(address(test)).sig(test.map_addr.selector).with_key(address(this)).checked_write(100);
|
||
|
assertEq(100, test.map_addr(address(this)));
|
||
|
}
|
||
|
|
||
|
function testStorageCheckedWriteMapBool() public {
|
||
|
stdstore.target(address(test)).sig(test.map_bool.selector).with_key(address(this)).checked_write(true);
|
||
|
assertTrue(test.map_bool(address(this)));
|
||
|
}
|
||
|
|
||
|
function testFailStorageCheckedWriteMapPacked() public {
|
||
|
// expect PackedSlot error but not external call so cant expectRevert
|
||
|
stdstore.target(address(test)).sig(test.read_struct_lower.selector).with_key(address(uint160(1337)))
|
||
|
.checked_write(100);
|
||
|
}
|
||
|
|
||
|
function testStorageCheckedWriteMapPackedSuccess() public {
|
||
|
uint256 full = test.map_packed(address(1337));
|
||
|
// keep upper 128, set lower 128 to 1337
|
||
|
full = (full & (uint256((1 << 128) - 1) << 128)) | 1337;
|
||
|
stdstore.target(address(test)).sig(test.map_packed.selector).with_key(address(uint160(1337))).checked_write(
|
||
|
full
|
||
|
);
|
||
|
assertEq(1337, test.read_struct_lower(address(1337)));
|
||
|
}
|
||
|
|
||
|
function testFailStorageConst() public {
|
||
|
// vm.expectRevert(abi.encodeWithSignature("NotStorage(bytes4)", bytes4(keccak256("const()"))));
|
||
|
stdstore.target(address(test)).sig("const()").find();
|
||
|
}
|
||
|
|
||
|
function testFailStorageNativePack() public {
|
||
|
stdstore.target(address(test)).sig(test.tA.selector).find();
|
||
|
stdstore.target(address(test)).sig(test.tB.selector).find();
|
||
|
|
||
|
// these both would fail
|
||
|
stdstore.target(address(test)).sig(test.tC.selector).find();
|
||
|
stdstore.target(address(test)).sig(test.tD.selector).find();
|
||
|
}
|
||
|
|
||
|
function testStorageReadBytes32() public {
|
||
|
bytes32 val = stdstore.target(address(test)).sig(test.tE.selector).read_bytes32();
|
||
|
assertEq(val, hex"1337");
|
||
|
}
|
||
|
|
||
|
function testStorageReadBool_False() public {
|
||
|
bool val = stdstore.target(address(test)).sig(test.tB.selector).read_bool();
|
||
|
assertEq(val, false);
|
||
|
}
|
||
|
|
||
|
function testStorageReadBool_True() public {
|
||
|
bool val = stdstore.target(address(test)).sig(test.tH.selector).read_bool();
|
||
|
assertEq(val, true);
|
||
|
}
|
||
|
|
||
|
function testStorageReadBool_Revert() public {
|
||
|
vm.expectRevert("stdStorage read_bool(StdStorage): Cannot decode. Make sure you are reading a bool.");
|
||
|
this.readNonBoolValue();
|
||
|
}
|
||
|
|
||
|
function readNonBoolValue() public {
|
||
|
stdstore.target(address(test)).sig(test.tE.selector).read_bool();
|
||
|
}
|
||
|
|
||
|
function testStorageReadAddress() public {
|
||
|
address val = stdstore.target(address(test)).sig(test.tF.selector).read_address();
|
||
|
assertEq(val, address(1337));
|
||
|
}
|
||
|
|
||
|
function testStorageReadUint() public {
|
||
|
uint256 val = stdstore.target(address(test)).sig(test.exists.selector).read_uint();
|
||
|
assertEq(val, 1);
|
||
|
}
|
||
|
|
||
|
function testStorageReadInt() public {
|
||
|
int256 val = stdstore.target(address(test)).sig(test.tG.selector).read_int();
|
||
|
assertEq(val, type(int256).min);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
contract StorageTest {
|
||
|
uint256 public exists = 1;
|
||
|
mapping(address => uint256) public map_addr;
|
||
|
mapping(uint256 => uint256) public map_uint;
|
||
|
mapping(address => uint256) public map_packed;
|
||
|
mapping(address => UnpackedStruct) public map_struct;
|
||
|
mapping(address => mapping(address => uint256)) public deep_map;
|
||
|
mapping(address => mapping(address => UnpackedStruct)) public deep_map_struct;
|
||
|
UnpackedStruct public basic;
|
||
|
|
||
|
uint248 public tA;
|
||
|
bool public tB;
|
||
|
|
||
|
bool public tC = false;
|
||
|
uint248 public tD = 1;
|
||
|
|
||
|
struct UnpackedStruct {
|
||
|
uint256 a;
|
||
|
uint256 b;
|
||
|
}
|
||
|
|
||
|
mapping(address => bool) public map_bool;
|
||
|
|
||
|
bytes32 public tE = hex"1337";
|
||
|
address public tF = address(1337);
|
||
|
int256 public tG = type(int256).min;
|
||
|
bool public tH = true;
|
||
|
|
||
|
constructor() {
|
||
|
basic = UnpackedStruct({a: 1337, b: 1337});
|
||
|
|
||
|
uint256 two = (1 << 128) | 1;
|
||
|
map_packed[msg.sender] = two;
|
||
|
map_packed[address(uint160(1337))] = 1 << 128;
|
||
|
}
|
||
|
|
||
|
function read_struct_upper(address who) public view returns (uint256) {
|
||
|
return map_packed[who] >> 128;
|
||
|
}
|
||
|
|
||
|
function read_struct_lower(address who) public view returns (uint256) {
|
||
|
return map_packed[who] & ((1 << 128) - 1);
|
||
|
}
|
||
|
|
||
|
function hidden() public view returns (bytes32 t) {
|
||
|
bytes32 slot = keccak256("my.random.var");
|
||
|
/// @solidity memory-safe-assembly
|
||
|
assembly {
|
||
|
t := sload(slot)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function const() public pure returns (bytes32 t) {
|
||
|
t = bytes32(hex"1337");
|
||
|
}
|
||
|
}
|