Contractless-PHP-RPC/README.md

5.8 KiB

PHP Contractless RPC

contractless-php-rpc connects PHP applications directly to a Contractless node. It implements the authenticated binary RPC protocol without invoking Contractless CLI programs.

The package is intended for faucets, block explorers, wallets, application backends, and other public Contractless integrations.

Scope

The client includes public blockchain lookups, wallet and address lookups, mempool lookups, asset lookups, loan lookups, storage lookups, governance lookups, wallet registration, signed transaction submission, and an RPC interface restricted to application-safe commands.

Miner relay commands, network mapping changes, monitor-state commands, node setup synchronization, and server-owner IP controls are intentionally not exposed.

Requirements

  • PHP 8.1 or newer, running as a 64-bit build
  • The PHP GD extension
  • The PHP OpenSSL extension
  • The skein module from contractless-php-crypto
  • The oqsphp module from contractless-php-crypto

Contractless uses the same Falcon key and signature sizes as Falcon-padded-512, but its FN-DSA signing mode requires a small message adaptation. NativeCrypto performs that adaptation automatically.

Installation

Install and enable contractless-php-crypto first. Its repository contains the native module build, installation, and compatibility-test instructions.

When this package is available through Packagist:

composer require contractless/contractless-php-rpc

Until the package is published, add it as a Composer path repository:

{
  "repositories": [
    {
      "type": "path",
      "url": "../contractless-php-rpc"
    }
  ],
  "require": {
    "contractless/contractless-php-rpc": "@dev"
  }
}

Then install it:

composer update contractless/contractless-php-rpc

Basic Use

<?php

require __DIR__ . '/vendor/autoload.php';

use Contractless\Rpc\Client;
use Contractless\Rpc\Crypto\NativeCrypto;
use Contractless\Rpc\Transport\StreamTransport;
use Contractless\Rpc\Wallet\Credentials;

$credentials = Credentials::fromHex(
    getenv('CONTRACTLESS_PUBLIC_KEY'),
    getenv('CONTRACTLESS_PRIVATE_KEY'),
);
$crypto = new NativeCrypto();

$client = new Client(
    new StreamTransport('127.0.0.1', 50050),
    $crypto,
    $credentials,
);

echo $client->totalBalance(
    'ab13318c26250b048db92920a80a86127c933b0c.cltc',
);

RPC replies are returned as their original bytes. Commands that return JSON can be decoded with json_decode($reply, true, flags: JSON_THROW_ON_ERROR). Binary block, torrent, header, and transaction replies remain available without a lossy conversion.

Transaction Submission

submitTransaction() accepts the complete serialized signed transaction as a hexadecimal string:

$reply = $client->submitTransaction($signedTransactionHex);

The first transaction builder covers the transfer used by faucets and ordinary currency, token, NFT, and RWA transfers:

use Contractless\Rpc\Transaction\TransferBuilder;

$transfer = (new TransferBuilder($crypto, $credentials))->create(
    sender: 'sender-address.cltc',
    receiver: 'receiver-address.cltc',
    coin: 'CLTC',
    value: 2_500_000_000,
    fee: 2_500,
);

$reply = $client->submitSignedTransaction($transfer);

Transaction builders are a separate layer over the protocol client. This keeps transport and node access stable when new transaction types are introduced.

Transaction Builders

  • TransferBuilder: currency, token, NFT, and RWA transfers
  • AssetBuilder: token creation, token issuance, NFT/RWA creation, burns, and vanity addresses
  • AgreementBuilder: two-party swaps and loan contracts
  • MiscellaneousBuilder: marketing records, loan payments, and collateral claims
  • StorageBuilder: storage keys, bool, signed and unsigned integers, strings, and deletion
  • GovernanceBuilder: proposal keys, proposal votes, and activation votes

Swaps and loans return DualSignedTransaction. The first signer exports it, the second signer imports it and calls signNext(), and only a complete result can be converted with toSignedTransaction() and broadcast.

The 128-bit storage methods accept decimal strings. This preserves the complete Rust u128 and i128 ranges instead of silently losing precision through PHP integers or floating-point numbers.

Wallet Material

The library can load a normal Contractless wallet file directly:

use Contractless\Rpc\Wallet\Credentials;

$credentials = Credentials::fromWalletFile(
    '/private/path/contractless.wallet',
    'wallet decryption key',
);

The loader decodes all supported Contractless private-key image orientations, verifies the encrypted payload HMAC, decrypts the Falcon private key, proves that the public and private keys match, and verifies the wallet's canonical short address.

Wallet files and decryption keys must remain outside public web directories, logs, repositories, and client-visible configuration.

Verify a wallet file and decryption key before using them in an application:

php examples/load_wallet.php /private/path/contractless.wallet 'wallet decryption key'

Successful output confirms that the image was decoded, its encrypted payload was authenticated and decrypted, the Falcon keypair matches, and the wallet address is valid.

Raw Falcon key bytes remain supported for applications that already manage their own protected key storage:

$credentials = Credentials::fromHex($publicKeyHex, $privateKeyHex);

Testing

composer install
composer test

Preparing The Composer Package

Validate the package before publishing:

composer validate --strict
composer install
composer test

Commit composer.json, README.md, src/, and tests/ to the contractless-php-rpc repository. Create a release tag such as v0.1.0, then submit the repository URL to Packagist. Future version tags become installable Composer releases.