Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Client Laravel Package

arkecosystem/client

PHP client for the Ark blockchain ecosystem. Query wallets, blocks, transactions, and delegates; build and broadcast signed transactions via Ark Core APIs, with a simple interface for Laravel and plain PHP projects.

View on GitHub
Deep Wiki
Context7

Getting Started

Install

composer require arkecosystem/client

Requires PHP 7.x+ and pulls in Guzzle as its HTTP transport. There is no framework coupling — it is a plain library.

Where to look first

  • src/Connection.php — the entry point; how the host/base URL and Guzzle client are configured.
  • src/API/ — one class per endpoint group (Blocks, Transactions, Wallets, Delegates, Peers, Node, Blockchain, Votes). This directory is the documentation; the method names track the REST paths.
  • The upstream ARK API docs (/api/node/status, /api/blocks, /api/transactions, …) for parameter semantics — the client is a thin passthrough, so the REST docs apply directly.

First use case: confirm you can reach a node

require 'vendor/autoload.php';

use ArkEcosystem\Client\Connection;

$connection = new Connection([
    'host' => 'https://api.ark.io/api', // scheme + host + /api, no trailing slash
]);

// Node status is the cheapest liveness + height probe.
$status = $connection->node()->status();   // ['data' => ['height' => ..., 'synced' => true, ...]]
echo $status['data']['height'];

// Then a first read: most recent blocks, one page.
$blocks = $connection->blocks()->all(['limit' => 5]);
foreach ($blocks['data'] as $block) {
    echo $block['height'] . ' ' . $block['id'] . PHP_EOL;
}

If an accessor doesn't exist in the version you installed, drop to the resource you need (blocks(), transactions(), wallets(), …) or use the connection's generic request method against a path — the underlying call is just <host>/<resource>.

Start with node()->status() and blocks()->all() before building anything else: they validate host formatting, TLS, and the {data, meta} response envelope in one shot.

Implementation Patterns

Laravel service binding + config

Keep the Connection a singleton and the host in config so you can swap nodes per environment.

// config/ark.php
return ['host' => env('ARK_HOST', 'https://api.ark.io/api')];

// app/Providers/AppServiceProvider.php
$this->app->singleton(\ArkEcosystem\Client\Connection::class, fn () => new \ArkEcosystem\Client\Connection([
    'host' => config('ark.host'),
]));

Wrap it in a domain gateway so controllers/jobs never touch the vendor class directly — this is your seam for fakes in tests and for failover logic later.

final class ArkGateway
{
    public function __construct(private Connection $connection) {}

    public function height(): int
    {
        return (int) $this->connection->node()->status()['data']['height'];
    }

    public function recentTransactions(int $limit = 50): array
    {
        return $this->connection->transactions()->all(['limit' => $limit])['data'] ?? [];
    }
}

Pagination loop

Every list endpoint returns {data: [...], meta: {page, pageCount, totalCount, ...}}. Write one helper and reuse it; limit caps at 100 per page.

$page = 1;
do {
    $res  = $connection->transactions()->all(['page' => $page, 'limit' => 100, 'orderBy' => 'timestamp:desc']);
    foreach ($res['data'] as $tx) { $this->persist($tx); }
    $page++;
} while ($page <= ($res['meta']['pageCount'] ?? 1));

For ongoing ingestion, don't deep-paginate — persist the last seen height/timestamp and poll forward with small pages.

Host pool / failover

Public ARK endpoints throttle and occasionally go down. Round-robin a list of hosts behind your gateway, catch RequestException, and move to the next. Treat node status (synced === true) as a health check before trusting reads.

Polling for confirmation

After broadcasting a transaction (signed elsewhere — see gotchas), poll transactions()->all(['id' => $id]) on a schedule (queued job, backoff every 8s up to ~30 blocks) rather than blocking a web request.

Caching

Chain reads are cheap but rate-limited. Cache node()->status() for 5–10s, delegates()->all() for minutes, and static lookups (fees, transaction types) for the process lifetime. Cache the envelope, not just data, so you keep meta for pagination.

Testing

Bind a fake Connection (or a Guzzle handler stack with MockHandler) into the container and assert your gateway's mapping. Don't mock the vendor resource classes — they're thin and will drift.

Gotchas and Tips

  • The host string is the #1 failure point. Include the scheme and, for standard ARK nodes, the /api suffix. Trailing slashes produce doubled paths and 404s. Some versions expect a base_uri-style key; check Connection::__construct in the installed tag.
  • Read-only by design. The client does not sign or build transactions. You must sign with arkecosystem/crypto (or an external signer) using the network's nonce/network byte, then POST the signed payload — either through the client's transaction resource or plain Guzzle. Never put a passphrase in a request body.
  • Amounts are arktoshi. 1 ARK = 10⁸. Values arrive as integers/strings; use bcmath or string math, and never float for balances. On 32-bit PHP this matters immediately.
  • Envelope vs. error shape. Successful responses are {data, meta}; errors from the node may be {error, message, statusCode} or a bare HTML 502 from a proxy. Always guard with $res['data'] ?? null and check meta for emptiness rather than assuming an array.
  • Rate limits and 429s. Public nodes throttle aggressively. Honour Retry-After, add jitter, and never fan out concurrent requests across a whole wallet list without a pool.
  • Guzzle exceptions leak. ConnectException, RequestException, and TooManyRedirectsException all propagate. Catch them at the gateway boundary and translate to domain errors; otherwise a node hiccup becomes a 500.
  • Timeouts. Default Guzzle timeout is effectively unbounded for some configurations — set timeout/connect_timeout explicitly, and inject your own Guzzle client (with logging middleware) into Connection if the constructor supports it. That's the cleanest extension point.
  • Deep pagination is slow and inconsistent. Blocks/transactions are appended constantly, so page 500 shifts under you. Prefer filtering by height/timestamp range or by ID.
  • Version drift. This package has very low adoption (single-digit stars, no known dependents). Pin an exact version in composer.json, read src/API/* for the methods you actually call, and be prepared to vendor a fork. For anything beyond a handful of endpoints, a 60-line Guzzle wrapper against the documented REST API is a legitimate alternative — you'd lose almost nothing.
  • Not consensus-critical. Treat all reads as eventually consistent. Confirm finality by height depth, not by a single transactions lookup returning a confirmations field.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus