-
Notifications
You must be signed in to change notification settings - Fork 58
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add owner guardian contracts * fix ownershipRequestedAt usage
- Loading branch information
Showing
3 changed files
with
158 additions
and
1 deletion.
There are no files selected for viewing
71 changes: 71 additions & 0 deletions
71
protocol/governance/contracts/modules/core/GuardianModule.sol
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,71 @@ | ||
//SPDX-License-Identifier: MIT | ||
pragma solidity >=0.8.11 <0.9.0; | ||
|
||
import {AccessError} from "@synthetixio/core-contracts/contracts/errors/AccessError.sol"; | ||
import {AddressError} from "@synthetixio/core-contracts/contracts/errors/AddressError.sol"; | ||
import {ChangeError} from "@synthetixio/core-contracts/contracts/errors/ChangeError.sol"; | ||
import {Guardian} from "../../storage/Guardian.sol"; | ||
|
||
contract GuardianModule { | ||
/** | ||
* @notice Thrown when an address tries to accept guardian role but has not been nominated. | ||
* @param addr The address that is trying to accept the guardian role. | ||
*/ | ||
error NotNominated(address addr); | ||
|
||
/** | ||
* @notice Emitted when an address has been nominated. | ||
* @param newOwner The address that has been nominated. | ||
*/ | ||
event GuardianNominated(address newOwner); | ||
|
||
/** | ||
* @notice Emitted when the guardianship of the contract has changed. | ||
* @param oldOwner The previous guardian of the contract. | ||
* @param newOwner The new guardian of the contract. | ||
*/ | ||
event GuardianChanged(address oldOwner, address newOwner); | ||
|
||
function acceptGuardianship() public { | ||
Guardian.Data storage store = Guardian.load(); | ||
|
||
address currentNominatedGuardian = store.nominatedGuardian; | ||
if (msg.sender != currentNominatedGuardian) { | ||
revert NotNominated(msg.sender); | ||
} | ||
|
||
emit GuardianChanged(store.guardian, currentNominatedGuardian); | ||
|
||
store.guardian = currentNominatedGuardian; | ||
store.nominatedGuardian = address(0); | ||
store.ownershipRequestedAt = 0; | ||
} | ||
|
||
function nominateNewGuardian(address newNominatedGuardian) public { | ||
Guardian.onlyGuardian(); | ||
|
||
Guardian.Data storage store = Guardian.load(); | ||
|
||
if (newNominatedGuardian == address(0)) { | ||
revert AddressError.ZeroAddress(); | ||
} | ||
|
||
if (newNominatedGuardian == store.nominatedGuardian) { | ||
revert ChangeError.NoChange(); | ||
} | ||
|
||
store.nominatedGuardian = newNominatedGuardian; | ||
emit GuardianNominated(newNominatedGuardian); | ||
} | ||
|
||
function renounceGuardianNomination() external { | ||
Guardian.Data storage store = Guardian.load(); | ||
|
||
if (store.nominatedGuardian != msg.sender) { | ||
revert NotNominated(msg.sender); | ||
} | ||
|
||
store.nominatedGuardian = address(0); | ||
store.ownershipRequestedAt = 0; | ||
} | ||
} |
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 |
---|---|---|
@@ -1,9 +1,61 @@ | ||
//SPDX-License-Identifier: MIT | ||
pragma solidity >=0.8.11 <0.9.0; | ||
|
||
import {AccessError} from "@synthetixio/core-contracts/contracts/errors/AccessError.sol"; | ||
import {AddressError} from "@synthetixio/core-contracts/contracts/errors/AddressError.sol"; | ||
import {ChangeError} from "@synthetixio/core-contracts/contracts/errors/ChangeError.sol"; | ||
import {SafeCastU256} from "@synthetixio/core-contracts/contracts/utils/SafeCast.sol"; | ||
import {OwnerModule as BaseOwnerModule} from "@synthetixio/core-modules/contracts/modules/OwnerModule.sol"; | ||
import {OwnableStorage} from "@synthetixio/core-contracts/contracts/ownership/OwnableStorage.sol"; | ||
import {Guardian} from "../../storage/Guardian.sol"; | ||
|
||
// solhint-disable-next-line no-empty-blocks | ||
contract OwnerModule is BaseOwnerModule { | ||
using SafeCastU256 for uint256; | ||
|
||
/** | ||
* @notice Thrown when an the ownership is accepted before the nomination delay | ||
*/ | ||
error OwnershipAcceptanceTooEarly(); | ||
|
||
function acceptOwnership() public override { | ||
super.acceptOwnership(); | ||
|
||
Guardian.Data storage store = Guardian.load(); | ||
|
||
if (block.timestamp.to64() - store.ownershipRequestedAt < Guardian.RESCUE_DELAY) { | ||
revert OwnershipAcceptanceTooEarly(); | ||
} | ||
|
||
store.ownershipRequestedAt = 0; | ||
} | ||
|
||
function nominateNewOwner(address newNominatedOwner) public override { | ||
Guardian.onlyGuardian(); | ||
|
||
OwnableStorage.Data storage ownableStore = OwnableStorage.load(); | ||
Guardian.Data storage guardianStore = Guardian.load(); | ||
|
||
if (newNominatedOwner == address(0)) { | ||
revert AddressError.ZeroAddress(); | ||
} | ||
|
||
if ( | ||
newNominatedOwner == ownableStore.nominatedOwner || | ||
newNominatedOwner == ownableStore.owner | ||
) { | ||
revert ChangeError.NoChange(); | ||
} | ||
|
||
guardianStore.ownershipRequestedAt = block.timestamp.to64(); | ||
ownableStore.nominatedOwner = newNominatedOwner; | ||
|
||
emit OwnerNominated(newNominatedOwner); | ||
} | ||
|
||
function renounceNomination() external override { | ||
super.renounceNomination(); | ||
|
||
Guardian.Data storage store = Guardian.load(); | ||
store.ownershipRequestedAt = 0; | ||
} | ||
} |
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,34 @@ | ||
//SPDX-License-Identifier: MIT | ||
pragma solidity >=0.8.11 <0.9.0; | ||
|
||
import {AccessError} from "@synthetixio/core-contracts/contracts/errors/AccessError.sol"; | ||
|
||
library Guardian { | ||
bytes32 private constant _STORAGE_SLOT = | ||
keccak256(abi.encode("io.synthetix.governance.Guardian")); | ||
|
||
uint64 public constant RESCUE_DELAY = 7 days; | ||
|
||
struct Data { | ||
address guardian; | ||
address nominatedGuardian; | ||
uint64 ownershipRequestedAt; | ||
} | ||
|
||
function load() internal pure returns (Data storage store) { | ||
bytes32 s = _STORAGE_SLOT; | ||
assembly { | ||
store.slot := s | ||
} | ||
} | ||
|
||
function onlyGuardian() internal view { | ||
if (msg.sender != getGuardian()) { | ||
revert AccessError.Unauthorized(msg.sender); | ||
} | ||
} | ||
|
||
function getGuardian() internal view returns (address) { | ||
return Guardian.load().guardian; | ||
} | ||
} |