// We will be using Solidity version 0.8.10
// OpenZeppelin Contracts v4.4.1 (utils/escrow/RefundEscrow.sol) -> customized RefundEscrowNilli.sol
pragma solidity 0.8.18;




/**
 * @title nilliv2
 * @dev This is an owner contract for a customized OZ 'RefundEscrow' contract
 * @dev Intended usage: See {Escrow}. Same usage guidelines apply here.
 * @dev This owner account (that is, the contract that instantiates RefundEscrow
 * contract) may deposit, close the deposit period, and allow for either
 * withdrawal by the beneficiary, or refunds to the depositors. All interactions
 * with `RefundEscrow` will be made through this owner contract. The customizations
 * allow for depositing/extraction of both ERC-20 and ERC-721 assets on top
 * of the native ETH deposits/extractions by the original OZ RefundEscrow contract
 */

contract ParentEscrow is Ownable {

    enum State {
        Locked,
        Unlocked,
        Refunded,
        Delivered
    }

    // Event that will be emitted whenever a new endowment is started
    event NilliContract(
        address contractAddress,
        string recDisplayName,
        string title,
        string creator,
        string condition1,
        string condition2,
        string condition3,
        bool[3] conditionFlags, //3 conditions and jury decision is 4th
        uint targetAmount,
        uint expirationDate,
        uint qtySigners,
        State curState
    );

    // Event that will be emitted whenever a deposit is initiated
    event ContractDeposit(
        address endowAddress,
        address depositorAddress,
        address depTokAddr,
        uint amtDeposited,
        string depType
    );

     // Event that will be emitted whenever a withdraw is initiated
    event ContractWithdraw(
        address endowAddress,
        address withdrawerAddress,
        address withdrawTokAddr,
        string withdrawType
    );

    // Event that will be emitted whenever an endowment state changes
    event ContractStateChange(
        address endowAddress,
        RefundEscrowNilli.State newState
    );

    /**
     * @dev Initiates a new endowment. This contract will act as owner
     * to the modified RefundEscrow contract it calls.
     */
    function startContract(
        string memory recDisplayName,
        string memory title,
        string memory creator,
        string memory condition1,
        string memory condition2,
        string memory condition3,
        uint targetAmount,
        uint expirationDate
    ) public {
        RefundEscrowNilli newContract = new RefundEscrowNilli(
            recDisplayName,
            title,
            creator,
            condition1,
            condition2,
            condition3,
            targetAmount, 
            expirationDate);
        emit NilliContract(
            address(newContract),
            recDisplayName,
            title,
            creator,
            condition1,
            condition2,
            condition3,
            [false,false,false],
            targetAmount,
            expirationDate,
            0,
            State.Locked
        );
    }

    /**
     * @dev Deposits ETH to the specific endowment contract.
     */
    function depositToContract(RefundEscrowNilli contractAddress) public payable returns (uint amt) {
        contractAddress.deposit{value: msg.value}(msg.sender);
        emit ContractDeposit(
            address(contractAddress),
            msg.sender,
            address(0),
            msg.value,
            "ETH"
        );
        return(msg.value);
    }
    
    /**
     * @dev Closes endowment so that deposits can no longer be issued. Once closed, the
     * beneficiary is free/allowed to withdraw their assets (via this contract).
     */
    function stateChangeContract(RefundEscrowNilli contractAddress, RefundEscrowNilli.State newState) public onlyOwner {
        contractAddress.stateChangeContract(newState);
        emit ContractStateChange(address(contractAddress), newState);
    }

    function verifyChild(RefundEscrowNilli contractAddress) public onlyOwner {
        contractAddress.verify();
        //TODO: do we need an event to fire?
    }

    function updateConditionFlags(RefundEscrowNilli contractAddress, bool[3] memory condFlags) public onlyOwner {
        contractAddress.updateConditionFlags(condFlags);
        //TODO: do we need an event to fire here?
    }

    /**
     * @dev Deposits a specific token (ERC-20) to the endowment
     */
    function depTokentoContract(RefundEscrowNilli contractAddress, IERC20 token, uint amount) public returns (uint amt) {
        contractAddress.depositToken(token, msg.sender, amount);
        emit ContractDeposit(
            address(contractAddress),
            msg.sender,
            address(token),
            amount,
            "Token"
        );
        return(amount);
    }

    /**
     * @dev if RefundsEnabled, the depositor can withdraw their submitted ERC-20 balance
     */
    function withdrawTokenContract(RefundEscrowNilli contractAddress, IERC20 token) public {
        contractAddress.withdrawToken(token, msg.sender);
        emit ContractWithdraw(
            address(contractAddress),
            msg.sender,
            address(token),
            "Token"
        );
    }

    /**
     * @dev Deposits a specific NFT (ERC-721) to the endowment
     */
    function depNFTtoContract(RefundEscrowNilli contractAddress, IERC721 token, uint tokenId) public {
        contractAddress.nftDepositContract(token, msg.sender, tokenId);
        emit ContractDeposit(
            address(contractAddress),
            msg.sender,
            address(token),
            1,
            "NFT"
        );
    }

    /**
     * @dev if RefundsEnabled, the depositor can withdraw their submitted ERC-721 NFTs
     */
    function withdrawNFTContract(RefundEscrowNilli contractAddress, IERC721 token, uint tokenId) public {
        contractAddress.nftRefundContract(token, msg.sender, tokenId);
        emit ContractWithdraw(
            address(contractAddress),
            msg.sender,
            address(token),
            "NFT"
        );
    }

    /**
     * @dev if endowment Closed, the beneficiary can withdraw ERC-20 tokens from endowment.
     */
    function withdrawTokenOwner(RefundEscrowNilli contractAddress, IERC20 token) public onlyOwner {
        contractAddress.tokenWithdrawOwner(token);
        emit ContractWithdraw(
            address(contractAddress),
            msg.sender,
            address(token),
            "Token"
        );
    }

    /**
     * @dev if endowment Closed, the beneficiary can withdraw ERC-721 NFTs from endowment.
     */
    function withdrawNFTOwner(RefundEscrowNilli contractAddress, IERC721 token, uint tokenId) public onlyOwner {
        contractAddress.nftWithdrawOwner(token, tokenId);
        emit ContractWithdraw(
            address(contractAddress),
            msg.sender,
            address(token),
            "NFT"
        );
    }

     /**
     * @dev if endowment Refunded, the depositor can withdraw ETH from endowment.
     */
    function withdrawETHDepositor(RefundEscrowNilli contractAddress) public {
        contractAddress.withdraw(payable(msg.sender));
        emit ContractWithdraw(
            address(contractAddress),
            msg.sender,
            address(0),
            "ETH"
        );
    }

    // typical renounce ownership - will likely totally shutdown contract as only owners can interact.
    function renounceContractOwnership(RefundEscrowNilli contractAddress) public onlyOwner {
        contractAddress.renounceOwnership();
    }

    // typical transfer of ownership
    function xferContractOwnership(RefundEscrowNilli contractAddress, address newOwner) public onlyOwner {
        contractAddress.transferOwnership(newOwner);
        stateChangeContract(contractAddress, RefundEscrowNilli.State.Delivered);
    }
   
}
[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"endowAddress","type":"address"},{"indexed":false,"internalType":"address","name":"depositorAddress","type":"address"},{"indexed":false,"internalType":"address","name":"depTokAddr","type":"address"},{"indexed":false,"internalType":"uint256","name":"amtDeposited","type":"uint256"},{"indexed":false,"internalType":"string","name":"depType","type":"string"}],"name":"ContractDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"endowAddress","type":"address"},{"indexed":false,"internalType":"enum RefundEscrowNilli.State","name":"newState","type":"uint8"}],"name":"ContractStateChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"endowAddress","type":"address"},{"indexed":false,"internalType":"address","name":"withdrawerAddress","type":"address"},{"indexed":false,"internalType":"address","name":"withdrawTokAddr","type":"address"},{"indexed":false,"internalType":"string","name":"withdrawType","type":"string"}],"name":"ContractWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":false,"internalType":"string","name":"recDisplayName","type":"string"},{"indexed":false,"internalType":"string","name":"title","type":"string"},{"indexed":false,"internalType":"string","name":"creator","type":"string"},{"indexed":false,"internalType":"string","name":"condition1","type":"string"},{"indexed":false,"internalType":"string","name":"condition2","type":"string"},{"indexed":false,"internalType":"string","name":"condition3","type":"string"},{"indexed":false,"internalType":"bool[3]","name":"conditionFlags","type":"bool[3]"},{"indexed":false,"internalType":"uint256","name":"targetAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"expirationDate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"qtySigners","type":"uint256"},{"indexed":false,"internalType":"enum ParentEscrow.State","name":"curState","type":"uint8"}],"name":"NilliContract","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"contract RefundEscrowNilli","name":"contractAddress","type":"address"},{"internalType":"contract IERC721","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"depNFTtoContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract RefundEscrowNilli","name":"contractAddress","type":"address"},{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"depTokentoContract","outputs":[{"internalType":"uint256","name":"amt","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract RefundEscrowNilli","name":"contractAddress","type":"address"}],"name":"depositToContract","outputs":[{"internalType":"uint256","name":"amt","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract RefundEscrowNilli","name":"contractAddress","type":"address"}],"name":"renounceContractOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"recDisplayName","type":"string"},{"internalType":"string","name":"title","type":"string"},{"internalType":"string","name":"creator","type":"string"},{"internalType":"string","name":"condition1","type":"string"},{"internalType":"string","name":"condition2","type":"string"},{"internalType":"string","name":"condition3","type":"string"},{"internalType":"uint256","name":"targetAmount","type":"uint256"},{"internalType":"uint256","name":"expirationDate","type":"uint256"}],"name":"startContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract RefundEscrowNilli","name":"contractAddress","type":"address"},{"internalType":"enum RefundEscrowNilli.State","name":"newState","type":"uint8"}],"name":"stateChangeContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract RefundEscrowNilli","name":"contractAddress","type":"address"},{"internalType":"bool[3]","name":"condFlags","type":"bool[3]"}],"name":"updateConditionFlags","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract RefundEscrowNilli","name":"contractAddress","type":"address"}],"name":"verifyChild","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract RefundEscrowNilli","name":"contractAddress","type":"address"}],"name":"withdrawETHDepositor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract RefundEscrowNilli","name":"contractAddress","type":"address"},{"internalType":"contract IERC721","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"withdrawNFTContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract RefundEscrowNilli","name":"contractAddress","type":"address"},{"internalType":"contract IERC721","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"withdrawNFTOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract RefundEscrowNilli","name":"contractAddress","type":"address"},{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"withdrawTokenContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract RefundEscrowNilli","name":"contractAddress","type":"address"},{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"withdrawTokenOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract RefundEscrowNilli","name":"contractAddress","type":"address"},{"internalType":"address","name":"newOwner","type":"address"}],"name":"xferContractOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]