PHP SCALE Codec For substrate
composer require gmajor/substrate-codec-php
Codec supports PSR-4
autoloaders.
<?php
# When installed via composer
require_once 'vendor/autoload.php';
<?php
use Codec\ScaleBytes;
use Codec\Base;
use Codec\Types\ScaleInstance;
$codec = new ScaleInstance(Base::create());
// Uint Support U8, U16, U32, U64, U128
$codec->process("U8", new ScaleBytes("64"));
$codec->process("U16", new ScaleBytes("0300"));
$codec->process("U32", new ScaleBytes("64000000"));
$codec->process("U64", new ScaleBytes("471b47acc5a70000"));
$codec->process("U128", new ScaleBytes("e52d2254c67c430a0000000000000000"));
// Compact Support Compact int or other Mixed type, like Compact<Balance>
// Compact decode always return GMP type
$codec->process("Compact", new ScaleBytes("02093d00"));
// Address Support Address/Account Id/MultiAddress
$codec->process("Address", new ScaleBytes("ff1fa9d1bd1db014b65872ee20aee4fd4d3a942d95d3357f463ea6c799130b6318"));
// Option
$codec->process("Option<bool>", new ScaleBytes("02"));
// String
$codec->process("String", new ScaleBytes("1054657374"));
// Bytes
$codec->process("Bytes", new ScaleBytes("08ffff"));
// Vec
$codec->process("Vec<(u32, u32, u16)>", new ScaleBytes("08cc0200000000ce0200000001"));
$codec->process("Vec<u8>", new ScaleBytes("08ffff"));
// Enum with value list
$codec =$codec->createTypeByTypeString("Enum");
$codec->valueList = [0, 1, 49, 50];
$codec->init(new ScaleBytes("02"));
$codec->decode();
// Enum with struct
$codec->typeStruct = ["int" => "u8", "bool" => "bool"];
$codec->init(new ScaleBytes("0x002a"));
$codec->decode();
// Struct
$codec =$codec->createTypeByTypeString("Struct");
$codec->typeStruct = ["a" => "Compact<u32>", "b" => "Compact<u32>"];
$codec->init(new ScaleBytes("0c00"));
$codec->decode();
// Tuple
$codec->process("(u8, u16, u32)", new ScaleBytes("01900100350c00"));
// Result
$codec->process("Result<u8, bool>", new ScaleBytes("0x002a"));
$codec->process("Result<u8, bool>", new ScaleBytes("0x0100"));
<?php
use Codec\Base;
use Codec\Types\ScaleInstance;
$codec = new ScaleInstance(Base::create());
// uint, encode support U8, U16, U32, U64, U128, Note that php int type support needs to be less than 9223372036854775807,
// if it exceeds, it needs to be changed to string type
$codec->createTypeByTypeString("U8")->encode(300);
$codec->createTypeByTypeString("U16")->encode(5000);
$codec->createTypeByTypeString("U32")->encode(100100100);
$codec->createTypeByTypeString("U64")->encode(184467440737095);
$codec->createTypeByTypeString("U128")->encode(739571955075788261);
// Compact
// Compact encode only support Int/GMP, if value is greater than 1073741823 (2**30-1), please use GMP type
// https://www.php.net/manual/en/function.gmp-init.php
$codec->createTypeByTypeString("Compact")->encode(2503000000000000000);
// Address
$codec->createTypeByTypeString("Address")->encode("1fa9d1bd1db014b65872ee20aee4fd4d3a942d95d3357f463ea6c799130b6318");
// Option
$codec->createTypeByTypeString("option<Compact>")->encode(63);
// String
$codec->createTypeByTypeString("String")->encode("Test");
// Bytes
$codec->createTypeByTypeString("Bytes")->encode("0xffff");
// Vec
$codec->createTypeByTypeString("Vec<u32>")->encode([1, 2, 3, 4]);
// Enum with value list
$codec =$codec->createTypeByTypeString("Enum");
$codec->valueList = [0, 1, 49, 50];
$codec->encode(49);
// Enum with struct
$codec->typeStruct = ["int" => "u8", "bool" => "bool"];
$codec->encode(["bool" => true]);
// Struct
$codec = $codec->createTypeByTypeString("Struct");
$codec->typeStruct = ["a" => "Compact", "b" => "Compact"];
$codec->encode(["a" => 3, "b" => 0]);
// Tuple
$codec->createTypeByTypeString("(u8, u16, u32)")->encode([1, 400, 800000]);
// Result
$codec->createTypeByTypeString("Result<u8, bool>")->encode(["Err" => false]);
All substrate Pallet types will be registered by default, refer to https://github.com/polkadot-js/api/tree/master/packages/types/src/interfaces, because the substrate itself is updated frequently, so https://github.com/gmajor-encrypt/php-scale-codec/tree/m2/src/Codec/interfaces will also be updated frequently here.
There are more than 50 polkadot-related applications so far, here are some custom types that need to be registered, here are some examples for reference
About custom type of documentation can be found here
<?php
use Codec\Base;
use Codec\ScaleBytes;
use Codec\Types\ScaleInstance;
$generator = Base::create();
Base::regCustom($generator,[
// direct
"a"=> "balance",
// struct
"b"=> ["b1"=>"u8","b2"=>"vec<u32>"],
// enum
"c"=> ["_enum"=>["c1","c2","c3"]],
// tuple
"d"=> "(u32, bool)",
// fixed
"e"=> "[u32; 5]",
// set
"f"=> ["_set"=>["_bitLength"=>64,"f1"=>1,"f2"=>2,"f3"=>4,"f4"=>8]]
]);
$codec = new ScaleInstance($generator);
// inherit
$this->assertEquals($codec->process("a", new ScaleBytes($codec->createTypeByTypeString("a")->encode(gmp_init(739571955075788261)))), gmp_init(739571955075788261));
// struct
$this->assertEquals($codec->process("b", new ScaleBytes($codec->createTypeByTypeString("b")->encode(["b1" => 1, "b2" => [1, 2]]))), ["b1" => 1, "b2" => [1, 2]]);
// enum
$this->assertEquals($codec->process("c", new ScaleBytes($codec->createTypeByTypeString("c")->encode("c2"))), "c2");
// tuple
$this->assertEquals($codec->process("d", new ScaleBytes($codec->createTypeByTypeString("d")->encode([1, true]))), [1, true]);
// fixed
$this->assertEquals($codec->process("e", new ScaleBytes($codec->createTypeByTypeString("e")->encode([1, 2, 3, 4, 5]))), [1, 2, 3, 4, 5]);
// set
$this->assertEquals($codec->process("f", new ScaleBytes($codec->createTypeByTypeString("f")->encode(["f1", "f2"]))), ["f1", "f2"]);
?>
For more information on metadata, please refer to https://substrate.dev/docs/en/knowledgebase/runtime/metadata#metadata-formats
Currently, metadata decode/encode only supports v12/13/v14 More test you can found here https://github.com/gmajor-encrypt/php-scale-codec/blob/master/test/Codec/Test/MetadataTest.php
<?php
use Codec\Base;
use Codec\ScaleBytes;
use Codec\Types\ScaleInstance;
$metadataV13 = "..."; // from json rpc state_getMetadata
$codec = new ScaleInstance(Base::create());
// decode
$metadataInstant = $codec->process("metadata", new ScaleBytes($metadataV13));
// encode
$codec->createTypeByTypeString("metadata")->encode($metadataInstant);
print_r($metadataInstant);
?>
For more information on Extrinsic, please refer to https://substrate.dev/docs/en/knowledgebase/learn-substrate/extrinsics
More test you can found here https://github.com/gmajor-encrypt/php-scale-codec/blob/master/test/Codec/Test/ExtrinsicTest.php
<?php
use Codec\Base;
use Codec\ScaleBytes;
use Codec\Types\ScaleInstance;
$metadataV13 = "..."; // from json rpc state_getMetadata
$codec = new ScaleInstance(Base::create());
$metadataInstant = $codec->process("metadata", new ScaleBytes($metadataV13));
// decode
$decodeExtrinsic = $codec->process("Extrinsic", new ScaleBytes("0x280403000b819fc2837a01"), $metadataInstant);
// encode
$codec->createTypeByTypeString("Extrinsic")->setMetadata($metadataInstant["metadata"])->encode($decodeExtrinsic);
?>
For more information on Event, please refer to https://substrate.dev/docs/en/knowledgebase/runtime/events
More test you can found here https://github.com/gmajor-encrypt/php-scale-codec/blob/master/test/Codec/Test/EventTest.php
<?php
use Codec\Base;
use Codec\ScaleBytes;
use Codec\Types\ScaleInstance;
$metadataV13 = "..."; // from json rpc state_getMetadata
$codec = new ScaleInstance(Base::create());
$metadataInstant = $codec->process("metadata", new ScaleBytes($metadataV13));
$decodeExtrinsic = $codec->process("Vec<EventRecord>", new ScaleBytes("0x080000000000000050e90b0b000000000200000001000000000080b2e60e00000000020000"), $metadataInstant);
?>
More examples can refer to the test file https://github.com/gmajor-encrypt/php-scale-codec/tree/master/test/Codec/Test
make test
The package is available as open source under the terms of the MIT License