// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; import {IOwnable} from "../interfaces/IOwnable.sol"; /// @title Ownable /// @author Rohan Kulkarni /// @author Iain Nash /// @notice Modified from OpenZeppelin Contracts v4.7.3 (access/OwnableUpgradeable.sol) /// - Uses custom errors declared in IOwnable /// - Adds optional two-step ownership transfer (`safeTransferOwnership` + `acceptOwnership`) abstract contract OwnableWithConfirmation is IOwnable { /// /// /// STORAGE /// /// /// /// @dev The address of the owner address internal _owner; /// @dev The address of the pending owner address internal _pendingOwner; /// /// /// MODIFIERS /// /// /// /// @dev Ensures the caller is the owner modifier onlyOwner() { if (msg.sender != _owner) revert ONLY_OWNER(); _; } /// @dev Ensures the caller is the pending owner modifier onlyPendingOwner() { if (msg.sender != _pendingOwner) revert ONLY_PENDING_OWNER(); _; } /// /// /// FUNCTIONS /// /// /// /// @dev Initializes contract ownership /// @param _initialOwner The initial owner address constructor(address _initialOwner) { _owner = _initialOwner; emit OwnershipTransferred(address(0), _initialOwner); } /// @notice The address of the owner function owner() public view virtual returns (address) { return _owner; } /// @notice The address of the pending owner function pendingOwner() public view returns (address) { return _pendingOwner; } /// @notice Forces an ownership transfer from the last owner /// @param _newOwner The new owner address function transferOwnership(address _newOwner) public onlyOwner { _transferOwnership(_newOwner); } /// @notice Forces an ownership transfer from any sender /// @param _newOwner New owner to transfer contract to /// @dev Ensure is called only from trusted internal code, no access control checks. function _transferOwnership(address _newOwner) internal { emit OwnershipTransferred(_owner, _newOwner); _owner = _newOwner; if (_pendingOwner != address(0)) delete _pendingOwner; } /// @notice Initiates a two-step ownership transfer /// @param _newOwner The new owner address function safeTransferOwnership(address _newOwner) public onlyOwner { _pendingOwner = _newOwner; emit OwnerPending(_owner, _newOwner); } /// @notice Accepts an ownership transfer function acceptOwnership() public onlyPendingOwner { emit OwnershipTransferred(_owner, msg.sender); _owner = _pendingOwner; delete _pendingOwner; } /// @notice Cancels a pending ownership transfer function cancelOwnershipTransfer() public onlyOwner { emit OwnerCanceled(_owner, _pendingOwner); delete _pendingOwner; } }