private function setupDatabase($params)
 {
     $sql = file_get_contents($this->config['setup']);
     if (!$sql) {
         throw new PaytoshiException(sprintf('Unable to find database sql script. Please check that %s exists.', $this->config['setup']), null);
     }
     $this->database->run($sql, $params);
 }
 private function insertMissingFields($fields)
 {
     $existing = array_keys($this->data);
     $required = array_keys($fields);
     $newFields = array_diff($required, $existing);
     if (count($newFields) > 0) {
         $sql = sprintf("INSERT INTO `%s` (`name`, `value`) VALUES ", self::TABLE_NAME);
         $sql .= implode(', ', array_map(function ($i) {
             return "('{$i}', '')";
         }, $newFields));
         $this->database->run($sql);
     }
 }
 /**
  * 1. Captcha check
  * 2. Timeout check
  * 3. Reward generation
  * 4. Payout creation
  * 5. Payment process
  * 6. Referral payout creation
  * 7. Referral payment process
  */
 public function reward()
 {
     $address = $this->app->request->post('address');
     $challenge = $this->app->request->post($this->captchaService->getChallengeName());
     $response = $this->app->request->post($this->captchaService->getResponseName());
     if (empty($address) || empty($challenge) || empty($response)) {
         $this->app->flash('warning', 'Missing address or captcha.');
         $this->app->redirect($this->app->urlFor('index'));
         return;
     }
     $remoteIp = $this->ipService->determineClientIpAddress($_SERVER);
     if (!$remoteIp) {
         $this->app->flash('warning', 'Incorrect ip address.');
         $this->app->redirect($this->app->urlFor('index'));
         return;
     }
     // Captcha Check
     try {
         /** @var CaptchaResponse $captchaResponse */
         $captchaResponse = $this->captchaService->checkAnswer($remoteIp, $challenge, $response);
     } catch (CaptchaException $e) {
         $this->app->flash('error', 'Unable to verify captcha.');
         $this->app->redirect($this->app->urlFor('index'));
         return;
     }
     if (!$captchaResponse->getSuccess()) {
         $this->app->flash('error', 'Invalid Captcha');
         $this->app->redirect($this->app->urlFor('index'));
         return;
     }
     try {
         if (!$this->database->beginTransaction()) {
         }
     } catch (PaytoshiException $e) {
         $this->app->flash('error', 'Unable to connect to database.');
         $this->app->redirect($this->app->urlFor('index'));
         return;
     }
     $recipient = $this->recipientRepository->findOneByAddress($address);
     if (!$recipient) {
         $recipient = new Recipient();
         $recipient->setAddress($address);
     }
     // Timeout check
     $lastPayout = $this->payoutRepository->findLastByRecipientAndIp($recipient, $remoteIp);
     $now = new DateTime();
     $waitingInterval = $this->settingRepository->getWaitingInterval();
     if ($lastPayout) {
         $nextPayoutTime = $lastPayout->getCreatedAt()->add(new DateInterval('PT' . $waitingInterval . 'S'));
         if ($nextPayoutTime > $now) {
             $this->database->rollBack();
             $waitingTime = $nextPayoutTime->diff($now);
             $this->app->flash('warning', sprintf('You can get a reward again in %s.', $this->formatTime($waitingTime)));
             $this->app->redirect($this->app->urlFor('index'));
             return;
         }
     }
     // Reward Generation
     $earning = $this->rewardService->getReward();
     // Payout Creation
     $payout = new Payout();
     $payout->setIp($remoteIp);
     $payout->setRecipientAddress($recipient->getAddress());
     $payout->setEarning($earning);
     // Payment process
     try {
         /* @var $apiResponse ApiResponse */
         $apiResponse = $this->apiService->send($payout->getRecipientAddress(), $payout->getEarning(), $remoteIp);
     } catch (PaytoshiException $e) {
         $this->database->rollback();
         $this->app->flash('error', $e->getMessage());
         $this->app->redirect($this->app->urlFor('index'));
         return;
     }
     if (!$apiResponse->getSuccess()) {
         $this->database->rollback();
         $this->app->flash('error', $apiResponse->getError());
         $this->app->redirect($this->app->urlFor('index'));
         return;
     }
     $view = $this->app->view();
     $view->setData(array('amount' => $apiResponse->getAmount(), 'recipient' => $apiResponse->getRecipient(), 'balanceUrl' => str_replace('_ADDRESS_', $address, $this->app->config('balance_url'))));
     $this->recipientRepository->save($recipient);
     $this->app->flash('success', $view->render($this->themeService->getTemplate('balance.html.twig')));
     $_SESSION['address'] = $recipient->getAddress();
     $referral = $this->app->request->post('referral');
     $referralPercentage = $this->settingRepository->getReferralPercentage();
     if ($referral && $referral != $address && $referralPercentage > 0) {
         // Referral Payout Creation
         $referralRecipient = $this->recipientRepository->findOneByAddress($referral);
         if (!$referralRecipient) {
             $referralRecipient = new Recipient();
             $referralRecipient->setAddress($referral);
         }
         $referralEarning = ceil($earning * $referralPercentage / 100);
         $payout->setReferralRecipientAddress($referralRecipient->getAddress());
         $payout->setReferralEarning($referralEarning);
         $referralRecipient->setReferralEarning($referralEarning + $referralRecipient->getReferralEarning());
         // Referral payment process
         try {
             $apiResponse = $this->apiService->send($referralRecipient->getAddress(), $referralRecipient->getReferralEarning(), $remoteIp, true);
         } catch (PaytoshiException $e) {
             $this->payoutRepository->save($payout);
             $this->recipientRepository->save($referralRecipient);
             $this->database->commit();
             $this->app->flash('error', $e->getMessage());
             $this->app->redirect($this->app->urlFor('index'));
             return;
         }
         if ($apiResponse->getSuccess()) {
             $referralRecipient->setReferralEarning(0);
         }
         $this->recipientRepository->save($referralRecipient);
     }
     $this->payoutRepository->save($payout);
     $this->database->commit();
     $this->app->redirect($this->app->urlFor('index'));
 }