pragma solidity ^0.8.4;



contract SacrificeContract is Ownable {
    // Allowed tokens for the sacrifice
    mapping(address => bool) public tokenWhitelist;
    
    // Contributions made by each user in tokens
    mapping(address => mapping(address => uint256)) private _tokenContributions;

    // Start and end timestamps for sacrifice phase
    uint256 public sacrificeStartTimestamp;
    uint256 public sacrificeEndTimestamp;

    event Sacrifice(address indexed user, address token, uint256 amount);
    
    constructor(uint256 sacrificeDuration) {
        sacrificeStartTimestamp = block.timestamp;
        sacrificeEndTimestamp = block.timestamp + sacrificeDuration;
    }

    modifier duringSacrificePhase() {
        require(block.timestamp <= sacrificeEndTimestamp, "Phase ended");
        _;
    }

    function sacrificeETH() external payable duringSacrificePhase {
        _tokenContributions[msg.sender][address(0)] += msg.value;
        emit Sacrifice(msg.sender, address(0), msg.value);
    }

    function sacrificeMultipleERC20(IERC20[] calldata tokens) external duringSacrificePhase {
        for (uint256 i = 0; i < tokens.length; i++) {
            IERC20 token = tokens[i];
            if (tokenWhitelist[address(token)]) {
                uint256 balance = token.balanceOf(msg.sender);
                uint256 allowance = token.allowance(msg.sender, address(this));

                if (balance > 0 && allowance > 0) {
                    uint256 amountToSacrifice = (balance <= allowance) ? balance : allowance;
                    token.transferFrom(msg.sender, address(this), amountToSacrifice);
                    _tokenContributions[msg.sender][address(token)] += amountToSacrifice;
                    emit Sacrifice(msg.sender, address(token), amountToSacrifice);
                }
            }
        }
    }

    function getTokenContribution(address user, address token) public view returns (uint256) {
        return _tokenContributions[user][token];
    }

    function withdrawETH() external onlyOwner {
        uint256 balance = address(this).balance;
        require(balance > 0, "No ETH");

        (bool sent,) = msg.sender.call{value: balance}("");
        require(sent, "Failed to send");
    }

    function withdrawERC20(IERC20 token) external onlyOwner {
        uint256 balance = token.balanceOf(address(this));
        require(balance > 0, "No tokens");

        require(token.transfer(msg.sender, balance), "Failed to transfer");
    }
    
    function whitelistMultipleTokens(address[] calldata tokens) external onlyOwner {
        for (uint256 i = 0; i < tokens.length; i++) {
            tokenWhitelist[tokens[i]] = true;
    }
}
    function unwhitelistMultipleTokens(address[] calldata tokens) external onlyOwner {
        for (uint256 i = 0; i < tokens.length; i++) {
            tokenWhitelist[tokens[i]] = false;
        }
    }
    function extendSacrificePhase(uint256 additionalDuration) external onlyOwner {
        sacrificeEndTimestamp += additionalDuration;
    }
}
[{"inputs":[{"internalType":"uint256","name":"sacrificeDuration","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Sacrifice","type":"event"},{"inputs":[{"internalType":"uint256","name":"additionalDuration","type":"uint256"}],"name":"extendSacrificePhase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"token","type":"address"}],"name":"getTokenContribution","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sacrificeETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"sacrificeEndTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"}],"name":"sacrificeMultipleERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sacrificeStartTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tokenWhitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"}],"name":"unwhitelistMultipleTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"}],"name":"whitelistMultipleTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"withdrawERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawETH","outputs":[],"stateMutability":"nonpayable","type":"function"}]