mirror of
https://github.com/pezkuwichain/pezkuwi-api.git
synced 2026-04-22 21:57:57 +00:00
31467f90d4
- @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.
176 lines
6.6 KiB
JavaScript
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
|