// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
//合约权限管理
contract egaijoe {
//需求分析,首先,要做一个合约的权限管理,角色类型分为admin和user
//2.只能管理员进行升级和降级角色
//3.合约部署的时候初始化一个管理员
//一,首先定义两个角色,使用abi加密比使用字符串更加节省gas
//Solidity 中的 constant 关键字用来定义常量。也就是在编译期间就确定值,以后都不能再改变的变量。因为 constant 是不能更改的
//小细节,这里加密后的值是固定的,无论你部署多少次,值始终是那么多
//0xdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec42
bytes32 public constant roleToAdminRole \= keccak256(abi.encodePacked("ADMIN"));
bytes32 public constant roleToUserRole \= keccak256(abi.encodePacked("USER"));
//七,补上一个事件触发,一般在操作后,我们需要知道是谁改变了谁做了什么 indexed 是补上索引,可以根据索引位置得知是谁
event upuser(bytes32 indexed role ,address indexed who);
event downuser(bytes32 indexed role ,address indexed who);
//二,定义角色的关系,在其他代码中,数组结构是:
/*
role=>{
address=>地址,
bool => ture
}
在solidity中,则使用 mapping,这个类似数组可以定义键值名
*/
mapping (bytes32 => mapping (address => bool)) public roleMapRoleRole;
//三,完成初始化,也就是部署的时候,完成管理员的定义
constructor() {
//在部署的时候,初始化一个管理员
roleMapRoleRole[roleToAdminRole][msg.sender] \= true; //添加管理员角色,msg.sender为当前合约部署者地址
}
//四,现在可以开始编写升降用户的权限了,但是在这之前,只能管理员调用
//所以,需要一个控制器,叫 modified
modifier checkAdmin (address onlyAdmin){
//获取管理员地址
bool roleAdmin \= roleMapRoleRole[roleToAdminRole][onlyAdmin]; //从roleMapRoleRole中找管理员地址
require(roleAdmin != true, "You are not admin"); //如果为空,则抛出异常,说明不是管理员
_;
}
//五,开始编写升级用户至管理员的方法
function upUser(bytes32 _role, address _to) external checkAdmin (_to){
//将用户的角色升级到管理员角色
roleMapRoleRole[_role][_to] \= true; //将用户的_to地址角色升级为true
emit upuser(_role, _to);
}
//六,降级管理员至用户权限
function downUser(bytes32 _role, address _to) external checkAdmin (_to){
//其实就是对数组的操作
roleMapRoleRole[_role][_to] \= false;
emit downuser(_role, _to);
}
}