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