-
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.
- Loading branch information
Showing
6 changed files
with
169 additions
and
36 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
[submodule "lib/forge-std"] | ||
path = lib/forge-std | ||
url = https://github.com/foundry-rs/forge-std | ||
[submodule "lib/openzeppelin-contracts-upgradeable"] | ||
path = lib/openzeppelin-contracts-upgradeable | ||
url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable |
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
Submodule forge-std
updated
42 files
Submodule openzeppelin-contracts-upgradeable
added at
723f8c
72 changes: 72 additions & 0 deletions
72
src/contracts/access-control/UpgradableOwnableWithGuardian.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,72 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.20; | ||
|
||
import {OwnableUpgradeable} from 'openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol'; | ||
import {IWithGuardian} from './interfaces/IWithGuardian.sol'; | ||
|
||
/** | ||
* Forked version of https://github.com/bgd-labs/solidity-utils/blob/main/src/contracts/access-control/OwnableWithGuardian.sol | ||
* Relying on UpgradableOwnable & moving the storage to 7201 | ||
*/ | ||
abstract contract UpgradableOwnableWithGuardian is OwnableUpgradeable, IWithGuardian { | ||
/// @custom:storage-location erc7201:aave.storage.OwnableWithGuardian | ||
struct OwnableWithGuardian { | ||
address _guardian; | ||
} | ||
|
||
// keccak256(abi.encode(uint256(keccak256("aave.storage.OwnableWithGuardian")) - 1)) & ~bytes32(uint256(0xff)) | ||
bytes32 private constant OwnableWithGuardianStorageLocation = | ||
0xdc8016945fab92f4608d8f23802ef36d865b35bd839402e24dec05cd76049e00; | ||
|
||
function _getOwnableWithGuardianStorage() private pure returns (OwnableWithGuardian storage $) { | ||
assembly { | ||
$.slot := OwnableWithGuardianStorageLocation | ||
} | ||
} | ||
|
||
/** | ||
* @dev Initializes the contract setting the address provided by the deployer as the initial owner. | ||
*/ | ||
function __Ownable_With_Guardian_init(address initialGuardian) internal onlyInitializing { | ||
_updateGuardian(initialGuardian); | ||
} | ||
|
||
modifier onlyGuardian() { | ||
_checkGuardian(); | ||
_; | ||
} | ||
|
||
modifier onlyOwnerOrGuardian() { | ||
_checkOwnerOrGuardian(); | ||
_; | ||
} | ||
|
||
function guardian() public view override returns (address) { | ||
OwnableWithGuardian storage $ = _getOwnableWithGuardianStorage(); | ||
return $._guardian; | ||
} | ||
|
||
/// @inheritdoc IWithGuardian | ||
function updateGuardian(address newGuardian) external override onlyOwnerOrGuardian { | ||
_updateGuardian(newGuardian); | ||
} | ||
|
||
/** | ||
* @dev method to update the guardian | ||
* @param newGuardian the new guardian address | ||
*/ | ||
function _updateGuardian(address newGuardian) internal { | ||
OwnableWithGuardian storage $ = _getOwnableWithGuardianStorage(); | ||
address oldGuardian = $._guardian; | ||
$._guardian = newGuardian; | ||
emit GuardianUpdated(oldGuardian, newGuardian); | ||
} | ||
|
||
function _checkGuardian() internal view { | ||
require(guardian() == _msgSender(), 'ONLY_BY_GUARDIAN'); | ||
} | ||
|
||
function _checkOwnerOrGuardian() internal view { | ||
require(_msgSender() == owner() || _msgSender() == guardian(), 'ONLY_BY_OWNER_OR_GUARDIAN'); | ||
} | ||
} |
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,59 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.20; | ||
|
||
import 'forge-std/Test.sol'; | ||
import {UpgradableOwnableWithGuardian} from '../src/contracts/access-control/UpgradableOwnableWithGuardian.sol'; | ||
|
||
contract ImplOwnableWithGuardian is UpgradableOwnableWithGuardian { | ||
function initialize(address owner, address guardian) public initializer { | ||
__Ownable_init(owner); | ||
__Ownable_With_Guardian_init(guardian); | ||
} | ||
|
||
function mock_onlyGuardian() external onlyGuardian {} | ||
|
||
function mock_onlyOwnerOrGuardian() external onlyOwnerOrGuardian {} | ||
} | ||
|
||
contract TestOfUpgradableOwnableWithGuardian is Test { | ||
UpgradableOwnableWithGuardian public withGuardian; | ||
|
||
address owner = address(0x4); | ||
address guardian = address(0x8); | ||
|
||
function setUp() public { | ||
withGuardian = new ImplOwnableWithGuardian(); | ||
ImplOwnableWithGuardian(address(withGuardian)).initialize(owner, guardian); | ||
} | ||
|
||
function test_initializer() external { | ||
assertEq(withGuardian.owner(), owner); | ||
assertEq(withGuardian.guardian(), guardian); | ||
} | ||
|
||
function test_onlyGuardian() external { | ||
ImplOwnableWithGuardian(address(withGuardian)).mock_onlyGuardian(); | ||
} | ||
|
||
function test_onlyOwnerOrGuardian() external { | ||
ImplOwnableWithGuardian(address(withGuardian)).mock_onlyOwnerOrGuardian(); | ||
} | ||
|
||
function test_updateGuardian_guardian(address newGuardian) external { | ||
vm.prank(guardian); | ||
withGuardian.updateGuardian(newGuardian); | ||
} | ||
|
||
function test_updateGuardian_owner(address newGuardian) external { | ||
vm.prank(owner); | ||
withGuardian.updateGuardian(newGuardian); | ||
} | ||
|
||
function test_updateGuardian_eoa(address newGuardian) external { | ||
vm.assume(newGuardian != owner && newGuardian != guardian); | ||
|
||
vm.prank(newGuardian); | ||
vm.expectRevert('ONLY_BY_OWNER_OR_GUARDIAN'); | ||
withGuardian.updateGuardian(newGuardian); | ||
} | ||
} |