Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use server timestamp #2

Merged
merged 2 commits into from
Dec 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 20 additions & 15 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,26 @@ public function __construct(
$this->logger = $logger;
}

public function market(): Endpoints\MarketEndpoint
{
return new Endpoints\MarketEndpoint($this);
}

public function crypto(): Endpoints\CryptoEndpoint
{
return new Endpoints\CryptoEndpoint($this);
}

public function user(): Endpoints\UserEndpoint
{
return new Endpoints\UserEndpoint($this);
}

public function system(): Endpoints\SystemEndpoint
{
return new Endpoints\SystemEndpoint($this);
}

public function getTransport(): Transport
{
return $this->transport;
Expand All @@ -62,19 +82,4 @@ public function sendRequest(PsrRequestInterface $request): PsrResponseInterface
{
return $this->transport->sendRequest($request);
}

public function market(): Endpoints\MarketEndpoint
{
return new Endpoints\MarketEndpoint($this);
}

public function system(): Endpoints\SystemEndpoint
{
return new Endpoints\SystemEndpoint($this);
}

public function user(): Endpoints\UserEndpoint
{
return new Endpoints\UserEndpoint($this);
}
}
12 changes: 6 additions & 6 deletions src/Endpoints/CryptoEndpoint.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public function addresses(array $params): ResponseInterface
return $this->makeRequest('GET', '/api/v3/crypto/addresses')
->withQuery(array_filter($params))
->acceptJson()
->withInterceptor(new GenerateSignatureV3($config))
->withInterceptor(new GenerateSignatureV3($config, $this->client))
->send();
}

Expand Down Expand Up @@ -89,7 +89,7 @@ public function withdrawal(array $params): ResponseInterface

return $this->makeRequest('POST', '/api/v3/crypto/withdraw')
->acceptJson()
->withInterceptor(new GenerateSignatureV3($config))
->withInterceptor(new GenerateSignatureV3($config, $this->client))
->withBody($params)
->send();
}
Expand Down Expand Up @@ -131,7 +131,7 @@ public function internalWithdrawal(array $params): ResponseInterface

return $this->makeRequest('POST', '/api/v3/crypto/internal-withdraw')
->acceptJson()
->withInterceptor(new GenerateSignatureV3($config))
->withInterceptor(new GenerateSignatureV3($config, $this->client))
->withBody($params)
->send();
}
Expand Down Expand Up @@ -175,7 +175,7 @@ public function depositHistory(array $params): ResponseInterface
return $this->makeRequest('POST', '/api/v3/crypto/deposit-history')
->withQuery(array_filter($params))
->acceptJson()
->withInterceptor(new GenerateSignatureV3($config))
->withInterceptor(new GenerateSignatureV3($config, $this->client))
->send();
}

Expand Down Expand Up @@ -218,7 +218,7 @@ public function withdrawalHistory(array $params): ResponseInterface
return $this->makeRequest('POST', '/api/v3/crypto/withdrawal-history')
->withQuery(array_filter($params))
->acceptJson()
->withInterceptor(new GenerateSignatureV3($config))
->withInterceptor(new GenerateSignatureV3($config, $this->client))
->send();
}

Expand Down Expand Up @@ -247,7 +247,7 @@ public function generateAddress(string $symbol): ResponseInterface
return $this->makeRequest('POST', '/api/v3/crypto/generate-address')
->withQuery(['sym' => $symbol])
->acceptJson()
->withInterceptor(new GenerateSignatureV3($config))
->withInterceptor(new GenerateSignatureV3($config, $this->client))
->send();
}
}
16 changes: 8 additions & 8 deletions src/Endpoints/MarketEndpoint.php
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@

return $this->makeRequest('POST', '/api/v3/market/wallet')
->acceptJson()
->withInterceptor(new GenerateSignatureV3($config))
->withInterceptor(new GenerateSignatureV3($config, $this->client))
->send();
}

Expand Down Expand Up @@ -276,7 +276,7 @@

return $this->makeRequest('POST', '/api/v3/market/place-bid')
->acceptJson()
->withInterceptor(new GenerateSignatureV3($config))
->withInterceptor(new GenerateSignatureV3($config, $this->client))
->withBody($params)
->send();
}
Expand Down Expand Up @@ -321,7 +321,7 @@

return $this->makeRequest('POST', '/api/v3/market/place-ask')
->acceptJson()
->withInterceptor(new GenerateSignatureV3($config))
->withInterceptor(new GenerateSignatureV3($config, $this->client))
->withBody($params)
->send();
}
Expand Down Expand Up @@ -353,7 +353,7 @@
return $this->makeRequest('POST', '/api/v3/market/cancel-order')
->acceptJson()
->withBody($params)
->withInterceptor(new GenerateSignatureV3($config))
->withInterceptor(new GenerateSignatureV3($config, $this->client))
->send();
}

