ETH Price: $2,485.48 (-1.47%)

Contract Diff Checker

Contract Name:
KaiStarter

Contract Source Code:

File 1 of 1 : KaiStarter

pragma solidity ^0.5.0;
/*
 * @title: SafeMath
 * @dev: Helper contract functions to arithmatic operations safely.
 */
contract SafeMath {
    function Sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        uint256 c = a - b;

        return c;
    }

    function Add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    function Mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }
}

/*
 * @title: Token
 * @dev: Interface contract for ERC20 tokens
 */
contract Token {
    function totalSupply() public view returns (uint256 supply);

    function balanceOf(address _owner) public view returns (uint256 balance);

    function transfer(address _to, uint256 _value)
        public
        returns (bool success);

    function transferFrom(
        address _from,
        address _to,
        uint256 _value
    ) public returns (bool success);

    function approve(address _spender, uint256 _value)
        public
        returns (bool success);

    function allowance(address _owner, address _spender)
        public
        view
        returns (uint256 remaining);

    event Transfer(address indexed _from, address indexed _to, uint256 _value);
    event Approval(
        address indexed _owner,
        address indexed _spender,
        uint256 _value
    );
}


contract ERC20Basic {
    uint public _totalSupply;
    function totalSupply() public view returns (uint256);
    function balanceOf(address who) public view returns (uint256);
    function transfer(address to, uint256 value) public;
    event Transfer(address indexed from, address indexed to, uint256 value);
}

/**
 * @title ERC20 interface
 * @dev see https://github.com/ethereum/EIPs/issues/20
 */
contract USDT is ERC20Basic {
    function allowance(address owner, address spender) public view returns (uint256);
    function transferFrom(address from, address to, uint256 value) public;
    function approve(address spender, uint256 value) public;
    event Approval(address indexed owner, address indexed spender, uint256 value);
}


/*
 * @title: Staking
 */
