...
 
Commits (2)
<?php
namespace Minds\Controllers\api\v2\admin\rewards;
use Minds\Api\Exportable;
use Minds\Core\Rewards\Withdraw\Repository;
use Exception;
use Minds\Common\Repository\Response;
use Minds\Core\Di\Di;
use Minds\Core\Rewards\Withdraw\Manager;
use Minds\Core\Rewards\Withdraw\Request;
use Minds\Entities\User;
use Minds\Interfaces;
use Minds\Api\Factory;
......@@ -11,32 +14,38 @@ class withdrawals implements Interfaces\Api, Interfaces\ApiAdminPam
{
/**
* Equivalent to HTTP GET method
* @param array $pages
* @param array $pages
* @return mixed|null
* @throws Exception
*/
public function get($pages)
{
$repository = new Repository();
$username = $_GET['user'];
/** @var Manager $manager */
$manager = Di::_()->get('Rewards\Withdraw\Manager');
if (!$username) {
return Factory::response([
'withdrawals' => [],
'load-next' => '',
]);
$userGuid = null;
if ($_GET['user']) {
$userGuid = (new User(strtolower($_GET['user'])))->guid;
}
$user = new User(strtolower($username));
$status = $_GET['status'] ?? null;
$withdrawals = $repository->getList([
$opts = [
'status' => $status,
'user_guid' => $userGuid,
'limit' => isset($_GET['limit']) ? (int) $_GET['limit'] : 12,
'offset' => isset($_GET['offset']) ? $_GET['offset'] : '',
'user_guid' => $user->guid
]);
'hydrate' => true,
'admin' => true,
];
/** @var Response $withdrawals */
$withdrawals = $manager->getList($opts);
return Factory::response([
'withdrawals' => Exportable::_($withdrawals['withdrawals']),
'load-next' => (string) base64_encode($withdrawals['token']),
'withdrawals' => $withdrawals,
'load-next' => $withdrawals->getPagingToken(),
]);
}
......@@ -57,6 +66,37 @@ class withdrawals implements Interfaces\Api, Interfaces\ApiAdminPam
*/
public function put($pages)
{
/** @var Manager $manager */
$manager = Di::_()->get('Rewards\Withdraw\Manager');
$request = $manager->get(
(new Request())
->setUserGuid((string) $pages[0] ?? null)
->setTimestamp((int) $pages[1] ?? null)
->setTx((string) $pages[2] ?? null)
);
if (!$request) {
return Factory::response([
'status' => 'error',
'message' => $errorMessage ?? 'Missing request',
]);
}
try {
$success = $manager->approve($request);
} catch (Exception $exception) {
$success = false;
$errorMessage = $exception->getMessage();
}
if (!$success) {
return Factory::response([
'status' => 'error',
'message' => $errorMessage ?? 'Cannot approve request',
]);
}
return Factory::response([]);
}
......@@ -67,6 +107,37 @@ class withdrawals implements Interfaces\Api, Interfaces\ApiAdminPam
*/
public function delete($pages)
{
/** @var Manager $manager */
$manager = Di::_()->get('Rewards\Withdraw\Manager');
$request = $manager->get(
(new Request())
->setUserGuid((string) $pages[0] ?? null)
->setTimestamp((int) $pages[1] ?? null)
->setTx((string) $pages[2] ?? null)
);
if (!$request) {
return Factory::response([
'status' => 'error',
'message' => $errorMessage ?? 'Missing request',
]);
}
try {
$success = $manager->reject($request);
} catch (Exception $exception) {
$success = false;
$errorMessage = $exception->getMessage();
}
if (!$success) {
return Factory::response([
'status' => 'error',
'message' => $errorMessage ?? 'Cannot reject request',
]);
}
return Factory::response([]);
}
}
......@@ -123,10 +123,11 @@ class transactions implements Interfaces\Api
break;
case "withdraw":
$request = new Withdraw\Request();
$request->setTx($_POST['tx'])
$request
->setUserGuid(Session::getLoggedInUser()->guid)
->setAddress($_POST['address'])
->setTimestamp(time())
->setTx($_POST['tx'])
->setAddress($_POST['address'])
->setGas($_POST['gas'])
->setAmount((string) BigNumber::_($_POST['amount']));
......
......@@ -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'];
......@@ -82,29 +92,43 @@ class WithdrawEvent implements BlockchainEventInterface
$gas = (string) BigNumber::fromHex($gas);
$amount = (string) BigNumber::fromHex($amount);
//double check the details of this transaction match with what the user actually requested
$request = new Withdraw\Request();
$request
->setTx($tx)
->setAddress($address)
->setUserGuid($user_guid)
->setGas($gas)
->setTimestamp($transaction->getTimestamp())
->setAmount($amount);
try {
$this->manager->complete($request, $transaction);
} catch (\Exception $e) {
error_log(print_r($e, true));
$request = $this->manager->get(
(new Request())
->setUserGuid($user_guid)
->setTimestamp($transaction->getTimestamp())
->setTx($tx)
);
if (!$request) {
throw new \Exception('Unknown withdrawal');
}
if ((string) $address !== (string) $request->getAddress()) {
throw new \Exception('Wrong address value');
} elseif ((string) $gas !== (string) $request->getGas()) {
throw new \Exception('Wrong gas value');
} elseif ((string) $amount !== (string) $request->getAmount()) {
throw new \Exception('Wrong amount value');
}
$this->manager->confirm($request, $transaction);
} catch (Exception $e) {
$this->manager->fail(
(new Request())
->setUserGuid($user_guid)
->setTimestamp($transaction->getTimestamp())
->setTx($tx)
);
error_log($e);
}
}
public function withdrawFail($log, $transaction)
{
if ($transaction->getContract() !== 'withdraw') {
throw new \Exception("Failed but not a withdrawal");
return;
throw new Exception("Failed but not a withdrawal");
}
$transaction->setFailed(true);
......
......@@ -1525,3 +1525,11 @@ CREATE TABLE minds.notification_batches (
primary key (user_guid, batch_id)
);
ALTER TABLE minds.withdrawals ADD (status text, address text, gas varint);
CREATE MATERIALIZED VIEW minds.withdrawals_by_status AS
SELECT *
FROM minds.withdrawals
WHERE status IS NOT NULL AND user_guid IS NOT NULL AND timestamp IS NOT NULL AND tx IS NOT NULL
PRIMARY KEY (status, timestamp, user_guid, tx)
WITH CLUSTERING ORDER BY (timestamp ASC, user_guid ASC, tx ASC);
<?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
*/
public function onFail(Request $request): void
{
$message = 'Your token withdrawal request transaction failed. Please contact an administrator.';
$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 %g OnChain token(s) were issued.",
BigNumber::fromPlain($request->getAmount(), 18)->toDouble()
);
$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 %g OffChain token(s) were refunded.",
BigNumber::fromPlain($request->getAmount(), 18)->toDouble()
);
$this->dispatcher->trigger('notification', 'all', [
'to' => [ $request->getUserGuid() ],
'from' => 100000000000000519,
'notification_view' => 'custom_message',
'params' => ['message' => $message],
'message' => $message,
]);
}
}
<?php
/**
* RequestHydrationDelegate
* @author edgebal
*/
namespace Minds\Core\Rewards\Withdraw\Delegates;
use Exception;
use Minds\Core\Rewards\Withdraw\Request;
use Minds\Entities\User;
class RequestHydrationDelegate
{
/**
* @param Request $request
* @return Request
* @throws Exception
*/
public function hydrate(Request $request)
{
$userGuid = $request->getUserGuid();
if (!$userGuid) {
return $request;
}
try {
$user = new User($userGuid);
} catch (Exception $exception) {
$user = null;
}
return $request
->setUser($user);
}
public function hydrateForAdmin(Request $request)
{
if (!$request->getUser()) {
$request = $this->hydrate($request);
if (!$request->getUser()) {
return $request;
}
}
$referrerGuid = $request->getUser()->referrer;
if (!$referrerGuid) {
return $request;
}
try {
$user = new User($referrerGuid);
} catch (Exception $exception) {
// Faux user in case of banned/deleted accounts
$user = new User();
$user->guid = $referrerGuid;
$user->username = $referrerGuid;
}
return $request
->setReferrer($user);
}
}
This diff is collapsed.
......@@ -3,93 +3,83 @@
namespace Minds\Core\Rewards\Withdraw;
use Cassandra;
use Cassandra\Varint;
use Cassandra\Decimal;
use Cassandra\Timestamp;
use Minds\Core\Blockchain\Transactions\Transaction;
use Exception;
use Minds\Core\Data\Cassandra\Client;
use Minds\Core\Data\Cassandra\Prepared\Custom;
use Minds\Core\Di\Di;
use Minds\Core\Rewards\Transactions;
use Minds\Core\Util\BigNumber;
use Minds\Entities\User;
class Repository
{
/** @var Client */
private $db;
protected $db;
/**
* Repository constructor.
* @param Client $db
*/
public function __construct($db = null)
{
$this->db = $db ? $db : Di::_()->get('Database\Cassandra\Cql');
}
/**
* @param Transaction[]|Transaction $transactions
* @return $this
* @param array $opts
* @return array
*/
public function add($requests)
{
if (!is_array($requests)) {
$requests = [ $requests ];
}
$queries = [];
$template = "INSERT INTO withdrawals (user_guid, timestamp, amount, tx, completed, completed_tx) VALUES (?,?,?,?,?,?)";
foreach ($requests as $request) {
$queries[] = [
'string' => $template,
'values' => [
new Varint($request->getUserGuid()),
new Timestamp($request->getTimestamp()),
new Varint($request->getAmount()),
$request->getTx(),
(bool) $request->isCompleted(),
$request->getCompletedTx()
]
];
}
$this->db->batchRequest($queries, Cassandra::BATCH_UNLOGGED);
return $this;
}
public function getList($options)
public function getList(array $opts): array
{
$options = array_merge([
$opts = array_merge([
'status' => null,
'user_guid' => null,
'from' => null,
'to' => null,
'completed' => null,
'completed_tx' => null,
'limit' => 12,
'offset' => null
], $options);
'offset' => null,
], $opts);
$cql = "SELECT * from withdrawals";
$where = [];
$values = [];
if ($options['user_guid']) {
if ($opts['status']) {
$cql = "SELECT * from withdrawals_by_status";
$where[] = 'status = ?';
$values[] = (string) $opts['status'];
}
if ($opts['user_guid']) {
$where[] = 'user_guid = ?';
$values[] = new Varint($options['user_guid']);
$values[] = new Varint($opts['user_guid']);
}
if ($opts['timestamp']) {
$where[] = 'timestamp = ?';
$values[] = new Timestamp($opts['timestamp']);
}
if ($opts['tx']) {
$where[] = 'tx = ?';
$values[] = (string) $opts['tx'];
}
if ($options['from']) {
if ($opts['from']) {
$where[] = 'timestamp >= ?';
$values[] = new Timestamp($options['from']);
$values[] = new Timestamp($opts['from']);
}
if ($options['to']) {
if ($opts['to']) {
$where[] = 'timestamp <= ?';
$values[] = new Timestamp($options['to']);
$values[] = new Timestamp($opts['to']);
}
if ($options['completed']) {
if ($opts['completed']) {
$where[] = 'completed = ?';
$values[] = (string) $options['completed'];
$values[] = (string) $opts['completed'];
}
if ($where) {
......@@ -99,47 +89,81 @@ class Repository
$query = new Custom();
$query->query($cql, $values);
$query->setOpts([
'page_size' => (int) $options['limit'],
'paging_state_token' => base64_decode($options['offset'], true)
'page_size' => (int) $opts['limit'],
'paging_state_token' => base64_decode($opts['offset'], true),
]);
try {
$rows = $this->db->request($query);
} catch (\Exception $e) {
$requests = [];
foreach ($rows ?: [] as $row) {
$request = new Request();
$request
->setUserGuid((string) $row['user_guid']->value())
->setTimestamp($row['timestamp']->time())
->setTx($row['tx'])
->setAddress($row['address'] ?: '')
->setAmount((string) BigNumber::_($row['amount']))
->setCompleted((bool) $row['completed'])
->setCompletedTx($row['completed_tx'] ?: null)
->setGas((string) BigNumber::_($row['gas']))
->setStatus($row['status'] ?: '')
;
$requests[] = $request;
}
return [
'withdrawals' => $requests,
'token' => $rows->pagingStateToken(),
];
} catch (Exception $e) {
error_log($e->getMessage());
return [];
}
}
if (!$rows) {
return [];
}
/**
* @param Request $request
* @return bool
*/
public function add(Request $request)
{
$cql = "INSERT INTO withdrawals (user_guid, timestamp, tx, address, amount, completed, completed_tx, gas, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
$values = [
new Varint($request->getUserGuid()),
new Timestamp($request->getTimestamp()),
$request->getTx(),
(string) $request->getAddress(),
new Varint($request->getAmount()),
(bool) $request->isCompleted(),
((string) $request->getCompletedTx()) ?: null,
new Varint($request->getGas()),
(string) $request->getStatus(),
];
$requests = [];
foreach ($rows as $row) {
$request = new Request();
$request->setUserGuid((string) $row['user_guid']->value());
$request->setTimestamp($row['timestamp']->time());
$request->setAmount((string) BigNumber::_($row['amount']));
$request->setTx($row['tx']);
$request->setCompleted((bool) $row['completed']);
$request->setCompletedTx($row['completed_tx']);
$requests[] = $request;
}
$prepared = new Custom();
$prepared->query($cql, $values);
return [
'withdrawals' => $requests,
'token' => $rows->pagingStateToken()
];
return $this->db->request($prepared, true);
}
public function update($key, $guids)
/**
* @param Request $request
* @return bool
*/
public function update(Request $request)
{
// TODO: Implement update() method.
return $this->add($request);
}
public function delete($entity)
/**
* @param Request $request
* @throws Exception
*/
public function delete(Request $request)
{
// TODO: Implement delete() method.
throw new Exception('Not allowed');
}
}
<?php
namespace Minds\Core\Rewards\Withdraw;
use JsonSerializable;
use Minds\Entities\User;
use Minds\Traits\MagicAttributes;
class Request
/**
* Class Request
* @package Minds\Core\Rewards\Withdraw
* @method string getTx()
* @method Request setTx(string $tx)
* @method string getCompletedTx
* @method Request setCompletedTx(string $completedTx)
* @method string getAddress()
* @method Request setAddress(string $address)
* @method int|string getUserGuid()
* @method Request setUserGuid(int|string $userGuid)
* @method double getGas()
* @method Request setGas(double $gas)
* @method string getAmount()
* @method Request setAmount(string $amount)
* @method string getStatus()
* @method Request setStatus(string $status)
* @method bool isCompleted()
* @method Request setCompleted(bool $completed)
* @method int getTimestamp()
* @method Request setTimestamp(int $timestamp)
* @method User|null getUser()
* @method Request setUser(User|null $user)
* @method User|null getReferrer()
* @method Request setReferrer(User|null $referrer)
*/
class Request implements JsonSerializable
{
use MagicAttributes;
/** @var string $tx **/
private $tx;
/** @var string **/
protected $tx;
/** @var string $completed_tx **/
private $completed_tx;
/** @var string **/
protected $completedTx;
/** @var string $address **/
private $address;
/** @var string **/
protected $address;
/** @var int $user_guid **/
private $user_guid;
/** @var int|string **/
protected $userGuid;
/** @var double $gas **/
private $gas;
/** @var double **/
protected $gas;
/** @var string $amount **/
private $amount;
/** @var string **/
protected $amount;
/** @var bool $completed **/
private $completed;
/** @var string */
protected $status;
/** @var int $timestamp **/
private $timestamp;
/** @var bool **/
protected $completed;
public function setUserGuid($user_guid)
{
$this->user_guid = $user_guid;
return $this;
}
/** @var int **/
protected $timestamp;
public function getUserGuid()
{
return $this->user_guid;
}
/** @var User */
protected $user;
public function setCompletedTx($completed_tx)
{
$this->completed_tx = $completed_tx;
return $this;
}
public function getCompletedTx()
{
return $this->completed_tx;
}
/** @var User */
protected $referrer;
/**
* @return array
*/
public function export()
{
return [
$data = [
'timestamp' => $this->timestamp,
'amount' => $this->amount,
'user_guid' => $this->user_guid,
'user_guid' => $this->userGuid,
'tx' => $this->tx,
'status' => $this->status,
'completed' => $this->completed,
'completed_tx' => $this->completed_tx
'completed_tx' => $this->completedTx,
];
if ($this->user) {
$data['user'] = $this->user->export();
}
if ($this->referrer) {
$data['referrer'] = $this->referrer->export();
}
return $data;
}
/**
* Specify data which should be serialized to JSON
* @link https://php.net/manual/en/jsonserializable.jsonserialize.php
* @return mixed data which can be serialized by <b>json_encode</b>,
* which is a value of any type other than a resource.
* @since 5.4.0
*/
public function jsonSerialize()
{
return $this->export();
}
}
......@@ -6,6 +6,7 @@ use Minds\Core\Blockchain\Transactions\Repository;
use Minds\Core\Blockchain\Transactions\Transaction;
use Minds\Core\Config\Config;
use Minds\Core\Rewards\Withdraw\Manager;
use Minds\Core\Rewards\Withdraw\Request;
use Minds\Core\Util\BigNumber;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
......@@ -31,9 +32,9 @@ class WithdrawEventSpec extends ObjectBehavior
->willReturn([
'contracts' => [
'withdraw' => [
'contract_address' => '0xasd'
]
]
'contract_address' => '0xasd',
],
],
]);
}
......@@ -46,30 +47,53 @@ class WithdrawEventSpec extends ObjectBehavior
{
$this->getTopics()->shouldReturn([
'0x317c0f5ab60805d3e3fb6aaa61ccb77253bbb20deccbbe49c544de4baa4d7f8f',
'blockchain:fail'
'blockchain:fail',
]);
}
public function it_should_complete_withdrawal_on_event()
{
$this->manager->complete(Argument::that(function ($request) {
return $request->getTx() == '0x62a70ccf3b37b9368efa3dd4785e715139c994ba9957a125e299b14a8eccd00c'
&& $request->getAddress() == '0x177fd9efd24535e73b81e99e7f838cdef265e6cb'
&& $request->getUserGuid() == (string) BigNumber::_('786645648014315523')
&& $request->getGas() == (string) BigNumber::_('67839000000000')
&& $request->getAmount() == (string) BigNumber::_('10000000000000000000');
}), Argument::type('\Minds\Core\Blockchain\Transactions\Transaction'))
public function it_should_complete_withdrawal_on_event(
Request $request,
Transaction $transaction
) {
$transaction->getTimestamp()
->shouldBeCalled()
->willReturn(123456789);
$request->getAddress()
->shouldBeCalled()
->willReturn('0x177fd9efd24535e73b81e99e7f838cdef265e6cb');
$request->getGas()
->shouldBeCalled()
->willReturn('67839000000000');
$request->getAmount()
->shouldBeCalled()
->willReturn('10000000000000000000');
$this->manager->get(
Argument::that(function (Request $request) {
return (string) $request->getUserGuid() === '786645648014315523' &&
$request->getTimestamp() === 123456789 &&
$request->getTx() === '0x62a70ccf3b37b9368efa3dd4785e715139c994ba9957a125e299b14a8eccd00c';
})
)
->shouldBeCalled()
->willReturn($request);
$this->manager->confirm($request, Argument::type('\Minds\Core\Blockchain\Transactions\Transaction'))
->shouldBeCalled();
$data = "0x000000000000000000000000177fd9efd24535e73b81e99e7f838cdef265e6cb"
. "0000000000000000000000000000000000000000000000000aeaba0c8e001003"
. "00000000000000000000000000000000000000000000000000003db2ff7f3600"
. "0000000000000000000000000000000000000000000000008ac7230489e80000";
$this->onRequest([
'address' => '0xasd',
'data' => $data,
'transactionHash' => '0x62a70ccf3b37b9368efa3dd4785e715139c994ba9957a125e299b14a8eccd00c'
], new Transaction);
'transactionHash' => '0x62a70ccf3b37b9368efa3dd4785e715139c994ba9957a125e299b14a8eccd00c',
], $transaction);
}
public function it_should_send_a_blockchain_fail_event(Transaction $transaction)
......@@ -115,8 +139,8 @@ class WithdrawEventSpec extends ObjectBehavior
'contracts' => [
'withdraw' => [
'contract_address' => '0x277fd9efd24535e73b81e99e7f838cdef265e6cb',
]
]
],
],
]);
$data = "0x000000000000000000000000177fd9efd24535e73b81e99e7f838cdef265e6cb"
......@@ -127,7 +151,7 @@ class WithdrawEventSpec extends ObjectBehavior
->duringOnRequest([
'address' => '0x177fd9efd24535e73b81e99e7f838cdef265e6cb',
'data' => $data,
'transactionHash' => '0x62a70ccf3b37b9368efa3dd4785e715139c994ba9957a125e299b14a8eccd00c'
'transactionHash' => '0x62a70ccf3b37b9368efa3dd4785e715139c994ba9957a125e299b14a8eccd00c',
], (new Transaction())->setContract('withdraw'));
}
}
This diff is collapsed.
......@@ -20,6 +20,16 @@ trait MagicAttributes
if (strpos($name, 'set', 0) === 0) {
$attribute = preg_replace('/^set/', '', $name);
$attribute = lcfirst($attribute);
if (!property_exists($this, $attribute)) {
error_log(sprintf(
"Attribute %s is not defined in %s (%s)",
$attribute,
get_class($this),
$name
));
}
$this->$attribute = $args[0];
// DirtyChecking interop
......@@ -32,13 +42,40 @@ trait MagicAttributes
$attribute = preg_replace('/^get/', '', $name);
$attribute = lcfirst($attribute);
if (!property_exists($this, $attribute)) {
error_log(sprintf(
"Attribute %s is not defined in %s (%s)",
$attribute,
get_class($this),
$name
));
}
return $this->$attribute;
} elseif (strpos($name, 'is', 0) === 0) {
$attribute = preg_replace('/^is/', '', $name);
$attribute = lcfirst($attribute);
if (!property_exists($this, $attribute)) {
error_log(sprintf(
"Attribute %s is not defined in %s (%s)",
$attribute,
get_class($this),
$name
));
}
return (bool) $this->$attribute;
} elseif (strpos($name, 'has', 0) === 0) {
if (!property_exists($this, $name)) {
error_log(sprintf(
"Attribute %s is not defined in %s (%s)",
$name,
get_class($this),
$name
));
}
return (bool) $this->$name;
}
......