Ethereum / EVM JSON-RPC client in pure PHP — raw eth_* mirror plus an ethers.js v6-style typed provider over any PSR-18 client, with EIP-1559 fee data.
An Ethereum JSON-RPC client in pure PHP for any EVM chain, built on any PSR-18 HTTP client. Two layers: a raw eth_* mirror (EthRpcClient) for audit-grade hex parity with the wire, and an ethers.js v6-flavoured facade (JsonRpcProvider) returning typed Value Objects — EthereumTransaction, EthereumTxBundle, EthereumBlock, EthereumFeeData, EthereumFeeHistory, EthereumTransactionLog. Wei values that exceed PHP_INT_MAX stay safe as decimal strings via ext-gmp, never lossy floats. EIP-1559 fee composition follows ethers.js (maxFeePerGas = 2 × baseFee + tip), and the provider gracefully handles real-world node quirks like Erigon's bare 0x returns and missing baseFeePerGas.
EthRpcClient mirrors the eth_* namespace (eth_blockNumber, eth_getBalance, eth_call, eth_getTransactionByHash, eth_getTransactionReceipt, eth_getLogs, eth_feeHistory, …); JsonRpcProvider wraps it with typed Value Objects and ethers.js naming.getTypedTransaction() / waitForTransaction() return an EthereumTxBundle with EIP-658 isStatusSuccess() / isStatusFail() / isStatusPending() predicates, so call sites never compare raw '0x1' / '0x0' strings.getFeeData() mirrors ethers.js (maxFeePerGas = 2 × baseFee + tip); getFeeHistory() carries the gwei-median math.'0x' empty returns and pre-London / missing-baseFeePerGas blocks without throwing.Numeric\HexInt / HexBig / Wei.waitForTransaction deadlines are driven by an injected Psr\Clock\ClockInterface, so polling is fully testable.web3p/web3.php is effectively abandoned and predates EIP-1559 — no typed fee data, no London-fork fee composition. This package targets modern PHP 8.3, ships EIP-1559 fee math out of the box, returns typed Value Objects with bigint-safe decimal strings, keeps PHPStan level 9 across the surface, and stays transport-agnostic so retries and API keys live in your PSR-18 pipeline.
composer require amashukov/eth-rpc-client-php
use Amashukov\EthRpc\EthRpcClient;
use Amashukov\EthRpc\JsonRpcProvider;
use Amashukov\HttpClient\CurlClient;
use Nyholm\Psr7\Factory\Psr17Factory;
use Symfony\Component\Clock\NativeClock;
$psr17 = new Psr17Factory();
$http = new CurlClient($psr17, $psr17, timeoutSeconds: 30);
$client = new EthRpcClient($http, $psr17, $psr17, 'https://your-eth-node.example/rpc');
$provider = new JsonRpcProvider($client, new NativeClock());
$balanceWei = $provider->getBalance('0xabc...'); // decimal string
$bundle = $provider->getTypedTransaction('0xtxhash'); // EthereumTxBundle
if ($bundle->isStatusSuccess()) {
$gasFee = $bundle->receipt->fee; // decimal wei
}
$fee = $provider->getFeeData(); // EthereumFeeData
$usdt = $provider->getErc20Balance('0xdAC17...', '0xholder...');
Wire a retry / API-key pipeline by composing
amashukov/http-client-php
middlewares around the CurlClient and passing the resulting PSR-18
Pipeline into EthRpcClient.
| Layer | Use it for |
|---|---|
EthRpcClient (eth_*) |
Audit-grade paths that need hex parity with the wire format. |
JsonRpcProvider |
New code — typed VOs, decimal-string balances, ethers.js naming. |
This package broadcasts already-signed raw transactions via
sendTransaction(). Offline EIP-1559 / EIP-155 signing lives in the
companion amashukov/eip1559-tx-signer-php.
ext-gmp, ext-bcmath| Package | Role |
|---|---|
| amashukov/abi-encoder-php | Solidity ABI encode / decode (dependency) |
| amashukov/eip1559-tx-signer-php | Offline EIP-1559 / EIP-155 transaction signing |
| amashukov/http-client-php | PSR-18 cURL client + retry / header-injection middleware |
| amashukov/keccak-php | Keccak-256 hashing |
| amashukov/eth-php | Ethereum meta-package |
| amashukov/blockchain-context-bundle | Symfony bundle wiring the whole family |
@PER-CS ruleset.maxFeePerGas = 2 × baseFee + tip).MIT — see LICENSE.
How can I help you explore Laravel packages today?