contract KaiStarter is SafeMath {
    // _kaiAddress: KAI ERC20 contract address
    // msg.sender: owner
    constructor(uint256 _contributeStartTime, uint256 _productReleasesTime, uint256 _lockDays) public {
        owner = msg.sender;
        isRevocable = false;
        isEnded = false;
        contributeStartTime = _contributeStartTime;
        productReleasesTime = _productReleasesTime;
        lockDays = _lockDays;
    }

    address public owner;
    address constant public kaiAddress = 0xD9Ec3ff1f8be459Bb9369b4E79e9Ebcf7141C093;
    address constant public usdtAddress = 0xdAC17F958D2ee523a2206206994597C13D831ec7;
    uint256 public currentCap;
    uint256 public totalBackers;
    address[] public listBackers;
    uint256[] public contributedAmount;
    uint256 public contributeStartTime;
    uint256 public productReleasesTime;
    uint256 public lockDays;
    uint256 public maxContributionEachBacker = 500000000000000000000000; //500000 KAI
    uint256 public hardCap = 7500000000000000000000000; //7500000 KAI
    uint256 public minContributionEachBacker = 1000000000000000000000; //1000 KAI
    /* isRevocable is true if the campaign does not raise enough fund after the endTime passed, 
     * and contributors can withdraw their fund; 
     * otherwise it's false
     */
    bool public isRevocable;
    bool public isEnded; // isEnded is true when the campaign ends
    uint256 public totalBonusUSDT;
    mapping (address => bool) isWithdrawBonus;
    mapping (address => bool) isWithdrawContribution;

    
    // Functions with this modifier can only be executed by the owner
    modifier onlyOwner() {
        require(msg.sender == owner);
        _;
    }

    // check if this backer has contributed to the compaign or not yet
    function existBacker(address backer) view private returns (uint256) {
        for (uint i; i< listBackers.length;i++){
          if (listBackers[i] == backer)
            return i+1;
        }
        return 0;
    }
    
    // owner sets global variables if the campaign fails
    function setRevocable() public onlyOwner {
        isRevocable = true;
        isEnded = true;
    }
    
    // owner sets global variables the campaign ends
    function setEnded() public onlyOwner {
        isEnded = true;
    }
    
    // backers contribute KAI to the campaign
    function contributeKAI(uint256 amount) public {
        require(now > contributeStartTime, 'Contribute time not comming');
        require(isEnded != true, 'Campaign ended');
        require(amount <= maxContributionEachBacker, 'Amount must be equal or smaller than 500000 KAI');
        require(amount >= minContributionEachBacker, 'Amount must be equal or greater than 1000 KAI');
        require(Add(amount, currentCap) <= hardCap, 'Exceed limit total cap');
        require(Token(kaiAddress).transferFrom(msg.sender, address(this), amount));
        
        uint256 indexBacker = existBacker(msg.sender);
        if (indexBacker != 0) {
            contributedAmount[indexBacker-1] += amount;
            require(contributedAmount[indexBacker-1] <= maxContributionEachBacker);
            
        } else {
            listBackers.push(msg.sender);
            contributedAmount.push(amount);
            totalBackers += 1;
        }
        
        currentCap = Add(currentCap, amount);
    }

    // Backers withdraw KAI to their personal addresses
    function withdrawKAI() public {
        if (isRevocable != true) {
            require((contributeStartTime + lockDays * 1 days) < now, "Locking period"); // ensure lock time is passeed
        }
        require(existBacker(msg.sender) != 0, "The backer not exist ");
        require(isWithdrawContribution[msg.sender] == false, "The backer withdraw only once"); //ensure the backer withdraw only once
        
        uint256 indexBacker = existBacker(msg.sender);
        uint256 amount = contributedAmount[indexBacker-1];
        require(Token(kaiAddress).transfer(msg.sender, amount));
        isWithdrawContribution[msg.sender] = true;
    }
    
    // Backers withdraw their distributed revenue
    function withdrawBonusUSDT() public {
        require((productReleasesTime + lockDays * 1 days) < now, "Locking period"); // ensure lock time is passeed
        require(existBacker(msg.sender) != 0, "The backer does not exist ");
        require(isWithdrawBonus[msg.sender] == false, "The backer withdraw only once"); // ensure the backer withdraw only once
        
        uint256 bonus = calculateBonus(msg.sender);
        USDT(usdtAddress).transfer(msg.sender, bonus);
        isWithdrawBonus[msg.sender] = true;
        
    }
    
    function calculateBonus(address backerAddr) private returns (uint256) {
        uint256 indexBacker = existBacker(backerAddr);
        uint256 amount = contributedAmount[indexBacker-1];
        uint256 bonus = Mul(amount, totalBonusUSDT) / currentCap;
        return bonus;
    }
   
     // owner contribute KAI to the campaign
    function fillRemaningKAI() public onlyOwner {
        uint256 amount = Sub(hardCap, currentCap);
        require(Add(amount, currentCap) == hardCap, 'Exceed limit total cap');
        require(Token(kaiAddress).transferFrom(msg.sender, address(this), amount));
        
        currentCap = Add(currentCap, amount);
    }
    
    function setContributeStartTime(uint256 _contributeStartTime) public onlyOwner {
        contributeStartTime = _contributeStartTime;
    }
   
    function setProductReleasesTime(uint256 _productReleasesTime) public onlyOwner {
        productReleasesTime = _productReleasesTime;
    }
    
    function setLockDays(uint256 _lockDays) public onlyOwner {
        lockDays = _lockDays;
    }
    
    function setMaxContributionEachBacker(uint256 _maxContributionEachBacker) public onlyOwner {
        maxContributionEachBacker = _maxContributionEachBacker;
    }
    
    function setTotalBonusUSDT(uint256 _totalBonusUSDT) public onlyOwner {
        require(USDT(usdtAddress).balanceOf(address(this)) >= _totalBonusUSDT);

        totalBonusUSDT = _totalBonusUSDT;
   }
    
    function getMyContribution(address backer) public view returns (uint256) {
        require(existBacker(backer) != 0);
        
        uint256 indexBacker = existBacker(backer);
        uint256 amount = contributedAmount[indexBacker-1];
        return amount;
    }

    function getTimeStamp() public view returns (uint256) {
        return now;
    }
    
    function emergencyWithdrawalETH(uint256 amount) public onlyOwner {
        require(msg.sender.send(amount));
    }
    
    function emergencyWithdrawalKAI(uint256 amount) public onlyOwner {
        require (now > (contributeStartTime + 32 * 1 weeks)); // after 32 weeks, owner can withdraw KAI
        Token(kaiAddress).transfer(msg.sender, amount);
    }
    
    function emergencyWithdrawalUSDT(uint256 amount) public onlyOwner {
        USDT(usdtAddress).transfer(msg.sender, amount);
    }
    
    // @notice Will receive any eth sent to the contract
    function () external payable {}
}

Please enter a contract address above to load the contract details and source code.

Context size (optional):