// SPDX-License-Identifier: LicenseRef-Blockwell-Smart-License
pragma solidity ^0.8.9;

import "common/ErrorCodes.sol";
import "../Groups.sol";

/**
 * @dev User groups for SwapRelay.
 *
 * Blockwell Exclusive (Intellectual Property that lives on-chain via Smart License)
 */
contract ContractGroups is ErrorCodes {
    uint8 public constant ADMIN = 1;
    uint8 public constant SWAPPERS = 7;

    using Groups for Groups.GroupMap;

    Groups.GroupMap groups;

    event AddedToGroup(uint8 indexed groupId, address indexed account);
    event RemovedFromGroup(uint8 indexed groupId, address indexed account);


    modifier onlyAdmin() {
        expect(isAdmin(msg.sender), ERROR_UNAUTHORIZED);
        _;
    }
    // ADMIN

    function _addAdmin(address account) internal {
        _add(ADMIN, account);
    }

    function addAdmin(address account) public onlyAdmin {
        _addAdmin(account);
    }

    function removeAdmin(address account) public onlyAdmin {
        _remove(ADMIN, account);
    }

    function isAdmin(address account) public view returns (bool) {
        return _contains(ADMIN, account);
    }

    // SWAPPERS

    function addSwapper(address account) public onlyAdmin {
        _addSwapper(account);
    }

    function _addSwapper(address account) internal {
        _add(SWAPPERS, account);
    }

    function removeSwapper(address account) public onlyAdmin {
        _remove(SWAPPERS, account);
    }

    function isSwapper(address account) public view returns (bool) {
        return _contains(SWAPPERS, account);
    }

    modifier onlySwapper() {
        expect(isSwapper(msg.sender), ERROR_UNAUTHORIZED);
        _;
    }

    // Internal functions

    function _add(uint8 groupId, address account) internal {
        groups.add(groupId, account);
        emit AddedToGroup(groupId, account);
    }

    function _remove(uint8 groupId, address account) internal {
        groups.remove(groupId, account);
        emit RemovedFromGroup(groupId, account);
    }

    function _contains(uint8 groupId, address account) internal view returns (bool) {
        return groups.contains(groupId, account);
    }
}
[{"inputs":[{"internalType":"uint256","name":"_swappersNeeded","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"SwapIdMismatch","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"groupId","type":"uint8"},{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"AddedToGroup","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"groupId","type":"uint8"},{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"RemovedFromGroup","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"swapId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"swapper","type":"address"},{"indexed":true,"internalType":"uint256","name":"count","type":"uint256"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract ERC721","name":"tokenContract","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"bytes32","name":"swapId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"fromChainId","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"SwapFromChain","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"toChainId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"swapNonce","type":"uint256"},{"indexed":false,"internalType":"contract ERC721","name":"tokenContract","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"bytes32","name":"swapId","type":"bytes32"},{"indexed":false,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"SwapToChain","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"count","type":"uint256"}],"name":"SwappersNeededUpdate","type":"event"},{"inputs":[],"name":"ADMIN","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SWAPPERS","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"addAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"addSwapper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bwtype","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bwver","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isSwapper","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"removeAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"removeSwapper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"count","type":"uint256"}],"name":"setSwappersNeeded","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"swapDone","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"relayContract","type":"address"},{"internalType":"uint256","name":"fromChainId","type":"uint256"},{"internalType":"uint256","name":"sourceSwapNonce","type":"uint256"},{"internalType":"address","name":"sourceTokenContract","type":"address"},{"internalType":"contract ERC721","name":"tokenContract","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes32","name":"swapId","type":"bytes32"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"swapFromChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"swapId","type":"bytes32"}],"name":"swapRelayers","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ERC721","name":"tokenContract","type":"address"},{"internalType":"uint256","name":"toChainId","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"swapToChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swappersNeeded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"swapIds","type":"bytes32[]"}],"name":"swapsDone","outputs":[{"internalType":"bool[]","name":"","type":"bool[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Erc20","name":"token","type":"address"}],"name":"withdrawTokens","outputs":[],"stateMutability":"nonpayable","type":"function"}]