Skip to content

Commit 724c39b

Browse files
authored
✨ LibTransient Registry (#1378)
1 parent c7f25d1 commit 724c39b

File tree

4 files changed

+453
-1
lines changed

4 files changed

+453
-1
lines changed

docs/utils/libtransient.md

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,18 @@ struct TBytes {
7575

7676
Pointer struct to a `bytes` in transient storage.
7777

78+
## Constants
79+
80+
### REGISTRY
81+
82+
```solidity
83+
address internal constant REGISTRY =
84+
0x000000000000297f64C7F8d9595e43257908F170
85+
```
86+
87+
The canonical address of the transient registry.
88+
See: https://gist.github.com/Vectorized/4ab665d7a234ef5aaaff2e5091ec261f
89+
7890
## Uint256 Operations
7991

8092
### tUint256(bytes32)
@@ -742,4 +754,65 @@ Clears the value at transient `ptr`.
742754
function clearCompat(TBytes storage ptr) internal
743755
```
744756

745-
Clears the value at transient `ptr`.
757+
Clears the value at transient `ptr`.
758+
759+
## Transient Registry Operations
760+
761+
### registrySet(bytes32,bytes)
762+
763+
```solidity
764+
function registrySet(bytes32 key, bytes memory value) internal
765+
```
766+
767+
Sets the value for the key.
768+
If the key does not exist, its admin will be set to the caller.
769+
If the key already exist, its value will be overwritten,
770+
and the caller must be the current admin for the key.
771+
Reverts with empty data if the registry has not been deployed.
772+
773+
### registryGet(bytes32)
774+
775+
```solidity
776+
function registryGet(bytes32 key)
777+
internal
778+
view
779+
returns (bytes memory result)
780+
```
781+
782+
Returns the value for the key.
783+
Reverts if the key does not exist.
784+
Reverts with empty data if the registry has not been deployed.
785+
786+
### registryClear(bytes32)
787+
788+
```solidity
789+
function registryClear(bytes32 key) internal
790+
```
791+
792+
Clears the admin and the value for the key.
793+
The caller must be the current admin of the key.
794+
Reverts with empty data if the registry has not been deployed.
795+
796+
### registryAdminOf(bytes32)
797+
798+
```solidity
799+
function registryAdminOf(bytes32 key)
800+
internal
801+
view
802+
returns (address result)
803+
```
804+
805+
Returns the admin of the key.
806+
Returns `address(0)` if the key does not exist.
807+
Reverts with empty data if the registry has not been deployed.
808+
809+
### registryChangeAdmin(bytes32,address)
810+
811+
```solidity
812+
function registryChangeAdmin(bytes32 key, address newAdmin) internal
813+
```
814+
815+
Changes the admin of the key.
816+
The caller must be the current admin of the key.
817+
The new admin must not be `address(0)`.
818+
Reverts with empty data if the registry has not been deployed.

src/utils/LibTransient.sol

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ library LibTransient {
5151
/// `bytes4(keccak256("_LIB_TRANSIENT_COMPAT_SLOT_SEED"))`.
5252
uint256 private constant _LIB_TRANSIENT_COMPAT_SLOT_SEED = 0x5a0b45f2;
5353

54+
/// @dev The canonical address of the transient registry.
55+
/// See: https://gist.github.com/Vectorized/4ab665d7a234ef5aaaff2e5091ec261f
56+
address internal constant REGISTRY = 0x000000000000297f64C7F8d9595e43257908F170;
57+
5458
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
5559
/* UINT256 OPERATIONS */
5660
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
@@ -690,6 +694,101 @@ library LibTransient {
690694
_compat(ptr)._spacer = 0;
691695
}
692696

697+
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
698+
/* TRANSIENT REGISTRY OPERATIONS */
699+
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
700+
701+
/// @dev Sets the value for the key.
702+
/// If the key does not exist, its admin will be set to the caller.
703+
/// If the key already exist, its value will be overwritten,
704+
/// and the caller must be the current admin for the key.
705+
/// Reverts with empty data if the registry has not been deployed.
706+
function registrySet(bytes32 key, bytes memory value) internal {
707+
/// @solidity memory-safe-assembly
708+
assembly {
709+
let m := mload(0x40)
710+
mstore(m, 0xaac438c0) // `set(bytes32,bytes)`.
711+
mstore(add(m, 0x20), key)
712+
mstore(add(m, 0x40), 0x40)
713+
let n := mload(value)
714+
mstore(add(m, 0x60), n)
715+
for { let i := 0 } lt(i, n) { i := add(i, 0x20) } {
716+
mstore(add(add(m, 0x80), i), mload(add(add(value, 0x20), i)))
717+
}
718+
if iszero(
719+
mul(
720+
returndatasize(),
721+
call(gas(), REGISTRY, 0, add(m, 0x1c), add(n, 0x64), 0x00, 0x20)
722+
)
723+
) { revert(0x00, returndatasize()) }
724+
}
725+
}
726+
727+
/// @dev Returns the value for the key.
728+
/// Reverts if the key does not exist.
729+
/// Reverts with empty data if the registry has not been deployed.
730+
function registryGet(bytes32 key) internal view returns (bytes memory result) {
731+
/// @solidity memory-safe-assembly
732+
assembly {
733+
result := mload(0x40)
734+
mstore(0x00, 0x8eaa6ac0) // `get(bytes32)`.
735+
mstore(0x20, key)
736+
if iszero(mul(returndatasize(), staticcall(gas(), REGISTRY, 0x1c, 0x24, 0x00, 0x20))) {
737+
revert(0x00, returndatasize())
738+
}
739+
// We can safely assume that the bytes will be containing the 0x20 offset.
740+
returndatacopy(result, 0x20, sub(returndatasize(), 0x20))
741+
mstore(0x40, add(result, returndatasize())) // Allocate memory.
742+
}
743+
}
744+
745+
/// @dev Clears the admin and the value for the key.
746+
/// The caller must be the current admin of the key.
747+
/// Reverts with empty data if the registry has not been deployed.
748+
function registryClear(bytes32 key) internal {
749+
/// @solidity memory-safe-assembly
750+
assembly {
751+
mstore(0x00, 0x97040a45) // `clear(bytes32)`.
752+
mstore(0x20, key)
753+
if iszero(mul(returndatasize(), call(gas(), REGISTRY, 0, 0x1c, 0x24, 0x00, 0x20))) {
754+
revert(0x00, returndatasize())
755+
}
756+
}
757+
}
758+
759+
/// @dev Returns the admin of the key.
760+
/// Returns `address(0)` if the key does not exist.
761+
/// Reverts with empty data if the registry has not been deployed.
762+
function registryAdminOf(bytes32 key) internal view returns (address result) {
763+
/// @solidity memory-safe-assembly
764+
assembly {
765+
mstore(0x00, 0xc5344411) // `adminOf(bytes32)`.
766+
mstore(0x20, key)
767+
if iszero(mul(returndatasize(), staticcall(gas(), REGISTRY, 0x1c, 0x24, 0x00, 0x20))) {
768+
revert(0x00, returndatasize())
769+
}
770+
result := mload(0x00)
771+
}
772+
}
773+
774+
/// @dev Changes the admin of the key.
775+
/// The caller must be the current admin of the key.
776+
/// The new admin must not be `address(0)`.
777+
/// Reverts with empty data if the registry has not been deployed.
778+
function registryChangeAdmin(bytes32 key, address newAdmin) internal {
779+
/// @solidity memory-safe-assembly
780+
assembly {
781+
let m := mload(0x40) // Cache the free memory pointer.
782+
mstore(0x00, 0x053b1ca3) // `changeAdmin(bytes32,address)`.
783+
mstore(0x20, key)
784+
mstore(0x40, shr(96, shl(96, newAdmin)))
785+
if iszero(mul(returndatasize(), call(gas(), REGISTRY, 0, 0x1c, 0x44, 0x00, 0x20))) {
786+
revert(0x00, returndatasize())
787+
}
788+
mstore(0x40, m) // Restore the free memory pointer.
789+
}
790+
}
791+
693792
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
694793
/* PRIVATE HELPERS */
695794
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

src/utils/g/LibTransient.sol

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ library LibTransient {
6060
/// `bytes4(keccak256("_LIB_TRANSIENT_COMPAT_SLOT_SEED"))`.
6161
uint256 private constant _LIB_TRANSIENT_COMPAT_SLOT_SEED = 0x5a0b45f2;
6262

63+
/// @dev The canonical address of the transient registry.
64+
/// See: https://gist.github.com/Vectorized/4ab665d7a234ef5aaaff2e5091ec261f
65+
address internal constant REGISTRY = 0x000000000000297f64C7F8d9595e43257908F170;
66+
6367
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
6468
/* UINT256 OPERATIONS */
6569
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
@@ -699,6 +703,101 @@ library LibTransient {
699703
_compat(ptr)._spacer = 0;
700704
}
701705

706+
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
707+
/* TRANSIENT REGISTRY OPERATIONS */
708+
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
709+
710+
/// @dev Sets the value for the key.
711+
/// If the key does not exist, its admin will be set to the caller.
712+
/// If the key already exist, its value will be overwritten,
713+
/// and the caller must be the current admin for the key.
714+
/// Reverts with empty data if the registry has not been deployed.
715+
function registrySet(bytes32 key, bytes memory value) internal {
716+
/// @solidity memory-safe-assembly
717+
assembly {
718+
let m := mload(0x40)
719+
mstore(m, 0xaac438c0) // `set(bytes32,bytes)`.
720+
mstore(add(m, 0x20), key)
721+
mstore(add(m, 0x40), 0x40)
722+
let n := mload(value)
723+
mstore(add(m, 0x60), n)
724+
for { let i := 0 } lt(i, n) { i := add(i, 0x20) } {
725+
mstore(add(add(m, 0x80), i), mload(add(add(value, 0x20), i)))
726+
}
727+
if iszero(
728+
mul(
729+
returndatasize(),
730+
call(gas(), REGISTRY, 0, add(m, 0x1c), add(n, 0x64), 0x00, 0x20)
731+
)
732+
) { revert(0x00, returndatasize()) }
733+
}
734+
}
735+
736+
/// @dev Returns the value for the key.
737+
/// Reverts if the key does not exist.
738+
/// Reverts with empty data if the registry has not been deployed.
739+
function registryGet(bytes32 key) internal view returns (bytes memory result) {
740+
/// @solidity memory-safe-assembly
741+
assembly {
742+
result := mload(0x40)
743+
mstore(0x00, 0x8eaa6ac0) // `get(bytes32)`.
744+
mstore(0x20, key)
745+
if iszero(mul(returndatasize(), staticcall(gas(), REGISTRY, 0x1c, 0x24, 0x00, 0x20))) {
746+
revert(0x00, returndatasize())
747+
}
748+
// We can safely assume that the bytes will be containing the 0x20 offset.
749+
returndatacopy(result, 0x20, sub(returndatasize(), 0x20))
750+
mstore(0x40, add(result, returndatasize())) // Allocate memory.
751+
}
752+
}
753+
754+
/// @dev Clears the admin and the value for the key.
755+
/// The caller must be the current admin of the key.
756+
/// Reverts with empty data if the registry has not been deployed.
757+
function registryClear(bytes32 key) internal {
758+
/// @solidity memory-safe-assembly
759+
assembly {
760+
mstore(0x00, 0x97040a45) // `clear(bytes32)`.
761+
mstore(0x20, key)
762+
if iszero(mul(returndatasize(), call(gas(), REGISTRY, 0, 0x1c, 0x24, 0x00, 0x20))) {
763+
revert(0x00, returndatasize())
764+
}
765+
}
766+
}
767+
768+
/// @dev Returns the admin of the key.
769+
/// Returns `address(0)` if the key does not exist.
770+
/// Reverts with empty data if the registry has not been deployed.
771+
function registryAdminOf(bytes32 key) internal view returns (address result) {
772+
/// @solidity memory-safe-assembly
773+
assembly {
774+
mstore(0x00, 0xc5344411) // `adminOf(bytes32)`.
775+
mstore(0x20, key)
776+
if iszero(mul(returndatasize(), staticcall(gas(), REGISTRY, 0x1c, 0x24, 0x00, 0x20))) {
777+
revert(0x00, returndatasize())
778+
}
779+
result := mload(0x00)
780+
}
781+
}
782+
783+
/// @dev Changes the admin of the key.
784+
/// The caller must be the current admin of the key.
785+
/// The new admin must not be `address(0)`.
786+
/// Reverts with empty data if the registry has not been deployed.
787+
function registryChangeAdmin(bytes32 key, address newAdmin) internal {
788+
/// @solidity memory-safe-assembly
789+
assembly {
790+
let m := mload(0x40) // Cache the free memory pointer.
791+
mstore(0x00, 0x053b1ca3) // `changeAdmin(bytes32,address)`.
792+
mstore(0x20, key)
793+
mstore(0x40, shr(96, shl(96, newAdmin)))
794+
if iszero(mul(returndatasize(), call(gas(), REGISTRY, 0, 0x1c, 0x44, 0x00, 0x20))) {
795+
revert(0x00, returndatasize())
796+
}
797+
mstore(0x40, m) // Restore the free memory pointer.
798+
}
799+
}
800+
702801
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
703802
/* PRIVATE HELPERS */
704803
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

0 commit comments

Comments
 (0)