Expand All @@ -380,7 +380,7 @@

return $this->makeRequest('POST', '/api/v3/market/balances')
->acceptJson()
->withInterceptor(new GenerateSignatureV3($config))
->withInterceptor(new GenerateSignatureV3($config, $this->client))
->send();
}

Expand Down Expand Up @@ -419,7 +419,7 @@

return $this->makeRequest('GET', '/api/v3/market/my-open-orders')
->acceptJson()
->withInterceptor(new GenerateSignatureV3($config))
->withInterceptor(new GenerateSignatureV3($config, $this->client))

Check warning on line 422 in src/Endpoints/MarketEndpoint.php

View check run for this annotation

Codecov / codecov/patch

src/Endpoints/MarketEndpoint.php#L422

Added line #L422 was not covered by tests
->withBody([
'sym' => $sym,
])
Expand Down Expand Up @@ -473,7 +473,7 @@
return $this->makeRequest('GET', '/api/v3/market/my-order-history')
->withQuery(array_filter($params))
->acceptJson()
->withInterceptor(new GenerateSignatureV3($config))
->withInterceptor(new GenerateSignatureV3($config, $this->client))

Check warning on line 476 in src/Endpoints/MarketEndpoint.php

View check run for this annotation

Codecov / codecov/patch

src/Endpoints/MarketEndpoint.php#L476

Added line #L476 was not covered by tests
->send();
}

Expand Down Expand Up @@ -531,7 +531,7 @@
return $this->makeRequest('GET', '/api/v3/market/order-info')
->withQuery(array_filter($params))
->acceptJson()
->withInterceptor(new GenerateSignatureV3($config))
->withInterceptor(new GenerateSignatureV3($config, $this->client))

Check warning on line 534 in src/Endpoints/MarketEndpoint.php

View check run for this annotation

Codecov / codecov/patch

src/Endpoints/MarketEndpoint.php#L534

Added line #L534 was not covered by tests
->send();
}
}
19 changes: 18 additions & 1 deletion src/Endpoints/SystemEndpoint.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,23 @@

class SystemEndpoint extends AbstractEndpoint
{
/**
* Get server status.
*
* @response
* [
* {
* "name":"Non-secure endpoints",
* "status":"ok",
* "message":""
* },
* {
* "name":"Secure endpoints",
* "status":"ok",
* "message":""
* }
* ]
*/
public function status(): ResponseInterface
{
return $this->makeRequest('GET', '/api/status')->send();
Expand All @@ -15,7 +32,7 @@ public function status(): ResponseInterface
* Get server timestamp.
*
* @response
* 1701251212273
* 1702793384662
*/
public function serverTimestamp(): ResponseInterface
{
Expand Down
4 changes: 2 additions & 2 deletions src/Endpoints/UserEndpoint.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public function tradingCredits(): ResponseInterface

return $this->makeRequest('POST', '/api/v3/user/trading-credits')
->acceptJson()
->withInterceptor(new GenerateSignatureV3($config))
->withInterceptor(new GenerateSignatureV3($config, $this->client))
->send();
}

Expand Down Expand Up @@ -69,7 +69,7 @@ public function userLimits(): ResponseInterface

return $this->makeRequest('POST', '/api/v3/user/limits')
->acceptJson()
->withInterceptor(new GenerateSignatureV3($config))
->withInterceptor(new GenerateSignatureV3($config, $this->client))
->send();
}
}
26 changes: 15 additions & 11 deletions src/Requests/GenerateSignatureV3.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

namespace Farzai\Bitkub\Requests;

use Farzai\Bitkub\Client;
use Farzai\Bitkub\Contracts\RequestInterceptor;
use Farzai\Bitkub\Utility;
use Psr\Http\Message\RequestInterface as PsrRequestInterface;

class GenerateSignatureV3 implements RequestInterceptor
Expand All @@ -14,25 +16,27 @@ class GenerateSignatureV3 implements RequestInterceptor
*/
private array $config;

public function __construct(array $config)
{
$this->config = $config;
}
/**
* The client instance.
*/
private Client $client;

public function generate($timestamp, $method, $path, $query, $payload)
/**
* Create a new client instance.
*/
public function __construct(array $config, Client $client)
{
$message = sprintf('%s%s%s%s%s', $timestamp, $method, $path, $query, $payload);
$signature = hash_hmac('sha256', $message, $this->config['secret']);

return $signature;
$this->config = $config;
$this->client = $client;
}

