Commit 6b846ec1 authored by Emiliano Balbuena's avatar Emiliano Balbuena

(feat): Refund on rejection and notifications on all steps

1 merge request!393WIP: (feat): Withdrawal status support
Pipeline #94717518 failed with stages
in 2 minutes and 48 seconds
......@@ -8,30 +8,39 @@
namespace Minds\Core\Blockchain\Events;
use Minds\Core\Blockchain\Contracts\MindsToken;
use Minds\Core\Blockchain\Transactions\Manager;
use Exception;
use Minds\Core\Blockchain\Transactions\Repository as TransactionsRepository;
use Minds\Core\Blockchain\Transactions\Transaction;
use Minds\Core\Blockchain\Util;
use Minds\Core\Config;
use Minds\Core\Di\Di;
use Minds\Core\Rewards\Withdraw;
use Minds\Core\Rewards\Withdraw\Manager;
use Minds\Core\Rewards\Withdraw\Request;
use Minds\Core\Util\BigNumber;
class WithdrawEvent implements BlockchainEventInterface
{
/** @var array $eventsMap */
/** @var array */
public static $eventsMap = [
'0x317c0f5ab60805d3e3fb6aaa61ccb77253bbb20deccbbe49c544de4baa4d7f8f' => 'onRequest',
'blockchain:fail' => 'withdrawFail',
];
/** @var Manager $manager */
private $manager;
/** @var Manager */
protected $manager;
/** @var Repository $repository **/
/** @var TransactionsRepository **/
protected $txRepository;
/** @var Config $config */
private $config;
/** @var Config */
protected $config;
/**
* WithdrawEvent constructor.
* @param Manager $manager
* @param TransactionsRepository $txRepository
* @param Config $config
*/
public function __construct($manager = null, $txRepository = null, $config = null)
{
$this->txRepository = $txRepository ?: Di::_()->get('Blockchain\Transactions\Repository');
......@@ -50,30 +59,31 @@ class WithdrawEvent implements BlockchainEventInterface
/**
* @param $topic
* @param array $log
* @throws \Exception
* @param $transaction
* @throws Exception
*/
public function event($topic, array $log, $transaction)
{
$method = static::$eventsMap[$topic];
if ($log['address'] != $this->config->get('blockchain')['contracts']['withdraw']['contract_address']) {
throw new \Exception('Event does not match address');
throw new Exception('Event does not match address');
}
if (method_exists($this, $method)) {
$this->{$method}($log, $transaction);
} else {
throw new \Exception('Method not found');
throw new Exception('Method not found');
}
}
public function onRequest($log, $transaction)
public function onRequest($log, Transaction $transaction)
{
$address = $log['address'];
if ($address != $this->config->get('blockchain')['contracts']['withdraw']['contract_address']) {
$this->withdrawFail($log, $transaction);
throw new \Exception('Incorrect address sent the withdraw event');
throw new Exception('Incorrect address sent the withdraw event');
}
$tx = $log['transactionHash'];
......@@ -83,7 +93,7 @@ class WithdrawEvent implements BlockchainEventInterface
$amount = (string) BigNumber::fromHex($amount);
//double check the details of this transaction match with what the user actually requested
$request = new Withdraw\Request();
$request = new Request();
$request
->setTx($tx)
......@@ -95,7 +105,7 @@ class WithdrawEvent implements BlockchainEventInterface
try {
$this->manager->confirm($request, $transaction);
} catch (\Exception $e) {
} catch (Exception $e) {
error_log(print_r($e, true));
}
}
......@@ -103,7 +113,7 @@ class WithdrawEvent implements BlockchainEventInterface
public function withdrawFail($log, $transaction)
{
if ($transaction->getContract() !== 'withdraw') {
throw new \Exception("Failed but not a withdrawal");
throw new Exception("Failed but not a withdrawal");
return;
}
......
<?php
/**
* NotificationsDelegate
* @author edgebal
*/
namespace Minds\Core\Rewards\Withdraw\Delegates;
use Exception;
use Minds\Core\Di\Di;
use Minds\Core\Events\EventsDispatcher;
use Minds\Core\Rewards\Withdraw\Request;
use Minds\Core\Util\BigNumber;
class NotificationsDelegate
{
/** @var EventsDispatcher */
protected $dispatcher;
/**
* NotificationsDelegate constructor.
* @param EventsDispatcher $dispatcher
*/
public function __construct(
$dispatcher = null
) {
$this->dispatcher = $dispatcher ?: Di::_()->get('EventsDispatcher');
}
/**
* @param Request $request
*/
public function onRequest(Request $request): void
{
$message = 'Your token withdrawal request was submitted successfully.';
$this->dispatcher->trigger('notification', 'all', [
'to' => [ $request->getUserGuid() ],
'from' => 100000000000000519,
'notification_view' => 'custom_message',
'params' => ['message' => $message],
'message' => $message,
]);
}
/**
* @param Request $request
*/
public function onConfirm(Request $request): void
{
$message = 'Your token withdrawal request transaction was confirmed by the blockchain and has been placed onto the review queue.';
$this->dispatcher->trigger('notification', 'all', [
'to' => [ $request->getUserGuid() ],
'from' => 100000000000000519,
'notification_view' => 'custom_message',
'params' => ['message' => $message],
'message' => $message,
]);
}
/**
* @param Request $request
* @throws Exception
*/
public function onApprove(Request $request): void
{
$message = sprintf(
"Your withdrawal request has been approved and %s OnChain token(s) were issued.",
BigNumber::fromPlain($request->getAmount(), 18)
);
$this->dispatcher->trigger('notification', 'all', [
'to' => [ $request->getUserGuid() ],
'from' => 100000000000000519,
'notification_view' => 'custom_message',
'params' => ['message' => $message],
'message' => $message,
]);
}
/**
* @param Request $request
* @throws Exception
*/
public function onReject(Request $request): void
{
$message = sprintf(
"Your withdrawal request has been rejected. Your %s OffChain token(s) were refunded.",
BigNumber::fromPlain($request->getAmount(), 18)
);
$this->dispatcher->trigger('notification', 'all', [
'to' => [ $request->getUserGuid() ],
'from' => 100000000000000519,
'notification_view' => 'custom_message',
'params' => ['message' => $message],
'message' => $message,
]);
}
}
......@@ -36,13 +36,17 @@ class Manager
/** @var OffchainBalance */
protected $offChainBalance;
/** @var Delegates\NotificationsDelegate */
protected $notificationsDelegate;
public function __construct(
$txManager = null,
$offChainTransactions = null,
$config = null,
$eth = null,
$repository = null,
$offChainBalance = null
$offChainBalance = null,
$notificationsDelegate = null
) {
$this->txManager = $txManager ?: Di::_()->get('Blockchain\Transactions\Manager');
$this->offChainTransactions = $offChainTransactions ?: Di::_()->get('Blockchain\Wallets\OffChain\Transactions');
......@@ -50,6 +54,7 @@ class Manager
$this->eth = $eth ?: Di::_()->get('Blockchain\Services\Ethereum');
$this->repository = $repository ?: new Repository();
$this->offChainBalance = $offChainBalance ?: Di::_()->get('Blockchain\Wallets\OffChain\Balance');
$this->notificationsDelegate = $notificationsDelegate ?: new Delegates\NotificationsDelegate();
}
/**
......@@ -130,6 +135,10 @@ class Manager
$this->repository->add($request);
$this->txManager->add($transaction);
// Notify
$this->notificationsDelegate->onRequest($request);
}
/**
......@@ -138,7 +147,7 @@ class Manager
* @return void
* @throws Exception
*/
public function confirm($request, $transaction)
public function confirm(Request $request, $transaction)
{
if ($request->getUserGuid() != $transaction->getUserGuid()) {
throw new Exception('The user who requested this operation does not match the transaction');
......@@ -179,11 +188,15 @@ class Manager
// Set request status
$request
->setStaus('pending_approval');
->setStatus('pending_approval');
// Update
$this->repository->add($request);
// Notify
$this->notificationsDelegate->onConfirm($request);
}
/**
......@@ -217,13 +230,33 @@ class Manager
// Update
$this->repository->add($request);
// Notify
$this->notificationsDelegate->onApprove($request);
}
/**
* @param Request $request
* @throws Exception
*/
public function reject(Request $request)
{
$user = new User;
$user->guid = (string) $request->getUserGuid();
// Refund tokens
try {
$this->offChainTransactions
->setUser($user)
->setType('withdraw_refund')
->setAmount((string) BigNumber::_($request->getAmount()))
->create();
} catch (LockFailedException $e) {
throw new \Exception('Cannot refund rejected withdrawal tokens');
}
// Set request status
$request
......@@ -232,5 +265,9 @@ class Manager
// Update
$this->repository->add($request);
// Notify
$this->notificationsDelegate->onReject($request);
}
}
......@@ -20,6 +20,15 @@ trait MagicAttributes
if (strpos($name, 'set', 0) === 0) {
$attribute = preg_replace('/^set/', '', $name);
$attribute = lcfirst($attribute);
if (!property_exists($this, $attribute)) {
trigger_error(sprintf(
"Attribute %s is not defined in %s",
$attribute,
get_class($this)
), E_USER_WARNING);
}
$this->$attribute = $args[0];
// DirtyChecking interop
......@@ -32,13 +41,37 @@ trait MagicAttributes
$attribute = preg_replace('/^get/', '', $name);
$attribute = lcfirst($attribute);
if (!property_exists($this, $attribute)) {
trigger_error(sprintf(
"Attribute %s is not defined in %s",
$attribute,
get_class($this)
), E_USER_WARNING);
}
return $this->$attribute;
} elseif (strpos($name, 'is', 0) === 0) {
$attribute = preg_replace('/^is/', '', $name);
$attribute = lcfirst($attribute);
if (!property_exists($this, $attribute)) {
trigger_error(sprintf(
"Attribute %s is not defined in %s",
$attribute,
get_class($this)
), E_USER_WARNING);
}
return (bool) $this->$attribute;
} elseif (strpos($name, 'has', 0) === 0) {
if (!property_exists($this, $name)) {
trigger_error(sprintf(
"Attribute %s is not defined in %s",
$name,
get_class($this)
), E_USER_WARNING);
}
return (bool) $this->$name;
}
......
Please register or to comment