-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: statemind - Incorrect address derivation through public key lead…
…s to registration inoperability
- Loading branch information
Showing
6 changed files
with
161 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.25; | ||
|
||
import {KeyManager} from "../../../managers/extendable/KeyManager.sol"; | ||
import {PauseableEnumerableSet} from "../../../libraries/PauseableEnumerableSet.sol"; | ||
|
||
/** | ||
* @title KeyManagerAddress | ||
* @notice Manages storage and validation of operator keys using address values | ||
* @dev Extends KeyManager to provide key management functionality | ||
*/ | ||
abstract contract KeyManagerAddress is KeyManager { | ||
uint64 public constant KeyManagerAddress_VERSION = 1; | ||
|
||
using PauseableEnumerableSet for PauseableEnumerableSet.AddressSet; | ||
|
||
error DuplicateKey(); | ||
error MaxDisabledKeysReached(); | ||
|
||
uint256 private constant MAX_DISABLED_KEYS = 1; | ||
|
||
struct KeyManagerAddressStorage { | ||
/// @notice Mapping from operator addresses to their keys | ||
mapping(address => PauseableEnumerableSet.AddressSet) _keys; | ||
/// @notice Mapping from keys to operator addresses | ||
mapping(address => address) _keyToOperator; | ||
} | ||
|
||
// keccak256(abi.encode(uint256(keccak256("symbiotic.storage.KeyManagerAddress")) - 1)) & ~bytes32(uint256(0xff)) | ||
bytes32 private constant KeyManagerAddressStorageLocation = | ||
0x3da47716e6090d5a5545e03387f4dac112d37cd069a5573bb81de8579bd9dc00; | ||
|
||
function _getKeyManagerAddressStorage() internal pure returns (KeyManagerAddressStorage storage s) { | ||
bytes32 location = KeyManagerAddressStorageLocation; | ||
assembly { | ||
s.slot := location | ||
} | ||
} | ||
|
||
/** | ||
* @notice Gets the operator address associated with a key | ||
* @param key The key to lookup | ||
* @return The operator address that owns the key, or zero address if none | ||
*/ | ||
function operatorByKey( | ||
bytes memory key | ||
) public view override returns (address) { | ||
KeyManagerAddressStorage storage $ = _getKeyManagerAddressStorage(); | ||
return $._keyToOperator[abi.decode(key, (address))]; | ||
} | ||
|
||
/** | ||
* @notice Gets an operator's active key at the current capture timestamp | ||
* @param operator The operator address to lookup | ||
* @return The operator's active key encoded as bytes, or encoded zero bytes if none | ||
*/ | ||
function operatorKey( | ||
address operator | ||
) public view override returns (bytes memory) { | ||
KeyManagerAddressStorage storage $ = _getKeyManagerAddressStorage(); | ||
address[] memory active = $._keys[operator].getActive(getCaptureTimestamp()); | ||
if (active.length == 0) { | ||
return abi.encode(address(0)); | ||
} | ||
return abi.encode(active[0]); | ||
} | ||
|
||
/** | ||
* @notice Checks if a key was active at a specific timestamp | ||
* @param timestamp The timestamp to check | ||
* @param key_ The key to check | ||
* @return True if the key was active at the timestamp, false otherwise | ||
*/ | ||
function keyWasActiveAt(uint48 timestamp, bytes memory key_) public view override returns (bool) { | ||
KeyManagerAddressStorage storage $ = _getKeyManagerAddressStorage(); | ||
address key = abi.decode(key_, (address)); | ||
return $._keys[$._keyToOperator[key]].wasActiveAt(timestamp, key); | ||
} | ||
|
||
/** | ||
* @notice Updates an operator's key | ||
* @dev Handles key rotation by disabling old key and registering new one | ||
* @param operator The operator address to update | ||
* @param key_ The new key to register, encoded as bytes | ||
*/ | ||
function _updateKey(address operator, bytes memory key_) internal override { | ||
KeyManagerAddressStorage storage $ = _getKeyManagerAddressStorage(); | ||
address key = abi.decode(key_, (address)); | ||
uint48 timestamp = _now(); | ||
|
||
if ($._keyToOperator[key] != address(0)) { | ||
revert DuplicateKey(); | ||
} | ||
|
||
// check if we have reached the max number of disabled keys | ||
// this allow us to limit the number times we can change the key | ||
if (key != address(0) && $._keys[operator].length() > MAX_DISABLED_KEYS + 1) { | ||
revert MaxDisabledKeysReached(); | ||
} | ||
|
||
if ($._keys[operator].length() > 0) { | ||
// try to remove disabled keys | ||
address prevKey = address($._keys[operator].set.array[0].value); | ||
if ($._keys[operator].checkUnregister(timestamp, _SLASHING_WINDOW(), prevKey)) { | ||
$._keys[operator].unregister(timestamp, _SLASHING_WINDOW(), prevKey); | ||
delete $._keyToOperator[prevKey]; | ||
} else if ($._keys[operator].wasActiveAt(timestamp, prevKey)) { | ||
$._keys[operator].pause(timestamp, prevKey); | ||
} | ||
} | ||
|
||
if (key != address(0)) { | ||
// register the new key | ||
$._keys[operator].register(timestamp, key); | ||
$._keyToOperator[key] = operator; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters