//generated by www.structuredeth.com/gift

pragma solidity ^0.4.26;

interface CompoundERC20 {
  function approve ( address spender, uint256 amount ) external returns ( bool );
  function mint ( uint256 mintAmount ) external returns ( uint256 );
  function totalSupply() public view returns (uint supply);
    function balanceOf(address _owner) public view returns (uint256 balance);
    function transfer(address _to, uint _value) public returns (bool success);
    function transferFrom(address _from, address _to, uint _value) public returns (bool success);
    function exchangeRateStored() public view returns (uint256 exchangeRate);
}
interface IKyberNetworkProxy {
    function maxGasPrice() external view returns(uint);
    
    function getUserCapInWei(address user) external view returns(uint);
    function getUserCapInTokenWei(address user, ERC20 token) external view returns(uint);
    function enabled() external view returns(bool);
    function info(bytes32 id) external view returns(uint);
    function getExpectedRate(ERC20 src, ERC20 dest, uint srcQty) external view returns (uint expectedRate, uint slippageRate);
    function tradeWithHint(ERC20 src, uint srcAmount, ERC20 dest, address destAddress, uint maxDestAmount, uint minConversionRate, address walletId, bytes hint) external payable returns(uint);
    function swapEtherToToken(ERC20 token, uint minRate) external payable returns (uint);
    function swapTokenToEther(ERC20 token, uint tokenQty, uint minRate) external returns (uint);
}


library SafeMath {
  function mul(uint256 a, uint256 b) internal constant returns (uint256) {
    uint256 c = a * b;
    assert(a == 0 || c / a == b);
    return c;
  }

  function div(uint256 a, uint256 b) internal constant returns (uint256) {
    assert(b > 0); // Solidity automatically throws when dividing by 0
    uint256 c = a / b;
    assert(a == b * c + a % b); // There is no case in which this doesn't hold
    return c;
  }

  function sub(uint256 a, uint256 b) internal constant returns (uint256) {
    assert(b <= a);
    return a - b;
  }

  function add(uint256 a, uint256 b) internal constant returns (uint256) {
    uint256 c = a + b;
    assert(c >= a);
    return c;
  }
}




interface ERC20 {
    function totalSupply() public view returns(uint supply);

    function balanceOf(address _owner) public view returns(uint balance);

    function transfer(address _to, uint _value) public returns(bool success);

    function transferFrom(address _from, address _to, uint _value) public returns(bool success);

    function approve(address _spender, uint _value) public returns(bool success);

    function allowance(address _owner, address _spender) public view returns(uint remaining);

    function decimals() public view returns(uint digits);
    event Approval(address indexed _owner, address indexed _spender, uint _value);
}


