protoTransactionTransfer = $protoTransactionTransfer; } public function getProto() { return $this->protoTransactionTransfer; } static public function build($amount, $memo, $receiver_public_hex, $sender_public_hex) { // repeated SenderAmount senderAmounts = 1; // repeated ReceiverAmount receiverAmounts = 2; $sender = new \Proto\Gradido\TransferAmount(); $sender->setAmount($amount); if(strlen($receiver_public_hex) != 64) { return ['state' => 'error', 'msg' => 'invalid receiver pubkey']; } if(strlen($sender_public_hex) != 64) { return ['state' => 'error', 'msg' => 'invalid sender pubkey']; } $receiverPubKeyBin = hex2bin($receiver_public_hex); $senderPubKeyBin = hex2bin($sender_public_hex); $sender->setPubkey($senderPubKeyBin); //var_dump($requestData); $creationDate = new \Proto\Gradido\TimestampSeconds(); $creationDate->setSeconds(time()); $transactionBody = new \Proto\Gradido\TransactionBody(); $transactionBody->setMemo($memo); $transactionBody->setCreated($creationDate); $transfer = new \Proto\Gradido\GradidoTransfer(); $local_transfer = new \Proto\Gradido\LocalTransfer(); $local_transfer->setReceiver($receiverPubKeyBin); $local_transfer->setSender($sender); $transfer->setLocal($local_transfer); $transactionBody->setTransfer($transfer); return ['state' => 'success', 'transactionBody' => $transactionBody]; } public function validate($sigPairs) { //$this->addError('TransactionTransfer::validate', 'not implemented yet'); //return false; //$time = microtime(true); static $functionName = 'TransactionTransfer::validate'; $sigPubHexs = []; foreach($sigPairs as $sigPair) { $pubkey = $sigPair->getPubKey(); $pubkey_hex = bin2hex($pubkey); //$hash = TransactionCreation::DRMakeStringHash($pubkey); $hash = $pubkey_hex; if(!isset($sigPubHexs[$hash])) { $sigPubHexs[$hash] = [$pubkey_hex]; } else { array_push($sigPubHexs[$hash], $pubkey_hex); } //array_push($sigPubHexs, $pubkey); } $stateUsersTable = TableRegistry::getTableLocator()->get('state_users'); $local_transfer = $this->protoTransactionTransfer->getLocal(); $sender = $local_transfer->getSender(); $senderPublic = $sender->getPubkey(); $senderPublicHex = bin2hex($senderPublic); if(strlen($senderPublicHex) != 64) { $this->addError($functionName, 'invalid sender public key'); return false; } // check if signature exist for sender //$hash = TransactionCreation::DRMakeStringHash($senderPublicHex); $hash = $senderPublicHex; if(!isset($sigPubHexs[$hash]) || in_array($senderPublicHex, $sigPubHexs[$hash]) === FALSE) { $this->addError($functionName, 'missing signature for sender'); return false; } // check if sender has enough Gradido $amount = $sender->getAmount(); $user = $stateUsersTable ->find('all') ->select(['id']) ->where(['public_key' => $senderPublic]) ->contain(['StateBalances' => ['fields' => ['amount', 'state_user_id']]])->first(); if(!$user) { $this->addError($functionName, 'couldn\'t find sender in db' ); return false; } //var_dump($user); if(intval($user->state_balances[0]->amount) < intval($amount)) { $this->addError($functionName, 'sender hasn\t enough GDD'); return false; } $receiver_public_key = $local_transfer->getReceiver(); if(strlen($receiver_public_key) != 32) { $this->addError($functionName, 'invalid receiver public key'); return false; } // check if receiver exist $receiver_user = $stateUsersTable->find('all')->select(['id'])->where(['public_key' => $receiver_public_key])->first(); if(!$receiver_user) { $this->addError($functionName, 'couldn\'t find receiver in db' ); return false; } if($amount < 0) { $this->addError($functionName, 'negative amount not supported'); return false; } return true; } public function save($transaction_id, $firstPublic, $received) { static $functionName = 'TransactionCreation::save'; $local_transfer = $this->protoTransactionTransfer->getLocal(); $senderAmount = $local_transfer->getSender(); $receiver = $local_transfer->getReceiver(); $transactionTransferTable = TableRegistry::getTableLocator()->get('TransactionSendCoins'); $senderUserId = $this->getStateUserId($senderAmount->getPubkey()); $receiverUserId = $this->getStateUserId($receiver); if($senderUserId === NULL || $receiverUserId === NULL) { return false; } $finalSenderBalance = $this->updateStateBalance($senderUserId, -$senderAmount->getAmount(), $received); if(false === $finalSenderBalance) { return false; } if(false === $this->updateStateBalance($receiverUserId, $senderAmount->getAmount(), $received)) { return false; } $transactionTransferEntity = $transactionTransferTable->newEntity(); $transactionTransferEntity->transaction_id = $transaction_id; $transactionTransferEntity->state_user_id = $senderUserId; $transactionTransferEntity->sender_public_key = $senderAmount->getPubkey(); $transactionTransferEntity->receiver_public_key = $receiver; $transactionTransferEntity->receiver_user_id = $receiverUserId; $transactionTransferEntity->amount = $senderAmount->getAmount(); $transactionTransferEntity->sender_final_balance = $finalSenderBalance; if(!$transactionTransferTable->save($transactionTransferEntity)) { $this->addError($functionName, 'error saving transactionSendCoins with errors: ' . json_encode($transactionTransferEntity->getErrors())); return false; } if(!$this->addStateUserTransaction($senderUserId, $transaction_id, 2, $senderAmount->getAmount(), $received)) { return false; } if(!$this->addStateUserTransaction($receiverUserId, $transaction_id, 2, -$senderAmount->getAmount(), $received)) { return false; } //$this->addError('TransactionTransfer::save', 'not implemented yet'); //return false; return true; } public function sendNotificationEmail($memo) { // send notification email $disable_email = Configure::read('disableEmail', false); if($disable_email) return true; $local_transfer = $this->protoTransactionTransfer->getLocal(); $sender = $local_transfer->getSender(); $senderAmount = $sender->getAmount(); $senderUser = $this->getStateUserFromPublickey($sender->getPubkey()); $receiverUser = $this->getStateUserFromPublickey($local_transfer->getReceiver()); $serverAdminEmail = Configure::read('ServerAdminEmail'); try { $email = new Email(); $emailViewBuilder = $email->viewBuilder(); $emailViewBuilder->setTemplate('notificationTransfer') ->setVars(['receiverUser' => $receiverUser, 'senderUser' => $senderUser, 'gdd_cent' => $senderAmount, 'memo' => $memo]); $receiverNames = $receiverUser->getNames(); if($receiverNames == '' || $receiverUser->email == '') { $this->addError('TransactionCreation::sendNotificationEmail', 'to email is empty for user: ' . $receiverUser->id); return false; } $noReplyEmail = Configure::read('noReplyEmail'); $email->setFrom([$noReplyEmail => 'Gradido (nicht antworten)']) ->setTo([$receiverUser->email => $receiverUser->getNames()]) ->setSubject(__('Gradidos erhalten')) ->send(); } catch(Exception $e) { //$this->addError('TransactionTransfer::sendNotificationEmail', 'error sending notification email: ' . $e->getMessage()); $this->addWarning('TransactionTransfer::sendNotificationEmail', 'error sending notification email: ' . $e->getMessage()); return false; } return true; } public function getSenderUser() { $local_transfer = $this->protoTransactionTransfer->getLocal(); return $this->getStateUserFromPublickey($local_transfer->getSender()->getPubkey()); } public function getReceiverUser() { $local_transfer = $this->protoTransactionTransfer->getLocal(); return $this->getStateUserFromPublickey($local_transfer->getReceiver()); } public function getAmount() { $local_transfer = $this->protoTransactionTransfer->getLocal(); $sender = $local_transfer->getSender(); return $sender->getAmount(); } static public function fromEntity($transactionTransferEntity) { $protoTransfer = new \Proto\Gradido\GradidoTransfer(); $stateUsersTable = TableRegistry::getTableLocator()->get('state_users'); return new TransactionTransfer($protoTransfer); } }