/// @title TSOwnable
/// @notice SPDX-License-Identifier: MIT
/// @author merkleplant (modified by @devtooligan)
/// @author asnared <https://github.com/abigger87>
/// @notice An Ownable Implementation using Two-Step Transfer Pattern
#include "./Address.huff"
#include "./CommonErrors.huff"
#include "../auth/NonPayable.huff"
// External Interface
/// @notice Returns the current owner address.
#define function owner() view returns (address)
/// @notice Returns the current pending owner address.
#define function pendingOwner() view returns (address)
/// @notice Sets the pending owner address.
/// @dev Only callable by owner.
#define function setPendingOwner(address) nonpayable returns ()
/// @notice Accepts the ownership.
/// @dev Only callable by pending owner.
#define function acceptOwnership() nonpayable returns ()
/// @notice Emitted when new owner set.
#define event NewOwner(address, address)
/// @notice Emitted when new pending owner set.
#define event NewPendingOwner(address, address)
// Storage
/// @notice Owner Storage Slot
#define constant OWNER_SLOT = FREE_STORAGE_POINTER()
/// @notice Pending Owner Storage Slot
#define constant PENDING_OWNER_SLOT = FREE_STORAGE_POINTER()
/// @notice Inner TSOwnable Constructor
#define macro TSOWNABLE_CONSTRUCTOR() = takes (0) returns (0) {
// Store msg.sender as owner
caller [OWNER_SLOT] sstore // []
}
/// @notice Only Owner Modifier
#define macro ONLY_OWNER_MODIFIER() = takes (0) returns (0) {
[OWNER_SLOT] sload // [owner]
caller eq authed jumpi // []
ONLY_OWNER(0x00) // []
authed: // []
}
/// @notice Only Pending Owner Modifier
#define macro ONLY_PENDING_OWNER_MODIFIER() = takes (0) returns (0) {
[PENDING_OWNER_SLOT] sload // [pending_owner]
caller eq // [msg.sender == pending_owner]
authed jumpi // []
ONLY_PENDING_OWNER(0x00) // []
authed: // []
}
// Mutating Functions
/// @notice Set Pending Owner
/// @param newOwner The address of the new pending owner
#define macro OWNABLE_SET_PENDING_OWNER() = takes (0) returns (0) {
NON_PAYABLE() // []
ONLY_OWNER_MODIFIER() // []
// Read argument and mask to address
0x04 calldataload MASK_ADDRESS() // [newOwner]
// Revert if address equals owner
dup1 caller // [owner, newOwner, newOwner]
eq iszero set jumpi // [newOwner]
ALREADY_OWNER(0x00) // []
set: // [newOwner]
// Duplicate address on stack
dup1 // [newOwner, newOwner]
// Emit NewPendingOwner event
[OWNER_SLOT] sload // [owner, newOwner, newOwner]
__EVENT_HASH(NewPendingOwner) 0x00 0x00 // [offset, size, sig, owner, newOwner, newOwner]
log3 // [newOwner]
// Store address as pending owner
[PENDING_OWNER_SLOT] sstore // []
// Stop execution
stop
}
/// @notice Accept Ownership
/// @notice Allows the pending owner to become the owner
#define macro OWNABLE_ACCEPT_OWNERSHIP() = takes (0) returns (0) {
NON_PAYABLE() // []
ONLY_PENDING_OWNER_MODIFIER() // []
// Emit NewOwner event
caller [OWNER_SLOT] sload // [owner, pending_owner]
__EVENT_HASH(NewOwner) 0x00 0x00 // [offset, size, sig, owner, pending_owner]
log3 // []
// Store msg.sender as owner
caller [OWNER_SLOT] sstore // []
// Clear pending owner
0x00 [PENDING_OWNER_SLOT] sstore // []
// Stop execution
stop
}
// View Functions
/// @notice Get Owner
/// @notice Returns the current owner
#define macro OWNABLE_GET_OWNER() = takes (0) returns (0) {
NON_PAYABLE() // []
[OWNER_SLOT] sload // [owner]
0x00 mstore // []
0x20 0x00 return // []
}
/// @notice Get Pending Owner
/// @notice Returns the current pending owner
#define macro OWNABLE_GET_PENDING_OWNER() = takes (0) returns (0) {
NON_PAYABLE() // []
[PENDING_OWNER_SLOT] sload // [pending_owner]
0x00 mstore // []
0x20 0x00 return // []
}
// Function Dispatching
#define macro TSOWNABLE_MAIN() = takes (1) returns (1) {
// Input stack: [sig]
// Output stack: [sig]
dup1 __FUNC_SIG(setPendingOwner) eq set_pending_owner jumpi
dup1 __FUNC_SIG(acceptOwnership) eq accept_ownership jumpi
dup1 __FUNC_SIG(owner) eq get_owner jumpi
dup1 __FUNC_SIG(pendingOwner) eq get_pending_owner jumpi
// Bubble up to the parent macro
no_match jump
set_pending_owner:
OWNABLE_SET_PENDING_OWNER()
accept_ownership:
OWNABLE_ACCEPT_OWNERSHIP()
get_owner:
OWNABLE_GET_OWNER()
get_pending_owner:
OWNABLE_GET_PENDING_OWNER()
no_match:
}