contract YOMAPresale {
    using SafeMath for uint256;
    
    address payable private _presaleVaultAddress;
    address private _contractAddress;
    uint256 public remainingEthInWei;
    uint256 public TOKENS_PER_ETH;
    uint256 public remainingTokens;
    address public owner;
    bool public hasPresaleOpened;
    
    constructor(address yoma_contract_address, address payable presale_address) public {
        owner = msg.sender;
        _contractAddress = yoma_contract_address;
        _presaleVaultAddress = presale_address;

        remainingEthInWei = 350 * 1e18;
        TOKENS_PER_ETH = 20;
        remainingTokens = remainingEthInWei.mul(TOKENS_PER_ETH);

        hasPresaleOpened = false;
    }
    
    // fallback executes the purchase process
    receive() external payable {
        _buyTokens(msg.sender);
    }

    function openPresale() external {
        require(msg.sender == owner, "YOMA owner can open presale");
        hasPresaleOpened = true;
    }
    
    function _buyTokens(address payable _toAddress) internal{
        require(hasPresaleOpened, "Presale not yet open!");
        
        // set wei amount to fill for the last purchase
        uint256 weiAmount = remainingEthInWei < msg.value ? remainingEthInWei : msg.value;
        
        // send ether to the vault
        _presaleVaultAddress.transfer(weiAmount);
        
        // buy tokens
        uint256 tokenAmount = weiAmount.mul(TOKENS_PER_ETH);
        releaseTokens(_toAddress, tokenAmount);
        
        // update remaining
        remainingEthInWei = remainingEthInWei.sub(weiAmount);
        remainingTokens = remainingTokens.sub(tokenAmount);
        
        // refund
        uint256 refund = msg.value.sub(weiAmount);
        if (refund > 0) {
            _toAddress.transfer(refund);
        }
    }
    
    function releaseTokens(address receiver, uint256 amount) internal {
        require(amount <= remainingTokens);
        
        Yomama yoma = Yomama(_contractAddress);
        yoma.transferFrom(_presaleVaultAddress, receiver, amount);
        
    }

}
//END REFERENCE
// PRESALE CODE
// fallback executes the purchase process