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.
This commit is contained in:
2026-01-22 15:40:12 +03:00
parent 6e91756e5c
commit 31467f90d4
150 changed files with 22742 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 Josep M Sobrepere
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+121
View File
@@ -0,0 +1,121 @@
# @polkadot-api/metadata-builders
This package has multiple functions that read a metadata object, denormalizes it, and builds other structures needed for different processes
## getLookupFn
```ts
interface MetadataLookup {
(id: number): LookupEntry
metadata: V14 | V15
}
function getLookupFn(metadata: Metadata): MetadataLookup
```
Given the a metadata, returns a function that will give the `LookupEntry` for an id along. The function also has access to the original metadata, as it's usually needed to work with the actual lookup.
The `LookupEntry` is a denormalized data structure for one entry in the metadata. It also "shortcuts" type references when those are pointers (composites or tuples of length 1). Essentially, it's a union of each of the different types that can be found in the lookup, mostly equivalent to something like:
```ts
type TerminalVar =
| PrimitiveVar // u8, str, char, i128, etc.
| CompactVar
| BitSequenceVar
| AccountId32
type ComposedVar =
| TupleVar
| StructVar
| SequenceVar
| ArrayVar
| OptionVar
| ResultVar
| EnumVar
type LookupEntry = TerminalVar | ComposedVar
```
Where, for instance, a StructVar is of the shape
```ts
type StructVar = {
type: "struct"
value: Record<string, LookupEntry>
}
```
It's useful to get types referenced by storage calls, etc.
## getDynamicBuilder
```ts
function getDynamicBuilder(metadataLookup: MetadataLookup): {
buildDefinition: (id: number) => Codec
buildConstant: (pallet: string, name: string) => Codec
buildEvent: (pallet: string, name: string) => VariantEntry
buildError: (pallet: string, name: string) => VariantEntry
buildCall: (pallet: string, name: string) => VariantEntry
buildStorage: (pallet: string, entry: string) => StorageEntry
buildRuntimeCall: (api: string, method: string) => RuntimeEntry
}
```
Generates all the codecs needed to SCALE encode or decode the data for any interaction with the chain.
`buildDefinition` returns the codec for the type identified by the parameter `id`
`buildConstant` returns the codec for the requested constant (equivalent as calling `buildDefinition` with the type id of that constant)
`buildEvent`, `buildError` and `buildCall` return an object with the codec, and the indices of the pallet and entry within the metadata:
```ts
interface VariantEntry {
location: [number, number] // [palletIdx, entryIdx],
codec: Codec
}
```
`buildStorage` creates all the encoders/decoders needed to encode a storage call and decode its result:
```ts
interface StorageEntry {
// Encodes the arguments of the storage call.
enc: (...args: any[]) => string
// Decodes the result from the storage call.
dec: (value: string) => any
// Decodes the arguments of the storage call
keyDecoder: (value: string) => any[]
// Expected number of arguments
len: number
// Decoded fallback value as defined in the metadata entry
fallback: unknown
}
```
Similarly, `buildRuntimeCall` returns the codecs for both encoding the arguments of the runtime call, and the codec for decoding the result
```ts
interface RuntimeEntry {
args: Codec<any[]>
value: Codec<any>
}
```
## getChecksumBuilder
```ts
function getChecksumBuilder(metadataLookup: MetadataLookup): {
buildDefinition: (id: number) => string | null
buildRuntimeCall: (api: string, method: string) => string | null
buildStorage: (pallet: string, entry: string) => string | null
buildCall: (pallet: string, name: string) => string | null
buildEvent: (pallet: string, name: string) => string | null
buildError: (pallet: string, name: string) => string | null
buildConstant: (pallet: string, constantName: string) => string | null
}
```
Generates the checksums for the different components defined in the metadata.
`buildDefinition` builds the checksum of one of the types in the lookup. The rest of the methods build the checksum for each of the interfaces of the chain.
+370
View File
@@ -0,0 +1,370 @@
import { h64 } from '@pezkuwi/bizinikiwi-bindings';
import { buildLookupGraph, getSubgraph, getStronglyConnectedComponents, mergeSCCsWithCommonNodes } from './lookup-graph.mjs';
const textEncoder = new TextEncoder();
const encodeText = textEncoder.encode.bind(textEncoder);
const getChecksum = (values) => {
const res = new Uint8Array(values.length * 8);
const dv = new DataView(res.buffer);
for (let i = 0; i < values.length; i++) dv.setBigUint64(i * 8, values[i]);
return h64(res);
};
const getStringChecksum = (values) => getChecksum(values.map((v) => h64(encodeText(v))));
const shapeIds = {
primitive: 0n,
vector: 1n,
tuple: 2n,
struct: 3n,
option: 4n,
result: 5n,
enum: 6n,
void: 7n
};
const runtimePrimitiveIds = {
undefined: 0n,
number: 1n,
string: 2n,
bigint: 3n,
boolean: 4n,
bitSequence: 5n,
// {bitsLen: number, bytes: Uint8Array}
byteSequence: 6n,
// Binary
accountId32: 7n,
// SS58String
accountId20: 8n
// EthAccount
};
const metadataPrimitiveIds = {
bool: runtimePrimitiveIds.boolean,
char: runtimePrimitiveIds.string,
str: runtimePrimitiveIds.string,
u8: runtimePrimitiveIds.number,
u16: runtimePrimitiveIds.number,
u32: runtimePrimitiveIds.number,
u64: runtimePrimitiveIds.bigint,
u128: runtimePrimitiveIds.bigint,
u256: runtimePrimitiveIds.bigint,
i8: runtimePrimitiveIds.number,
i16: runtimePrimitiveIds.number,
i32: runtimePrimitiveIds.number,
i64: runtimePrimitiveIds.bigint,
i128: runtimePrimitiveIds.bigint,
i256: runtimePrimitiveIds.bigint
};
const structLikeBuilder = (shapeId, input, innerChecksum) => {
const sortedEntries = Object.entries(input).sort(
([a], [b]) => a.localeCompare(b)
);
const keysChecksum = getStringChecksum(sortedEntries.map(([key]) => key));
const valuesChecksum = getChecksum(
sortedEntries.map(([, entry]) => innerChecksum(entry))
);
return getChecksum([shapeId, keysChecksum, valuesChecksum]);
};
const _buildChecksum = (input, buildNextChecksum) => {
if (input.type === "primitive")
return getChecksum([shapeIds.primitive, metadataPrimitiveIds[input.value]]);
if (input.type === "void") return getChecksum([shapeIds.void]);
if (input.type === "compact")
return getChecksum([
shapeIds.primitive,
runtimePrimitiveIds[input.isBig ? "bigint" : "number"]
]);
if (input.type === "bitSequence")
return getChecksum([shapeIds.primitive, runtimePrimitiveIds.bitSequence]);
if (input.type === "AccountId32") {
return getChecksum([shapeIds.primitive, runtimePrimitiveIds.accountId32]);
}
if (input.type === "AccountId20") {
return getChecksum([shapeIds.primitive, runtimePrimitiveIds.accountId20]);
}
const buildVector = (entry, length) => {
const innerChecksum = buildNextChecksum(entry);
return getChecksum(
length !== void 0 ? [shapeIds.vector, innerChecksum, BigInt(length)] : [shapeIds.vector, innerChecksum]
);
};
if (input.type === "array") {
const innerValue = input.value;
if (innerValue.type === "primitive" && innerValue.value === "u8") {
return getChecksum([
shapeIds.primitive,
runtimePrimitiveIds.byteSequence,
BigInt(input.len)
]);
}
return buildVector(innerValue, input.len);
}
if (input.type === "sequence") {
const innerValue = input.value;
if (innerValue.type === "primitive" && innerValue.value === "u8") {
return getChecksum([shapeIds.primitive, runtimePrimitiveIds.byteSequence]);
}
return buildVector(innerValue);
}
const buildTuple = (entries) => getChecksum([shapeIds.tuple, ...entries.map(buildNextChecksum)]);
const buildStruct = (entries) => structLikeBuilder(shapeIds.struct, entries, buildNextChecksum);
if (input.type === "tuple") return buildTuple(input.value);
if (input.type === "struct") return buildStruct(input.value);
if (input.type === "option")
return getChecksum([shapeIds.option, buildNextChecksum(input.value)]);
if (input.type === "result")
return getChecksum([
shapeIds.result,
buildNextChecksum(input.value.ok),
buildNextChecksum(input.value.ko)
]);
return structLikeBuilder(shapeIds.enum, input.value, (entry) => {
if (entry.type === "lookupEntry") return buildNextChecksum(entry.value);
switch (entry.type) {
case "void":
return getChecksum([shapeIds.void]);
case "tuple":
return buildTuple(entry.value);
case "struct":
return buildStruct(entry.value);
case "array":
return buildVector(entry.value, entry.len);
}
});
};
const sortCyclicGroups = (groups, graph) => {
const getReachableNodes = (group) => {
const result2 = /* @__PURE__ */ new Set();
const toVisit = Array.from(group);
while (toVisit.length) {
const id = toVisit.pop();
if (result2.has(id)) continue;
result2.add(id);
graph.get(id)?.refs.forEach((id2) => toVisit.push(id2));
}
return Array.from(result2);
};
const result = new Array();
function dependentsFirst(group) {
if (result.includes(group)) return;
const dependents = groups.filter(
(candidate) => candidate !== group && getReachableNodes(group).some((node) => candidate.has(node))
);
dependents.forEach((group2) => dependentsFirst(group2));
if (result.includes(group)) return;
result.push(group);
}
groups.forEach((group) => dependentsFirst(group));
return result;
};
function iterateChecksums(group, iterations, cache, graph) {
const groupReadCache = new Map([...group].map((id) => [id, 0n]));
const groupWriteCache = /* @__PURE__ */ new Map();
const recursiveBuildChecksum = (entry, skipCache = true) => {
if (!skipCache && (groupReadCache.has(entry.id) || cache.has(entry.id))) {
return groupReadCache.get(entry.id) ?? cache.get(entry.id);
}
const result = _buildChecksum(
entry,
(nextEntry) => recursiveBuildChecksum(nextEntry, false)
);
if (group.has(entry.id)) {
groupWriteCache.set(entry.id, result);
} else {
cache.set(entry.id, result);
}
return result;
};
for (let i = 0; i < iterations; i++) {
group.forEach((id) => recursiveBuildChecksum(graph.get(id).entry));
group.forEach((id) => groupReadCache.set(id, groupWriteCache.get(id)));
}
return groupReadCache;
}
function getMirroredNodes(cyclicGroups, graph) {
const maxSize = cyclicGroups.reduce(
(acc, group) => Math.max(acc, group.size),
0
);
const allEntries = new Set([...graph.values()].map((v) => v.entry.id));
const resultingChecksums = iterateChecksums(
allEntries,
maxSize,
// Cache won't be used, since it's using the internal one for every node.
/* @__PURE__ */ new Map(),
graph
);
const checksumToNodes = /* @__PURE__ */ new Map();
for (const id of allEntries) {
const checksum = resultingChecksums.get(id);
if (checksum == void 0) throw new Error("Unreachable");
if (!checksumToNodes.has(checksum)) {
checksumToNodes.set(checksum, []);
}
checksumToNodes.get(checksum).push(id);
}
const checksumsWithDuplicates = [...checksumToNodes.entries()].filter(
([, nodes]) => nodes.length > 1
);
const duplicatesMap = {};
checksumsWithDuplicates.forEach(([, nodes]) => {
nodes.forEach((n) => duplicatesMap[n] = nodes);
});
return duplicatesMap;
}
const buildChecksum = (entry, cache, graph) => {
if (cache.has(entry.id)) return cache.get(entry.id);
const subGraph = getSubgraph(entry.id, graph);
const cycles = getStronglyConnectedComponents(subGraph).filter(
// SCCs can be of length=1, but for those we're only interested with those that are circular with themselves
(group) => group.size > 1 || isSelfCircular(group, subGraph)
);
const cyclicGroups = mergeSCCsWithCommonNodes(cycles).filter((group) => {
return !cache.has(group.values().next().value);
});
const mirrored = getMirroredNodes(cyclicGroups, subGraph);
const sortedCyclicGroups = sortCyclicGroups(cyclicGroups, subGraph);
sortedCyclicGroups.forEach((group) => {
if (cache.has(group.values().next().value)) {
return;
}
const result = iterateChecksums(group, group.size, cache, graph);
group.forEach((id) => {
const checksum = result.get(id);
if (id in mirrored) {
mirrored[id].forEach((id2) => cache.set(id2, checksum));
} else {
cache.set(id, checksum);
}
});
});
const getChecksum2 = (entry2) => {
if (cache.has(entry2.id)) return cache.get(entry2.id);
return _buildChecksum(entry2, getChecksum2);
};
return getChecksum2(entry);
};
const isSelfCircular = (group, graph) => {
if (group.size !== 1) return false;
const [id] = group;
return graph.get(id).refs.has(id);
};
const getChecksumBuilder = (getLookupEntryDef) => {
const { metadata } = getLookupEntryDef;
const graph = buildLookupGraph(getLookupEntryDef, metadata.lookup.length);
const cache = /* @__PURE__ */ new Map();
const buildDefinition = (id) => buildChecksum(getLookupEntryDef(id), cache, graph);
const buildStorage = (pallet, entry) => {
try {
const storageEntry = metadata.pallets.find((x) => x.name === pallet).storage.items.find((s) => s.name === entry);
if (storageEntry.type.tag === "plain")
return buildDefinition(storageEntry.type.value);
const { key, value } = storageEntry.type.value;
const val = buildDefinition(value);
const returnKey = buildDefinition(key);
return getChecksum([val, returnKey]);
} catch (_) {
return null;
}
};
const buildViewFns = (pallet, entry) => {
try {
const viewFn = metadata.pallets.find((x) => x.name === pallet)?.viewFns.find((x) => x.name === entry);
if (!viewFn) throw null;
const argNamesChecksum = getStringChecksum(
viewFn.inputs.map((x) => x.name)
);
const argValuesChecksum = getChecksum(
viewFn.inputs.map((x) => buildDefinition(x.type))
);
const outputChecksum = buildDefinition(viewFn.output);
return getChecksum([argNamesChecksum, argValuesChecksum, outputChecksum]);
} catch (_) {
return null;
}
};
const buildRuntimeCall = (api, method) => {
try {
const entry = metadata.apis.find((x) => x.name === api)?.methods.find((x) => x.name === method);
if (!entry) throw null;
const argNamesChecksum = getStringChecksum(
entry.inputs.map((x) => x.name)
);
const argValuesChecksum = getChecksum(
entry.inputs.map((x) => buildDefinition(x.type))
);
const outputChecksum = buildDefinition(entry.output);
return getChecksum([argNamesChecksum, argValuesChecksum, outputChecksum]);
} catch (_) {
return null;
}
};
const buildComposite = (input) => {
if (input.type === "void") return getChecksum([0n]);
if (input.type === "tuple") {
const values = Object.values(input.value).map(
(entry) => buildDefinition(entry.id)
);
return getChecksum([shapeIds.tuple, ...values]);
}
if (input.type === "array") {
return getChecksum([
shapeIds.vector,
buildDefinition(input.value.id),
BigInt(input.len)
]);
}
return structLikeBuilder(
shapeIds.struct,
input.value,
(entry) => buildDefinition(entry.id)
);
};
const buildNamedTuple = (input) => {
return structLikeBuilder(
shapeIds.tuple,
input.value,
(entry) => buildDefinition(entry.id)
);
};
const variantShapeId = {
errors: 1n,
events: 2n,
calls: 3n
};
const buildVariant = (variantType) => (pallet, name) => {
try {
const palletEntry = metadata.pallets.find((x) => x.name === pallet);
const enumLookup = getLookupEntryDef(palletEntry[variantType].type);
buildDefinition(enumLookup.id);
if (enumLookup.type !== "enum") throw null;
const entry = enumLookup.value[name];
const valueChecksum = entry.type === "lookupEntry" ? buildDefinition(entry.value.id) : buildComposite(entry);
return getChecksum([variantShapeId[variantType], valueChecksum]);
} catch (_) {
return null;
}
};
const buildConstant = (pallet, constantName) => {
try {
const storageEntry = metadata.pallets.find((x) => x.name === pallet).constants.find((s) => s.name === constantName);
return buildDefinition(storageEntry.type);
} catch (_) {
return null;
}
};
const toStringEnhancer = (fn) => (...args) => fn(...args)?.toString(32) ?? null;
return {
buildDefinition: toStringEnhancer(buildDefinition),
buildRuntimeCall: toStringEnhancer(buildRuntimeCall),
buildStorage: toStringEnhancer(buildStorage),
buildViewFns: toStringEnhancer(buildViewFns),
buildCall: toStringEnhancer(buildVariant("calls")),
buildEvent: toStringEnhancer(buildVariant("events")),
buildError: toStringEnhancer(buildVariant("errors")),
buildConstant: toStringEnhancer(buildConstant),
buildComposite: toStringEnhancer(buildComposite),
buildNamedTuple: toStringEnhancer(buildNamedTuple),
getAllGeneratedChecksums: () => Array.from(cache.values()).map((v) => v.toString(32))
};
};
export { getChecksumBuilder };
//# sourceMappingURL=checksum-builder.mjs.map
File diff suppressed because one or more lines are too long
+136
View File
@@ -0,0 +1,136 @@
import * as scale from '@pezkuwi/bizinikiwi-bindings';
import { mapObject } from '@pezkuwi/papi-utils';
import { getLookupCodecBuilder } from './lookup-codec-builder.mjs';
const nullCodec = scale.enhanceCodec(
scale._void,
() => void 0,
() => null
);
const getDynamicBuilder = (getLookupEntryDef) => {
const { metadata } = getLookupEntryDef;
let buildDefinition = getLookupCodecBuilder(getLookupEntryDef);
const prefix = metadata.pallets.find((x) => x.name === "System")?.constants.find((x) => x.name === "SS58Prefix");
let ss58Prefix;
if (prefix) {
try {
const prefixVal = buildDefinition(prefix.type).dec(prefix.value);
if (typeof prefixVal === "number") {
ss58Prefix = prefixVal;
buildDefinition = getLookupCodecBuilder(
getLookupEntryDef,
scale.AccountId(prefixVal)
);
}
} catch (_) {
}
}
const storagePallets = /* @__PURE__ */ new Map();
const buildStorage = (pallet, entry) => {
let storagePallet = storagePallets.get(pallet);
if (!storagePallet)
storagePallets.set(pallet, storagePallet = scale.Storage(pallet));
const storageEntry = metadata.pallets.find((x) => x.name === pallet).storage.items.find((s) => s.name === entry);
const withNullVoid = (codec) => codec === scale._void ? nullCodec : codec;
const storageWithFallback = (len, value2, ...args) => {
const keys = storagePallet(...args);
const [, ...encodersWithHash] = args;
return {
args: scale.Tuple(...encodersWithHash.map(([codec]) => codec)),
keys,
value: value2,
len,
fallback: storageEntry.modifier === 1 ? value2.dec(storageEntry.fallback) : void 0
};
};
if (storageEntry.type.tag === "plain")
return storageWithFallback(
0,
withNullVoid(buildDefinition(storageEntry.type.value)),
entry
);
const { key, value, hashers } = storageEntry.type.value;
const val = withNullVoid(buildDefinition(value));
const hashes = hashers.map((x) => scale[x.tag]);
const hashArgs = (() => {
if (hashes.length === 1) {
return [[buildDefinition(key), hashes[0]]];
}
const keyDef = getLookupEntryDef(key);
switch (keyDef.type) {
case "array":
return hashes.map((hash) => [buildDefinition(keyDef.value.id), hash]);
case "tuple":
return keyDef.value.map((x, idx) => [
buildDefinition(x.id),
hashes[idx]
]);
default:
throw new Error("Invalid key type");
}
})();
return storageWithFallback(hashes.length, val, entry, ...hashArgs);
};
const buildEnumEntry = (entry) => {
switch (entry.type) {
case "void":
return scale._void;
case "lookupEntry":
return buildDefinition(entry.value.id);
case "tuple":
return scale.Tuple(
...Object.values(entry.value).map((l) => buildDefinition(l.id))
);
case "struct":
return scale.Struct(
mapObject(entry.value, (x) => buildDefinition(x.id))
);
case "array":
return scale.Vector(buildDefinition(entry.value.id), entry.len);
}
};
const buildConstant = (pallet, constantName) => {
const storageEntry = metadata.pallets.find((x) => x.name === pallet).constants.find((s) => s.name === constantName);
return buildDefinition(storageEntry.type);
};
const buildVariant = (type) => (pallet, name) => {
const palletEntry = metadata.pallets.find((x) => x.name === pallet);
const lookup = getLookupEntryDef(palletEntry[type].type);
if (lookup.type !== "enum") throw null;
const entry = lookup.value[name];
return {
location: [palletEntry.index, entry.idx],
codec: buildEnumEntry(lookup.value[name])
};
};
const buildViewFn = (pallet, entry) => {
const fn = metadata.pallets.find((x) => x.name === pallet)?.viewFns.find((x) => x.name === entry);
if (!fn) throw null;
return {
args: scale.Tuple(...fn.inputs.map((x) => buildDefinition(x.type))),
value: buildDefinition(fn.output)
};
};
const buildRuntimeCall = (api, method) => {
const entry = metadata.apis.find((x) => x.name === api)?.methods.find((x) => x.name === method);
if (!entry) throw null;
return {
args: scale.Tuple(...entry.inputs.map((x) => buildDefinition(x.type))),
value: buildDefinition(entry.output)
};
};
return {
buildDefinition,
buildStorage,
buildEvent: buildVariant("events"),
buildError: buildVariant("errors"),
buildViewFn,
buildRuntimeCall,
buildCall: buildVariant("calls"),
buildConstant,
ss58Prefix
};
};
export { getDynamicBuilder };
//# sourceMappingURL=dynamic-builder.mjs.map
File diff suppressed because one or more lines are too long
+5
View File
@@ -0,0 +1,5 @@
export { denormalizeLookup, getLookupFn } from './lookups.mjs';
export { getDynamicBuilder } from './dynamic-builder.mjs';
export { getChecksumBuilder } from './checksum-builder.mjs';
export { getLookupCodecBuilder } from './lookup-codec-builder.mjs';
//# sourceMappingURL=index.mjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"}
@@ -0,0 +1,81 @@
import * as scale from '@pezkuwi/bizinikiwi-bindings';
import { withCache } from './with-cache.mjs';
const _bytes = scale.Bin();
const _buildCodec = (input, cache, stack, _accountId) => {
if (input.type === "primitive") return scale[input.value];
if (input.type === "void") return scale._void;
if (input.type === "AccountId32") return _accountId;
if (input.type === "AccountId20") return scale.ethAccount;
if (input.type === "compact")
return input.isBig ? scale.compactBn : scale.compactNumber;
if (input.type === "bitSequence") return scale.BitSeq(input.isLSB);
const buildNextCodec = (nextInput) => buildCodec(nextInput, cache, stack, _accountId);
const buildVector = (inner2, len) => {
const innerCodec = buildNextCodec(inner2);
return len ? scale.Vector(innerCodec, len) : scale.Vector(innerCodec);
};
const buildTuple = (value) => scale.Tuple(...value.map(buildNextCodec));
const buildStruct = (value) => {
const inner2 = Object.fromEntries(
Object.entries(value).map(([key, value2]) => [key, buildNextCodec(value2)])
);
return scale.Struct(inner2);
};
if (input.type === "sequence" && input.value.type === "primitive" && input.value.value === "u8") {
return _bytes;
}
if (input.type === "array") {
if (input.value.type === "primitive" && input.value.value === "u8")
return scale.Bin(input.len);
return buildVector(input.value, input.len);
}
if (input.type === "sequence") return buildVector(input.value);
if (input.type === "tuple") return buildTuple(input.value);
if (input.type === "struct") return buildStruct(input.value);
if (input.type === "option") return scale.Option(buildNextCodec(input.value));
if (input.type === "result")
return scale.Result(
buildNextCodec(input.value.ok),
buildNextCodec(input.value.ko)
);
const dependencies = Object.values(input.value).map((v) => {
switch (v.type) {
case "void":
return scale._void;
case "lookupEntry":
return buildNextCodec(v.value);
case "tuple":
return buildTuple(v.value);
case "struct":
return buildStruct(v.value);
case "array":
return buildVector(v.value, v.len);
}
});
const inner = Object.fromEntries(
Object.keys(input.value).map((key, idx) => {
return [key, dependencies[idx]];
})
);
const indexes = Object.values(input.value).map((x) => x.idx);
const areIndexesSorted = indexes.every((idx, i) => idx === i);
const variantCodec = areIndexesSorted ? scale.Variant(inner) : scale.Variant(inner, indexes);
return input.byteLength ? fixedSizeCodec(variantCodec, input.byteLength) : variantCodec;
};
const buildCodec = withCache(_buildCodec, scale.Self, (res) => res);
const getLookupCodecBuilder = (lookup, accountId = scale.AccountId()) => {
const cache = /* @__PURE__ */ new Map();
const buildDefinition = (id) => buildCodec(lookup(id), cache, /* @__PURE__ */ new Set(), accountId);
return (id) => buildDefinition(id);
};
const fixedSizeCodec = (codec, size) => {
const allBytes = scale.Bytes(size);
return scale.createCodec(
(value) => allBytes.enc(codec.enc(value)),
(data) => codec.dec(allBytes.dec(data))
);
};
export { getLookupCodecBuilder };
//# sourceMappingURL=lookup-codec-builder.mjs.map
File diff suppressed because one or more lines are too long
+161
View File
@@ -0,0 +1,161 @@
function buildLookupGraph(lookupFn, lookupLength) {
const result = /* @__PURE__ */ new Map();
const visited = /* @__PURE__ */ new Set();
const addEdge = (from, to) => {
if (!result.has(from))
result.set(from, {
entry: lookupFn(from),
backRefs: /* @__PURE__ */ new Set(),
refs: /* @__PURE__ */ new Set()
});
if (!result.has(to))
result.set(to, {
entry: lookupFn(to),
backRefs: /* @__PURE__ */ new Set(),
refs: /* @__PURE__ */ new Set()
});
result.get(from).refs.add(to);
result.get(to).backRefs.add(from);
};
for (let i = 0; i < lookupLength; i++) {
const entry = lookupFn(i);
if (i !== entry.id) {
addEdge(i, entry.id);
}
if (visited.has(entry.id)) continue;
visited.add(entry.id);
switch (entry.type) {
case "array":
case "option":
case "sequence":
addEdge(entry.id, entry.value.id);
break;
case "enum":
Object.values(entry.value).forEach((enumEntry) => {
switch (enumEntry.type) {
case "array":
case "lookupEntry":
addEdge(entry.id, enumEntry.value.id);
break;
case "struct":
case "tuple":
Object.values(enumEntry.value).forEach(
(v) => addEdge(entry.id, v.id)
);
break;
}
});
break;
case "result":
addEdge(entry.id, entry.value.ok.id);
addEdge(entry.id, entry.value.ko.id);
break;
case "struct":
case "tuple":
Object.values(entry.value).forEach((v) => addEdge(entry.id, v.id));
break;
}
if (!result.has(entry.id)) {
result.set(entry.id, {
backRefs: /* @__PURE__ */ new Set(),
refs: /* @__PURE__ */ new Set(),
entry
});
}
}
return result;
}
const subgraphCache = /* @__PURE__ */ new WeakMap();
function _getSubgraph(id, graph, result, cache) {
if (result.has(id)) return;
const node = graph.get(id);
result.set(id, node);
cache.set(id, result);
node.refs.forEach((ref) => _getSubgraph(ref, graph, result, cache));
node.backRefs.forEach((ref) => _getSubgraph(ref, graph, result, cache));
}
function getSubgraph(id, graph) {
if (!subgraphCache.has(graph)) {
subgraphCache.set(graph, /* @__PURE__ */ new Map());
}
const cache = subgraphCache.get(graph);
if (cache.has(id)) return cache.get(id);
const result = /* @__PURE__ */ new Map();
_getSubgraph(id, graph, result, cache);
return result;
}
function getStronglyConnectedComponents(graph) {
const tarjanState = /* @__PURE__ */ new Map();
let index = 0;
const stack = [];
const result = [];
function strongConnect(v) {
const state = {
index,
lowLink: index,
onStack: true
};
tarjanState.set(v, state);
index++;
stack.push(v);
const edges = graph.get(v).refs;
for (let w of edges) {
const edgeState = tarjanState.get(w);
if (!edgeState) {
strongConnect(w);
state.lowLink = Math.min(state.lowLink, tarjanState.get(w).lowLink);
} else if (edgeState.onStack) {
state.lowLink = Math.min(state.lowLink, edgeState.index);
}
}
if (state.lowLink === state.index) {
const component = /* @__PURE__ */ new Set();
let poppedNode = -1;
do {
poppedNode = stack.pop();
tarjanState.get(poppedNode).onStack = false;
component.add(poppedNode);
} while (poppedNode !== v);
result.push(component);
}
}
for (const node of graph.keys()) {
if (!tarjanState.has(node)) {
strongConnect(node);
}
}
return result;
}
function mergeSCCsWithCommonNodes(stronglyConnectedComponents) {
const scc = stronglyConnectedComponents;
const ungroupedCycles = new Set(scc.map((_, i) => i));
const edges = new Map(scc.map((_, i) => [i, /* @__PURE__ */ new Set()]));
scc.forEach((cycle, i) => {
scc.slice(i + 1).forEach((otherCycle, _j) => {
const j = _j + i + 1;
const combined = /* @__PURE__ */ new Set([...cycle, ...otherCycle]);
if (combined.size !== cycle.size + otherCycle.size) {
edges.get(i).add(j);
edges.get(j).add(i);
}
});
});
const groups = [];
while (ungroupedCycles.size) {
const group = /* @__PURE__ */ new Set();
const toVisit = [ungroupedCycles.values().next().value];
while (toVisit.length) {
const idx = toVisit.pop();
if (!ungroupedCycles.has(idx)) continue;
ungroupedCycles.delete(idx);
const cycle = scc[idx];
cycle.forEach((v) => group.add(Number(v)));
edges.get(idx).forEach((n) => toVisit.push(n));
}
groups.push(group);
}
return groups;
}
export { buildLookupGraph, getStronglyConnectedComponents, getSubgraph, mergeSCCsWithCommonNodes };
//# sourceMappingURL=lookup-graph.mjs.map
File diff suppressed because one or more lines are too long
+224
View File
@@ -0,0 +1,224 @@
const isBytes = (value, nBytes) => value.type === "array" && value.len === nBytes && value.value.type === "primitive" && value.value.value === "u8";
const _void = { type: "void" };
const _denormalizeLookup = (lookupData, customMap = () => null) => {
const lookups = /* @__PURE__ */ new Map();
const from = /* @__PURE__ */ new Set();
const withCache = (fn) => {
return (id) => {
let entry = lookups.get(id);
if (entry) return entry;
if (from.has(id)) {
const entry2 = {
id
};
lookups.set(id, entry2);
return entry2;
}
from.add(id);
const value = fn(id);
entry = lookups.get(id);
if (entry) {
Object.assign(entry, value);
} else {
entry = {
id,
...value
};
lookups.set(id, entry);
}
from.delete(id);
return entry;
};
};
let isAccountId32SearchOn = true;
let isAccountId20SearchOn = true;
const getLookupEntryDef = withCache((id) => {
const custom = customMap(lookupData[id]);
if (custom) return custom;
const { def, path, params } = lookupData[id];
if (def.tag === "composite") {
if (def.value.length === 0) return _void;
if (def.value.length === 1) {
const inner = getLookupEntryDef(def.value[0].type);
if (isAccountId32SearchOn && path.at(-1) === "AccountId32" && isBytes(inner, 32)) {
isAccountId32SearchOn = false;
return { type: "AccountId32" };
}
if (isAccountId20SearchOn && path.at(-1) === "AccountId20" && isBytes(inner, 20)) {
isAccountId20SearchOn = false;
return { type: "AccountId20" };
}
return inner;
}
return getComplexVar(def.value);
}
if (def.tag === "variant") {
if (path.length === 1 && path[0] === "Option" && params.length === 1 && params[0].name === "T") {
const value = getLookupEntryDef(params[0].type);
return value.type === "void" ? (
// Option<void> would return a Codec<undefined> which makes no sense
// Therefore, we better treat it as a bool
{ type: "primitive", value: "bool" }
) : {
type: "option",
value
};
}
if (path.length === 1 && path[0] === "Result" && params.length === 2 && params[0].name === "T" && params[1].name === "E") {
return {
type: "result",
value: {
ok: getLookupEntryDef(params[0].type),
ko: getLookupEntryDef(params[1].type)
}
};
}
if (def.value.length === 0) return _void;
const enumValue = {};
const enumDocs = {};
def.value.forEach((x) => {
const key = x.name;
enumDocs[key] = x.docs;
if (x.fields.length === 0) {
enumValue[key] = { ..._void, idx: x.index };
return;
}
if (x.fields.length === 1 && !x.fields[0].name) {
enumValue[key] = {
type: "lookupEntry",
value: getLookupEntryDef(x.fields[0].type),
idx: x.index
};
return;
}
enumValue[key] = { ...getComplexVar(x.fields), idx: x.index };
});
return {
type: "enum",
value: enumValue,
innerDocs: enumDocs
};
}
if (def.tag === "sequence")
return {
type: "sequence",
value: getLookupEntryDef(def.value)
};
if (def.tag === "array") {
const { len } = def.value;
const value = getLookupEntryDef(def.value.type);
return !len || value.type === "void" ? _void : len > 1 ? {
type: "array",
value,
len: def.value.len
} : value;
}
if (def.tag === "tuple") {
if (def.value.length === 0) return _void;
return def.value.length > 1 ? getArrayOrTuple(
def.value.map((x) => getLookupEntryDef(x)),
def.value.map((x) => lookupData[x].docs)
) : getLookupEntryDef(def.value[0]);
}
if (def.tag === "primitive") {
return {
type: "primitive",
value: def.value.tag
};
}
if (def.tag === "compact") {
const translated = getLookupEntryDef(def.value);
if (translated.type === "void") return _void;
const isBig = Number(translated.value.slice(1)) > 32;
return {
type: "compact",
isBig,
size: translated.value
};
}
return {
type: def.tag,
isLSB: (lookupData[def.value.bitOrderType].path.at(-1) ?? "LSB").toUpperCase().startsWith("LSB")
};
});
const getComplexVar = (input) => {
let allKey = true;
const values = {};
const innerDocs = {};
input.forEach((x, idx) => {
allKey = allKey && !!x.name;
const key = x.name || idx;
const value = getLookupEntryDef(x.type);
if (value.type !== "void") {
values[key] = value;
innerDocs[key] = x.docs;
}
});
return allKey ? {
type: "struct",
value: values,
innerDocs
} : getArrayOrTuple(Object.values(values), Object.values(innerDocs));
};
const getArrayOrTuple = (values, innerDocs) => {
if (values.every((v) => v.id === values[0].id) && innerDocs.every((doc) => !doc.length)) {
const [value] = values;
return value.type === "void" ? _void : {
type: "array",
value: values[0],
len: values.length
};
}
return {
type: "tuple",
value: values,
innerDocs
};
};
return getLookupEntryDef;
};
const denormalizeLookup = (lookupData) => _denormalizeLookup(lookupData);
const getLookupFn = (metadata) => {
const getLookupEntryDef = _denormalizeLookup(metadata.lookup, ({ def }) => {
if (def.tag === "composite") {
const moduleErrorLength = getModuleErrorLength(def);
if (moduleErrorLength) {
return {
type: "enum",
innerDocs: {},
value: Object.fromEntries(
metadata.pallets.map((p) => [
p.name,
p.errors == null ? { ..._void, idx: p.index } : {
type: "lookupEntry",
value: getLookupEntryDef(p.errors.type),
idx: p.index
}
])
),
byteLength: moduleErrorLength
};
}
}
return null;
});
function getModuleErrorLength(def) {
const preChecks = def.value.length === 2 && def.value[0].name === "index" && def.value[1].name === "error";
if (!preChecks) return null;
const index = getLookupEntryDef(def.value[0].type);
const error = getLookupEntryDef(def.value[1].type);
return index.type === "primitive" && index.value === "u8" && error.type === "array" && error.value.type === "primitive" && error.value.value === "u8" ? 1 + error.len : null;
}
const getCall = () => {
if ("call" in metadata.extrinsic) {
return metadata.extrinsic.call;
}
const extrinsic = metadata.lookup[metadata.extrinsic.type];
const call = extrinsic?.params.find((p) => p.name === "Call");
return call?.type ?? null;
};
return Object.assign(getLookupEntryDef, { metadata, call: getCall() });
};
export { denormalizeLookup, getLookupFn };
//# sourceMappingURL=lookups.mjs.map
File diff suppressed because one or more lines are too long
+19
View File
@@ -0,0 +1,19 @@
const withCache = (fn, onEnterCircular, onExitCircular) => (input, cache, stack, ...rest) => {
const { id } = input;
if (cache.has(id)) return cache.get(id);
if (stack.has(id)) {
const res = onEnterCircular(() => cache.get(id), input, ...rest);
cache.set(id, res);
return res;
}
stack.add(id);
let result = fn(input, cache, stack, ...rest);
stack.delete(id);
if (cache.has(id))
result = onExitCircular(result, cache.get(id), input, ...rest);
cache.set(id, result);
return result;
};
export { withCache };
//# sourceMappingURL=with-cache.mjs.map
@@ -0,0 +1 @@
{"version":3,"file":"with-cache.mjs","sources":["../../src/with-cache.ts"],"sourcesContent":["import { LookupEntry } from \"./lookups\"\n\ntype FnWithStack<Other extends Array<any>, T> = (\n input: LookupEntry,\n cache: Map<number, T>,\n stack: Set<number>,\n ...rest: Other\n) => T\n\nexport const withCache =\n <Other extends Array<any>, T>(\n fn: FnWithStack<Other, T>,\n onEnterCircular: (\n cacheGetter: () => T,\n circular: LookupEntry,\n ...rest: Other\n ) => T,\n onExitCircular: (\n outter: T,\n inner: T,\n circular: LookupEntry,\n ...rest: Other\n ) => T,\n ): FnWithStack<Other, T> =>\n (input, cache, stack, ...rest) => {\n const { id } = input\n if (cache.has(id)) return cache.get(id)!\n\n if (stack.has(id)) {\n const res = onEnterCircular(() => cache.get(id)!, input, ...rest)\n cache.set(id, res)\n return res\n }\n\n stack.add(id)\n let result = fn(input, cache, stack, ...rest)\n stack.delete(id)\n\n if (cache.has(id))\n result = onExitCircular(result, cache.get(id)!, input, ...rest)\n\n cache.set(id, result)\n return result\n }\n"],"names":[],"mappings":"AASO,MAAM,SAAA,GACX,CACE,EAAA,EACA,eAAA,EAKA,mBAOF,CAAC,KAAA,EAAO,KAAA,EAAO,KAAA,EAAA,GAAU,IAAA,KAAS;AAChC,EAAA,MAAM,EAAE,IAAG,GAAI,KAAA;AACf,EAAA,IAAI,MAAM,GAAA,CAAI,EAAE,GAAG,OAAO,KAAA,CAAM,IAAI,EAAE,CAAA;AAEtC,EAAA,IAAI,KAAA,CAAM,GAAA,CAAI,EAAE,CAAA,EAAG;AACjB,IAAA,MAAM,GAAA,GAAM,gBAAgB,MAAM,KAAA,CAAM,IAAI,EAAE,CAAA,EAAI,KAAA,EAAO,GAAG,IAAI,CAAA;AAChE,IAAA,KAAA,CAAM,GAAA,CAAI,IAAI,GAAG,CAAA;AACjB,IAAA,OAAO,GAAA;AAAA,EACT;AAEA,EAAA,KAAA,CAAM,IAAI,EAAE,CAAA;AACZ,EAAA,IAAI,SAAS,EAAA,CAAG,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,GAAG,IAAI,CAAA;AAC5C,EAAA,KAAA,CAAM,OAAO,EAAE,CAAA;AAEf,EAAA,IAAI,KAAA,CAAM,IAAI,EAAE,CAAA;AACd,IAAA,MAAA,GAAS,cAAA,CAAe,QAAQ,KAAA,CAAM,GAAA,CAAI,EAAE,CAAA,EAAI,KAAA,EAAO,GAAG,IAAI,CAAA;AAEhE,EAAA,KAAA,CAAM,GAAA,CAAI,IAAI,MAAM,CAAA;AACpB,EAAA,OAAO,MAAA;AACT;;;;"}
+152
View File
@@ -0,0 +1,152 @@
import * as scale from '@pezkuwi/bizinikiwi-bindings';
import { StringRecord, UnifiedMetadata, V14Lookup, Codec } from '@pezkuwi/bizinikiwi-bindings';
type SignedPrimitive = "i8" | "i16" | "i32" | "i64" | "i128" | "i256";
type UnsignedPrimitive = "u8" | "u16" | "u32" | "u64" | "u128" | "u256";
type MetadataPrimitives = "bool" | "char" | "str" | SignedPrimitive | UnsignedPrimitive;
type PrimitiveVar = {
type: "primitive";
value: MetadataPrimitives;
};
type VoidVar = {
type: "void";
};
type CompactVar = {
type: "compact";
isBig: boolean;
size: UnsignedPrimitive;
};
type BitSequenceVar = {
type: "bitSequence";
isLSB: boolean;
};
type AccountId32 = {
type: "AccountId32";
};
type AccountId20 = {
type: "AccountId20";
};
type TerminalVar = PrimitiveVar | VoidVar | CompactVar | BitSequenceVar | AccountId32 | AccountId20;
type TupleVar = {
type: "tuple";
value: LookupEntry[];
innerDocs: Array<string[]>;
};
type StructVar = {
type: "struct";
value: StringRecord<LookupEntry>;
innerDocs: StringRecord<string[]>;
};
type EnumVar = {
type: "enum";
value: StringRecord<({
type: "lookupEntry";
value: LookupEntry;
} | VoidVar | TupleVar | StructVar | ArrayVar) & {
idx: number;
}>;
innerDocs: StringRecord<string[]>;
byteLength?: number;
};
type OptionVar = {
type: "option";
value: LookupEntry;
};
type ResultVar = {
type: "result";
value: {
ok: LookupEntry;
ko: LookupEntry;
};
};
type SequenceVar = {
type: "sequence";
value: LookupEntry;
};
type ArrayVar = {
type: "array";
value: LookupEntry;
len: number;
};
type ComposedVar = TupleVar | StructVar | SequenceVar | ArrayVar | OptionVar | ResultVar | EnumVar;
type Var = TerminalVar | ComposedVar;
type LookupEntry = {
id: number;
} & Var;
interface MetadataLookup {
(id: number): LookupEntry;
metadata: UnifiedMetadata;
call: number | null;
}
declare const denormalizeLookup: (lookupData: V14Lookup) => (id: number) => LookupEntry;
declare const getLookupFn: (metadata: UnifiedMetadata) => MetadataLookup;
declare const getDynamicBuilder: (getLookupEntryDef: MetadataLookup) => {
buildDefinition: (id: number) => Codec<any>;
buildStorage: (pallet: string, entry: string) => {
args: [scale.Encoder<any[]>, scale.Decoder<any[]>] & {
enc: scale.Encoder<any[]>;
dec: scale.Decoder<any[]>;
} & {
inner: Codec<any>[];
};
keys: {
enc: (...args: any[]) => string;
dec: (value: string) => any[];
};
value: Codec<any>;
len: number;
fallback: any;
};
buildEvent: (pallet: string, name: string) => {
codec: Codec<any>;
location: [number, number];
};
buildError: (pallet: string, name: string) => {
codec: Codec<any>;
location: [number, number];
};
buildViewFn: (pallet: string, entry: string) => {
args: [scale.Encoder<any[]>, scale.Decoder<any[]>] & {
enc: scale.Encoder<any[]>;
dec: scale.Decoder<any[]>;
} & {
inner: Codec<any>[];
};
value: Codec<any>;
};
buildRuntimeCall: (api: string, method: string) => {
args: [scale.Encoder<any[]>, scale.Decoder<any[]>] & {
enc: scale.Encoder<any[]>;
dec: scale.Decoder<any[]>;
} & {
inner: Codec<any>[];
};
value: Codec<any>;
};
buildCall: (pallet: string, name: string) => {
codec: Codec<any>;
location: [number, number];
};
buildConstant: (pallet: string, constantName: string) => Codec<any>;
ss58Prefix: number | undefined;
};
declare const getChecksumBuilder: (getLookupEntryDef: MetadataLookup) => {
buildDefinition: (id: number) => string | null;
buildRuntimeCall: (api: string, method: string) => string | null;
buildStorage: (pallet: string, entry: string) => string | null;
buildViewFns: (pallet: string, entry: string) => string | null;
buildCall: (pallet: string, name: string) => string | null;
buildEvent: (pallet: string, name: string) => string | null;
buildError: (pallet: string, name: string) => string | null;
buildConstant: (pallet: string, constantName: string) => string | null;
buildComposite: (input: VoidVar | TupleVar | StructVar | ArrayVar) => string | null;
buildNamedTuple: (input: StructVar) => string | null;
getAllGeneratedChecksums: () => string[];
};
declare const getLookupCodecBuilder: (lookup: (id: number) => LookupEntry, accountId?: Codec<scale.SS58String>) => (id: number) => Codec<any>;
export { denormalizeLookup, getChecksumBuilder, getDynamicBuilder, getLookupCodecBuilder, getLookupFn };
export type { AccountId20, AccountId32, ArrayVar, BitSequenceVar, CompactVar, ComposedVar, EnumVar, LookupEntry, MetadataLookup, MetadataPrimitives, OptionVar, PrimitiveVar, ResultVar, SequenceVar, SignedPrimitive, StructVar, TerminalVar, TupleVar, UnsignedPrimitive, Var, VoidVar };
+999
View File
@@ -0,0 +1,999 @@
'use strict';
var scale = require('@pezkuwi/bizinikiwi-bindings');
var utils = require('@pezkuwi/papi-utils');
function _interopNamespaceDefault(e) {
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var scale__namespace = /*#__PURE__*/_interopNamespaceDefault(scale);
const isBytes = (value, nBytes) => value.type === "array" && value.len === nBytes && value.value.type === "primitive" && value.value.value === "u8";
const _void = { type: "void" };
const _denormalizeLookup = (lookupData, customMap = () => null) => {
const lookups = /* @__PURE__ */ new Map();
const from = /* @__PURE__ */ new Set();
const withCache = (fn) => {
return (id) => {
let entry = lookups.get(id);
if (entry) return entry;
if (from.has(id)) {
const entry2 = {
id
};
lookups.set(id, entry2);
return entry2;
}
from.add(id);
const value = fn(id);
entry = lookups.get(id);
if (entry) {
Object.assign(entry, value);
} else {
entry = {
id,
...value
};
lookups.set(id, entry);
}
from.delete(id);
return entry;
};
};
let isAccountId32SearchOn = true;
let isAccountId20SearchOn = true;
const getLookupEntryDef = withCache((id) => {
const custom = customMap(lookupData[id]);
if (custom) return custom;
const { def, path, params } = lookupData[id];
if (def.tag === "composite") {
if (def.value.length === 0) return _void;
if (def.value.length === 1) {
const inner = getLookupEntryDef(def.value[0].type);
if (isAccountId32SearchOn && path.at(-1) === "AccountId32" && isBytes(inner, 32)) {
isAccountId32SearchOn = false;
return { type: "AccountId32" };
}
if (isAccountId20SearchOn && path.at(-1) === "AccountId20" && isBytes(inner, 20)) {
isAccountId20SearchOn = false;
return { type: "AccountId20" };
}
return inner;
}
return getComplexVar(def.value);
}
if (def.tag === "variant") {
if (path.length === 1 && path[0] === "Option" && params.length === 1 && params[0].name === "T") {
const value = getLookupEntryDef(params[0].type);
return value.type === "void" ? (
// Option<void> would return a Codec<undefined> which makes no sense
// Therefore, we better treat it as a bool
{ type: "primitive", value: "bool" }
) : {
type: "option",
value
};
}
if (path.length === 1 && path[0] === "Result" && params.length === 2 && params[0].name === "T" && params[1].name === "E") {
return {
type: "result",
value: {
ok: getLookupEntryDef(params[0].type),
ko: getLookupEntryDef(params[1].type)
}
};
}
if (def.value.length === 0) return _void;
const enumValue = {};
const enumDocs = {};
def.value.forEach((x) => {
const key = x.name;
enumDocs[key] = x.docs;
if (x.fields.length === 0) {
enumValue[key] = { ..._void, idx: x.index };
return;
}
if (x.fields.length === 1 && !x.fields[0].name) {
enumValue[key] = {
type: "lookupEntry",
value: getLookupEntryDef(x.fields[0].type),
idx: x.index
};
return;
}
enumValue[key] = { ...getComplexVar(x.fields), idx: x.index };
});
return {
type: "enum",
value: enumValue,
innerDocs: enumDocs
};
}
if (def.tag === "sequence")
return {
type: "sequence",
value: getLookupEntryDef(def.value)
};
if (def.tag === "array") {
const { len } = def.value;
const value = getLookupEntryDef(def.value.type);
return !len || value.type === "void" ? _void : len > 1 ? {
type: "array",
value,
len: def.value.len
} : value;
}
if (def.tag === "tuple") {
if (def.value.length === 0) return _void;
return def.value.length > 1 ? getArrayOrTuple(
def.value.map((x) => getLookupEntryDef(x)),
def.value.map((x) => lookupData[x].docs)
) : getLookupEntryDef(def.value[0]);
}
if (def.tag === "primitive") {
return {
type: "primitive",
value: def.value.tag
};
}
if (def.tag === "compact") {
const translated = getLookupEntryDef(def.value);
if (translated.type === "void") return _void;
const isBig = Number(translated.value.slice(1)) > 32;
return {
type: "compact",
isBig,
size: translated.value
};
}
return {
type: def.tag,
isLSB: (lookupData[def.value.bitOrderType].path.at(-1) ?? "LSB").toUpperCase().startsWith("LSB")
};
});
const getComplexVar = (input) => {
let allKey = true;
const values = {};
const innerDocs = {};
input.forEach((x, idx) => {
allKey = allKey && !!x.name;
const key = x.name || idx;
const value = getLookupEntryDef(x.type);
if (value.type !== "void") {
values[key] = value;
innerDocs[key] = x.docs;
}
});
return allKey ? {
type: "struct",
value: values,
innerDocs
} : getArrayOrTuple(Object.values(values), Object.values(innerDocs));
};
const getArrayOrTuple = (values, innerDocs) => {
if (values.every((v) => v.id === values[0].id) && innerDocs.every((doc) => !doc.length)) {
const [value] = values;
return value.type === "void" ? _void : {
type: "array",
value: values[0],
len: values.length
};
}
return {
type: "tuple",
value: values,
innerDocs
};
};
return getLookupEntryDef;
};
const denormalizeLookup = (lookupData) => _denormalizeLookup(lookupData);
const getLookupFn = (metadata) => {
const getLookupEntryDef = _denormalizeLookup(metadata.lookup, ({ def }) => {
if (def.tag === "composite") {
const moduleErrorLength = getModuleErrorLength(def);
if (moduleErrorLength) {
return {
type: "enum",
innerDocs: {},
value: Object.fromEntries(
metadata.pallets.map((p) => [
p.name,
p.errors == null ? { ..._void, idx: p.index } : {
type: "lookupEntry",
value: getLookupEntryDef(p.errors.type),
idx: p.index
}
])
),
byteLength: moduleErrorLength
};
}
}
return null;
});
function getModuleErrorLength(def) {
const preChecks = def.value.length === 2 && def.value[0].name === "index" && def.value[1].name === "error";
if (!preChecks) return null;
const index = getLookupEntryDef(def.value[0].type);
const error = getLookupEntryDef(def.value[1].type);
return index.type === "primitive" && index.value === "u8" && error.type === "array" && error.value.type === "primitive" && error.value.value === "u8" ? 1 + error.len : null;
}
const getCall = () => {
if ("call" in metadata.extrinsic) {
return metadata.extrinsic.call;
}
const extrinsic = metadata.lookup[metadata.extrinsic.type];
const call = extrinsic?.params.find((p) => p.name === "Call");
return call?.type ?? null;
};
return Object.assign(getLookupEntryDef, { metadata, call: getCall() });
};
const withCache = (fn, onEnterCircular, onExitCircular) => (input, cache, stack, ...rest) => {
const { id } = input;
if (cache.has(id)) return cache.get(id);
if (stack.has(id)) {
const res = onEnterCircular(() => cache.get(id), input, ...rest);
cache.set(id, res);
return res;
}
stack.add(id);
let result = fn(input, cache, stack, ...rest);
stack.delete(id);
if (cache.has(id))
result = onExitCircular(result, cache.get(id), input, ...rest);
cache.set(id, result);
return result;
};
const _bytes = scale__namespace.Bin();
const _buildCodec = (input, cache, stack, _accountId) => {
if (input.type === "primitive") return scale__namespace[input.value];
if (input.type === "void") return scale__namespace._void;
if (input.type === "AccountId32") return _accountId;
if (input.type === "AccountId20") return scale__namespace.ethAccount;
if (input.type === "compact")
return input.isBig ? scale__namespace.compactBn : scale__namespace.compactNumber;
if (input.type === "bitSequence") return scale__namespace.BitSeq(input.isLSB);
const buildNextCodec = (nextInput) => buildCodec(nextInput, cache, stack, _accountId);
const buildVector = (inner2, len) => {
const innerCodec = buildNextCodec(inner2);
return len ? scale__namespace.Vector(innerCodec, len) : scale__namespace.Vector(innerCodec);
};
const buildTuple = (value) => scale__namespace.Tuple(...value.map(buildNextCodec));
const buildStruct = (value) => {
const inner2 = Object.fromEntries(
Object.entries(value).map(([key, value2]) => [key, buildNextCodec(value2)])
);
return scale__namespace.Struct(inner2);
};
if (input.type === "sequence" && input.value.type === "primitive" && input.value.value === "u8") {
return _bytes;
}
if (input.type === "array") {
if (input.value.type === "primitive" && input.value.value === "u8")
return scale__namespace.Bin(input.len);
return buildVector(input.value, input.len);
}
if (input.type === "sequence") return buildVector(input.value);
if (input.type === "tuple") return buildTuple(input.value);
if (input.type === "struct") return buildStruct(input.value);
if (input.type === "option") return scale__namespace.Option(buildNextCodec(input.value));
if (input.type === "result")
return scale__namespace.Result(
buildNextCodec(input.value.ok),
buildNextCodec(input.value.ko)
);
const dependencies = Object.values(input.value).map((v) => {
switch (v.type) {
case "void":
return scale__namespace._void;
case "lookupEntry":
return buildNextCodec(v.value);
case "tuple":
return buildTuple(v.value);
case "struct":
return buildStruct(v.value);
case "array":
return buildVector(v.value, v.len);
}
});
const inner = Object.fromEntries(
Object.keys(input.value).map((key, idx) => {
return [key, dependencies[idx]];
})
);
const indexes = Object.values(input.value).map((x) => x.idx);
const areIndexesSorted = indexes.every((idx, i) => idx === i);
const variantCodec = areIndexesSorted ? scale__namespace.Variant(inner) : scale__namespace.Variant(inner, indexes);
return input.byteLength ? fixedSizeCodec(variantCodec, input.byteLength) : variantCodec;
};
const buildCodec = withCache(_buildCodec, scale__namespace.Self, (res) => res);
const getLookupCodecBuilder = (lookup, accountId = scale__namespace.AccountId()) => {
const cache = /* @__PURE__ */ new Map();
const buildDefinition = (id) => buildCodec(lookup(id), cache, /* @__PURE__ */ new Set(), accountId);
return (id) => buildDefinition(id);
};
const fixedSizeCodec = (codec, size) => {
const allBytes = scale__namespace.Bytes(size);
return scale__namespace.createCodec(
(value) => allBytes.enc(codec.enc(value)),
(data) => codec.dec(allBytes.dec(data))
);
};
const nullCodec = scale__namespace.enhanceCodec(
scale__namespace._void,
() => void 0,
() => null
);
const getDynamicBuilder = (getLookupEntryDef) => {
const { metadata } = getLookupEntryDef;
let buildDefinition = getLookupCodecBuilder(getLookupEntryDef);
const prefix = metadata.pallets.find((x) => x.name === "System")?.constants.find((x) => x.name === "SS58Prefix");
let ss58Prefix;
if (prefix) {
try {
const prefixVal = buildDefinition(prefix.type).dec(prefix.value);
if (typeof prefixVal === "number") {
ss58Prefix = prefixVal;
buildDefinition = getLookupCodecBuilder(
getLookupEntryDef,
scale__namespace.AccountId(prefixVal)
);
}
} catch (_) {
}
}
const storagePallets = /* @__PURE__ */ new Map();
const buildStorage = (pallet, entry) => {
let storagePallet = storagePallets.get(pallet);
if (!storagePallet)
storagePallets.set(pallet, storagePallet = scale__namespace.Storage(pallet));
const storageEntry = metadata.pallets.find((x) => x.name === pallet).storage.items.find((s) => s.name === entry);
const withNullVoid = (codec) => codec === scale__namespace._void ? nullCodec : codec;
const storageWithFallback = (len, value2, ...args) => {
const keys = storagePallet(...args);
const [, ...encodersWithHash] = args;
return {
args: scale__namespace.Tuple(...encodersWithHash.map(([codec]) => codec)),
keys,
value: value2,
len,
fallback: storageEntry.modifier === 1 ? value2.dec(storageEntry.fallback) : void 0
};
};
if (storageEntry.type.tag === "plain")
return storageWithFallback(
0,
withNullVoid(buildDefinition(storageEntry.type.value)),
entry
);
const { key, value, hashers } = storageEntry.type.value;
const val = withNullVoid(buildDefinition(value));
const hashes = hashers.map((x) => scale__namespace[x.tag]);
const hashArgs = (() => {
if (hashes.length === 1) {
return [[buildDefinition(key), hashes[0]]];
}
const keyDef = getLookupEntryDef(key);
switch (keyDef.type) {
case "array":
return hashes.map((hash) => [buildDefinition(keyDef.value.id), hash]);
case "tuple":
return keyDef.value.map((x, idx) => [
buildDefinition(x.id),
hashes[idx]
]);
default:
throw new Error("Invalid key type");
}
})();
return storageWithFallback(hashes.length, val, entry, ...hashArgs);
};
const buildEnumEntry = (entry) => {
switch (entry.type) {
case "void":
return scale__namespace._void;
case "lookupEntry":
return buildDefinition(entry.value.id);
case "tuple":
return scale__namespace.Tuple(
...Object.values(entry.value).map((l) => buildDefinition(l.id))
);
case "struct":
return scale__namespace.Struct(
utils.mapObject(entry.value, (x) => buildDefinition(x.id))
);
case "array":
return scale__namespace.Vector(buildDefinition(entry.value.id), entry.len);
}
};
const buildConstant = (pallet, constantName) => {
const storageEntry = metadata.pallets.find((x) => x.name === pallet).constants.find((s) => s.name === constantName);
return buildDefinition(storageEntry.type);
};
const buildVariant = (type) => (pallet, name) => {
const palletEntry = metadata.pallets.find((x) => x.name === pallet);
const lookup = getLookupEntryDef(palletEntry[type].type);
if (lookup.type !== "enum") throw null;
const entry = lookup.value[name];
return {
location: [palletEntry.index, entry.idx],
codec: buildEnumEntry(lookup.value[name])
};
};
const buildViewFn = (pallet, entry) => {
const fn = metadata.pallets.find((x) => x.name === pallet)?.viewFns.find((x) => x.name === entry);
if (!fn) throw null;
return {
args: scale__namespace.Tuple(...fn.inputs.map((x) => buildDefinition(x.type))),
value: buildDefinition(fn.output)
};
};
const buildRuntimeCall = (api, method) => {
const entry = metadata.apis.find((x) => x.name === api)?.methods.find((x) => x.name === method);
if (!entry) throw null;
return {
args: scale__namespace.Tuple(...entry.inputs.map((x) => buildDefinition(x.type))),
value: buildDefinition(entry.output)
};
};
return {
buildDefinition,
buildStorage,
buildEvent: buildVariant("events"),
buildError: buildVariant("errors"),
buildViewFn,
buildRuntimeCall,
buildCall: buildVariant("calls"),
buildConstant,
ss58Prefix
};
};
function buildLookupGraph(lookupFn, lookupLength) {
const result = /* @__PURE__ */ new Map();
const visited = /* @__PURE__ */ new Set();
const addEdge = (from, to) => {
if (!result.has(from))
result.set(from, {
entry: lookupFn(from),
backRefs: /* @__PURE__ */ new Set(),
refs: /* @__PURE__ */ new Set()
});
if (!result.has(to))
result.set(to, {
entry: lookupFn(to),
backRefs: /* @__PURE__ */ new Set(),
refs: /* @__PURE__ */ new Set()
});
result.get(from).refs.add(to);
result.get(to).backRefs.add(from);
};
for (let i = 0; i < lookupLength; i++) {
const entry = lookupFn(i);
if (i !== entry.id) {
addEdge(i, entry.id);
}
if (visited.has(entry.id)) continue;
visited.add(entry.id);
switch (entry.type) {
case "array":
case "option":
case "sequence":
addEdge(entry.id, entry.value.id);
break;
case "enum":
Object.values(entry.value).forEach((enumEntry) => {
switch (enumEntry.type) {
case "array":
case "lookupEntry":
addEdge(entry.id, enumEntry.value.id);
break;
case "struct":
case "tuple":
Object.values(enumEntry.value).forEach(
(v) => addEdge(entry.id, v.id)
);
break;
}
});
break;
case "result":
addEdge(entry.id, entry.value.ok.id);
addEdge(entry.id, entry.value.ko.id);
break;
case "struct":
case "tuple":
Object.values(entry.value).forEach((v) => addEdge(entry.id, v.id));
break;
}
if (!result.has(entry.id)) {
result.set(entry.id, {
backRefs: /* @__PURE__ */ new Set(),
refs: /* @__PURE__ */ new Set(),
entry
});
}
}
return result;
}
const subgraphCache = /* @__PURE__ */ new WeakMap();
function _getSubgraph(id, graph, result, cache) {
if (result.has(id)) return;
const node = graph.get(id);
result.set(id, node);
cache.set(id, result);
node.refs.forEach((ref) => _getSubgraph(ref, graph, result, cache));
node.backRefs.forEach((ref) => _getSubgraph(ref, graph, result, cache));
}
function getSubgraph(id, graph) {
if (!subgraphCache.has(graph)) {
subgraphCache.set(graph, /* @__PURE__ */ new Map());
}
const cache = subgraphCache.get(graph);
if (cache.has(id)) return cache.get(id);
const result = /* @__PURE__ */ new Map();
_getSubgraph(id, graph, result, cache);
return result;
}
function getStronglyConnectedComponents(graph) {
const tarjanState = /* @__PURE__ */ new Map();
let index = 0;
const stack = [];
const result = [];
function strongConnect(v) {
const state = {
index,
lowLink: index,
onStack: true
};
tarjanState.set(v, state);
index++;
stack.push(v);
const edges = graph.get(v).refs;
for (let w of edges) {
const edgeState = tarjanState.get(w);
if (!edgeState) {
strongConnect(w);
state.lowLink = Math.min(state.lowLink, tarjanState.get(w).lowLink);
} else if (edgeState.onStack) {
state.lowLink = Math.min(state.lowLink, edgeState.index);
}
}
if (state.lowLink === state.index) {
const component = /* @__PURE__ */ new Set();
let poppedNode = -1;
do {
poppedNode = stack.pop();
tarjanState.get(poppedNode).onStack = false;
component.add(poppedNode);
} while (poppedNode !== v);
result.push(component);
}
}
for (const node of graph.keys()) {
if (!tarjanState.has(node)) {
strongConnect(node);
}
}
return result;
}
function mergeSCCsWithCommonNodes(stronglyConnectedComponents) {
const scc = stronglyConnectedComponents;
const ungroupedCycles = new Set(scc.map((_, i) => i));
const edges = new Map(scc.map((_, i) => [i, /* @__PURE__ */ new Set()]));
scc.forEach((cycle, i) => {
scc.slice(i + 1).forEach((otherCycle, _j) => {
const j = _j + i + 1;
const combined = /* @__PURE__ */ new Set([...cycle, ...otherCycle]);
if (combined.size !== cycle.size + otherCycle.size) {
edges.get(i).add(j);
edges.get(j).add(i);
}
});
});
const groups = [];
while (ungroupedCycles.size) {
const group = /* @__PURE__ */ new Set();
const toVisit = [ungroupedCycles.values().next().value];
while (toVisit.length) {
const idx = toVisit.pop();
if (!ungroupedCycles.has(idx)) continue;
ungroupedCycles.delete(idx);
const cycle = scc[idx];
cycle.forEach((v) => group.add(Number(v)));
edges.get(idx).forEach((n) => toVisit.push(n));
}
groups.push(group);
}
return groups;
}
const textEncoder = new TextEncoder();
const encodeText = textEncoder.encode.bind(textEncoder);
const getChecksum = (values) => {
const res = new Uint8Array(values.length * 8);
const dv = new DataView(res.buffer);
for (let i = 0; i < values.length; i++) dv.setBigUint64(i * 8, values[i]);
return scale.h64(res);
};
const getStringChecksum = (values) => getChecksum(values.map((v) => scale.h64(encodeText(v))));
const shapeIds = {
primitive: 0n,
vector: 1n,
tuple: 2n,
struct: 3n,
option: 4n,
result: 5n,
enum: 6n,
void: 7n
};
const runtimePrimitiveIds = {
undefined: 0n,
number: 1n,
string: 2n,
bigint: 3n,
boolean: 4n,
bitSequence: 5n,
// {bitsLen: number, bytes: Uint8Array}
byteSequence: 6n,
// Binary
accountId32: 7n,
// SS58String
accountId20: 8n
// EthAccount
};
const metadataPrimitiveIds = {
bool: runtimePrimitiveIds.boolean,
char: runtimePrimitiveIds.string,
str: runtimePrimitiveIds.string,
u8: runtimePrimitiveIds.number,
u16: runtimePrimitiveIds.number,
u32: runtimePrimitiveIds.number,
u64: runtimePrimitiveIds.bigint,
u128: runtimePrimitiveIds.bigint,
u256: runtimePrimitiveIds.bigint,
i8: runtimePrimitiveIds.number,
i16: runtimePrimitiveIds.number,
i32: runtimePrimitiveIds.number,
i64: runtimePrimitiveIds.bigint,
i128: runtimePrimitiveIds.bigint,
i256: runtimePrimitiveIds.bigint
};
const structLikeBuilder = (shapeId, input, innerChecksum) => {
const sortedEntries = Object.entries(input).sort(
([a], [b]) => a.localeCompare(b)
);
const keysChecksum = getStringChecksum(sortedEntries.map(([key]) => key));
const valuesChecksum = getChecksum(
sortedEntries.map(([, entry]) => innerChecksum(entry))
);
return getChecksum([shapeId, keysChecksum, valuesChecksum]);
};
const _buildChecksum = (input, buildNextChecksum) => {
if (input.type === "primitive")
return getChecksum([shapeIds.primitive, metadataPrimitiveIds[input.value]]);
if (input.type === "void") return getChecksum([shapeIds.void]);
if (input.type === "compact")
return getChecksum([
shapeIds.primitive,
runtimePrimitiveIds[input.isBig ? "bigint" : "number"]
]);
if (input.type === "bitSequence")
return getChecksum([shapeIds.primitive, runtimePrimitiveIds.bitSequence]);
if (input.type === "AccountId32") {
return getChecksum([shapeIds.primitive, runtimePrimitiveIds.accountId32]);
}
if (input.type === "AccountId20") {
return getChecksum([shapeIds.primitive, runtimePrimitiveIds.accountId20]);
}
const buildVector = (entry, length) => {
const innerChecksum = buildNextChecksum(entry);
return getChecksum(
length !== void 0 ? [shapeIds.vector, innerChecksum, BigInt(length)] : [shapeIds.vector, innerChecksum]
);
};
if (input.type === "array") {
const innerValue = input.value;
if (innerValue.type === "primitive" && innerValue.value === "u8") {
return getChecksum([
shapeIds.primitive,
runtimePrimitiveIds.byteSequence,
BigInt(input.len)
]);
}
return buildVector(innerValue, input.len);
}
if (input.type === "sequence") {
const innerValue = input.value;
if (innerValue.type === "primitive" && innerValue.value === "u8") {
return getChecksum([shapeIds.primitive, runtimePrimitiveIds.byteSequence]);
}
return buildVector(innerValue);
}
const buildTuple = (entries) => getChecksum([shapeIds.tuple, ...entries.map(buildNextChecksum)]);
const buildStruct = (entries) => structLikeBuilder(shapeIds.struct, entries, buildNextChecksum);
if (input.type === "tuple") return buildTuple(input.value);
if (input.type === "struct") return buildStruct(input.value);
if (input.type === "option")
return getChecksum([shapeIds.option, buildNextChecksum(input.value)]);
if (input.type === "result")
return getChecksum([
shapeIds.result,
buildNextChecksum(input.value.ok),
buildNextChecksum(input.value.ko)
]);
return structLikeBuilder(shapeIds.enum, input.value, (entry) => {
if (entry.type === "lookupEntry") return buildNextChecksum(entry.value);
switch (entry.type) {
case "void":
return getChecksum([shapeIds.void]);
case "tuple":
return buildTuple(entry.value);
case "struct":
return buildStruct(entry.value);
case "array":
return buildVector(entry.value, entry.len);
}
});
};
const sortCyclicGroups = (groups, graph) => {
const getReachableNodes = (group) => {
const result2 = /* @__PURE__ */ new Set();
const toVisit = Array.from(group);
while (toVisit.length) {
const id = toVisit.pop();
if (result2.has(id)) continue;
result2.add(id);
graph.get(id)?.refs.forEach((id2) => toVisit.push(id2));
}
return Array.from(result2);
};
const result = new Array();
function dependentsFirst(group) {
if (result.includes(group)) return;
const dependents = groups.filter(
(candidate) => candidate !== group && getReachableNodes(group).some((node) => candidate.has(node))
);
dependents.forEach((group2) => dependentsFirst(group2));
if (result.includes(group)) return;
result.push(group);
}
groups.forEach((group) => dependentsFirst(group));
return result;
};
function iterateChecksums(group, iterations, cache, graph) {
const groupReadCache = new Map([...group].map((id) => [id, 0n]));
const groupWriteCache = /* @__PURE__ */ new Map();
const recursiveBuildChecksum = (entry, skipCache = true) => {
if (!skipCache && (groupReadCache.has(entry.id) || cache.has(entry.id))) {
return groupReadCache.get(entry.id) ?? cache.get(entry.id);
}
const result = _buildChecksum(
entry,
(nextEntry) => recursiveBuildChecksum(nextEntry, false)
);
if (group.has(entry.id)) {
groupWriteCache.set(entry.id, result);
} else {
cache.set(entry.id, result);
}
return result;
};
for (let i = 0; i < iterations; i++) {
group.forEach((id) => recursiveBuildChecksum(graph.get(id).entry));
group.forEach((id) => groupReadCache.set(id, groupWriteCache.get(id)));
}
return groupReadCache;
}
function getMirroredNodes(cyclicGroups, graph) {
const maxSize = cyclicGroups.reduce(
(acc, group) => Math.max(acc, group.size),
0
);
const allEntries = new Set([...graph.values()].map((v) => v.entry.id));
const resultingChecksums = iterateChecksums(
allEntries,
maxSize,
// Cache won't be used, since it's using the internal one for every node.
/* @__PURE__ */ new Map(),
graph
);
const checksumToNodes = /* @__PURE__ */ new Map();
for (const id of allEntries) {
const checksum = resultingChecksums.get(id);
if (checksum == void 0) throw new Error("Unreachable");
if (!checksumToNodes.has(checksum)) {
checksumToNodes.set(checksum, []);
}
checksumToNodes.get(checksum).push(id);
}
const checksumsWithDuplicates = [...checksumToNodes.entries()].filter(
([, nodes]) => nodes.length > 1
);
const duplicatesMap = {};
checksumsWithDuplicates.forEach(([, nodes]) => {
nodes.forEach((n) => duplicatesMap[n] = nodes);
});
return duplicatesMap;
}
const buildChecksum = (entry, cache, graph) => {
if (cache.has(entry.id)) return cache.get(entry.id);
const subGraph = getSubgraph(entry.id, graph);
const cycles = getStronglyConnectedComponents(subGraph).filter(
// SCCs can be of length=1, but for those we're only interested with those that are circular with themselves
(group) => group.size > 1 || isSelfCircular(group, subGraph)
);
const cyclicGroups = mergeSCCsWithCommonNodes(cycles).filter((group) => {
return !cache.has(group.values().next().value);
});
const mirrored = getMirroredNodes(cyclicGroups, subGraph);
const sortedCyclicGroups = sortCyclicGroups(cyclicGroups, subGraph);
sortedCyclicGroups.forEach((group) => {
if (cache.has(group.values().next().value)) {
return;
}
const result = iterateChecksums(group, group.size, cache, graph);
group.forEach((id) => {
const checksum = result.get(id);
if (id in mirrored) {
mirrored[id].forEach((id2) => cache.set(id2, checksum));
} else {
cache.set(id, checksum);
}
});
});
const getChecksum2 = (entry2) => {
if (cache.has(entry2.id)) return cache.get(entry2.id);
return _buildChecksum(entry2, getChecksum2);
};
return getChecksum2(entry);
};
const isSelfCircular = (group, graph) => {
if (group.size !== 1) return false;
const [id] = group;
return graph.get(id).refs.has(id);
};
const getChecksumBuilder = (getLookupEntryDef) => {
const { metadata } = getLookupEntryDef;
const graph = buildLookupGraph(getLookupEntryDef, metadata.lookup.length);
const cache = /* @__PURE__ */ new Map();
const buildDefinition = (id) => buildChecksum(getLookupEntryDef(id), cache, graph);
const buildStorage = (pallet, entry) => {
try {
const storageEntry = metadata.pallets.find((x) => x.name === pallet).storage.items.find((s) => s.name === entry);
if (storageEntry.type.tag === "plain")
return buildDefinition(storageEntry.type.value);
const { key, value } = storageEntry.type.value;
const val = buildDefinition(value);
const returnKey = buildDefinition(key);
return getChecksum([val, returnKey]);
} catch (_) {
return null;
}
};
const buildViewFns = (pallet, entry) => {
try {
const viewFn = metadata.pallets.find((x) => x.name === pallet)?.viewFns.find((x) => x.name === entry);
if (!viewFn) throw null;
const argNamesChecksum = getStringChecksum(
viewFn.inputs.map((x) => x.name)
);
const argValuesChecksum = getChecksum(
viewFn.inputs.map((x) => buildDefinition(x.type))
);
const outputChecksum = buildDefinition(viewFn.output);
return getChecksum([argNamesChecksum, argValuesChecksum, outputChecksum]);
} catch (_) {
return null;
}
};
const buildRuntimeCall = (api, method) => {
try {
const entry = metadata.apis.find((x) => x.name === api)?.methods.find((x) => x.name === method);
if (!entry) throw null;
const argNamesChecksum = getStringChecksum(
entry.inputs.map((x) => x.name)
);
const argValuesChecksum = getChecksum(
entry.inputs.map((x) => buildDefinition(x.type))
);
const outputChecksum = buildDefinition(entry.output);
return getChecksum([argNamesChecksum, argValuesChecksum, outputChecksum]);
} catch (_) {
return null;
}
};
const buildComposite = (input) => {
if (input.type === "void") return getChecksum([0n]);
if (input.type === "tuple") {
const values = Object.values(input.value).map(
(entry) => buildDefinition(entry.id)
);
return getChecksum([shapeIds.tuple, ...values]);
}
if (input.type === "array") {
return getChecksum([
shapeIds.vector,
buildDefinition(input.value.id),
BigInt(input.len)
]);
}
return structLikeBuilder(
shapeIds.struct,
input.value,
(entry) => buildDefinition(entry.id)
);
};
const buildNamedTuple = (input) => {
return structLikeBuilder(
shapeIds.tuple,
input.value,
(entry) => buildDefinition(entry.id)
);
};
const variantShapeId = {
errors: 1n,
events: 2n,
calls: 3n
};
const buildVariant = (variantType) => (pallet, name) => {
try {
const palletEntry = metadata.pallets.find((x) => x.name === pallet);
const enumLookup = getLookupEntryDef(palletEntry[variantType].type);
buildDefinition(enumLookup.id);
if (enumLookup.type !== "enum") throw null;
const entry = enumLookup.value[name];
const valueChecksum = entry.type === "lookupEntry" ? buildDefinition(entry.value.id) : buildComposite(entry);
return getChecksum([variantShapeId[variantType], valueChecksum]);
} catch (_) {
return null;
}
};
const buildConstant = (pallet, constantName) => {
try {
const storageEntry = metadata.pallets.find((x) => x.name === pallet).constants.find((s) => s.name === constantName);
return buildDefinition(storageEntry.type);
} catch (_) {
return null;
}
};
const toStringEnhancer = (fn) => (...args) => fn(...args)?.toString(32) ?? null;
return {
buildDefinition: toStringEnhancer(buildDefinition),
buildRuntimeCall: toStringEnhancer(buildRuntimeCall),
buildStorage: toStringEnhancer(buildStorage),
buildViewFns: toStringEnhancer(buildViewFns),
buildCall: toStringEnhancer(buildVariant("calls")),
buildEvent: toStringEnhancer(buildVariant("events")),
buildError: toStringEnhancer(buildVariant("errors")),
buildConstant: toStringEnhancer(buildConstant),
buildComposite: toStringEnhancer(buildComposite),
buildNamedTuple: toStringEnhancer(buildNamedTuple),
getAllGeneratedChecksums: () => Array.from(cache.values()).map((v) => v.toString(32))
};
};
exports.denormalizeLookup = denormalizeLookup;
exports.getChecksumBuilder = getChecksumBuilder;
exports.getDynamicBuilder = getDynamicBuilder;
exports.getLookupCodecBuilder = getLookupCodecBuilder;
exports.getLookupFn = getLookupFn;
//# sourceMappingURL=index.js.map
File diff suppressed because one or more lines are too long
+45
View File
@@ -0,0 +1,45 @@
{
"name": "@pezkuwi/metadata-builders",
"version": "1.0.0",
"author": "Dijital Kurdistan Tech Institute <info@pezkuwichain.io>",
"bugs": "https://github.com/pezkuwichain/pezkuwi-api/issues",
"homepage": "https://github.com/pezkuwichain/pezkuwi-api/tree/master/packages/metadata-builders#readme",
"repository": {
"directory": "packages/metadata-builders",
"type": "git",
"url": "https://github.com/pezkuwichain/pezkuwi-api.git"
},
"license": "MIT",
"sideEffects": false,
"type": "module",
"exports": {
".": {
"node": {
"production": {
"import": "./dist/esm/index.mjs",
"require": "./dist/index.js",
"default": "./dist/index.js"
},
"import": "./dist/esm/index.mjs",
"require": "./dist/index.js",
"default": "./dist/index.js"
},
"module": "./dist/esm/index.mjs",
"import": "./dist/esm/index.mjs",
"require": "./dist/index.js",
"default": "./dist/index.js"
},
"./package.json": "./package.json"
},
"main": "./dist/index.js",
"module": "./dist/esm/index.mjs",
"browser": "./dist/esm/index.mjs",
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"dependencies": {
"@pezkuwi/bizinikiwi-bindings": "1.0.0",
"@pezkuwi/papi-utils": "1.0.0"
}
}