chore(papi): commit the sources behind the four polkadot-api packages

papi-utils, bizinikiwi-bindings, metadata-builders and merkleize-metadata
held only dist/ builds, and no repository held their source. Every
source map in dist/ embeds the TypeScript it was compiled from; that is
now committed as src/ (59 files), and it matches upstream polkadot-api
(MIT) exactly once @polkadot-api/* imports are renamed:

  papi-utils           @polkadot-api/utils 0.2.0
  bizinikiwi-bindings  @polkadot-api/substrate-bindings 0.16.6
  metadata-builders    @polkadot-api/metadata-builders 0.13.0-0.13.2
  merkleize-metadata   @polkadot-api/merkleize-metadata 1.1.21-1.1.23

scripts/check-papi-sources.mjs, run in the lint job, fails unless the
source embedded in dist/ is exactly the committed src/. tsconfig.json
excludes these src/ trees; ESLint already skipped the packages. Each
README now states the upstream package and version.
This commit is contained in:
Satoshi Qazi Muhammed committed 2026-10-19 21:08:01 +04:00
1 parent 622f49e4a8
commit ea8cb96cea
67 files changed
+4678 -6

No files matched your search

+152
View File
@@ -0,0 +1,152 @@
import {
Bytes,
Codec,
CodecType,
Option,
ScaleEnum,
Struct,
Tuple,
V14Lookup,
Vector,
_void,
bool,
compact,
compactNumber,
extrinsicFormat,
str,
u16,
u32,
u8,
} from "@pezkuwi/bizinikiwi-bindings"
const extraInfoInner = {
specVersion: u32,
specName: str,
base58Prefix: u16,
decimals: u8,
tokenSymbol: str,
}
export const extraInfo = Struct(extraInfoInner)
export type ExtraInfo = CodecType<typeof extraInfo>
export const hash = Bytes(32)
export const metadataDigest = ScaleEnum({
V0: _void,
V1: Struct({
typeInformationTreeRoot: hash,
extrinsicMetadataHash: hash,
...extraInfoInner,
}),
})
export type MetadataDigest = CodecType<typeof metadataDigest>
export const scalePrimitive = ScaleEnum({
bool: _void,
char: _void,
str: _void,
u8: _void,
u16: _void,
u32: _void,
u64: _void,
u128: _void,
u256: _void,
i8: _void,
i16: _void,
i32: _void,
i64: _void,
i128: _void,
i256: _void,
})
export type ScalePrimitive = CodecType<typeof scalePrimitive>
export const typeRef = ScaleEnum({
bool: _void,
char: _void,
str: _void,
u8: _void,
u16: _void,
u32: _void,
u64: _void,
u128: _void,
u256: _void,
i8: _void,
i16: _void,
i32: _void,
i64: _void,
i128: _void,
i256: _void,
compactU8: _void,
compactU16: _void,
compactU32: _void,
compactU64: _void,
compactU128: _void,
compactU256: _void,
void: _void,
perId: compactNumber,
})
export type TypeRef = CodecType<typeof typeRef>
const field = Struct({
name: Option(str),
ty: typeRef,
typeName: Option(str),
})
export const typeDef = ScaleEnum({
composite: Vector(field),
enumeration: Struct({
name: str,
fields: Vector(field),
index: compactNumber,
}),
sequence: typeRef,
array: Struct({
len: u32,
typeParam: typeRef,
}),
tuple: Vector(typeRef),
bitSequence: Struct({
numBytes: u8,
leastSignificantBitFirst: bool,
}),
})
export type TypeDef = CodecType<typeof typeDef>
export const lookupType = Struct({
path: Vector(str),
typeDef: typeDef,
typeId: compactNumber,
})
export type LookupEntry = CodecType<typeof lookupType>
export type Lookup = Array<LookupEntry>
export const lookup: Codec<Lookup> = Vector(lookupType)
export const extrinsicMetadata = Struct({
version: u8,
addressTy: typeRef,
callTy: typeRef,
signatureTy: typeRef,
signedExtensions: Vector(
Struct({
identifier: str,
includedInExtrinsic: typeRef,
includedInSignedData: typeRef,
}),
),
})
export type ExtrinsicMetadata = CodecType<typeof extrinsicMetadata>
export type LookupValue = V14Lookup[number]
export const extrinsicDec = Tuple.dec(
compact[1],
extrinsicFormat[1],
Bytes(Infinity)[1],
)
export const proof = Struct({
leaves: lookup,
leafIdxs: Vector(u32),
proofs: Vector(hash),
extrinsic: extrinsicMetadata,
info: extraInfo,
})
export type Proof = CodecType<typeof proof>
@@ -0,0 +1,135 @@
import {
HexString,
_void,
compact,
createDecoder,
i128,
i16,
i256,
i32,
i64,
i8,
str,
u128,
u16,
u256,
u32,
u64,
u8,
} from "@pezkuwi/bizinikiwi-bindings"
import { Lookup, TypeDef, TypeRef } from "./codecs"
const typeRefDecoders = {
bool: u8,
char: u8,
str,
u8,
u16,
u32,
u64,
u128,
u256,
i8,
i16,
i32,
i64,
i128,
i256,
void: _void,
compactU8: compact,
compactU16: compact,
compactU32: compact,
compactU64: compact,
compactU128: compact,
compactU256: compact,
}
const innerDecodeAndCollect = (
input: Uint8Array,
typeRef: TypeRef,
idToLookups: Map<number, Array<number>>,
lookup: Lookup,
collected: Set<number>,
) => {
if (typeRef.tag !== "perId") {
typeRefDecoders[typeRef.tag][1](input)
return
}
const handleTypeRef = (typeRef: TypeRef) => {
innerDecodeAndCollect(input, typeRef, idToLookups, lookup, collected)
}
const lookupIdxs = idToLookups.get(typeRef.value)!
const [currentIdx] = lookupIdxs
const current = lookup[currentIdx]
if (lookupIdxs.length === 1) collected.add(currentIdx)
switch (current.typeDef.tag) {
case "enumeration": {
const selectedIdx = u8.dec(input)
const [selected, collectedIdx] = lookupIdxs
.map(
(lookupIdx) =>
[lookup[lookupIdx].typeDef, lookupIdx] as [
TypeDef & { tag: "enumeration" },
number,
],
)
.find(([x]) => x.value.index === selectedIdx)!
collected.add(collectedIdx)
selected.value.fields.forEach(({ ty }) => {
handleTypeRef(ty)
})
break
}
case "sequence": {
const len = compact.dec(input)
for (let i = 0; i < len; i++) handleTypeRef(current.typeDef.value)
break
}
case "array": {
for (let i = 0; i < current.typeDef.value.len; i++)
handleTypeRef(current.typeDef.value.typeParam)
break
}
case "composite": {
current.typeDef.value.forEach((x) => {
handleTypeRef(x.ty)
})
break
}
case "tuple": {
current.typeDef.value.forEach(handleTypeRef)
break
}
case "bitSequence":
throw new Error("bitSequence is not supported")
}
}
export const decodeAndCollectKnownLeafs = (
data: Uint8Array | HexString,
typeRefs: Array<TypeRef>,
lookup: Lookup,
): Array<number> => {
let input: Uint8Array<ArrayBufferLike> = new Uint8Array()
createDecoder((_input) => {
input = _input
})(data)
const idToLookups = new Map<number, number[]>()
lookup.forEach((lookup, idx) => {
const arr = idToLookups.get(lookup.typeId)
if (arr) arr.push(idx)
else idToLookups.set(lookup.typeId, [idx])
})
const result = new Set<number>()
typeRefs.forEach((typeRef) => {
innerDecodeAndCollect(input, typeRef, idToLookups, lookup, result)
})
return [...result].sort((a, b) => a - b)
}
@@ -0,0 +1,60 @@
import { UnifiedMetadata } from "@pezkuwi/bizinikiwi-bindings"
import { LookupValue } from "./codecs"
export const getAccessibleTypes = (
metadata: UnifiedMetadata<15 | 16>,
definitions: Map<number, LookupValue>,
): Map<number, number> => {
const types = new Set<number>()
const collectTypesFromId = (id: number) => {
if (types.has(id)) return
const { tag, value } = definitions.get(id)!.def
switch (tag) {
case "composite":
if (!value.length) break
types.add(id)
value.forEach(({ type }) => {
collectTypesFromId(type)
})
break
case "variant":
if (!value.length) break
types.add(id)
value.forEach(({ fields }) => {
fields.forEach(({ type }) => {
collectTypesFromId(type)
})
})
break
case "tuple":
if (!value.length) break
types.add(id)
value.forEach(collectTypesFromId)
break
case "sequence":
types.add(id)
collectTypesFromId(value)
break
case "array":
types.add(id)
collectTypesFromId(value.type)
break
case "bitSequence": // bitSequence inner types are not stored
types.add(id)
// primitive and compact are not stored
}
}
collectTypesFromId(metadata.extrinsic.call)
collectTypesFromId(metadata.extrinsic.address)
collectTypesFromId(metadata.extrinsic.signature)
metadata.extrinsic.signedExtensions.forEach(({ type, additionalSigned }) => {
collectTypesFromId(type)
collectTypesFromId(additionalSigned)
})
const sortedTypes = [...types].sort((a, b) => a - b)
return new Map(sortedTypes.map((value, idx) => [value, idx]))
}
@@ -0,0 +1,119 @@
import { Lookup, LookupValue, ScalePrimitive, TypeDef, TypeRef } from "./codecs"
const bitSequenceBytes = {
u8: 1,
u16: 2,
u32: 4,
u64: 8,
}
const constructTypeDef = (
definitions: Map<number, LookupValue>,
getTypeRef: (frameId: number) => TypeRef,
getPrimitive: (frameId: number) => ScalePrimitive["tag"] | null,
frameId: number,
): TypeDef[] => {
const {
def: { tag, value },
} = definitions.get(frameId)!
switch (tag) {
case "composite":
return [
{
tag,
value: value.map((f) => ({
name: f.name,
typeName: f.typeName,
ty: getTypeRef(f.type),
})),
},
]
case "variant": {
return value.map((v) => ({
tag: "enumeration",
value: {
name: v.name,
index: v.index,
fields: v.fields.map((f) => ({
name: f.name,
typeName: f.typeName,
ty: getTypeRef(f.type),
})),
},
}))
}
case "sequence":
return [
{
tag,
value: getTypeRef(value),
},
]
case "array":
return [
{
tag,
value: {
len: value.len,
typeParam: getTypeRef(value.type),
},
},
]
case "tuple":
return [
{
tag,
value: value.map(getTypeRef),
},
]
case "bitSequence": {
const primitive = getPrimitive(value.bitStoreType)
const numBytes = bitSequenceBytes[primitive as "u8"]
if (!numBytes) throw new Error("Invalid primitive for BitSequence")
const storeOrderPath = definitions.get(value.bitOrderType)!.path
const leastSignificantBitFirst = storeOrderPath.includes("Lsb0")
if (!leastSignificantBitFirst && !storeOrderPath.includes("Msb0"))
throw new Error("BitOrderType not recognized")
return [
{
tag: "bitSequence",
value: { numBytes, leastSignificantBitFirst },
},
]
}
}
throw new Error(`FrameId(${frameId}) should have been filtered out`)
}
export const getLookup = (
definitions: Map<number, LookupValue>,
accessibleTypes: Map<number, number>,
getTypeRef: (frameId: number) => TypeRef,
getPrimitive: (frameId: number) => ScalePrimitive["tag"] | null,
) => {
const typeTree: Lookup = []
;[...accessibleTypes.entries()].forEach(([frameId, typeId]) => {
const { path } = definitions.get(frameId)!
constructTypeDef(definitions, getTypeRef, getPrimitive, frameId).forEach(
(typeDef) => {
typeTree.push({
path,
typeId,
typeDef,
})
},
)
})
typeTree.sort((a, b) => {
if (a.typeId !== b.typeId) return a.typeId - b.typeId // in general
// should only happen for variants
if (a.typeDef.tag !== "enumeration" || b.typeDef.tag !== "enumeration")
throw new Error("Found two types with same id")
return a.typeDef.value.index - b.typeDef.value.index
})
return typeTree
}
@@ -0,0 +1,18 @@
import {
decAnyMetadata,
UnifiedMetadata,
type HexString,
unifyMetadata,
} from "@pezkuwi/bizinikiwi-bindings"
export const getMetadata = (
input: Uint8Array | HexString,
): UnifiedMetadata<15 | 16> => {
try {
const metadata = unifyMetadata(decAnyMetadata(input))
if (metadata.version <= 14) throw new Error("Wrong metadata version")
return metadata as UnifiedMetadata<15 | 16>
} catch (e) {
throw e || new Error("Unable to decode metadata")
}
}
+294
View File
@@ -0,0 +1,294 @@
import {
Blake3256,
HexString,
compact,
u32,
} from "@pezkuwi/bizinikiwi-bindings"
import {
ExtraInfo,
ExtrinsicMetadata,
LookupValue,
MetadataDigest,
ScalePrimitive,
TypeRef,
extraInfo,
extrinsicMetadata,
lookupType,
metadataDigest,
extrinsicDec,
} from "./codecs"
import { getAccessibleTypes } from "./get-accessible-types"
import { getLookup } from "./get-lookup"
import { getMetadata } from "./get-metadata"
import { compactTypeRefs, toBytes } from "./utils"
import { decodeAndCollectKnownLeafs } from "./decode-and-collect"
import { getProofData } from "./proof"
import { getDynamicBuilder, getLookupFn } from "@pezkuwi/metadata-builders"
import { mergeUint8 } from "@pezkuwi/papi-utils"
export interface MetadataMerkleizer {
/**
* @returns Digest value of the metadata (aka its merkleized root-hash)
*/
digest: () => Uint8Array
/**
* Get proof for an `Extrinsic`.
*
* @param transaction Encoded `Extrinsic`, both signed or unsigned.
* @param txAdditionalSigned Optionally collect types for given
* `additionalSigned` part of signedExtensions.
* @returns Encoded `Proof`
*/
getProofForExtrinsic: (
transaction: Uint8Array | HexString,
txAdditionalSigned?: Uint8Array | HexString,
) => Uint8Array
/**
* Get proof for `ExtrinsicPayload` parts.
*
* @param callData Call data of the transaction. It has to be
* bare; i.e.
* without prepended compact length.
* @param includedInExtrinsic Extra part of the signed extensions, all of
* them concatenated.
* @param includedInSignedData Additional signed part of the signed
* extensions, all of them concatenated.
* @returns Encoded `Proof`
*/
getProofForExtrinsicParts: (
callData: Uint8Array | HexString,
includedInExtrinsic: Uint8Array | HexString,
includedInSignedData: Uint8Array | HexString,
) => Uint8Array
/**
* Get proof for `ExtrinsicPayload`.
*
* @param extrinsicPayload Call data, extra part of signedExtensions and
* additional signed part of signedExtensions
* concatenated. It has to be bare; i.e. without
* prepended compact length.
* @returns Encoded `Proof`
*/
getProofForExtrinsicPayload: (
extrinsicPayload: Uint8Array | HexString,
) => Uint8Array
}
const assertExpected = <T>(name: string, expected: T, received?: T): void => {
if (received != null && received !== expected)
throw new Error(
`${name} not expected. Received ${received} expected ${expected}`,
)
}
export const merkleizeMetadata = (
metadataBytes: Uint8Array | HexString,
{
decimals,
tokenSymbol,
...hinted
}: { decimals: number; tokenSymbol: string } & Partial<ExtraInfo>,
): MetadataMerkleizer => {
const metadata = getMetadata(metadataBytes)
const checkedVersion = metadata.extrinsic.version.includes(4) ? 4 : null
if (checkedVersion == null) throw new Error("Only extrinsic v4 is supported")
const { ss58Prefix, buildDefinition } = getDynamicBuilder(
getLookupFn(metadata),
)
if (ss58Prefix == null) throw new Error("SS58 prefix not found in metadata")
assertExpected("SS58 prefix", ss58Prefix, hinted.base58Prefix)
const version = metadata.pallets
.find((x) => x.name === "System")
?.constants.find((x) => x.name === "Version")
if (version == null) throw new Error("System.Version constant not found")
const { spec_name: specName, spec_version: specVersion } = buildDefinition(
version.type,
).dec(version.value)
if (typeof specName !== "string" || typeof specVersion !== "number")
throw new Error("Spec name or spec version not found")
assertExpected("Spec name", specName, hinted.specName)
assertExpected("Spec version", specVersion, hinted.specVersion)
const info: ExtraInfo = {
decimals,
tokenSymbol,
specVersion,
specName,
base58Prefix: ss58Prefix,
}
const definitions = new Map<number, LookupValue>(
metadata.lookup.map((value) => [value.id, value]),
)
const accessibleTypes = getAccessibleTypes(metadata, definitions)
const getPrimitive = (frameId: number): ScalePrimitive["tag"] | null => {
const {
def: { tag, value },
} = definitions.get(frameId)!
if (tag === "primitive") return value.tag
if ((tag !== "composite" && tag !== "tuple") || value.length > 1)
throw new Error("The provided definition doesn't map to a primitive")
return value.length === 0
? null // signals `void`
: getPrimitive(tag === "tuple" ? value[0] : value[0].type)
}
const getTypeRef = (frameId: number): TypeRef => {
const { def } = definitions.get(frameId)!
if (def.tag === "primitive") return { tag: def.value.tag, value: undefined }
if (def.tag === "compact") {
const primitive = getPrimitive(def.value)
const tag = compactTypeRefs[primitive as "u8"]
if (!tag) throw new Error("Invalid primitive for Compact")
return { tag, value: undefined }
}
return accessibleTypes.has(frameId)
? { tag: "perId", value: accessibleTypes.get(frameId)! }
: { tag: "void", value: undefined }
}
const extrinsic: ExtrinsicMetadata = {
version: checkedVersion,
addressTy: getTypeRef(metadata.extrinsic.address),
callTy: getTypeRef(metadata.extrinsic.call),
signatureTy: getTypeRef(metadata.extrinsic.signature),
signedExtensions: metadata.extrinsic.signedExtensions.map((se) => ({
identifier: se.identifier,
includedInExtrinsic: getTypeRef(se.type),
includedInSignedData: getTypeRef(se.additionalSigned),
})),
}
const lookup = getLookup(
definitions,
accessibleTypes,
getTypeRef,
getPrimitive,
)
const lookupEncoded = lookup.map(lookupType.enc)
let hashTree: Array<Uint8Array> | undefined
const getHashTree = (): Array<Uint8Array> => {
if (hashTree) return hashTree
if (!lookupEncoded.length) return (hashTree = [new Uint8Array(32).fill(0)])
hashTree = new Array(lookupEncoded.length * 2 - 1)
let leavesStartIdx = lookupEncoded.length - 1
for (let i = 0; i < lookupEncoded.length; i++)
hashTree[leavesStartIdx + i] = Blake3256(lookupEncoded[i])
for (let i = hashTree.length - 2; i > 0; i -= 2)
hashTree[(i - 1) / 2] = Blake3256(
mergeUint8([hashTree[i], hashTree[i + 1]]),
)
return hashTree
}
let digested: undefined | Uint8Array
const digest = () => {
if (digested) return digested
const rootLookupHash = getHashTree()[0]
const digest: MetadataDigest = {
tag: "V1",
value: {
typeInformationTreeRoot: rootLookupHash,
extrinsicMetadataHash: Blake3256(extrinsicMetadata.enc(extrinsic)),
...info,
},
}
return (digested = Blake3256(metadataDigest.enc(digest)))
}
const generateProof = (knownIndexes: number[]) => {
const proofData = getProofData(lookupEncoded, knownIndexes)
const hashTree = getHashTree()
const proofs = proofData.proofIdxs.map((idx) => hashTree[idx])
return mergeUint8([
compact.enc(proofData.leaves.length),
...proofData.leaves,
compact.enc(proofData.leafIdxs.length),
...proofData.leafIdxs.map((x) => u32.enc(x)),
compact.enc(proofs.length),
...proofs,
extrinsicMetadata.enc(extrinsic),
extraInfo.enc(info),
])
}
const getProofForExtrinsicPayload = (
extrinsicPayload: Uint8Array | HexString,
) => {
const typeRefs: Array<TypeRef> = [
extrinsic.callTy,
...extrinsic.signedExtensions.map((x) => x.includedInExtrinsic),
...extrinsic.signedExtensions.map((x) => x.includedInSignedData),
]
return generateProof(
decodeAndCollectKnownLeafs(extrinsicPayload, typeRefs, lookup),
)
}
const getProofForExtrinsicParts = (
callData: Uint8Array | HexString,
includedInExtrinsic: Uint8Array | HexString,
includedInSignedData: Uint8Array | HexString,
) => {
const bytes = mergeUint8(
[callData, includedInExtrinsic, includedInSignedData].map(toBytes),
)
return getProofForExtrinsicPayload(bytes)
}
const getProofForExtrinsic = (
transaction: Uint8Array | HexString,
txAdditionalSigned?: Uint8Array | HexString,
) => {
let [, { version, type }, bytes] = extrinsicDec(transaction)
if (version !== extrinsic.version)
throw new Error("Incorrect extrinsic version")
const typeRefs: TypeRef[] =
type === "signed"
? [
extrinsic.addressTy,
extrinsic.signatureTy,
...extrinsic.signedExtensions.map((x) => x.includedInExtrinsic),
extrinsic.callTy,
]
: [extrinsic.callTy]
if (txAdditionalSigned) {
bytes = mergeUint8([bytes, toBytes(txAdditionalSigned)])
typeRefs.push(
...extrinsic.signedExtensions.map((x) => x.includedInSignedData),
)
}
return generateProof(decodeAndCollectKnownLeafs(bytes, typeRefs, lookup))
}
return {
digest,
getProofForExtrinsic,
getProofForExtrinsicParts,
getProofForExtrinsicPayload,
}
}
+57
View File
@@ -0,0 +1,57 @@
const getLevelFromIdx = (idx: number) => Math.log2(idx + 1) | 0
const getAncestorIdx = (from: number, nLevels: number) =>
((from + 1) >> nLevels) - 1
export function getProofData(
leaves: Array<Uint8Array>,
knownLeavesIdxs: Array<number>,
) {
const knownLeaves = knownLeavesIdxs.map((idx) => leaves[idx])
const startingIdx = leaves.length - 1
const leafIdxs = knownLeavesIdxs.map((idx) => startingIdx + idx)
const proofIdxs: Array<number> = []
if (leafIdxs.length) {
const nLevels = getLevelFromIdx(leafIdxs.at(-1)!)
const splitPosition = Math.pow(2, nLevels) - 1
const splitIdx = leafIdxs.findIndex((x) => x >= splitPosition)
if (splitIdx > 0) {
leafIdxs.unshift(...leafIdxs.splice(splitIdx))
knownLeaves.unshift(...knownLeaves.splice(splitIdx))
}
}
let targetIdx = 0
const traverse = (nodeIdx: number): void => {
if (targetIdx === leafIdxs.length) {
proofIdxs.push(nodeIdx)
return
}
const target = leafIdxs[targetIdx]
if (target === nodeIdx) {
++targetIdx
return
}
const currentLevel = getLevelFromIdx(nodeIdx)
const targetLevel = getLevelFromIdx(target)
if (nodeIdx !== getAncestorIdx(target, targetLevel - currentLevel)) {
proofIdxs.push(nodeIdx)
return
}
const leftSon = 2 * nodeIdx + 1
traverse(leftSon)
traverse(leftSon + 1)
}
traverse(0)
return {
leaves: knownLeaves,
leafIdxs,
proofIdxs,
}
}
+15
View File
@@ -0,0 +1,15 @@
import { type HexString } from "@pezkuwi/bizinikiwi-bindings"
import { fromHex } from "@pezkuwi/papi-utils"
export const toBytes = (input: Uint8Array | HexString) =>
typeof input === "string" ? fromHex(input) : input
export const compactTypeRefs = {
null: "void" as const,
u8: "compactU8" as const,
u16: "compactU16" as const,
u32: "compactU32" as const,
u64: "compactU64" as const,
u128: "compactU128" as const,
u256: "compactU256" as const,
}