// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

interface IVWXToken {
    function _founderMint(address _mintAddress, uint _amount) external;
}

contract FounderMintMultiSign {
    IVWXToken VWXToken;
    mapping(address => bool) public isOwner;
    address[] public owners;
    mapping(address => mapping(address => bool)) public mintAddressConfirmInfo;
    address public VWXTokenAddress;
    address public deployerAddress;
    mapping(address => bool) public isMinted;

    constructor(address[] memory _owners) {
        owners = _owners;
        for (uint i = 0; i < _owners.length; i++) {
            isOwner[owners[i]] = true;
        }
        deployerAddress = msg.sender;
    }

    event ConfrimFounderMint(address indexed _mintAddress);
    event FounderMint(address _mintAddress, uint _amount);

    function getSignAddress(address _mintAddress, bytes memory _signature) internal pure returns(address) {
        require(_signature.length == 65, "Invalid signature.");
        bytes32 r;
        bytes32 s;
        uint8 v;
        
        bytes32 msgHash;

        assembly{
            r := mload(add(_signature, 0x20))
            s := mload(add(_signature, 0x40))
            v := byte(0, mload(add(_signature, 0x60)))            
        }
        msgHash = getEthMessageHash(_mintAddress);
        return ecrecover(msgHash, v, r, s);
    }

    function getEthMessageHash(address _mintAddress) internal pure returns(bytes32) {
        bytes32 messageHash;
        messageHash = keccak256(abi.encodePacked(_mintAddress));
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", messageHash));
    }

    function confrimFounderMint(address mintAddress, bytes memory signature) public returns(bool) {
        address _signAddress = getSignAddress(mintAddress, signature);
        require(isOwner[_signAddress], "Only Owner");
        require(!isMinted[mintAddress], "Already minted.");
        mintAddressConfirmInfo[mintAddress][_signAddress] = true;
        emit ConfrimFounderMint(mintAddress);
        return true;
    }

    function founderMint(address mintAddress, uint amount) public returns(bool) {
        require(
            mintAddressConfirmInfo[mintAddress][owners[0]]
            && mintAddressConfirmInfo[mintAddress][owners[1]]
            && mintAddressConfirmInfo[mintAddress][owners[2]],
            "Only passed.");
        require(!isMinted[mintAddress], "Already minted.");
        require(msg.sender == deployerAddress, "Only deployerAddress.");
        VWXToken._founderMint(mintAddress, amount);
        isMinted[mintAddress] = true;
        emit FounderMint(mintAddress, amount);
        return true;
    }

    function setVWXTokenAddress(address _VWXTokenAddress) public returns(bool) {
        require(msg.sender == deployerAddress, "Only deployerAddress.");
        require(VWXTokenAddress == address(0), "Already set.");

        VWXTokenAddress = _VWXTokenAddress;
        VWXToken = IVWXToken(VWXTokenAddress);
        
        return true;
    }
}