From 06ecd8119bd43954a28b82654df7aa2db9f71a17 Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Wed, 4 Mar 2026 12:41:41 +0000 Subject: [PATCH 1/7] feat: tokens endpoint --- src/API/Tokens.php | 96 ++++++++++++++++++++++++++++++++++++++++ src/ArkClient.php | 6 +++ tests/API/TokensTest.php | 51 +++++++++++++++++++++ 3 files changed, 153 insertions(+) create mode 100644 src/API/Tokens.php create mode 100644 tests/API/TokensTest.php diff --git a/src/API/Tokens.php b/src/API/Tokens.php new file mode 100644 index 0000000..fb07706 --- /dev/null +++ b/src/API/Tokens.php @@ -0,0 +1,96 @@ +requestGet('tokens', $parameters); + } + + /** + * Get all tokens using whitelist filtering. + * + * This method sends a POST request with whitelist parameters. + * + * @param array $parameters + * + * @return array + */ + public function allWithWhitelist(array $parameters = []): ?array + { + return $this->requestPost('tokens', $parameters); + } + + /** + * Get a token by contract address. + * + * @param string $address + * + * @return array + */ + public function get(string $address): ?array + { + return $this->requestGet("tokens/{$address}"); + } + + /** + * Get token holders for a given token. + * + * @param string $address + * @param array $query + * + * @return array + */ + public function holders(string $address, array $query = []): ?array + { + return $this->requestGet("tokens/{$address}/holders", $query); + } + + /** + * Get token transfers for a given token. + * + * @param string $address + * @param array $query + * + * @return array + */ + public function transfersByToken(string $address, array $query = []): ?array + { + return $this->requestGet("tokens/{$address}/transfers", $query); + } + + /** + * Get all token transfers. + * + * @param array $query + * + * @return array + */ + public function transfers(array $query = []): ?array + { + return $this->requestGet('tokens/transfers', $query); + } + + /** + * Get the token whitelist. + * + * @param array $query + * + * @return array + */ + public function whitelist(array $query = []): ?array + { + return $this->requestGet('tokens/whitelist', $query); + } +} diff --git a/src/ArkClient.php b/src/ArkClient.php index 8b97082..043fee9 100644 --- a/src/ArkClient.php +++ b/src/ArkClient.php @@ -14,6 +14,7 @@ use ArkEcosystem\Client\API\Peers; use ArkEcosystem\Client\API\Receipts; use ArkEcosystem\Client\API\Rounds; +use ArkEcosystem\Client\API\Tokens; use ArkEcosystem\Client\API\Transactions; use ArkEcosystem\Client\API\Validators; use ArkEcosystem\Client\API\Votes; @@ -79,6 +80,11 @@ public function rounds(): Rounds return new Rounds($this->connection); } + public function tokens(): Tokens + { + return new Tokens($this->connection); + } + public function transactions(): Transactions { return new Transactions($this->connection); diff --git a/tests/API/TokensTest.php b/tests/API/TokensTest.php new file mode 100644 index 0000000..9e8f4ff --- /dev/null +++ b/tests/API/TokensTest.php @@ -0,0 +1,51 @@ +assertResponse('GET', 'tokens', function (ArkClient $client) { + return $client->tokens()->all(); + }); +}); + +it('calls correct url for all with whitelist', function () { + $this->assertResponse('POST', 'tokens', function (ArkClient $client) { + return $client->tokens()->all([ + 'whitelist' => ['0x1234567890abcdef1234567890abcdef12345678'], + ]); + }); +}); + +it('calls correct url for get', function () { + $this->assertResponse('GET', 'tokens/dummy', function (ArkClient $client) { + return $client->tokens()->get('dummy'); + }); +}); + +it('calls correct url for holders', function () { + $this->assertResponse('GET', 'tokens/dummy/holders', function (ArkClient $client) { + return $client->tokens()->holders('dummy'); + }); +}); + +it('calls correct url for transfers by token', function () { + $this->assertResponse('GET', 'tokens/dummy/transfers', function (ArkClient $client) { + return $client->tokens()->transfersByToken('dummy'); + }); +}); + +it('calls correct url for all transfers', function () { + $this->assertResponse('GET', 'tokens/transfers', function (ArkClient $client) { + return $client->tokens()->transfers(); + }); +}); + +it('calls correct url for whitelist', function () { + $this->assertResponse('GET', 'tokens/whitelist', function (ArkClient $client) { + return $client->tokens()->whitelist(); + }); +}); From 57e9bc612671ebb8e94c7dd939f200825661136a Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Wed, 4 Mar 2026 12:45:13 +0000 Subject: [PATCH 2/7] fix failing test --- tests/API/TokensTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/API/TokensTest.php b/tests/API/TokensTest.php index 9e8f4ff..f27480f 100644 --- a/tests/API/TokensTest.php +++ b/tests/API/TokensTest.php @@ -14,7 +14,7 @@ it('calls correct url for all with whitelist', function () { $this->assertResponse('POST', 'tokens', function (ArkClient $client) { - return $client->tokens()->all([ + return $client->tokens()->allWithWhitelist([ 'whitelist' => ['0x1234567890abcdef1234567890abcdef12345678'], ]); }); From 98cc28b78b46f1cac76a7f9daa375b3c20be6937 Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Wed, 4 Mar 2026 12:49:04 +0000 Subject: [PATCH 3/7] Update src/API/Tokens.php Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/API/Tokens.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/API/Tokens.php b/src/API/Tokens.php index fb07706..60fd8c7 100644 --- a/src/API/Tokens.php +++ b/src/API/Tokens.php @@ -9,13 +9,13 @@ class Tokens extends AbstractAPI /** * Get all tokens. * - * @param array $parameters + * @param array $query * * @return array */ - public function all(array $parameters = []): ?array + public function all(array $query = []): ?array { - return $this->requestGet('tokens', $parameters); + return $this->requestGet('tokens', $query); } /** From 02ce9a4b114ce2cfcbb172c677977088df526c63 Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Wed, 4 Mar 2026 12:51:03 +0000 Subject: [PATCH 4/7] combine all methods --- src/API/Tokens.php | 18 ++++-------------- tests/API/TokensTest.php | 2 +- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/API/Tokens.php b/src/API/Tokens.php index 60fd8c7..6355385 100644 --- a/src/API/Tokens.php +++ b/src/API/Tokens.php @@ -15,21 +15,11 @@ class Tokens extends AbstractAPI */ public function all(array $query = []): ?array { - return $this->requestGet('tokens', $query); - } + if (isset($query['whitelist'])) { + return $this->requestPost('tokens', $query); + } - /** - * Get all tokens using whitelist filtering. - * - * This method sends a POST request with whitelist parameters. - * - * @param array $parameters - * - * @return array - */ - public function allWithWhitelist(array $parameters = []): ?array - { - return $this->requestPost('tokens', $parameters); + return $this->requestGet('tokens', $query); } /** diff --git a/tests/API/TokensTest.php b/tests/API/TokensTest.php index f27480f..9e8f4ff 100644 --- a/tests/API/TokensTest.php +++ b/tests/API/TokensTest.php @@ -14,7 +14,7 @@ it('calls correct url for all with whitelist', function () { $this->assertResponse('POST', 'tokens', function (ArkClient $client) { - return $client->tokens()->allWithWhitelist([ + return $client->tokens()->all([ 'whitelist' => ['0x1234567890abcdef1234567890abcdef12345678'], ]); }); From a2bc09eec69ccce742696851026bd01e47d7d0aa Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Wed, 4 Mar 2026 13:35:06 +0000 Subject: [PATCH 5/7] wallet endpoints --- src/API/Wallets.php | 25 +++++++++++++++++++++++++ tests/API/WalletsTest.php | 28 ++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/src/API/Wallets.php b/src/API/Wallets.php index f473a8c..04b8729 100644 --- a/src/API/Wallets.php +++ b/src/API/Wallets.php @@ -91,4 +91,29 @@ public function top(): ?array { return $this->requestGet('wallets/top'); } + + /** + * Get all tokens held by the given wallet. + * + * @param string $id + * @param array $query + * + * @return array + */ + public function tokensFor(string $id, array $query = []): ?array + { + return $this->requestGet("wallets/{$id}/tokens", $query); + } + + /** + * Get all tokens held by wallets. + * + * @param array $query + * + * @return array + */ + public function tokens(array $query = []): ?array + { + return $this->requestGet('wallets/tokens', $query); + } } diff --git a/tests/API/WalletsTest.php b/tests/API/WalletsTest.php index f2c04cd..bbd8849 100644 --- a/tests/API/WalletsTest.php +++ b/tests/API/WalletsTest.php @@ -47,3 +47,31 @@ return $client->wallets()->votes('dummy'); }); }); + +it('calls correct url for all wallet tokens', function () { + $this->assertResponse('GET', 'wallets/tokens', function (ArkClient $client) { + return $client->wallets()->tokens(); + }); +}); + +it('calls correct url for all wallet tokens with query', function () { + $this->assertResponse('GET', 'wallets/tokens?limit=10', function (ArkClient $client) { + return $client->wallets()->tokens([ + 'limit' => 10, + ]); + }); +}); + +it('calls correct url for a wallet tokens', function () { + $this->assertResponse('GET', 'wallets/dummy/tokens', function (ArkClient $client) { + return $client->wallets()->tokensFor('dummy'); + }); +}); + +it('calls correct url for a wallet tokens with query', function () { + $this->assertResponse('GET', 'wallets/dummy/tokens?limit=10', function (ArkClient $client) { + return $client->wallets()->tokensFor('dummy', [ + 'limit' => 10, + ]); + }); +}); From 6f6f31ace9750238b4c46db1ade63e9f6f0d153f Mon Sep 17 00:00:00 2001 From: Alex Barnsley <8069294+alexbarnsley@users.noreply.github.com> Date: Wed, 4 Mar 2026 13:48:54 +0000 Subject: [PATCH 6/7] wallet endpoints --- src/API/Wallets.php | 8 ++++++++ tests/API/TokensTest.php | 41 ++++++++++++++++++++++++++++++++++++++-- tests/TestCase.php | 16 ++++++++++++++-- 3 files changed, 61 insertions(+), 4 deletions(-) diff --git a/src/API/Wallets.php b/src/API/Wallets.php index 04b8729..b67ab2b 100644 --- a/src/API/Wallets.php +++ b/src/API/Wallets.php @@ -102,6 +102,10 @@ public function top(): ?array */ public function tokensFor(string $id, array $query = []): ?array { + if (isset($query['whitelist'])) { + return $this->requestPost("wallets/{$id}/tokens", $query); + } + return $this->requestGet("wallets/{$id}/tokens", $query); } @@ -114,6 +118,10 @@ public function tokensFor(string $id, array $query = []): ?array */ public function tokens(array $query = []): ?array { + if (isset($query['whitelist'])) { + return $this->requestPost("wallets/tokens", $query); + } + return $this->requestGet('wallets/tokens', $query); } } diff --git a/tests/API/TokensTest.php b/tests/API/TokensTest.php index 9e8f4ff..ef83c59 100644 --- a/tests/API/TokensTest.php +++ b/tests/API/TokensTest.php @@ -13,9 +13,46 @@ }); it('calls correct url for all with whitelist', function () { - $this->assertResponse('POST', 'tokens', function (ArkClient $client) { - return $client->tokens()->all([ + $this->assertResponse( + 'POST', + 'tokens', + function (ArkClient $client) { + return $client->tokens()->all([ + 'whitelist' => ['0x1234567890abcdef1234567890abcdef12345678'], + ]); + }, + expectedRequestBody: [ 'whitelist' => ['0x1234567890abcdef1234567890abcdef12345678'], + ] + ); +}); + +it('sends all whitelist values in the request body', function () { + $this->assertResponse( + 'POST', + 'tokens', + function (ArkClient $client) { + return $client->tokens()->all([ + 'whitelist' => [ + '0x1234567890abcdef1234567890abcdef12345678', + '0xabcdef1234567890abcdef1234567890abcdef12', + ], + ]); + }, + expectedRequestBody: [ + 'whitelist' => [ + '0x1234567890abcdef1234567890abcdef12345678', + '0xabcdef1234567890abcdef1234567890abcdef12', + ], + ] + ); +}); + +it('calls correct url for whitelist with query', function () { + $this->assertResponse('GET', 'tokens/whitelist?page=2&limit=10', function (ArkClient $client) { + return $client->tokens()->whitelist([ + 'page' => 2, + 'limit' => 10, ]); }); }); diff --git a/tests/TestCase.php b/tests/TestCase.php index 5d38ae8..0344464 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -28,7 +28,15 @@ abstract class TestCase extends BaseTestCase * @param callable $callback * @param array|null $expectedBody */ - protected function assertResponse(string $method, string $path, callable $callback, array $expectedBody = [], string $expectedApi = 'api', array $response = []): void + protected function assertResponse( + string $method, + string $path, + callable $callback, + array $expectedBody = [], + string $expectedApi = 'api', + array $response = [], + ?array $expectedRequestBody = null + ): void { $hosts = [ 'api' => 'https://dwallets-evm.mainsailhq.com/api', @@ -37,10 +45,14 @@ protected function assertResponse(string $method, string $path, callable $callba ]; $mockHandler = new MockHandler([ - function (Request $request) use ($method, $path, $response, $hosts, $expectedApi) { + function (Request $request) use ($method, $path, $response, $hosts, $expectedApi, $expectedRequestBody) { $this->assertSame($method, $request->getMethod()); $this->assertSame($hosts[$expectedApi].'/'.$path, $request->getUri()->__toString()); + if ($expectedRequestBody !== null) { + $this->assertSame($expectedRequestBody, json_decode($request->getBody()->getContents(), true)); + } + return new Response(200, [], json_encode($response)); }, ]); From 89077421f186f1c424550aab15abc72c188b117f Mon Sep 17 00:00:00 2001 From: alexbarnsley Date: Wed, 4 Mar 2026 13:50:27 +0000 Subject: [PATCH 7/7] style: resolve style guide violations --- src/API/Wallets.php | 2 +- tests/API/TokensTest.php | 2 +- tests/TestCase.php | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/API/Wallets.php b/src/API/Wallets.php index b67ab2b..ab2d3dd 100644 --- a/src/API/Wallets.php +++ b/src/API/Wallets.php @@ -119,7 +119,7 @@ public function tokensFor(string $id, array $query = []): ?array public function tokens(array $query = []): ?array { if (isset($query['whitelist'])) { - return $this->requestPost("wallets/tokens", $query); + return $this->requestPost('wallets/tokens', $query); } return $this->requestGet('wallets/tokens', $query); diff --git a/tests/API/TokensTest.php b/tests/API/TokensTest.php index ef83c59..d9b7b40 100644 --- a/tests/API/TokensTest.php +++ b/tests/API/TokensTest.php @@ -51,7 +51,7 @@ function (ArkClient $client) { it('calls correct url for whitelist with query', function () { $this->assertResponse('GET', 'tokens/whitelist?page=2&limit=10', function (ArkClient $client) { return $client->tokens()->whitelist([ - 'page' => 2, + 'page' => 2, 'limit' => 10, ]); }); diff --git a/tests/TestCase.php b/tests/TestCase.php index 0344464..64cc507 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -36,8 +36,7 @@ protected function assertResponse( string $expectedApi = 'api', array $response = [], ?array $expectedRequestBody = null - ): void - { + ): void { $hosts = [ 'api' => 'https://dwallets-evm.mainsailhq.com/api', 'transactions' => 'https://dwallets-evm.mainsailhq.com/tx/api',