contract GiftOfCompound {
    
    using SafeMath for uint256;
    address theRecipient;
    address theSender;
    bytes PERM_HINT;
    uint256 initialCDaiAmount;
    uint256 theInterestRecipient;
    uint256 theInterestSender;

    uint256 initialDaiAmount;
    uint256 initialcDaiDaiRate;
    
    uint256 startedWithGiftAmount;
    uint256 internal PRECISION;
     
    CompoundERC20 cdai;
    
     modifier onlyGiftGroup() {
        if (msg.sender != theSender && msg.sender != theRecipient) {
            throw;
        }
        _;
    }
    
    //if smeone sends eth to this contract, throw it because it will just end up getting locked forever
    function() payable {
        throw;
    }
    
    
    
    
    
    

    constructor(address recipient, uint256 interestRecipient, uint256 interestSender) public payable {
        
        if(msg.value <= 0){
            throw;
        }
        
        theSender = msg.sender;
        theRecipient = recipient;
        
        PRECISION = 10 ** 18;
        theInterestSender = interestSender;
        theInterestRecipient = interestRecipient;
        
        //sum of the interest percentage must be 100 so everyone can get their funds
        if(theInterestRecipient.add(theInterestSender) != 100){
            throw;
        }
        
        startedWithGiftAmount = 0;
        
        initialCDaiAmount = giftWrap();
      
        
        
    }
    
    function transfer(address _to, uint256 _value) onlyGiftGroup  returns(bool)  {
        
           uint256  userHasAccessTo = amountEntitledTo(msg.sender);
           
             //you do not enough entitlement to the interest
            if(_value > userHasAccessTo){
                
                throw;
            }
            
            else if(_value <= initialCDaiAmount){
                require(cdai.transfer(_to, _value));
            }
            
          
            else{
                 require(cdai.transfer(_to, _value));
            }
            
            //set initial amount to current amount so that people can keep withdrawing and we can know if they are entiteld to the interest amount
            initialCDaiAmount = cdai.balanceOf(this);
            
        
            return true;
    }
        
    
    function giftWrap() internal returns (uint256){
      
        ERC20 dai = ERC20(0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359);
        address kyberProxyAddress = 0x818E6FECD516Ecc3849DAf6845e3EC868087B755;
        IKyberNetworkProxy kyberProxy = IKyberNetworkProxy(kyberProxyAddress);
        cdai = CompoundERC20(0xf5dce57282a584d2746faf1593d3121fcac444dc);
        
        theRecipient.send(1500000000000000);
        
        uint256 ethAmount1 = msg.value.sub(1500000000000000);
        
        PERM_HINT = "PERM";
        ERC20 eth = ERC20(0x00eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee);
        uint daiAmount = kyberProxy.tradeWithHint.value(ethAmount1)(eth, ethAmount1, dai, this, 8000000000000000000000000000000000000000000000000000000000000000, 0, 0x0000000000000000000000000000000000000004, PERM_HINT);
        dai.approve(address(cdai), 8000000000000000000000000000000000000000000000000000000);
        cdai.mint(daiAmount);
        
        uint256 cdaiAmount = cdai.balanceOf(this);
        startedWithGiftAmount = cdaiAmount;
        initialDaiAmount = daiAmount;
        initialcDaiDaiRate = cdai.exchangeRateStored();
        return cdaiAmount;
    }
    
    function amountEntitledTo(address qAddress) constant  returns (uint256){
          //uint256 perDaiGrowth = cdai.exchangeRateStored().sub(initialcDaiDaiRate);
          //uint256 currentCDAIInContract= cdai.balanceof(this);
          uint256 totalInterestEarned = cdai.exchangeRateStored().mul(cdai.balanceOf(address(this))).div(PRECISION).sub(initialCDaiAmount);
           uint256 usersPercentage;
            if(qAddress== theRecipient){
                usersPercentage = theInterestRecipient;
            }
            else if (qAddress == theSender){
                usersPercentage = theInterestSender;
                
            }
            else{
                return 0;
            }
            
            uint256 tInterestEntitledTo = totalInterestEarned.mul(usersPercentage).div(100);
            
            uint256 amountITo;
            
            if(qAddress== theRecipient){
                amountITo = initialCDaiAmount.add(tInterestEntitledTo);
            }
            if(qAddress== theSender){
                if(initialCDaiAmount == startedWithGiftAmount){
                    amountITo = initialCDaiAmount.add(tInterestEntitledTo);
                }
                else{
                    amountITo = tInterestEntitledTo;
                }
              
            }
            
           uint256 responseAmount = cdai.exchangeRateStored().div(amountITo);
            
            return responseAmount;
          
    }
    
    function getStartedWithGiftAmount() constant external returns (uint256){
        return startedWithGiftAmount;
    }
    
    function getStartedWithDaiValueAmount() constant external returns (uint256){
        return initialDaiAmount;
    }
    function getStartedWithCDaiDaiRate() constant external returns (uint256){
        return initialcDaiDaiRate;
    }
    
    
    
    function getRecipient() constant external returns (address){
        return theRecipient;
    }
    
    function getSender() constant external returns (address){
        return theSender;
    }
    
    function percentageInterestEntitledTo(address qAddress) constant external returns (uint256){
            uint256 usersPercentage;
            if(qAddress== theRecipient){
                usersPercentage = theInterestRecipient;
            }
            else if (qAddress == theSender){
                usersPercentage = theInterestSender;
                
            }
            else{
                return 0;
            }
            
           return usersPercentage;
    }
    
    
   
    
    function currentGiftAmount() constant external returns (uint256){
        uint256 cDaiMinted = cdai.balanceOf(this);
        return cDaiMinted;
    }
}