contract DaiSwap is SafeMath {
    mapping (address => uint) public daiposit;
    uint public totaldai = 0;
    uint public baseMultiplier = 20;
    uint fee = 997; // 0.3%
    uint constant decOffset = 1e12;
    Token   daiContract = Token(0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359);
    Token  usdcContract = Token(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);
    //Kovan Testnet
    //Token   daiContract = Token(0xE888757Fbf1f29B520a80f977DBE52F9AD20d6C9);
    //Token  usdcContract = Token(0x3502B803f2a516cD6e9d6E8938b700d78ABF1373);
    
    function usdcAmountFromDai(uint dai) public view returns (uint) {
        if (totaldai == 0) return dai / decOffset; // Initialisation
        uint base = safeMul(baseMultiplier, totaldai);
        uint amt_dai  =  daiContract.balanceOf(address(this));
        uint amt_usdc = safeMul(usdcContract.balanceOf(address(this)), decOffset);
        return safeMul(dai, safeAdd(amt_usdc, base)) / safeAdd(amt_dai, base) / decOffset;
    }
    
    function deposit(uint dai) public {
        uint usdc = usdcAmountFromDai(dai);
        daiposit[msg.sender] = safeAdd(daiposit[msg.sender], dai);
        totaldai             = safeAdd(totaldai, dai);
        if ( !daiContract.transferFrom(msg.sender, address(this), dai)) revert();
        if (!usdcContract.transferFrom(msg.sender, address(this), usdc)) revert();
    }
    
    function withdraw() public {
        uint dai  = safeMul(daiposit[msg.sender],  daiContract.balanceOf(address(this))) / totaldai;
        uint usdc = safeMul(daiposit[msg.sender], usdcContract.balanceOf(address(this))) / totaldai;
        totaldai  = safeSub(totaldai, daiposit[msg.sender]);
        daiposit[msg.sender] = 0;
        if ( !daiContract.transfer(msg.sender, dai)) revert();
        if (!usdcContract.transfer(msg.sender, usdc)) revert();
    }
    
    function calcSwapForUSDC(uint dai) public view returns (uint) {
        uint base     = safeMul(baseMultiplier, totaldai);
        uint amt_dai  =          daiContract.balanceOf(address(this));
        uint amt_usdc = safeMul(usdcContract.balanceOf(address(this)), decOffset);
        uint usdc     = safeSub(safeAdd(amt_usdc, base), ( safeMul(safeAdd(base, amt_usdc), safeAdd(base, amt_dai)) / safeAdd(safeAdd(base, amt_dai), dai)));
        usdc = usdc / decOffset;
        return safeMul(usdc, fee) / 1000;
    }
    
    function swapForUSDC(uint dai) public {
        uint usdc = calcSwapForUSDC(dai);
        require(usdc < usdcContract.balanceOf(address(this)));
        if ( !daiContract.transferFrom(msg.sender, address(this), dai)) revert();
        if (!usdcContract.transfer(msg.sender, usdc)) revert();
    }
    
    function calcSwapForDai(uint usdc) public view returns (uint) {
        uint base     = safeMul(baseMultiplier, totaldai);
        uint amt_dai  =          daiContract.balanceOf(address(this));
        uint amt_usdc = safeMul(usdcContract.balanceOf(address(this)), decOffset);
        uint dai      = safeSub(safeAdd(amt_dai, base), ( safeMul(safeAdd(base, amt_usdc), safeAdd(base, amt_dai)) / safeAdd(safeAdd(base, amt_usdc), safeMul(usdc, decOffset))));
        return safeMul(dai, fee) / 1000;
    }
    
    function swapForDai(uint usdc) public {
        uint dai = calcSwapForDai(usdc);
        require(dai < daiContract.balanceOf(address(this)));
        if (!usdcContract.transferFrom(msg.sender, address(this), usdc)) revert();
        if ( !daiContract.transfer(msg.sender, dai)) revert();
    }
}
function usdcAmountFromDai(uint dai) public view returns (uint) {
    if (totaldai == 0) return dai / decOffset; // Initialisation
    uint base = safeMul(baseMultiplier, totaldai);
    uint amt_dai  =  daiContract.balanceOf(address(this));
    uint amt_usdc = safeMul(usdcContract.balanceOf(address(this)), decOffset);
    return safeMul(dai, safeAdd(amt_usdc, base)) / safeAdd(amt_dai, base) / decOffset;
}

//Kovan Testnet
//Token   daiContract = Token(0xE888757Fbf1f29B520a80f977DBE52F9AD20d6C9);
//Token  usdcContract = Token(0x3502B803f2a516cD6e9d6E8938b700d78ABF1373);