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

Substrate Codec Php Laravel Package

gmajor/substrate-codec-php

PHP implementation of the Substrate SCALE codec for encoding and decoding Polkadot/Substrate data structures, with compact serialization for integers, strings, arrays, tuples, and custom types in PHP applications.

View on GitHub
Deep Wiki
Context7

Getting Started

gmajor/substrate-codec-php is a SCALE (Simple Concatenated Aggregate Little-Endian) codec plus a thin Substrate helper layer: type encoding/decoding, compact integers, composite/struct types, SS58 addresses, keyring signing, and extrinsic/RPC plumbing. For a Laravel developer the value is narrow but sharp: when your app has to read or write raw Substrate bytes — storage values from an indexer, call data for offline signing, or hex blobs pulled from state_getStorage — this package lets you do it in PHP instead of standing up a Node sidecar. If you only ever consume a friendly REST API, you probably don't need it.

Minimal setup:

composer require gmajor/substrate-codec-php

There is no service provider, no config file, no facade. It is a plain library, so you wire it yourself:

// config/services.php
'substrate' => [
    'rpc'       => env('SUBSTRATE_RPC', 'wss://rpc.polkadot.io'),
    'ss58'      => (int) env('SUBSTRATE_SS58_PREFIX', 0),  // 0 = Polkadot, 2 = Kusama, 42 = generic
    'decimals'  => (int) env('SUBSTRATE_DECIMALS', 10),
],
// app/Providers/SubstrateServiceProvider.php
public function register(): void
{
    $this->app->singleton(Substrate::class, fn () => new Substrate(
        config('services.substrate.rpc')
    ));
}

Where to look first, in this order: src/ for the codec entry point and the Substrate helper, then tests/ — for a small, low-star package the test suite is the real documentation, since it holds the known-good vectors. The README covers the happy path only.

First use case, and the one you'll hit 80% of the time: decoding an account's on-chain balance. System.Account returns a SCALE blob of AccountInfo — nonce, consumers, providers, sufficients, { free, reserved, frozen, flags } — where the three balance fields are u128. Decoding that gives you balances your app can display and reconcile, without trusting a third-party API's formatting.

// Illustrative — confirm exact method names against vendor/gmajor/... on install
$info = $codec->decode($accountInfoType, $storageHex);

$free = $info['data']['free']; // u128 — comes back as string, not int

Implementation Patterns

1. Type-driven decoding of RPC payloads. SCALE is not self-describing; you supply the shape. Build the descriptor once (as a constant or a small class) and reuse it:

final class Types
{
    public const ACCOUNT_INFO = 'AccountInfo';      // nonce/consumers/providers/sufficients + AccountData
    public const ACCOUNT_DATA = 'AccountData';      // free/reserved/frozen/flags, all u128
}

Keep descriptors in one file per chain. When a runtime upgrade changes a struct, you change one line and the diff is reviewable.

2. Encode calls, don't hand-roll hex. For transfers, staking, governance votes — build the call data from a pallet/call index plus SCALE-encoded args, then submit or hand off for signing:

$callData = $codec->encodeCall(
    palletIndex: $meta['Balances'],   // read from metadata, never hardcode
    callIndex:   $meta['transfer_keep_alive'],
    args:        [$destAddress, $amountPlanck],
);

3. Wrap the client in a service, not in controllers. The Substrate helper is stateful (websocket/RPC connection). Bind it as a singleton, expose intention-revealing methods, and let the container handle lifecycle:

final class ChainGateway
{
    public function __construct(private Substrate $client) {}

    public function balanceOf(string $ss58): string { /* decode + format */ }
    public function buildTransfer(string $to, string $planck): string { /* encoded call */ }
}

4. Format balances at the boundary. Store planck as string in the DB (decimal(38,0) or varchar), convert to human units only in the presenter. A u128 does not fit in PHP's 64-bit int — see Gotchas.

5. Offline signing / air-gapped flows. Encode the call → construct the payload with the correct specVersion, transactionVersion, genesisHash, blockHash, era, nonce, tip and the chain's signed extensions in metadata order → sign with the keyring → submit the signed extrinsic hex. This is the most fragile path in the package and the one most worth a test.

6. Verification loop with polkadot-js. During development, encode the same value in polkadot-js (api.registry.createType(...).toHex()) and assert byte equality against this package's output. Keep those pairs as PHPUnit data providers; they become your regression net across runtime upgrades.

7. Prefer reads over writes where you can. If you only need balances, events and block data, substrate-api-sidecar or a hosted indexer will save you a lot of pain. Reserve this package for the write path and for byte-exact decoding tasks.

Gotchas and Tips

  • No self-description. Decoding with the wrong type doesn't error — it silently returns structured garbage. Always round-trip: encode the decoded value and assert it equals the original hex.
  • u128 overflows PHP ints. Polkadot's total issuance (~1.4e9 DOT → ~1.4e19 planck) exceeds PHP_INT_MAX (~9.2e18). Treat all amounts as strings or use bcmath/gmp. This is the single most common bug in PHP Substrate integrations.
  • Compact vs fixed integers. Compact<u128> and u128 have different byte widths. Balances in storage are usually plain u128; nonces and indices are often Compact. Mixing them shifts every subsequent field.
  • Everything is little-endian. When hand-verifying hex, remember the low byte comes first.
  • Never hardcode pallet/call indices or signed extension order. Read them from chain metadata. A runtime upgrade that inserts a new signed extension will invalidate every signed payload your app builds — and the failure is an opaque "invalid transaction" from the node.
  • SS58 prefix is per-chain. An address encoded with prefix 42 is valid but will look wrong (and may be rejected by UI validation) on Polkadot (0) or Kusama (2). Decode to the public key, re-encode to the target prefix.
  • Connections are stateful and fragile. WebSocket clients die silently. Set timeouts, reconnect per job, and never share a socket across queue workers. Wrap RPC calls in retry() with backoff.
  • Bus factor of one. 8 stars, 0 dependents, MIT. It works, but assume you may have to patch it. Pin an exact version ("gmajor/substrate-codec-php": "0.x.y"), vendor nothing critical on a path you can't rewrite, and keep your own codec wrapper thin so a swap to polkadot-js via a Node microservice stays a one-file change.
  • Debugging toolkit: log the input hex and the descriptor on every failure; compare against Subscan's "raw" view; use state_getStorage directly rather than a wrapper so you see real bytes.
  • Extension points: the keyring and the type registry are the two things you'll realistically want to subclass — a custom signer (HSM/KMS) and custom composite types for your parachain's structs. Everything else is a static codec and doesn't need extending.
  • Tests first. Before writing a single integration call, add a data-provider test with three known hex/value pairs from a real chain. That test will catch every upstream change that matters.
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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons