189 lines
5.6 KiB
Solidity
189 lines
5.6 KiB
Solidity
// SPDX-License-Identifier: CC0-1.0
|
|
pragma solidity ^0.8.7;
|
|
import "./interfaces/IEIP6366Error.sol";
|
|
import "./interfaces/IEIP6366Core.sol";
|
|
|
|
/**
|
|
* @dev Implement the core of EIP-6366
|
|
*/
|
|
contract EIP6366Core is IEIP6366Core {
|
|
/**
|
|
* @dev Stored permission of an address
|
|
*/
|
|
mapping(address => uint256) private permissions;
|
|
|
|
/**
|
|
* @dev Stored delegation information
|
|
*/
|
|
mapping(bytes32 => uint256) private delegations;
|
|
|
|
/**
|
|
* @dev Transfer a subset of owning permission to a target address
|
|
* @param _to New permission owner's address
|
|
* @param _permission A subset of owning permission
|
|
*/
|
|
function transfer(
|
|
address _to,
|
|
uint256 _permission
|
|
) external virtual override returns (bool success) {
|
|
return _transfer(_to, _permission);
|
|
}
|
|
|
|
/**
|
|
* @dev Allowed a delegatee to act for permission owner's behalf
|
|
* @param _delegatee Delegatee address
|
|
* @param _permission A subset of permission
|
|
*/
|
|
function approve(
|
|
address _delegatee,
|
|
uint256 _permission
|
|
) external virtual override returns (bool success) {
|
|
return _approve(_delegatee, _permission);
|
|
}
|
|
|
|
/**
|
|
* @dev Get all owning permission of an address
|
|
* @param _owner Permission owner's address
|
|
*/
|
|
function permissionOf(
|
|
address _owner
|
|
) external view virtual override returns (uint256 permission) {
|
|
return _permissionOf(_owner);
|
|
}
|
|
|
|
/**
|
|
* @dev Checking the existance of required permission on a given permission set
|
|
* @param _required Required permission set
|
|
* @param _permission Checking permission set
|
|
*/
|
|
function permissionRequire(
|
|
uint256 _permission,
|
|
uint256 _required
|
|
) external view virtual override returns (bool isPermissioned) {
|
|
return _permissionRequire(_permission, _required);
|
|
}
|
|
|
|
/**
|
|
* @dev Checking if an actor has sufficient permission, by himself or from a delegation, on a given permission set
|
|
* @param _owner Permission owner's address
|
|
* @param _actor Actor's address
|
|
* @param _required Required permission set
|
|
*/
|
|
function hasPermission(
|
|
address _owner,
|
|
address _actor,
|
|
uint256 _required
|
|
) external view override returns (bool isPermissioned) {
|
|
return _hasPermission(_owner, _actor, _required);
|
|
}
|
|
|
|
/**
|
|
* @dev Get delegated permission that owner approved to delegatee
|
|
* @param _owner Permission owner's address
|
|
* @param _delegatee Delegatee's address
|
|
*/
|
|
function delegated(
|
|
address _owner,
|
|
address _delegatee
|
|
) external view virtual override returns (uint256 permission) {
|
|
return _delegated(_owner, _delegatee);
|
|
}
|
|
|
|
/**
|
|
* @dev Mint a new set of permission to a new owner
|
|
* @param _owner New permission owner
|
|
* @param _permission Permission
|
|
*/
|
|
function _mint(
|
|
address _owner,
|
|
uint256 _permission
|
|
) internal returns (bool) {
|
|
permissions[_owner] = _permission;
|
|
emit Transfer(address(0x0), _owner, _permission);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @dev Burn all permission of the owner
|
|
* @param _owner New permission owner
|
|
*/
|
|
function _burn(address _owner) internal returns (bool) {
|
|
emit Transfer(_owner, address(0x0), permissions[_owner]);
|
|
permissions[_owner] = 0;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @dev Create an unique key that linked permission owner and delegatee
|
|
* @param _owner Permission owner's address
|
|
* @param _delegatee Delegate's address
|
|
*/
|
|
function _uniqueKey(
|
|
address _owner,
|
|
address _delegatee
|
|
) private pure returns (bytes32) {
|
|
return keccak256(abi.encodePacked(_owner, _delegatee));
|
|
}
|
|
|
|
function _transfer(
|
|
address _to,
|
|
uint256 _permission
|
|
) internal returns (bool success) {
|
|
address owner = msg.sender;
|
|
// Prevent permission to be burnt
|
|
if (permissions[_to] & _permission > 0) {
|
|
revert IEIP6366Error.DuplicatedPermission(_permission);
|
|
}
|
|
// Clean subset of permission from owner
|
|
permissions[owner] = permissions[owner] ^ _permission;
|
|
// Set subset of permission to new owner
|
|
permissions[_to] = permissions[_to] | _permission;
|
|
emit Transfer(owner, _to, _permission);
|
|
return true;
|
|
}
|
|
|
|
function _approve(
|
|
address _delegatee,
|
|
uint256 _permission
|
|
) internal returns (bool success) {
|
|
address owner = msg.sender;
|
|
delegations[_uniqueKey(owner, _delegatee)] = _permission;
|
|
emit Approval(owner, _delegatee, _permission);
|
|
return true;
|
|
}
|
|
|
|
function _permissionOf(
|
|
address _owner
|
|
) internal view returns (uint256 permission) {
|
|
return permissions[_owner];
|
|
}
|
|
|
|
function _permissionRequire(
|
|
uint256 _permission,
|
|
uint256 _required
|
|
) internal pure returns (bool isPermissioned) {
|
|
return _required == _permission & _required;
|
|
}
|
|
|
|
function _hasPermission(
|
|
address _owner,
|
|
address _actor,
|
|
uint256 _required
|
|
) internal view returns (bool isPermissioned) {
|
|
return
|
|
_permissionRequire(
|
|
_permissionOf(_actor) | _delegated(_owner, _actor),
|
|
_required
|
|
);
|
|
}
|
|
|
|
function _delegated(
|
|
address _owner,
|
|
address _delegatee
|
|
) internal view returns (uint256 permission) {
|
|
// Delegated permission can't be the superset of owner's permission
|
|
return
|
|
delegations[_uniqueKey(_owner, _delegatee)] & permissions[_owner];
|
|
}
|
|
}
|