// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import { EnumerableSet } from'../../data/EnumerableSet.sol';
import { AddressUtils } from'../../utils/AddressUtils.sol';
import { UintUtils } from'../../utils/UintUtils.sol';
import { IAccessControlInternal } from'./IAccessControlInternal.sol';
import { AccessControlStorage } from'./AccessControlStorage.sol';
/**
* @title Role-based access control system
* @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts (MIT license)
*/abstractcontractAccessControlInternalisIAccessControlInternal{
usingAddressUtilsforaddress;
usingEnumerableSetforEnumerableSet.AddressSet;
usingUintUtilsforuint256;
modifieronlyRole(bytes32 role) {
_checkRole(role);
_;
}
/*
* @notice query whether role is assigned to account
* @param role role to query
* @param account account to query
* @return whether role is assigned to account
*/function_hasRole(bytes32 role,
address account
) internalviewvirtualreturns (bool) {
return
AccessControlStorage.layout().roles[role].members.contains(account);
}
/**
* @notice revert if sender does not have given role
* @param role role to query
*/function_checkRole(bytes32 role) internalviewvirtual{
_checkRole(role, msg.sender);
}
/**
* @notice revert if given account does not have given role
* @param role role to query
* @param account to query
*/function_checkRole(bytes32 role, address account) internalviewvirtual{
if (!_hasRole(role, account)) {
revert(
string(
abi.encodePacked(
'AccessControl: account ',
account.toString(),
' is missing role ',
uint256(role).toHexString(32)
)
)
);
}
}
/*
* @notice query admin role for given role
* @param role role to query
* @return admin role
*/function_getRoleAdmin(bytes32 role
) internalviewvirtualreturns (bytes32) {
return AccessControlStorage.layout().roles[role].adminRole;
}
/**
* @notice set role as admin role
* @param role role to set
* @param adminRole admin role to set
*/function_setRoleAdmin(bytes32 role, bytes32 adminRole) internalvirtual{
bytes32 previousAdminRole = _getRoleAdmin(role);
AccessControlStorage.layout().roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/*
* @notice assign role to given account
* @param role role to assign
* @param account recipient of role assignment
*/function_grantRole(bytes32 role, address account) internalvirtual{
AccessControlStorage.layout().roles[role].members.add(account);
emit RoleGranted(role, account, msg.sender);
}
/*
* @notice unassign role from given account
* @param role role to unassign
* @parm account
*/function_revokeRole(bytes32 role, address account) internalvirtual{
AccessControlStorage.layout().roles[role].members.remove(account);
emit RoleRevoked(role, account, msg.sender);
}
/**
* @notice relinquish role
* @param role role to relinquish
*/function_renounceRole(bytes32 role) internalvirtual{
_revokeRole(role, msg.sender);
}
/**
* @notice query role for member at given index
* @param role role to query
* @param index index to query
*/function_getRoleMember(bytes32 role,
uint256 index
) internalviewvirtualreturns (address) {
return AccessControlStorage.layout().roles[role].members.at(index);
}
/**
* @notice query role for member count
* @param role role to query
*/function_getRoleMemberCount(bytes32 role
) internalviewvirtualreturns (uint256) {
return AccessControlStorage.layout().roles[role].members.length();
}
}
// SPDX-License-Identifier: MITpragmasolidity ^0.8.8;import { UintUtils } from'./UintUtils.sol';
libraryAddressUtils{
usingUintUtilsforuint256;
errorAddressUtils__InsufficientBalance();
errorAddressUtils__NotContract();
errorAddressUtils__SendValueFailed();
functiontoString(address account) internalpurereturns (stringmemory) {
returnuint256(uint160(account)).toHexString(20);
}
functionisContract(address account) internalviewreturns (bool) {
uint256 size;
assembly {
size :=extcodesize(account)
}
return size >0;
}
functionsendValue(addresspayable account, uint256 amount) internal{
(bool success, ) = account.call{ value: amount }('');
if (!success) revert AddressUtils__SendValueFailed();
}
functionfunctionCall(address target,
bytesmemory data
) internalreturns (bytesmemory) {
return
functionCall(target, data, 'AddressUtils: failed low-level call');
}
functionfunctionCall(address target,
bytesmemory data,
stringmemoryerror) internalreturns (bytesmemory) {
return _functionCallWithValue(target, data, 0, error);
}
functionfunctionCallWithValue(address target,
bytesmemory data,
uint256 value
) internalreturns (bytesmemory) {
return
functionCallWithValue(
target,
data,
value,
'AddressUtils: failed low-level call with value'
);
}
functionfunctionCallWithValue(address target,
bytesmemory data,
uint256 value,
stringmemoryerror) internalreturns (bytesmemory) {
if (value >address(this).balance)
revert AddressUtils__InsufficientBalance();
return _functionCallWithValue(target, data, value, error);
}
/**
* @notice execute arbitrary external call with limited gas usage and amount of copied return data
* @dev derived from https://github.com/nomad-xyz/ExcessivelySafeCall (MIT License)
* @param target recipient of call
* @param gasAmount gas allowance for call
* @param value native token value to include in call
* @param maxCopy maximum number of bytes to copy from return data
* @param data encoded call data
* @return success whether call is successful
* @return returnData copied return data
*/functionexcessivelySafeCall(address target,
uint256 gasAmount,
uint256 value,
uint16 maxCopy,
bytesmemory data
) internalreturns (bool success, bytesmemory returnData) {
returnData =newbytes(maxCopy);
assembly {
// execute external call via assembly to avoid automatic copying of return data
success :=call(
gasAmount,
target,
value,
add(data, 0x20),
mload(data),
0,
0
)
// determine whether to limit amount of data to copylet toCopy :=returndatasize()
ifgt(toCopy, maxCopy) {
toCopy := maxCopy
}
// store the length of the copied bytesmstore(returnData, toCopy)
// copy the bytes from returndata[0:toCopy]returndatacopy(add(returnData, 0x20), 0, toCopy)
}
}
function_functionCallWithValue(address target,
bytesmemory data,
uint256 value,
stringmemoryerror) privatereturns (bytesmemory) {
if (!isContract(target)) revert AddressUtils__NotContract();
(bool success, bytesmemory returnData) = target.call{ value: value }(
data
);
if (success) {
return returnData;
} elseif (returnData.length>0) {
assembly {
let returnData_size :=mload(returnData)
revert(add(32, returnData), returnData_size)
}
} else {
revert(error);
}
}
}
Contract Source Code
File 4 of 10: Context.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)pragmasolidity ^0.8.0;/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/abstractcontractContext{
function_msgSender() internalviewvirtualreturns (address) {
returnmsg.sender;
}
function_msgData() internalviewvirtualreturns (bytescalldata) {
returnmsg.data;
}
function_contextSuffixLength() internalviewvirtualreturns (uint256) {
return0;
}
}
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)pragmasolidity ^0.8.0;/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/interfaceIERC20{
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/eventTransfer(addressindexedfrom, addressindexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/eventApproval(addressindexed owner, addressindexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/functiontotalSupply() externalviewreturns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/functionbalanceOf(address account) externalviewreturns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/functiontransfer(address to, uint256 amount) externalreturns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/functionallowance(address owner, address spender) externalviewreturns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/functionapprove(address spender, uint256 amount) externalreturns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/functiontransferFrom(addressfrom, address to, uint256 amount) externalreturns (bool);
}
Contract Source Code
File 9 of 10: Ownable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)pragmasolidity ^0.8.0;import"../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/abstractcontractOwnableisContext{
addressprivate _owner;
eventOwnershipTransferred(addressindexed previousOwner, addressindexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/modifieronlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/functionowner() publicviewvirtualreturns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/function_checkOwner() internalviewvirtual{
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/functionrenounceOwnership() publicvirtualonlyOwner{
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/functiontransferOwnership(address newOwner) publicvirtualonlyOwner{
require(newOwner !=address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/function_transferOwnership(address newOwner) internalvirtual{
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
Contract Source Code
File 10 of 10: UintUtils.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.8;/**
* @title utility functions for uint256 operations
* @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts/ (MIT license)
*/libraryUintUtils{
errorUintUtils__InsufficientHexLength();
bytes16privateconstant HEX_SYMBOLS ='0123456789abcdef';
functionadd(uint256 a, int256 b) internalpurereturns (uint256) {
return b <0 ? sub(a, -b) : a +uint256(b);
}
functionsub(uint256 a, int256 b) internalpurereturns (uint256) {
return b <0 ? add(a, -b) : a -uint256(b);
}
functiontoString(uint256 value) internalpurereturns (stringmemory) {
if (value ==0) {
return'0';
}
uint256 temp = value;
uint256 digits;
while (temp !=0) {
digits++;
temp /=10;
}
bytesmemory buffer =newbytes(digits);
while (value !=0) {
digits -=1;
buffer[digits] =bytes1(uint8(48+uint256(value %10)));
value /=10;
}
returnstring(buffer);
}
functiontoHexString(uint256 value) internalpurereturns (stringmemory) {
if (value ==0) {
return'0x00';
}
uint256 length =0;
for (uint256 temp = value; temp !=0; temp >>=8) {
unchecked {
length++;
}
}
return toHexString(value, length);
}
functiontoHexString(uint256 value,
uint256 length
) internalpurereturns (stringmemory) {
bytesmemory buffer =newbytes(2* length +2);
buffer[0] ='0';
buffer[1] ='x';
unchecked {
for (uint256 i =2* length +1; i >1; --i) {
buffer[i] = HEX_SYMBOLS[value &0xf];
value >>=4;
}
}
if (value !=0) revert UintUtils__InsufficientHexLength();
returnstring(buffer);
}
}