DCIPs/assets/eip-4671/ERC4671Consensus.sol

86 lines
3.1 KiB
Solidity

// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "./ERC4671.sol";
import "./IERC4671Consensus.sol";
contract ERC4671Consensus is ERC4671, IERC4671Consensus {
// Consensus voters addresses
mapping(address => bool) private _voters;
address[] private _votersArray;
// Mapping from voter to mint approvals
mapping(address => mapping(address => bool)) private _mintApprovals;
// Mapping from owner to approval counts
mapping(address => uint256) private _mintApprovalCounts;
// Mapping from voter to revoke approvals
mapping(address => mapping(uint256 => bool)) private _revokeApprovals;
// Mapping from tokenId to revoke counts
mapping(uint256 => uint256) private _revokeApprovalCounts;
constructor (string memory name_, string memory symbol_, address[] memory voters_) ERC4671(name_, symbol_) {
_votersArray = voters_;
for (uint256 i=0; i<voters_.length; i++) {
_voters[voters_[i]] = true;
}
}
/// @notice Get voters addresses for this consensus contract
/// @return Addresses of the voters
function voters() public view virtual override returns (address[] memory) {
return _votersArray;
}
/// @notice Cast a vote to mint a token for a specific address
/// @param owner Address for whom to mint the token
function approveMint(address owner) public virtual override {
require(_voters[msg.sender], "You are not a voter");
require(!_mintApprovals[msg.sender][owner], "You already approved this address");
_mintApprovals[msg.sender][owner] = true;
_mintApprovalCounts[owner] += 1;
if (_mintApprovalCounts[owner] == _votersArray.length) {
_resetMintApprovals(owner);
_mint(owner);
}
}
/// @notice Cast a vote to revoke a token for a specific address
/// @param tokenId Identifier of the token to revoke
function approveRevoke(uint256 tokenId) public virtual override {
require(_voters[msg.sender], "You are not a voter");
require(!_revokeApprovals[msg.sender][tokenId], "You already approved this address");
_revokeApprovals[msg.sender][tokenId] = true;
_revokeApprovalCounts[tokenId] += 1;
if (_revokeApprovalCounts[tokenId] == _votersArray.length) {
_resetRevokeApprovals(tokenId);
_revoke(tokenId);
}
}
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC4671) returns (bool) {
return
interfaceId == type(IERC4671Consensus).interfaceId ||
super.supportsInterface(interfaceId);
}
function _resetMintApprovals(address owner) private {
for (uint256 i=0; i<_votersArray.length; i++) {
_mintApprovals[_votersArray[i]][owner] = false;
}
_mintApprovalCounts[owner] = 0;
}
function _resetRevokeApprovals(uint256 tokenId) private {
for (uint256 i=0; i<_votersArray.length; i++) {
_revokeApprovals[_votersArray[i]][tokenId] = false;
}
_revokeApprovalCounts[tokenId] = 0;
}
}