Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 74 additions & 1 deletion docs/utils/libtransient.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,18 @@ struct TBytes {

Pointer struct to a `bytes` in transient storage.

## Constants

### REGISTRY

```solidity
address internal constant REGISTRY =
0x000000000000297f64C7F8d9595e43257908F170
```

The canonical address of the transient registry.
See: https://gist.github.com/Vectorized/4ab665d7a234ef5aaaff2e5091ec261f

## Uint256 Operations

### tUint256(bytes32)
Expand Down Expand Up @@ -742,4 +754,65 @@ Clears the value at transient `ptr`.
function clearCompat(TBytes storage ptr) internal
```

Clears the value at transient `ptr`.
Clears the value at transient `ptr`.

## Transient Registry Operations

### registrySet(bytes32,bytes)

```solidity
function registrySet(bytes32 key, bytes memory value) internal
```

Sets the value for the key.
If the key does not exist, its admin will be set to the caller.
If the key already exist, its value will be overwritten,
and the caller must be the current admin for the key.
Reverts with empty data if the registry has not been deployed.

### registryGet(bytes32)

```solidity
function registryGet(bytes32 key)
internal
view
returns (bytes memory result)
```

Returns the value for the key.
Reverts if the key does not exist.
Reverts with empty data if the registry has not been deployed.

### registryClear(bytes32)

```solidity
function registryClear(bytes32 key) internal
```

Clears the admin and the value for the key.
The caller must be the current admin of the key.
Reverts with empty data if the registry has not been deployed.

### registryAdminOf(bytes32)

```solidity
function registryAdminOf(bytes32 key)
internal
view
returns (address result)
```

Returns the admin of the key.
Returns `address(0)` if the key does not exist.
Reverts with empty data if the registry has not been deployed.

### registryChangeAdmin(bytes32,address)

```solidity
function registryChangeAdmin(bytes32 key, address newAdmin) internal
```

Changes the admin of the key.
The caller must be the current admin of the key.
The new admin must not be `address(0)`.
Reverts with empty data if the registry has not been deployed.
99 changes: 99 additions & 0 deletions src/utils/LibTransient.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ library LibTransient {
/// `bytes4(keccak256("_LIB_TRANSIENT_COMPAT_SLOT_SEED"))`.
uint256 private constant _LIB_TRANSIENT_COMPAT_SLOT_SEED = 0x5a0b45f2;

/// @dev The canonical address of the transient registry.
/// See: https://gist.github.com/Vectorized/4ab665d7a234ef5aaaff2e5091ec261f
address internal constant REGISTRY = 0x000000000000297f64C7F8d9595e43257908F170;

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* UINT256 OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
Expand Down Expand Up @@ -690,6 +694,101 @@ library LibTransient {
_compat(ptr)._spacer = 0;
}

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* TRANSIENT REGISTRY OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

/// @dev Sets the value for the key.
/// If the key does not exist, its admin will be set to the caller.
/// If the key already exist, its value will be overwritten,
/// and the caller must be the current admin for the key.
/// Reverts with empty data if the registry has not been deployed.
function registrySet(bytes32 key, bytes memory value) internal {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, 0xaac438c0) // `set(bytes32,bytes)`.
mstore(add(m, 0x20), key)
mstore(add(m, 0x40), 0x40)
let n := mload(value)
mstore(add(m, 0x60), n)
for { let i := 0 } lt(i, n) { i := add(i, 0x20) } {
mstore(add(add(m, 0x80), i), mload(add(add(value, 0x20), i)))
}
if iszero(
mul(
returndatasize(),
call(gas(), REGISTRY, 0, add(m, 0x1c), add(n, 0x64), 0x00, 0x20)
)
) { revert(0x00, returndatasize()) }
}
}

/// @dev Returns the value for the key.
/// Reverts if the key does not exist.
/// Reverts with empty data if the registry has not been deployed.
function registryGet(bytes32 key) internal view returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
mstore(0x00, 0x8eaa6ac0) // `get(bytes32)`.
mstore(0x20, key)
if iszero(mul(returndatasize(), staticcall(gas(), REGISTRY, 0x1c, 0x24, 0x00, 0x20))) {
revert(0x00, returndatasize())
}
// We can safely assume that the bytes will be containing the 0x20 offset.
returndatacopy(result, 0x20, sub(returndatasize(), 0x20))
mstore(0x40, add(result, returndatasize())) // Allocate memory.
}
}

/// @dev Clears the admin and the value for the key.
/// The caller must be the current admin of the key.
/// Reverts with empty data if the registry has not been deployed.
function registryClear(bytes32 key) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, 0x97040a45) // `clear(bytes32)`.
mstore(0x20, key)
if iszero(mul(returndatasize(), call(gas(), REGISTRY, 0, 0x1c, 0x24, 0x00, 0x20))) {
revert(0x00, returndatasize())
}
}
}

/// @dev Returns the admin of the key.
/// Returns `address(0)` if the key does not exist.
/// Reverts with empty data if the registry has not been deployed.
function registryAdminOf(bytes32 key) internal view returns (address result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, 0xc5344411) // `adminOf(bytes32)`.
mstore(0x20, key)
if iszero(mul(returndatasize(), staticcall(gas(), REGISTRY, 0x1c, 0x24, 0x00, 0x20))) {
revert(0x00, returndatasize())
}
result := mload(0x00)
}
}

/// @dev Changes the admin of the key.
/// The caller must be the current admin of the key.
/// The new admin must not be `address(0)`.
/// Reverts with empty data if the registry has not been deployed.
function registryChangeAdmin(bytes32 key, address newAdmin) internal {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x00, 0x053b1ca3) // `changeAdmin(bytes32,address)`.
mstore(0x20, key)
mstore(0x40, shr(96, shl(96, newAdmin)))
if iszero(mul(returndatasize(), call(gas(), REGISTRY, 0, 0x1c, 0x44, 0x00, 0x20))) {
revert(0x00, returndatasize())
}
mstore(0x40, m) // Restore the free memory pointer.
}
}

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PRIVATE HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
Expand Down
99 changes: 99 additions & 0 deletions src/utils/g/LibTransient.sol
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ library LibTransient {
/// `bytes4(keccak256("_LIB_TRANSIENT_COMPAT_SLOT_SEED"))`.
uint256 private constant _LIB_TRANSIENT_COMPAT_SLOT_SEED = 0x5a0b45f2;

/// @dev The canonical address of the transient registry.
/// See: https://gist.github.com/Vectorized/4ab665d7a234ef5aaaff2e5091ec261f
address internal constant REGISTRY = 0x000000000000297f64C7F8d9595e43257908F170;

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* UINT256 OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
Expand Down Expand Up @@ -699,6 +703,101 @@ library LibTransient {
_compat(ptr)._spacer = 0;
}

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* TRANSIENT REGISTRY OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

/// @dev Sets the value for the key.
/// If the key does not exist, its admin will be set to the caller.
/// If the key already exist, its value will be overwritten,
/// and the caller must be the current admin for the key.
/// Reverts with empty data if the registry has not been deployed.
function registrySet(bytes32 key, bytes memory value) internal {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, 0xaac438c0) // `set(bytes32,bytes)`.
mstore(add(m, 0x20), key)
mstore(add(m, 0x40), 0x40)
let n := mload(value)
mstore(add(m, 0x60), n)
for { let i := 0 } lt(i, n) { i := add(i, 0x20) } {
mstore(add(add(m, 0x80), i), mload(add(add(value, 0x20), i)))
}
if iszero(
mul(
returndatasize(),
call(gas(), REGISTRY, 0, add(m, 0x1c), add(n, 0x64), 0x00, 0x20)
)
) { revert(0x00, returndatasize()) }
}
}

/// @dev Returns the value for the key.
/// Reverts if the key does not exist.
/// Reverts with empty data if the registry has not been deployed.
function registryGet(bytes32 key) internal view returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
mstore(0x00, 0x8eaa6ac0) // `get(bytes32)`.
mstore(0x20, key)
if iszero(mul(returndatasize(), staticcall(gas(), REGISTRY, 0x1c, 0x24, 0x00, 0x20))) {
revert(0x00, returndatasize())
}
// We can safely assume that the bytes will be containing the 0x20 offset.
returndatacopy(result, 0x20, sub(returndatasize(), 0x20))
mstore(0x40, add(result, returndatasize())) // Allocate memory.
}
}

/// @dev Clears the admin and the value for the key.
/// The caller must be the current admin of the key.
/// Reverts with empty data if the registry has not been deployed.
function registryClear(bytes32 key) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, 0x97040a45) // `clear(bytes32)`.
mstore(0x20, key)
if iszero(mul(returndatasize(), call(gas(), REGISTRY, 0, 0x1c, 0x24, 0x00, 0x20))) {
revert(0x00, returndatasize())
}
}
}

/// @dev Returns the admin of the key.
/// Returns `address(0)` if the key does not exist.
/// Reverts with empty data if the registry has not been deployed.
function registryAdminOf(bytes32 key) internal view returns (address result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, 0xc5344411) // `adminOf(bytes32)`.
mstore(0x20, key)
if iszero(mul(returndatasize(), staticcall(gas(), REGISTRY, 0x1c, 0x24, 0x00, 0x20))) {
revert(0x00, returndatasize())
}
result := mload(0x00)
}
}

/// @dev Changes the admin of the key.
/// The caller must be the current admin of the key.
/// The new admin must not be `address(0)`.
/// Reverts with empty data if the registry has not been deployed.
function registryChangeAdmin(bytes32 key, address newAdmin) internal {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x00, 0x053b1ca3) // `changeAdmin(bytes32,address)`.
mstore(0x20, key)
mstore(0x40, shr(96, shl(96, newAdmin)))
if iszero(mul(returndatasize(), call(gas(), REGISTRY, 0, 0x1c, 0x44, 0x00, 0x20))) {
revert(0x00, returndatasize())
}
mstore(0x40, m) // Restore the free memory pointer.
}
}

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PRIVATE HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
Expand Down
Loading
Loading