contract BloctoPointExchange is Ownable {
    event Buy(address buyer, address receiver, uint256 ethAmount, uint256 daiAmount, uint256 point);

    uint256 deadline = 2**256 - 1;
    uint256 daiPerPoint;
    uint256 minPoint;
    address payable bloctoReceiver;
    address uniswapExContract;
    address daiERC20Contract;

    constructor(address owner, address _uniswapExContract, address _daiERC20Contract, address payable _bloctoReceiver, uint256 _daiPerPoint, uint256 _minPoint) public {
        transferOwnership(owner);
        uniswapExContract = _uniswapExContract;
        daiERC20Contract = _daiERC20Contract;
        bloctoReceiver = _bloctoReceiver;
        daiPerPoint = _daiPerPoint;
        minPoint = _minPoint;
    }

    function() external payable {
        if (msg.value > 0) {
          bloctoReceiver.transfer(msg.value);
        }
    }

    function getExDetail() external view returns(address _owner, address _uniswapExContract, address _daiERC20Contract, address _bloctoReceiver, uint256 _daiPerPoint, uint256 _minPoint) {
        return (owner(), uniswapExContract, daiERC20Contract, bloctoReceiver, daiPerPoint, minPoint);
    }

    function setBloctoReceiver(address payable _bloctoReceiver) external onlyOwner {
        bloctoReceiver = _bloctoReceiver;
    }

    function setDaiPerPoint(uint256 _daiPerPoint) external onlyOwner {
        daiPerPoint = _daiPerPoint;
    }

    function setMinPoint(uint256 _minPoint) external onlyOwner {
            minPoint = _minPoint;
    }

    function buyBP() external payable {
        UniswapExchangeInterface _uniswapExContract = UniswapExchangeInterface(uniswapExContract);
        ERC20Interface _daiERC20Contract = ERC20Interface(daiERC20Contract);

        uint256 daiAmount = _uniswapExContract.ethToTokenSwapInput.value(msg.value)(daiPerPoint, deadline);
        uint256 point = daiAmount / daiPerPoint;
        require(point >= minPoint, "point < minPoint");

        bool success = _daiERC20Contract.transfer(bloctoReceiver, daiAmount);
        require(success, "transfer dai fail");

        emit Buy(msg.sender, msg.sender, msg.value, daiAmount, point);
    }

    // make sure `toAddr` is blocto wallet address
    function buyBPTo(address toAddr) external payable {
        UniswapExchangeInterface _uniswapExContract = UniswapExchangeInterface(uniswapExContract);
        ERC20Interface _daiERC20Contract = ERC20Interface(daiERC20Contract);

        uint256 daiAmount = _uniswapExContract.ethToTokenSwapInput.value(msg.value)(daiPerPoint, deadline);
        uint256 point = daiAmount / daiPerPoint;
        require(point >= minPoint, "point < minPoint");

        bool success = _daiERC20Contract.transfer(bloctoReceiver, daiAmount);
        require(success, "transfer dai fail");

        emit Buy(msg.sender, toAddr, msg.value, daiAmount, point);
    }

    function estimateBP(uint256 ethAmount) external view returns(uint256) {
        UniswapExchangeInterface _uniswapExContract = UniswapExchangeInterface(uniswapExContract);
        uint256 daiAmount = _uniswapExContract.getEthToTokenInputPrice(ethAmount);
        uint256 point = daiAmount / daiPerPoint;
        return point;
    }
}
function buyBPTo(address toAddr) external payable {
    UniswapExchangeInterface _uniswapExContract = UniswapExchangeInterface(uniswapExContract);
    ERC20Interface _daiERC20Contract = ERC20Interface(daiERC20Contract);

    uint256 daiAmount = _uniswapExContract.ethToTokenSwapInput.value(msg.value)(daiPerPoint, deadline);
    uint256 point = daiAmount / daiPerPoint;
    require(point >= minPoint, "point < minPoint");

    bool success = _daiERC20Contract.transfer(bloctoReceiver, daiAmount);
    require(success, "transfer dai fail");

    emit Buy(msg.sender, toAddr, msg.value, daiAmount, point);
}

// make sure `toAddr` is blocto wallet address