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

import "./ContractGroups.sol";
import "common/Type.sol";

/**
 * @dev Relay contract for verifying crosschain swaps.
 *
 * Blockwell Exclusive (Intellectual Property that lives on-chain via Smart License)
 */
contract RelayBase is ContractGroups, Type {
    struct SwapData {
        bool swapped;
        address[] swappers;
    }

    string public name = "SwapRelay";

    uint256 public swappersNeeded;

    mapping(bytes32 => bool) public swapDone;

    mapping(bytes32 => address[]) internal swaps;

    event Swap(bytes32 indexed swapId, address indexed swapper, uint256 indexed count);
    event SwappersNeededUpdate(uint256 indexed count);

    constructor(uint256 _swappersNeeded) {
        swappersNeeded = _swappersNeeded;
        _addAdmin(msg.sender);

        bwtype = SWAP_RELAY;
        bwver = 85;
    }

    function setSwappersNeeded(uint256 count) public onlyAdmin {
        expect(count > 0, ERROR_BAD_PARAMETER_1);
        swappersNeeded = count;
        emit SwappersNeededUpdate(count);
    }

    function swapsDone(bytes32[] calldata swapIds) public view returns (bool[] memory) {
        bool[] memory done = new bool[](swapIds.length);

        for (uint256 i = 0; i < swapIds.length; i++) {
            done[i] = swapDone[swapIds[i]];
        }

        return done;
    }

    function swapRelayers(bytes32 swapId) public view returns (address[] memory) {
        return swaps[swapId];
    }

    function shouldSwap(bytes32 swapId, address swapper) internal returns (bool) {
        if (swapDone[swapId]) {
            return false;
        }
        address[] storage swappers = swaps[swapId];

        for (uint256 i = 0; i < swappers.length; i++) {
            if (swappers[i] == swapper) {
                return false;
            }
        }

        emit Swap(swapId, swapper, swappers.length + 1);
        if (swappers.length + 1 >= swappersNeeded) {
            swapDone[swapId] = true;
            if (swappers.length > 0) {
                delete swaps[swapId];
            }
            return true;
        }

        swappers.push(swapper);

        return false;
    }
}
[{"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"}]