This contract's source code is verified! Compiler
0.8.13+commit.abaa5c0e
File 1 of 5: Auth.sol
pragma solidity >=0.8.0;
abstract contract Auth {
event OwnerUpdated (address indexed user, address indexed newOwner ) ;
address public owner;
constructor (address _owner ) {
owner = _owner;
emit OwnerUpdated(msg .sender , _owner);
}
modifier requiresAuth ( ) virtual {
require (isAuthorized(msg .sender , msg .sig ), "UNAUTHORIZED" );
_ ;
}
function isAuthorized (address user, bytes4 functionSig ) internal view virtual returns (bool ) {
return canCall(user, functionSig) | | user = = owner;
}
function setOwner (address newOwner ) public virtual requiresAuth {
owner = newOwner;
emit OwnerUpdated(msg .sender , newOwner);
}
function canCall (
address user,
bytes4 functionSig
) public view virtual returns (bool ) ;
}
File 2 of 5: ERC20.sol
pragma solidity >=0.8.0;
abstract contract ERC20 {
event Transfer (address indexed from , address indexed to, uint256 amount ) ;
event Approval (address indexed owner, address indexed spender, uint256 amount ) ;
string public name;
string public symbol;
uint8 public immutable decimals;
uint256 public totalSupply;
mapping (address = > uint256 ) public balanceOf;
mapping (address = > mapping (address = > uint256 )) public allowance;
uint256 internal immutable INITIAL_CHAIN_ID;
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
mapping (address = > uint256 ) public nonces;
constructor (
string memory _name,
string memory _symbol,
uint8 _decimals
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID = block .chainid ;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
function approve (address spender, uint256 amount ) public virtual returns (bool ) {
allowance[msg .sender ][spender] = amount;
emit Approval(msg .sender , spender, amount);
return true ;
}
function transfer (address to, uint256 amount ) public virtual returns (bool ) {
balanceOf[msg .sender ] - = amount;
unchecked {
balanceOf[to] + = amount;
}
emit Transfer(msg .sender , to, amount);
return true ;
}
function transferFrom (
address from ,
address to,
uint256 amount
) public virtual returns (bool ) {
uint256 allowed = allowance[from ][msg .sender ];
if (allowed ! = type (uint256 ).max ) allowance[from ][msg .sender ] = allowed - amount;
balanceOf[from ] - = amount;
unchecked {
balanceOf[to] + = amount;
}
emit Transfer(from , to, amount);
return true ;
}
function permit (
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
require (deadline > = block .timestamp , "PERMIT_DEADLINE_EXPIRED" );
unchecked {
address recoveredAddress = ecrecover (
keccak256 (
abi .encodePacked (
"\x19\x01" ,
DOMAIN_SEPARATOR(),
keccak256 (
abi .encode (
keccak256 (
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
),
owner,
spender,
value,
nonces[owner]+ + ,
deadline
)
)
)
),
v,
r,
s
);
require (recoveredAddress ! = address (0 ) & & recoveredAddress = = owner, "INVALID_SIGNER" );
allowance[recoveredAddress][spender] = value;
}
emit Approval(owner, spender, value);
}
function DOMAIN_SEPARATOR ( ) public view virtual returns (bytes32 ) {
return block .chainid = = INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
function computeDomainSeparator ( ) internal view virtual returns (bytes32 ) {
return
keccak256 (
abi .encode (
keccak256 ("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" ),
keccak256 (bytes (name)),
keccak256 ("1" ),
block .chainid ,
address (this )
)
);
}
function _mint (address to, uint256 amount ) internal virtual {
totalSupply + = amount;
unchecked {
balanceOf[to] + = amount;
}
emit Transfer(address (0 ), to, amount);
}
function _burn (address from , uint256 amount ) internal virtual {
balanceOf[from ] - = amount;
unchecked {
totalSupply - = amount;
}
emit Transfer(from , address (0 ), amount);
}
}
File 3 of 5: MorphoToken.sol
pragma solidity ^0.8.13;
import "@semitransferable-token/Token.sol" ;
contract MorphoToken is Token {
constructor (address _owner ) Token ("Morpho Token" , "MORPHO" , 18 , _owner ) {
_mint(_owner, 0 .2e9 ether );
}
}
File 4 of 5: RolesAuthority.sol
pragma solidity >=0.8.0;
import {Auth } from "./Auth.sol" ;
contract RolesAuthority is Auth {
event UserRoleUpdated (address indexed user, uint8 indexed role, bool enabled ) ;
event PublicCapabilityUpdated (bytes4 indexed functionSig, bool enabled ) ;
event RoleCapabilityUpdated (uint8 indexed role, bytes4 indexed functionSig, bool enabled ) ;
constructor (address _owner ) Auth (_owner ) {}
mapping (address = > bytes32 ) public getUserRoles;
mapping (bytes4 = > bool ) public isCapabilityPublic;
mapping (bytes4 = > bytes32 ) public getRolesWithCapability;
function doesUserHaveRole (address user, uint8 role ) public view virtual returns (bool ) {
return (uint256 (getUserRoles[user]) > > role) & 1 ! = 0 ;
}
function doesRoleHaveCapability (
uint8 role,
bytes4 functionSig
) public view virtual returns (bool ) {
return (uint256 (getRolesWithCapability[functionSig]) > > role) & 1 ! = 0 ;
}
function canCall (
address user,
bytes4 functionSig
) public view virtual override returns (bool ) {
return
isCapabilityPublic[functionSig] | |
bytes32 (0 ) ! = getUserRoles[user] & getRolesWithCapability[functionSig];
}
function setPublicCapability (
bytes4 functionSig,
bool enabled
) public virtual requiresAuth {
isCapabilityPublic[functionSig] = enabled;
emit PublicCapabilityUpdated(functionSig, enabled);
}
function setRoleCapability (
uint8 role,
bytes4 functionSig,
bool enabled
) public virtual requiresAuth {
if (enabled) {
getRolesWithCapability[functionSig] | = bytes32 (1 < < role);
} else {
getRolesWithCapability[functionSig] & = ~ bytes32 (1 < < role);
}
emit RoleCapabilityUpdated(role, functionSig, enabled);
}
function setUserRole (
address user,
uint8 role,
bool enabled
) public virtual requiresAuth {
if (enabled) {
getUserRoles[user] | = bytes32 (1 < < role);
} else {
getUserRoles[user] & = ~ bytes32 (1 < < role);
}
emit UserRoleUpdated(user, role, enabled);
}
}
File 5 of 5: Token.sol
pragma solidity ^0.8.13;
import {ERC20 } from "solmate/tokens/ERC20.sol" ;
import {RolesAuthority } from "./RolesAuthority.sol" ;
contract Token is ERC20 , RolesAuthority {
constructor (
string memory _name,
string memory _symbol,
uint8 _decimals,
address _owner
) ERC20 (_name, _symbol, _decimals ) RolesAuthority (_owner ) {}
function transfer (address to, uint256 amount )
public
override
requiresAuth
returns (bool )
{
return super .transfer (to, amount);
}
function transferFrom (
address from ,
address to,
uint256 amount
) public override requiresAuth returns (bool ) {
return super .transferFrom(from , to, amount);
}
function mint (address to, uint256 amount ) external requiresAuth {
_mint(to, amount);
}
function burn (uint256 amount ) external {
_burn(msg .sender , amount);
}
} {
"compilationTarget" : {
"src/MorphoToken.sol" : "MorphoToken"
} ,
"evmVersion" : "london" ,
"libraries" : { } ,
"metadata" : {
"bytecodeHash" : "ipfs"
} ,
"optimizer" : {
"enabled" : true ,
"runs" : 200
} ,
"remappings" : [
":@semitransferable-token/=lib/semitransferable-token/src/" ,
":ds-test/=lib/forge-std/lib/ds-test/src/" ,
":forge-std/=lib/forge-std/src/" ,
":script/=script/" ,
":semitransferable-token/=lib/semitransferable-token/src/" ,
":solmate/=lib/semitransferable-token/lib/solmate/src/" ,
":src/=src/" ,
":test/=test/"
]
} [{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes4","name":"functionSig","type":"bytes4"},{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"PublicCapabilityUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"role","type":"uint8"},{"indexed":true,"internalType":"bytes4","name":"functionSig","type":"bytes4"},{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"RoleCapabilityUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint8","name":"role","type":"uint8"},{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"UserRoleUpdated","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"bytes4","name":"functionSig","type":"bytes4"}],"name":"canCall","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"role","type":"uint8"},{"internalType":"bytes4","name":"functionSig","type":"bytes4"}],"name":"doesRoleHaveCapability","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint8","name":"role","type":"uint8"}],"name":"doesUserHaveRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"name":"getRolesWithCapability","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"getUserRoles","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"name":"isCapabilityPublic","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"functionSig","type":"bytes4"},{"internalType":"bool","name":"enabled","type":"bool"}],"name":"setPublicCapability","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"role","type":"uint8"},{"internalType":"bytes4","name":"functionSig","type":"bytes4"},{"internalType":"bool","name":"enabled","type":"bool"}],"name":"setRoleCapability","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint8","name":"role","type":"uint8"},{"internalType":"bool","name":"enabled","type":"bool"}],"name":"setUserRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]