/**
* Apply the request.
*/
public function apply(PsrRequestInterface $request): PsrRequestInterface
{
$timestamp = (int) (microtime(true) * 1000);
$timestamp = (int) Utility::getServerTimestamp($this->client)->format('U');

$method = strtoupper($request->getMethod());
$path = '/'.trim($request->getUri()->getPath(), '/');
$payload = $request->getBody()->getContents() ?: '';
Expand All @@ -42,7 +46,7 @@ public function apply(PsrRequestInterface $request): PsrRequestInterface
$query = '?'.$query;
}

$signature = $this->generate($timestamp, $method, $path, $query, $payload);
$signature = Utility::generateSignature($this->config['secret'], $timestamp, $method, $path, $query, $payload);

return $request->withHeader('X-BTK-APIKEY', $this->config['api_key'])
->withHeader('X-BTK-SIGN', $signature)
Expand Down
14 changes: 7 additions & 7 deletions src/Requests/PendingRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,20 @@

class PendingRequest
{
private ClientInterface $client;
public ClientInterface $client;

private string $method;
public string $method;

private string $path;
public string $path;

private array $options;
public array $options;

/**
* The request interceptors.
*
* @var array<\Farzai\Bitkub\Contracts\RequestInterceptor>
*/
private $interceptors = [];
public $interceptors = [];

/**
* Create a new pending request instance.
Expand Down Expand Up @@ -141,7 +141,7 @@ public function send(): ResponseInterface
/**
* Create a new request instance.
*/
protected function createRequest(string $method, string $path, array $options = []): PsrRequestInterface
public function createRequest(string $method, string $path, array $options = []): PsrRequestInterface
{
// Normalize path
$path = '/'.trim($path, '/');
Expand Down Expand Up @@ -170,7 +170,7 @@ protected function createRequest(string $method, string $path, array $options =
/**
* Create a new response instance.
*/
protected function createResponse(PsrRequestInterface $request, PsrResponseInterface $baseResponse): ResponseInterface
public function createResponse(PsrRequestInterface $request, PsrResponseInterface $baseResponse): ResponseInterface
{
$response = new Response($request, $baseResponse);
$response = new ResponseWithValidateErrorCode($response);
Expand Down
31 changes: 31 additions & 0 deletions src/Utility.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace Farzai\Bitkub;

use DateTimeImmutable;

class Utility
{
/**
* Generate signature.
*/
public static function generateSignature($secret, $timestamp, $method, $path, $query, $payload)
{
$message = sprintf('%s%s%s%s%s', $timestamp, $method, $path, $query, $payload);
$signature = hash_hmac('sha256', $message, $secret);

return $signature;
}

/**
* Get server timestamp.
*/
public static function getServerTimestamp(Client $client): DateTimeImmutable
{
$timestamp = (int) $client->system()
->serverTimestamp()
->throw()->body();

return \DateTimeImmutable::createFromFormat('U', $timestamp);
}
}
26 changes: 17 additions & 9 deletions tests/AuthorizerTest.php
Original file line number Diff line number Diff line change
@@ -1,22 +1,30 @@
<?php

use Farzai\Bitkub\Requests\GenerateSignatureV3;
use Farzai\Bitkub\ClientBuilder;
use Farzai\Bitkub\Tests\MockHttpClient;
use Farzai\Bitkub\Utility;

it('can generate signature success', function () {
$secret = 'test-secret';
$secret = 'secret';
$timestamp = 1630483200000;

$method = 'POST';
$path = '/api/v3/market/balances';
$query = '';
$payload = '';

$authorizer = new GenerateSignatureV3([
'api_key' => 'test',
'secret' => $secret,
]);
$psrClient = MockHttpClient::make()
->addSequence(fn ($client) => $client->createResponse(200, (string) $timestamp));

$client = ClientBuilder::create()
->setCredentials('test', 'secret')
->setHttpClient($psrClient)
->build();

$timestamp = (int) Utility::getServerTimestamp($client)->format('U');

expect($timestamp)->toBe(1630483200000);

$signature = $authorizer->generate($timestamp, $method, $path, $query, $payload);
$signature = Utility::generateSignature($secret, $timestamp, $method, $path, $query, $payload);

expect($signature)->toBe('b8403c345ce41b25b47885254fb8aeed9ad7ceb9e30425b86a9a151dd6ac2e35');
expect($signature)->toBe('ae6fd3dc7d85ebea023e54292fa6eebaeea6dc02002433c51b57136eeb0a03e5');
});
Loading