QX ERC20科学代币 /** *在2020-12-24上提交验证以进行验证 * /
PRAGMA固体 ^0.6.0;
/**
@Dev包装器对Solidity的算术操作以及增加的溢出
检查。
在溢出上固体包装中的算术操作。这很容易导致
在错误中,因为程序员通常假定溢出会增加
错误,这是高级编程语言中的标准行为。
SafeMath通过在
操作溢出。
使用此库代替未检查的操作消除了整个
类别类别,因此建议始终使用它。 / Library Safemath { / *
@Dev返回两个未签名的整数,恢复
溢出。
与Solidity的+运算符相对。
要求:
返回c; }
/**
-员相对。/**
@Dev返回两个未签名整数的减法,并在自定义消息上恢复
溢出(结果为负)。
与坚固的-员相对。
要求:
返回c; }
/**
@Dev返回两个未签名整数的乘法,恢复
溢出。
与Solidity的*操作员相对。
要求:
uint256 c = a * b;需要(c / a == b,“ safemath:乘法溢出”);
返回c; }
/**
/操作员相对。注意:此功能使用revert OpCode(剩余的气体未触及),而坚固/**
@Dev返回两个未签名整数的整数部门。带有自定义消息的恢复
零。结果朝零舍入。
与固体/操作员相对。注意:此功能使用
revert OpCode(剩余的气体未触及),而坚固
使用无效的操作码还原(消耗所有剩余气体)。
要求:
返回c; }
/**
%操作员相对。此功能使用一个revert/**
%操作员相对。此功能使用一个revert//部分许可证:麻省理工学院
PRAGMA固体 ^0.6.0;
/**
@DEV标准数学实用程序中缺少坚固性语言。 /库数学{ / *
/**
/**
//部分许可证:麻省理工学院
PRAGMA固体 ^0.6.0;
/**
@Dev搜索一个排序的array ,并返回包含的第一个索引
一个更大或等于element的值。如果没有这样的索引(即
数组中的值严格小于element ),数组长度为
返回。时间复杂性o(log n)。
预计array将按升序排序,并且不包含
重复元素。 */ function findupperbound(uint256 []存储阵列,uint256元素)内部视图返回(uint256){if(array.length == 0){return 0; }
UINT256低= 0; uint256高= array.length;
而(低<high){uint256 mid = math.averager(低,高);
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
// because Math.average rounds down (it does integer division with truncation).
if (array[mid] > element) {
high = mid;
} else {
low = mid + 1;
}
}
//此时low是独家上限。我们将返回包含的上限。 if(low> 0 && array [low -1] ==元素){返回低-1; } else {return low; }}}}
//部分许可证:麻省理工学院
PRAGMA固体 ^0.6.0;
/**
@Title计数器
@author Matt Condon(@shrugs)
@DEV提供只能由一个可以增加或减少的计数器。这可以用来跟踪数字
映射中的元素,发行ERC721 ID或计数请求ID。
包括using Counters for Counters.Counter;
由于无法以一个增量为单位的256位整数溢出,因此increment可以跳过{safemath}
溢出检查,从而节省了气体。这确实假定正确的用法,因为基础_value永远不会
直接访问。 */库计数器{使用safemath for uint256;
struct Counter {//该变量绝不应由库的用户直接访问:交互必须仅限于// //库的函数。从固体v0.5.2开始,尽管有一个提议添加此功能,但不能强制执行此功能:请参阅以太坊/固体#4637 uint256 _value; //默认值:0}
功能电流(计数器存储计数器)内部视图返回(UINT256){return Counter._value; }
函数增量(计数器存储计数器)内部{// {safemath}溢出检查可以在此处跳过,请参阅顶部计数器的注释。_value += 1; }
函数降低(计数器存储计数器)内部{counter._value = counter._value.sub(1); }}}
//部分许可证:麻省理工学院
PRAGMA固体 ^0.6.0;
/*
@DEV提供有关当前执行上下文的信息,包括
交易的发件人及其数据。虽然这些通常可用
通过msg.sender和msg.data,不应在这样的直接中访问它们
方式,因为在处理GSN元转移时,帐户发送和
支付执行可能不是实际发件人(就申请而言
关心)。
该合同仅是中间,类似图书馆的合同所必需的。 */抽象合同上下文{function _msgsender()内部视图虚拟返回(应付付款){return msg.sender; }
函数_msgdata()内部视图虚拟返回(bytes memory){this; //沉默状态可突变性警告而无需产生字节码 - 请参见以太坊/固体#2691返回msg.data; }}}
//部分许可证:麻省理工学院
PRAGMA固体 ^0.6.0;
/**
EIP中定义的ERC20标准的@DEV接口。 /接口IERC20 { / *
/**
account拥有的令牌金额。 */ function Balanceof(地址帐户)外部视图返回(UINT256);/**
amount令牌从呼叫者的帐户移至recipient 。/**
spender币数量owner支出。这是/**
amount设置为在呼叫者令牌上的spender津贴。/**
amount令牌从sender移动到recipientamount/**
value代币从一个帐户从一个帐户转移fromto )。value可能为零。 */事件传输(地址索引,从地址索引为uint256值);/**
owner的spender的津贴由value是新的津贴。 */事件批准(地址索引所有者,地址索引索引,UINT256值); }//部分许可证:麻省理工学院
PRAGMA固体 ^0.6.2;
/**
@DEV集合与地址类型/库地址相关的功能{ / *
@Dev如果account是合同,则返回true。
[重要的]
====
假设此功能返回的地址是不安全的
false是一个外部账户(EOA),而不是合同。
除其他外, isContract将返回false以下
地址类型:
==== */ function isontract(地址帐户)内部视图返回(bool){//此方法依赖于extCodesize,该方法返回//构造中的合同为0,因为该代码仅存储在//构造器执行的末尾。
UINT256尺寸; // solhint-disable-next-line noinline-eSembly汇编{size:= extCodesize(account)}返回size> 0; }
/**
@Dev替换固体transfer :将amount发送给
recipient ,转发所有可用的气体并恢复错误。
https://eips.ethereum.org/eips/eip-1884 [eip1884]增加了气体成本
在某些OPCODES中,可能会签订合同超过2300气体限制
通过transfer施加,使他们无法通过
transfer 。 {sendValue}消除了此限制。
https://diligence.consensys.net/posts/2019/09/stop-using-solisitys-transfer-now/ [leym More]。
重要的是:因为控制被转移到recipient ,所以护理必须是
不创造重新进入的漏洞。考虑使用
{retrancyguard}或
https://solity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-ecks-effects-interactions-pattern [checks-ecks-effects-effects-interactions模式]。 */ function sendValue(应付收款人,UINT256金额)内部{require(地址(this).balance> =金额,“地址:不足余额”);
// solhint-disable-next-line避免避开低级别的呼叫,避免呼叫值(bool success)= conterient.call.call {value:nose}(量}(“”);要求(成功,“地址:无法发送价值,收件人可能已经恢复”); }
/**
call执行坚固的功能调用。一个call是功能呼叫的不安全替代:使用此target恢复为恢复原因,则它会被此弹起target必须是合同。data调用target不得恢复。/**
functionCall ],但使用target恢复时, errorMessage误差为后备原因。/**
functionCall ],value转移到target 。value的ETH余额。payable 。/**
functionCallWithValue ]相同,但是target恢复时,以errorMessage作为后备原因恢复了原因。函数_functionCallWithValue(地址目标,BYTES内存数据,UINT256 Weivalue,String Memory Errormessage)私人返回(bytes memory){require(requart(isContract(isContract(isContract)),“地址:call to nontartract”);
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
// solhint-disable-next-line no-inline-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}}}
//部分许可证:麻省理工学院
PRAGMA固体 ^0.6.0;
/**
{IERC20}接口的@DEV实现。
这种实现对代币的创建方式不可知。这意味着
必须使用{_mint}中的派生合同中添加供应机制。
有关通用机制,请参见{erc20presetminterpauser}。
提示:有关详细的写作,请参阅我们的指南
https://forum.zeppelin.solutions/t/how-to-to-implement-erc20-supply-mechanisms/226 [how
实施供应机制]。
我们遵循了一般OpenZeppelin指南:功能恢复
失败时返回false 。尽管如此,这种行为仍然是常规的
并且不会与ERC20应用程序的期望发生冲突。
此外,在{Transferfrom}的呼叫上发出了{批准}事件。
这允许应用程序重建所有帐户的津贴
通过收听所述事件。 EIP的其他实现可能不会发出
这些事件,因为规范不是必需的。
最后,非标准{depaneAseAllowance}和{highteAllowance}
已经添加了功能来减轻围绕设置的知名问题
津贴。请参阅{ierc20-approve}。 */ Contract ERC20是上下文,IERC20 {使用SafeMath for Uint256;使用地址;
映射(地址=> uint256)私人_Balances;
映射(地址=>映射(address => uint256))私人_Allowances;
uint256私人_totalsupply;
字符串私有_name;字符串私有_symbol; uint8私有_decimals;
/**
/**
/**
/**
decimals等于2 ,则余额为505代币5,05 ( 505 / 10 ** 2 )。/**
/**
/**
recipient不能是零地址。amount 。 */函数传输(地址收件人,UINT256金额)公共虚拟覆盖返回(bool){_transfer(_msgsender(),收件人,金额);返回true; }/**
/**
spender不能是零地址。 */函数批准(地址spender,uint256金额)公共虚拟替代返回(bool){_approve(_msgsender(),spender,金额);返回true; }/**
sender和recipient不能是零地址。sender必须具有至少amount 。sender的令牌津贴amount 。 */函数转移From(地址发送者,地址收件人,UINT256金额)公共虚拟覆盖返回(bool){_transfer(发送者,收件人,金额); _approve(sender,_msgsender(),_ allowances [sender] [_ msgsender()]。子(金额,“ erc20:转移金额超过津贴”));返回true; }/**
spender的津贴。spender不能是零地址。 */函数highteAllowance(地址spender,uint256 addValue)public Virtual返回(bool){_approve(_MSGSENDER(),spender,_allowances [_MSGSENDER(_MSGSENDER()]返回true; }/**
spender的津贴。spender不能是零地址。spender必须至少有呼叫者的津贴subtractedValue 。 */函数降低(地址spender,uint256 suptractedValue)公共虚拟返回(bool){_approve(_MSGSENDER(),spender,_allowaness,_ spender,_msgsender(_msgsender()[_msgsender()]返回true; }/**
@Dev将令牌amount从sender移至recipient 。
这是内部功能等同于{transfer},可以使用
例如,实施自动令牌费用,削减机制等。
发出{传输}事件。
要求:
sender不能是零地址。recipient不能是零地址。sender必须具有至少amount 。 */ function _transfer(地址发送者,地址收件人,UINT256金额)内部虚拟{require(sender!=地址(0),“ erc20:从零地址转移”); require(收件人!=地址(0),“ erc20:转移到零地址”);_BEFORETOKENTRANSFER(发送者,收件人,金额);
_ balances [sender] = _ balances [sender] .sub(金额,“ erc20:转移金额超过余额”); _ balances [收件人] = _ balances [收件人] .add(量);发射转移(发件人,收件人,金额); }
/** @dev创建amount令牌并将其分配给account ,增加
总供应。
发出一个from设置到零地址的事件。
要求
to是零地址。 */ function _mint(地址帐户,uint256金额)内部虚拟{require(account!= address(0),“ erc20:mint至零地址”);_BEFORETOKENTRANSFER(地址(0),帐户,金额);
_totalsupply = _totalsupply.add(量); _ balances [account] = _ balances [account] .add(量);发射转移(地址(0),帐户,金额); }
/**
@Dev从account中销毁amount令牌,减少
总供应。
发出{Transfer}事件, to为零地址。
要求
account不能是零地址。account必须至少具有amount币。 */ function _burn(地址帐户,UINT256金额)内部虚拟{require(account!=地址(0),“ erc20:从零地址刻录”);_BEFORETOKENTRANSFER(帐户,地址(0),金额);
_balances [account] = _ balances [account] .sub(金额,“ erc20:烧伤金额超过余额”); _totalsupply = _totalsupply.sub(量);发射转移(帐户,地址(0),金额); }
/**
@Dev将amount设置为对owner的代币的spender津贴。
此内部功能等同于approve ,可以用来
例如,设置某些子系统的自动津贴,等等。
发出{批准}事件。
要求:
owner不能是零地址。spender不能是零地址。 */ function _approve(地址所有者,地址spender,uint256金额)内部虚拟{require(lands!=地址(0),“ erc20:从零地址批准”); require(spender!=地址(0),“ erc20:批准零地址”);_Allowances [所有者] [Spender] =金额;发射批准(所有者,支出者,金额); }
/**
/**
from from amount toto 。from零零时,将to amount令牌。to ,将燃烧from S标记的amount 。from和to永远都不是零。//部分许可证:麻省理工学院
PRAGMA固体 ^0.6.0;
/**
@Dev此合同使用快照机制扩展了ERC20令牌。创建快照时,平衡和
记录当时的总供应,以供以后访问。
这可以用来根据令牌余额(例如无信任的股息或加权投票)安全创建机制。
在天真的实现中,可以通过重复不同的平衡来执行“双重支出”攻击
帐户。通过使用快照来计算股息或投票权,这些攻击不再适用。也可以
用于创建有效的ERC20分叉机制。
快照是由内部{_snapshot}函数创建的,它将发射{snapshot}事件并返回
快照ID。要在快照时获取总电源,请使用快照调用函数{
ID。要在快照时获得帐户的余额,请使用快照ID调用{Balanceofat}函数
和帐户地址。
====气体成本
快照是有效的。快照创建是O(1) 。从快照中检索余额或总供水为_o(log
n)_在创建的快照数量中,尽管特定帐户的n通常会很大
较小,因为随后的快照中相同的平衡存储为单个条目。
由于额外的快照簿记,正常ERC20转移的开销不断。这个开销是
仅对于立即在特定帐户的快照之后的第一个转移才有意义。随后的
直到下一个快照,依此类推,转移的成本将正常。 */ abstract contract ERC20Snapshot is ERC20 { // Inspired by Jordi Baylina's MiniMeToken to record historical balances: // https://github.com/Giveth/minimd/blob/ea04d950eea153a04c51fa510b068b9dded390cb/contracts/MiniMeToken.sol
使用Safemath进行UINT256;使用uint256 []的数组;使用计数器进行计数器。
//快照值具有ID数组和与该ID相对应的值。这些可能是A //快照结构的数组,但这会阻碍在数组上起作用的功能。 struct快照{uint256 [] ids; uint256 []值; }
映射(地址=>快照)私有_accountbalancesnapshots;快照私有_totalsupplysnapshots;
//快照ID单调增加,第一个值为1。ID为0是无效的。 counter.counter private _currentsNapShotid;
/**
id标识的快照时,{_snapshot}发射的@Dev。 */事件快照(UINT256 ID);/**
@Dev创建了一个新的快照并返回其快照ID。
发出包含相同ID的事件{快照}事件。
{_snapshot}是internal ,您必须决定如何外部暴露它。它的使用可能仅限于
一组帐户,例如使用{AccessControl},或者可以向公众开放。
[警告]
====
虽然需要一种开放的调用{_snapshot}的方式,而某些信任最小化机制(例如分叉)需要
您必须认为攻击者可以通过两种方式使用它。
首先,它可以用来增加快照中值的收回成本,尽管它将增长
从而使对数从长远来看使这种攻击无效。其次,它可以用于靶向
特定帐户并增加了ERC20转移的成本,以汽油成本指定的方式
上面的部分。
我们尚未测量实际数字;如果这是您感兴趣的事情,请与我们联系。
==== */ function _snapShot()内部虚拟返回(uint256){_currentsnapshotid.increment();
uint256 currentId = _currentsNapShotid.current();发射快照(CurrentId);返回CurrentID; }
/**
@Dev检索snapshotId时的account余额。 */ function BalanceOfat(地址帐户,UINT256快照)公共视图返回(UINT256){(bool snapshotted,uint256 value)= _VALUEAT(snapshotid,_accountbalancesnapsnapshots [account]);
返回快照?价值:BalanceOf(帐户); }
/**
@Dev检索创建snapshotId时的总电源。 */ function tostalsupplyat(uint256 snapshotid)public view返回(uint256){(bool snapshotted,uint256 value)= _valueat(snapshotid,_totalSupplysnapsnapshots);
返回快照?价值:tostalsupply(); }
//在修改值之前,更新余额和/或总电源快照。这是在_beforetokentransfer Hook中实现的,该挂钩是为_mint,_burn和_transfer操作执行的。函数_beforetOkentRansfer(地址,地址到,UINT256量)内部虚拟覆盖{super._beforetokentransfer(从,到量);
if(来自==地址(0)){// mint _updateaccountsnapshot(to); _updateTotalSupplySnapShot(); } else if(to ==地址(0)){// burn _updateaccountsnapshot(from); _updateTotalSupplySnapShot(); } else {//传输_updateaccountsnapshot(来自); _updateaccountsnapshot(to); }}}
函数_valueat(uint256快照,快照存储快照)私人视图返回(bool,uint256){require(snapshotid> 0,“ erc20snapshot:id is id is id is id is d is 0”); // solhint-disable-next-line max-line长度require(snapshotid <= _currentsnapshotid.current(),“ erc20snapshot:nonexistent ID”);
// When a valid snapshot is queried, there are three possibilities:
// a) The queried value was not modified after the snapshot was taken. Therefore, a snapshot entry was never
// created for this id, and all stored snapshot ids are smaller than the requested one. The value that corresponds
// to this id is the current one.
// b) The queried value was modified after the snapshot was taken. Therefore, there will be an entry with the
// requested id, and its value is the one to return.
// c) More snapshots were created after the requested one, and the queried value was later modified. There will be
// no entry for the requested id: the value that corresponds to it is that of the smallest snapshot id that is
// larger than the requested one.
//
// In summary, we need to find an element in an array, returning the index of the smallest value that is larger if
// it is not found, unless said value doesn't exist (e.g. when all values are smaller). Arrays.findUpperBound does
// exactly this.
uint256 index = snapshots.ids.findUpperBound(snapshotId);
if (index == snapshots.ids.length) {
return (false, 0);
} else {
return (true, snapshots.values[index]);
}
}
函数_updateaccountsnapshot(地址帐户)private {_updatesNapShot(_accountbalancesnapshots [account],ballackof(account)); }
函数_updateTotalSupplySnapShot()private {_updatesNapShot(_totalsupplysnapshots,ptalsupply()); }
函数_updatesNapShot(快照存储快照,uint256 CurrentValue)private {uint256 CurrentId = _CurrentsNapShotId.current(); if(_lastSnapShotId(snapshots.ids)<currentid){snapshots.ids.push(currentId); snapshots.values.push(CurrentValue); }}}
函数_lastSnapShotID(uint256 []存储IDS)私有视图返回(uint256){if(ids.length == 0){返回0; } else {返回IDS [ids.length -1]; }}}}
//部分许可证:麻省理工学院
PRAGMA固体 ^0.6.0;
/**
@DEV库管理
https://en.wikipedia.org/wiki/set_(abstract_data_type) [sets]
类型。
集合具有以下属性:
(O(1))。
合同示例{
// Add the library methods
using EnumerableSet for EnumerableSet.AddressSet;
// Declare a set state variable
EnumerableSet.AddressSet private mySet;
}
从v3.0.0开始,仅类型address ( AddressSet集)和uint256
( UintSet )得到支持。 */ library enumerableset {//要为多种类型实现此库,以少量代码//重复,我们将其编写为具有// bytes32值的通用集类型。 // SET实现使用私有功能,而面向用户//实现(例如地址集)只是围绕//基础设置的包装器。 //这意味着我们只能为适合bytes32中的类型创建新的Enumerableset。
struct SET {//设置值Bytes32 [] _values的存储;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping (bytes32 => uint256) _indexes;
}
/**
/**
@Dev从集合中删除一个值。 o(1)。
如果该值已从集合中删除,则返回为true
展示。 */ function _remove(设置存储集,bytes32值)私人返回(bool){//我们读取和存储值的索引,以防止从同一存储插槽uint256 uint256 valueindex = set._indexes [value];
if(valueIndex!= 0){//等效于包含(set,value)//要从o(1)中的_values数组删除元素,我们将元素交换以用//阵列中的最后一个元素删除,然后删除最后一个元素(有时称为“ swap and pop”)。 //如{at}中指出的那样,这修改了数组的顺序。
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
// When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
// so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.
bytes32 lastvalue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastvalue;
// Update the index for the moved value
set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {return false; }}}
/**
/**
/**
index中存储的值。 o(1)。index必须严格小于{长度}。 */ function _at(设置存储集,UINT256索引)私有视图返回(bytes32){requike(set._values.length> index,“ enumerableset:in yumerableset:in bounds of Bounds”);返回set._values [index]; }//地址集
struct addressset {set _inner; }
/**
/**
/**
/**
/**
index in the set. O(1).index must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint256(_at(set._inner, index))); }// UintSet
struct UintSet { Set _inner; }
/**
/**
/**
/**
/**
index in the set. O(1).index must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); }}}// Partial License: MIT
pragma solidity ^0.6.0;
/**
@dev Contract module that allows children to implement role-based access
control mechanisms.
Roles are referred to by their bytes32 identifier.这些应该暴露
in the external API and be unique.实现这一目标的最好方法是
using public constant hash digests:
bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
Roles can be used to represent a set of permissions.限制访问
function call, use {hasRole}:
function foo() public {
require(hasRole(MY_ROLE, msg.sender));
...
}
Roles can be granted and revoked dynamically via the {grantRole} and
{revokeRole} functions.每个角色都具有关联的管理角色,只有
accounts that have a role's admin role can call {grantRole} and {revokeRole}.
By default, the admin role for all roles is DEFAULT_ADMIN_ROLE , which means
that only accounts with this role will be able to grant or revoke other
角色。 More complex role relationships can be created by using
{_setRoleAdmin}.
WARNING: The DEFAULT_ADMIN_ROLE is also its own admin: it has permission to
grant and revoke this role.应采取额外的预防措施以确保
accounts that have been granted it. */ abstract contract AccessControl is Context { using EnumerableSet for EnumerableSet.AddressSet; using Address for address;
struct RoleData { EnumerableSet.AddressSet members; bytes32 adminRole; }
mapping (bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
newAdminRole is set as role 's admin role, replacing previousAdminRoleDEFAULT_ADMIN_ROLE is the starting admin for all roles, despite/**
account is granted role .sender is the account that originated the contract call, an admin role/**
account is revoked role .sender is the account that originated the contract call:revokeRole , it is the admin role bearerrenounceRole , it is the role bearer (ie account ) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);/**
true if account has been granted role . */ function hasRole(bytes32 role, address account) public view returns (bool) { return _roles[role].members.contains(account); }/**
role .可以使用/**
role . index must be a/**
role . See {grantRole} and/**
@dev Grants role to account .
If account had not been already granted role , emits a {RoleGranted}
事件。
要求:
role 's admin role. */ function grantRole(bytes32 role, address account) public virtual { require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to grant");_grantRole(role, account); }
/**
@dev Revokes role from account .
If account had been granted role , emits a {RoleRevoked} event.
要求:
role 's admin role. */ function revokeRole(bytes32 role, address account) public virtual { require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to revoke");_revokeRole(role, account); }
/**
@dev Revokes role from the calling account.
Roles are often managed via {grantRole} and {revokeRole}: this function's
purpose is to provide a mechanism for accounts to lose their privileges
if they are compromised (such as when a trusted device is misplaced).
If the calling account had been granted role , emits a {RoleRevoked}
事件。
要求:
account . */ function renounceRole(bytes32 role, address account) public virtual { require(account == _msgSender(), "AccessControl: can only renounce roles for self");_revokeRole(role, account); }
/**
role to account .account had not been already granted role , emits a {RoleGranted}/**
adminRole as role 's admin role.function _grantRole(bytes32 role, address account) private { if (_roles[role].members.add(account)) { emit RoleGranted(role, account, _msgSender()); }}}
function _revokeRole(bytes32 role, address account) private { if (_roles[role].members.remove(account)) { emit RoleRevoked(role, account, _msgSender()); }}}}
pragma solidity 0.6.8;
contract QXToken is Context, AccessControl, ERC20Snapshot { bytes32 public constant SNAPSHOT_ROLE = keccak256("SNAPSHOT_ROLE");
constructor(uint256 amount, uint8 decimals) ERC20("QX ERC20", "QX") public {
_setupDecimals(decimals);
_mint(msg.sender, amount);
// set up required roles
_setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
_setupRole(SNAPSHOT_ROLE, _msgSender());
}
/**
* @dev Creates a new snapshot and returns its snapshot id.
* Emits a {Snapshot} event that contains the same id.
*/
function snapshot() public {
require(hasRole(SNAPSHOT_ROLE, _msgSender()), "Must have snapshot role to create a snapshot");
_snapshot();
}
}