hardcastle / xrpl_php
PHP SDK / Client for the XRP Ledger
Requires
- php: ^8.2
- ext-bcmath: *
- brick/math: >=0.11 <0.15
- codedungeon/php-cli-colors: ^1.12
- guzzlehttp/guzzle: ^7.15.2
- hardcastle/buffer: ^2.0
- php-ds/php-ds: ^1.4
- simplito/bn-php: ^1.1.4
- simplito/elliptic-php: ^1.0.12
- vlucas/phpdotenv: ^5.6
Requires (Dev)
- donatj/mock-webserver: ^2.10.0
- phpunit/phpunit: ^11.5
- rector/rector: ^2.3
- vimeo/psalm: ^6.8
Suggests
None
Provides
None
Conflicts
None
Replaces
None
- dev-master
- 2.4.0
- 2.3.0
- 2.2.0
- 2.1.0
- 2.0.0
- 1.1.2
- 1.1.1
- 1.1.0
- 1.0.0
- 0.10.2
- 0.10.1
- 0.10.0
- 0.9.10
- 0.9.9
- 0.9.8
- 0.9.7
- 0.9.6
- 0.9.5
- 0.9.4
- 0.9.3
- 0.9.2
- v0.9.1
- v0.9.0
- v0.8.8
- v0.8.7
- v0.8.6
- v0.8.5
- v0.8.4
- v0.8.3
- v0.8.2
- v0.8.1
- v0.8.0
- v0.7.6
- v0.7.5
- v0.7.4
- v0.7.3
- v0.7.2
- v0.7.1
- v0.7.0
- v0.6.5-alpha
- v0.6.4-alpha
- v0.6.3-alpha
- v0.6.2-alpha
- v0.6.1-alpha
- v0.6.0-alpha
- v0.5.0-alpha
- v0.4.0-alpha
- dev-nested-object-end-marker
- dev-replaceable-collaborators
- dev-quality-pass
- dev-injectable-definitions
- dev-2026-08-update
- dev-bump-buffer-version
- dev-issue/base-response-return-type
- dev-tech-stack-file
- dev-issue/remove-optional-dependencies
This package is auto-updated.
Last update: 2026-09-02 10:06:44 UTC
README
PHP SDK / Client Library to interact with the XRP Ledger and the Xahau Network. It offers all the functionality available in the JavaScript and Java Versions emphasizing robustness and code readability for those interested in looking under the hood and getting into the nitty-gritty of XRPL development.
Features
- XRP Ledger / rippled version 3.3.0 compatible
- Managing & creating keys and wallets
- Submitting transactions to the XRP Ledger
- Sending requests to observe the ledger
- Creating and signing transactions (e.g. Payments) to modify the ledger state
- Parsing ledger data into more convenient formats
Installation
This library is installable via Composer:
composer require hardcastle/xrpl_php
Requirements
This library requires PHP 8.2 or later and two PHP extensions:
- bcmath — used directly for the ledger's fixed point arithmetic.
- gmp — required by
simplito/elliptic-php, which does the secp256k1 signing. Composer will refuse to install without it.
Examples
The "Quickstart" Examples
These examples reproduce the functionality from the JavaScript quickstart examples:
php 1.get-accounts-send-xrp.php php 2.create-trustline-send-currency.php php 3.mint-nfts.php
How-to Examples
These examples show how to use key features:
php examples/client.php php examples/faucet-wallet.php php examples/payment.php php examples/token-create.php // IOU + Token + CBDC - Wallet Matrix with Trustlines php examples/mptoken.php // Multi-Purpose Token: issue, authorize, send, claw back php examples/permissioned-domain.php // Credentials + PermissionedDomain + PermissionedDEX php examples/amm-clawback.php // Claw a token back out of an AMM pool php examples/nftoken-modify.php // Mint a mutable NFT and change its URI php examples/rlusd.php // Trust line and payment in Ripple USD php examples/custom-currency-codes.php // Currency codes beyond the three character form php examples/payment-with-destination-tag.php php examples/xrp-balance.php php examples/provoke-error.php // What an error response looks like
All of these run against the Testnet and fund their own wallets from the faucet.
Core Examples
These examples can be used to explore XRPL core functionality:
php examples/internal/address-codec.php php examples/internal/binary-codec.php etc...
Try it yourself
Issuing an account_objects request
require __DIR__.'/../vendor/autoload.php'; use Hardcastle\XRPL_PHP\Client\JsonRpcClient; use Hardcastle\XRPL_PHP\Models\Account\AccountObjectsRequest; // Those will be purged from the Testnet in regular intervals, you can use fundWallet() // to generate prefunded Wallets on the Testnet $testnetAccountAddress = 'raKXrkYfbh4Uzqc481jTXbaKsWnW5XRMjp'; $client = new JsonRpcClient("https://s.altnet.rippletest.net:51234"); $request = new AccountObjectsRequest( account: $testnetAccountAddress, ledgerIndex: 'validated', deletionBlockersOnly: true ); // Synchronous $response = $client->syncRequest($request); print_r($response->getResult()); // Asynchronous - the promise resolves to the same response object // $response = $client->request($request)->wait(); // print_r($response->getResult());
Making a payment
// Use your own credentials here: $senderWallet = Wallet::fromSeed('sEdTcvQ9k4UUEHD9y947QiXEs93Fp2k'); $destination = 'rEQ3ik2kmAvajqpFweKgDghJFZQGpXxuRN'; $client = new JsonRpcClient("https://s.altnet.rippletest.net:51234"); $tx = [ "TransactionType" => "Payment", "Account" => $senderWallet->getAddress(), "Amount" => xrpToDrops("10"), "Destination" => $destination ]; // Fills in Sequence, Fee and LastLedgerSequence, signs, submits, and waits // until the transaction is in a validated ledger. $txResponse = $client->submitAndWait($tx, autofill: true, wallet: $senderWallet); $result = $txResponse->getResult(); // A tec result still reaches the ledger, so the code has to be checked - // submitAndWait() returning is not by itself a success. if ($result['meta']['TransactionResult'] !== 'tesSUCCESS') { print_r("Payment failed with {$result['meta']['TransactionResult']}! TxHash: {$result['hash']}" . PHP_EOL); } else { print_r("Payment done! TxHash: {$result['hash']}" . PHP_EOL); }
Signing yourself and submitting the blob works just as well, and is what the
files in examples/ do:
$signedTx = $senderWallet->sign($client->autofill($tx)); $txResponse = $client->submitAndWait($signedTx['tx_blob']);
The objects behind the client
JsonRpcClient is a facade. Behind each of its operations sits a class that can
also be used on its own:
| Class | What it does |
|---|---|
Autofiller |
fills in Sequence, Fee and LastLedgerSequence |
Submitter |
submits transactions and polls for their outcome |
AccountReader |
balances and transaction history |
OrderbookReader |
the offers in one order book |
FeeCalculator |
the current network fee |
Faucet |
funds a wallet on a test network |
$balances = (new AccountReader($client))->getBalances($address); // same as $balances = $client->getBalances($address);
The functions in the Hardcastle\XRPL_PHP\Sugar namespace do the same and keep
working, but they are deprecated as of 2.2.0 and delegate to these classes.
Xahau support
The library ships the Xahau transaction types alongside the XRP Ledger ones, but
the two networks have drifted apart: Xahau kept its URIToken types on the
ordinals 45–49 and moved everything the XRP Ledger added afterwards further up.
MPTokenIssuanceCreate, for instance, is 54 on the XRP Ledger and 63 on Xahau.
A single set of definitions cannot be correct for both networks, and this
library resolves the overlap in favour of the XRP Ledger.
Works on Xahau:
- All classic transaction types —
Payment,AccountSet,TrustSet,OfferCreate/OfferCancel,Escrow*,Check*,PaymentChannel*,NFToken*,AMM*,Clawback,TicketCreate,SignerListSet,DepositPreauth,AccountDelete,SetRegularKey. These carry the same ordinal on both networks. - The Xahau-specific types —
SetHook,Invoke,Import,ClaimReward,GenesisMint,UNLReport,URIToken*,TicketCancel.
Does not work on Xahau yet:
- Every type the XRP Ledger added from ordinal 41 onwards:
XChain*,DID*,Oracle*,MPToken*,Credential*,PermissionedDomain*,NFTokenModify. These encode with the XRP Ledger ordinal, which means a different transaction type on Xahau — without an error. Do not submit them to Xahau. - Decoding is ambiguous for the five shared ordinals: a Xahau
URITokenMintdecodes asXChainAddClaimAttestation, and the XahauBlobfield decodes asDIDDocument. The bytes are correct, only the names are read through the XRP Ledger definitions. hooksDefinitions.jsonpredates the current Xahau release and is missingRemit,SetRemarks,CronandCronSet.
Using your own definitions
Since 2.1.0 the codec works against definitions handed in from outside, so a
package for another network can supply its own definitions.json instead of the
bundled one. Every entry point takes an optional Definitions instance and
falls back to the XRP Ledger when it is omitted:
use Hardcastle\XRPL_PHP\Core\RippleBinaryCodec\BinaryCodec; use Hardcastle\XRPL_PHP\Core\RippleBinaryCodec\Definitions\Definitions; use Hardcastle\XRPL_PHP\Client\JsonRpcClient; use Hardcastle\XRPL_PHP\Wallet\Wallet; $definitions = Definitions::fromFile('/path/to/xahau-definitions.json'); // or Definitions::fromArray($decodedJson); $codec = new BinaryCodec($definitions); $wallet = Wallet::fromSeed($seed, $definitions); $client = new JsonRpcClient('https://xahau.network', null, null, 3.0, $definitions);
A node serves its own definitions, so they can be fetched rather than vendored:
curl -X POST https://xahau.network -H 'Content-Type: application/json' \ -d '{"method":"server_definitions","params":[{}]}'
The definitions travel through the whole encode and decode, including nested objects and arrays. They do not touch the shared default instance, so a process can talk to both networks at once.
Replacing what the client works with
The definitions decide how a transaction is encoded, but not everything a network does differently. Xahau prices a transaction individually, because hooks may fire, so the XRP Ledger's fee formula produces too low a fee there.
Since 2.3.0 the client exposes the objects it works with, and a subclass can substitute one:
use Hardcastle\XRPL_PHP\Client\Autofiller; use Hardcastle\XRPL_PHP\Client\JsonRpcClient; class XahauClient extends JsonRpcClient { public function getAutofiller(): Autofiller { return new XahauAutofiller($this); } }
The replacement is used wherever that object is reached, including
submitAndWait(), which autofills through the Submitter rather than through
the client. The same works for getSubmitter(), getAccountReader(),
getOrderbookReader(), getFeeCalculator() and getFaucet().
A dedicated Xahau package building on this is planned; the Xahau types will then move out of this library.
Development
Running the project via Docker
- Tell the container which user to run as, so the files it writes belong to
you. The values differ between Linux and macOS, so they come from
.env:
printf 'DOCKER_UID=%s\nDOCKER_GID=%s\n' "$(id -u)" "$(id -g)" > .env
- Start the project and open a shell:
docker compose up -d docker compose exec php bash
- In the container shell, install the composer dependencies:
composer install
The image is built from docker/. Xdebug is preconfigured to reach the host on
port 9090 via host.docker.internal, which works on Linux as well because the
compose file maps it to the host gateway. For anything else that is specific to
your machine, add a docker-compose.override.yml; it is gitignored.
Running the tests
You can run the tests with the following command:
./vendor/bin/phpunit tests
You can perform static code analysis with psalm with the following command:
./vendor/bin/psalm --config=psalm.xml