编译器
0.8.20+commit.a1b79de6
文件 1 的 2:AccessControl.sol
pragma solidity 0.8.20;
abstract contract AccessControl {
event RoleAdminChanged(bytes32 role, bytes32 previousAdminRole, bytes32 newAdminRole);
event RoleGranted(bytes32 role, address account, address sender);
event RoleRevoked(bytes32 role, address account, address sender);
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 internal constant DEFAULT_ADMIN_ROLE = 0x00;
modifier onlyRole(bytes32 role) {
_checkRole(role, msg.sender);
_;
}
function hasRole(bytes32 role, address account) public view returns (bool) {
return _roles[role].members[account];
}
function _checkRole(bytes32 role, address account) internal view {
if (!hasRole(role, account)) {
revert("Account is missing role");
}
}
function getRoleAdmin(bytes32 role) public view returns (bytes32) {
return _roles[role].adminRole;
}
function grantRole(bytes32 role, address account) external onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
function revokeRole(bytes32 role, address account) external onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
function renounceRole(bytes32 role, address account) external {
require(account == msg.sender);
_revokeRole(role, account);
}
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
function _grantRole(bytes32 role, address account) internal {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, msg.sender);
}
}
function _revokeRole(bytes32 role, address account) internal {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, msg.sender);
}
}
}
文件 2 的 2:NinfaWhitelist.sol
pragma solidity 0.8.20;
import "./access/AccessControl.sol";
contract NinfaWhitelist is AccessControl {
address private feeAccount;
bytes32 private DOMAIN_SEPARATOR;
bytes32 private DOMAIN_TYPEHASH;
bytes32 private WHITELIST_PERMIT_TYPEHASH;
bytes32 private constant CURATOR_ROLE = 0x850d585eb7f024ccee5e68e55f2c26cc72e1e6ee456acf62135757a5eb9d4a10;
uint256 private flatFee;
mapping(bytes => bool) private usedSignatures;
mapping(address => bool) public isWhitelisted;
struct WhitelistPermit {
address collection;
bool isWhitelisted;
bytes32 collectionType;
bytes32 salt;
}
event Whitelist(
address collection, address indexed whitelister, bytes32 indexed collectionType, bool isWhitelisted
);
function whitelistCollection(WhitelistPermit calldata _permit, bytes memory _signature) external payable {
require(msg.value >= flatFee);
if (flatFee > 0) {
_sendValue(feeAccount, flatFee);
}
address _signer = _recover(_permit, _signature);
require(hasRole(CURATOR_ROLE, _signer) && !usedSignatures[_signature]);
usedSignatures[_signature] = true;
isWhitelisted[_permit.collection] = _permit.isWhitelisted;
emit Whitelist(_permit.collection, msg.sender, _permit.collectionType, _permit.isWhitelisted);
}
function _recover(
WhitelistPermit calldata _permit,
bytes memory _signature
)
private
view
returns (address _signer)
{
bytes32 digest = keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR,
keccak256(
abi.encode(
WHITELIST_PERMIT_TYPEHASH,
_permit.collection,
_permit.isWhitelisted,
_permit.collectionType,
_permit.salt
)
)
)
);
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := mload(add(_signature, 0x20))
s := mload(add(_signature, 0x40))
v := byte(0, mload(add(_signature, 0x60)))
}
_signer = ecrecover(digest, v, r, s);
if (_signer == address(0)) revert();
}
function setFlatFee(uint256 _flatFee) external onlyRole(DEFAULT_ADMIN_ROLE) {
flatFee = _flatFee;
}
function setFeeAccount(address _feeAccount) external onlyRole(DEFAULT_ADMIN_ROLE) {
feeAccount = _feeAccount;
}
function whitelistCollection(address collection, bool isWhitelisted_) external onlyRole(CURATOR_ROLE) {
isWhitelisted[collection] = isWhitelisted_;
}
function whitelistCollections(address[] memory collections, bool isWhitelisted_) external onlyRole(CURATOR_ROLE) {
for (uint256 i = 0; i < collections.length; i++) {
isWhitelisted[collections[i]] = isWhitelisted_;
}
}
receive() external payable {
revert();
}
function _sendValue(address _receiver, uint256 _amount) private {
(bool success,) = payable(_receiver).call{ value: _amount }("");
require(success);
}
constructor(string memory _eip712DomainName) {
DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)");
WHITELIST_PERMIT_TYPEHASH =
keccak256("WhitelistPermit(address collection,bool isWhitelisted,bytes32 collectionType,bytes32 salt)");
DOMAIN_SEPARATOR = keccak256(
abi.encode(
DOMAIN_TYPEHASH,
keccak256(bytes(_eip712DomainName)),
block.chainid,
address(this)
)
);
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
}
}
{
"compilationTarget": {
"src/NinfaWhitelist.sol": "NinfaWhitelist"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"appendCBOR": false,
"bytecodeHash": "none"
},
"optimizer": {
"details": {
"constantOptimizer": true,
"cse": true,
"deduplicate": true,
"inliner": true,
"jumpdestRemover": true,
"orderLiterals": true,
"peephole": true,
"yul": true,
"yulDetails": {
"optimizerSteps": "dhfoDgvulfnTUtnIf:fDnTOc",
"stackAllocation": true
}
},
"runs": 4194304
},
"remappings": [
":ds-test/=lib/forge-std/lib/ds-test/src/",
":forge-std/=lib/forge-std/src/",
":openzeppelin-contracts/=lib/openzeppelin-contracts/",
":openzeppelin/=lib/openzeppelin-contracts/contracts/",
":solmate/=lib/solmate/src/",
":src/=src/",
":test/=test/"
],
"viaIR": true
}
[{"inputs":[{"internalType":"string","name":"_eip712DomainName","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"collection","type":"address"},{"indexed":true,"internalType":"address","name":"whitelister","type":"address"},{"indexed":true,"internalType":"bytes32","name":"collectionType","type":"bytes32"},{"indexed":false,"internalType":"bool","name":"isWhitelisted","type":"bool"}],"name":"Whitelist","type":"event"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isWhitelisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeAccount","type":"address"}],"name":"setFeeAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_flatFee","type":"uint256"}],"name":"setFlatFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"bool","name":"isWhitelisted","type":"bool"},{"internalType":"bytes32","name":"collectionType","type":"bytes32"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"internalType":"struct NinfaWhitelist.WhitelistPermit","name":"_permit","type":"tuple"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"whitelistCollection","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"bool","name":"isWhitelisted_","type":"bool"}],"name":"whitelistCollection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"collections","type":"address[]"},{"internalType":"bool","name":"isWhitelisted_","type":"bool"}],"name":"whitelistCollections","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]