Files
pezkuwi-api/packages/merkleize-metadata/dist/esm/main.mjs
T
pezkuwichain 31467f90d4 feat: add PAPI rebrand packages
- @pezkuwi/papi-utils (rebrand of @polkadot-api/utils)
- @pezkuwi/bizinikiwi-bindings (rebrand of @polkadot-api/substrate-bindings)
- @pezkuwi/metadata-builders (rebrand of @polkadot-api/metadata-builders)
- @pezkuwi/merkleize-metadata (rebrand of @polkadot-api/merkleize-metadata)

All @polkadot-api references replaced with @pezkuwi equivalents.
2026-01-22 15:40:12 +03:00

176 lines
6.6 KiB
JavaScript

import { Blake3256, compact, u32 } from '@pezkuwi/bizinikiwi-bindings';
import { lookupType, extrinsicDec, extrinsicMetadata, metadataDigest, extraInfo } from './codecs.mjs';
import { getAccessibleTypes } from './get-accessible-types.mjs';
import { getLookup } from './get-lookup.mjs';
import { getMetadata } from './get-metadata.mjs';
import { compactTypeRefs, toBytes } from './utils.mjs';
import { decodeAndCollectKnownLeafs } from './decode-and-collect.mjs';
import { getProofData } from './proof.mjs';
import { getDynamicBuilder, getLookupFn } from '@pezkuwi/metadata-builders';
import { mergeUint8 } from '@pezkuwi/papi-utils';
const assertExpected = (name, expected, received) => {
if (received != null && received !== expected)
throw new Error(
`${name} not expected. Received ${received} expected ${expected}`
);
};
const merkleizeMetadata = (metadataBytes, {
decimals,
tokenSymbol,
...hinted
}) => {
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 = {
decimals,
tokenSymbol,
specVersion,
specName,
base58Prefix: ss58Prefix
};
const definitions = new Map(
metadata.lookup.map((value) => [value.id, value])
);
const accessibleTypes = getAccessibleTypes(metadata, definitions);
const getPrimitive = (frameId) => {
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 : getPrimitive(tag === "tuple" ? value[0] : value[0].type);
};
const getTypeRef = (frameId) => {
const { def } = definitions.get(frameId);
if (def.tag === "primitive") return { tag: def.value.tag, value: void 0 };
if (def.tag === "compact") {
const primitive = getPrimitive(def.value);
const tag = compactTypeRefs[primitive];
if (!tag) throw new Error("Invalid primitive for Compact");
return { tag, value: void 0 };
}
return accessibleTypes.has(frameId) ? { tag: "perId", value: accessibleTypes.get(frameId) } : { tag: "void", value: void 0 };
};
const extrinsic = {
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;
const getHashTree = () => {
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;
const digest = () => {
if (digested) return digested;
const rootLookupHash = getHashTree()[0];
const digest2 = {
tag: "V1",
value: {
typeInformationTreeRoot: rootLookupHash,
extrinsicMetadataHash: Blake3256(extrinsicMetadata.enc(extrinsic)),
...info
}
};
return digested = Blake3256(metadataDigest.enc(digest2));
};
const generateProof = (knownIndexes) => {
const proofData = getProofData(lookupEncoded, knownIndexes);
const hashTree2 = getHashTree();
const proofs = proofData.proofIdxs.map((idx) => hashTree2[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) => {
const typeRefs = [
extrinsic.callTy,
...extrinsic.signedExtensions.map((x) => x.includedInExtrinsic),
...extrinsic.signedExtensions.map((x) => x.includedInSignedData)
];
return generateProof(
decodeAndCollectKnownLeafs(extrinsicPayload, typeRefs, lookup)
);
};
const getProofForExtrinsicParts = (callData, includedInExtrinsic, includedInSignedData) => {
const bytes = mergeUint8(
[callData, includedInExtrinsic, includedInSignedData].map(toBytes)
);
return getProofForExtrinsicPayload(bytes);
};
const getProofForExtrinsic = (transaction, txAdditionalSigned) => {
let [, { version: version2, type }, bytes] = extrinsicDec(transaction);
if (version2 !== extrinsic.version)
throw new Error("Incorrect extrinsic version");
const typeRefs = 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
};
};
export { merkleizeMetadata };
//# sourceMappingURL=main.mjs.map