@koralabs/kora-labs-common 6.9.2 → 6.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/mpt/index.d.ts +9 -13
- package/mpt/index.js +10 -13
- package/package.json +1 -1
- package/mpt/registryValue.d.ts +0 -25
- package/mpt/registryValue.js +0 -78
package/mpt/index.d.ts
CHANGED
|
@@ -1,21 +1,17 @@
|
|
|
1
1
|
import { Trie } from '@aiken-lang/merkle-patricia-forestry';
|
|
2
2
|
import * as labelSet from './labelSet';
|
|
3
|
-
|
|
4
|
-
export { labelSet, registryValue };
|
|
3
|
+
export { labelSet };
|
|
5
4
|
export { Trie };
|
|
6
5
|
/**
|
|
7
6
|
* A minting-data MPT entry. A bare string is shorthand for a handle with no registry value
|
|
8
|
-
* (value = ""). The object form carries the
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* allowance). The DeMi free-virtual mint/burn path writes this into the root key's value, so it
|
|
12
|
-
* MUST be supplied or the off-chain root drifts from chain on every root holding a free virtual.
|
|
13
|
-
* - `labels`: the sorted CIP-67 label set (001-004). The in-band `MintLabelAssets` path is NOT
|
|
14
|
-
* yet deployed on-chain, so callers pass "" today; flip to the real label set when it ships.
|
|
7
|
+
* (value = ""). The object form carries the key's on-chain value — the sorted CIP-67 label set
|
|
8
|
+
* (001-004) bytes. (The 3-free-virtual feature was removed, so keys no longer carry a free-name
|
|
9
|
+
* value; the only non-empty value is the label set, once the in-band MintLabelAssets path ships.)
|
|
15
10
|
*/
|
|
16
11
|
export interface MintingDataEntry {
|
|
17
12
|
name: string;
|
|
18
|
-
|
|
13
|
+
/** Sorted CIP-67 label set (001-004) hex. Empty/absent => value "". The in-band MintLabelAssets
|
|
14
|
+
* path is not on-chain yet, so callers pass "" today; flip to the real set when it ships. */
|
|
19
15
|
labels?: string;
|
|
20
16
|
}
|
|
21
17
|
type MintingDataInput = ReadonlyArray<string | MintingDataEntry>;
|
|
@@ -24,10 +20,10 @@ type MintingDataInput = ReadonlyArray<string | MintingDataEntry>;
|
|
|
24
20
|
* Consumers that only need the root hash should use {@link computeMintingDataRoot}; consumers that
|
|
25
21
|
* generate proofs (the minting engine's verifyRootHash) keep the returned Trie.
|
|
26
22
|
*
|
|
27
|
-
* The value at each key is
|
|
23
|
+
* The value at each key is the sorted label-set bytes (CIP-67 001-004), byte-identical to what the
|
|
28
24
|
* on-chain `demimntmpt` validator stores (`mpt.update` verifies the old bytes). A handle with no
|
|
29
|
-
*
|
|
30
|
-
*
|
|
25
|
+
* labels => value "" (the `update_root` `mpt.insert(root, name, #"")` case), so passing bare strings
|
|
26
|
+
* reproduces the empty-valued root exactly — which is every key today (labels not yet on-chain).
|
|
31
27
|
*/
|
|
32
28
|
export declare const buildMintingDataTrie: (handles: MintingDataInput) => Promise<Trie>;
|
|
33
29
|
/**
|
package/mpt/index.js
CHANGED
|
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.computeMintingDataRoot = exports.buildMintingDataTrie = exports.Trie = exports.
|
|
26
|
+
exports.computeMintingDataRoot = exports.buildMintingDataTrie = exports.Trie = exports.labelSet = void 0;
|
|
27
27
|
// Server-only (Node) MPT module. Pulls @aiken-lang/merkle-patricia-forestry (native `level`/`blake2b`)
|
|
28
28
|
// so it is NOT re-exported from the package root — import it from the subpath:
|
|
29
29
|
// import { computeMintingDataRoot } from '@koralabs/kora-labs-common/mpt';
|
|
@@ -32,21 +32,19 @@ const merkle_patricia_forestry_1 = require("@aiken-lang/merkle-patricia-forestry
|
|
|
32
32
|
Object.defineProperty(exports, "Trie", { enumerable: true, get: function () { return merkle_patricia_forestry_1.Trie; } });
|
|
33
33
|
const labelSet = __importStar(require("./labelSet"));
|
|
34
34
|
exports.labelSet = labelSet;
|
|
35
|
-
const registryValue = __importStar(require("./registryValue"));
|
|
36
|
-
exports.registryValue = registryValue;
|
|
37
35
|
const EMPTY_ROOT_HEX = Buffer.alloc(32).toString('hex');
|
|
38
36
|
/**
|
|
39
37
|
* THE canonical minting-data MPT (a real {@link Trie}, for proof generation during mint/burn).
|
|
40
38
|
* Consumers that only need the root hash should use {@link computeMintingDataRoot}; consumers that
|
|
41
39
|
* generate proofs (the minting engine's verifyRootHash) keep the returned Trie.
|
|
42
40
|
*
|
|
43
|
-
* The value at each key is
|
|
41
|
+
* The value at each key is the sorted label-set bytes (CIP-67 001-004), byte-identical to what the
|
|
44
42
|
* on-chain `demimntmpt` validator stores (`mpt.update` verifies the old bytes). A handle with no
|
|
45
|
-
*
|
|
46
|
-
*
|
|
43
|
+
* labels => value "" (the `update_root` `mpt.insert(root, name, #"")` case), so passing bare strings
|
|
44
|
+
* reproduces the empty-valued root exactly — which is every key today (labels not yet on-chain).
|
|
47
45
|
*/
|
|
48
46
|
const buildMintingDataTrie = async (handles) => {
|
|
49
|
-
var _a
|
|
47
|
+
var _a;
|
|
50
48
|
const seen = new Set();
|
|
51
49
|
const entries = [];
|
|
52
50
|
for (const handle of handles) {
|
|
@@ -54,12 +52,11 @@ const buildMintingDataTrie = async (handles) => {
|
|
|
54
52
|
if (!name || seen.has(name))
|
|
55
53
|
continue;
|
|
56
54
|
seen.add(name);
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
// MPF treats string values as UTF-8; supply
|
|
61
|
-
|
|
62
|
-
entries.push({ key: name, value: encoded ? Buffer.from(encoded, 'hex') : '' });
|
|
55
|
+
const labels = typeof handle === 'string' ? '' : (_a = handle.labels) !== null && _a !== void 0 ? _a : '';
|
|
56
|
+
// The key's value is the sorted label-set bytes (CIP-67 001-004), or "" when it holds none.
|
|
57
|
+
// The 3-free-virtual feature was removed, so no key carries a free-name value any more.
|
|
58
|
+
// MPF treats string values as UTF-8; supply decoded bytes for a non-empty label set.
|
|
59
|
+
entries.push({ key: name, value: labels ? Buffer.from(labels, 'hex') : '' });
|
|
63
60
|
}
|
|
64
61
|
return merkle_patricia_forestry_1.Trie.fromList(entries);
|
|
65
62
|
};
|
package/package.json
CHANGED
package/mpt/registryValue.d.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Byte-identical to on-chain `registry_value.encode(free_names, labels)`.
|
|
3
|
-
* free_names == [] -> labels (an empty handle stays "", any pure-label handle is WS1-identical)
|
|
4
|
-
* free_names != [] -> "ff" ++ serialise_data(free_names) ++ labels
|
|
5
|
-
*/
|
|
6
|
-
export declare const encode: (freeNames: string[], labels: string) => string;
|
|
7
|
-
/** A free slot is available iff the root holds fewer than the configured free count. */
|
|
8
|
-
export declare const hasFreeSlot: (freeNames: string[], freeVirtualCount: number) => boolean;
|
|
9
|
-
/** Is this sub-name one of the root's current free names? */
|
|
10
|
-
export declare const hasFreeName: (freeNames: string[], name: string) => boolean;
|
|
11
|
-
/**
|
|
12
|
-
* Add a sub-name to the free set (a free private-virtual MINT). Prepends (mirrors aiken
|
|
13
|
-
* `list.push`) and is idempotent — the prepend order is part of the encoded bytes, so it MUST
|
|
14
|
-
* match the contract's `add_free_name`.
|
|
15
|
-
*/
|
|
16
|
-
export declare const addFreeName: (freeNames: string[], name: string) => string[];
|
|
17
|
-
/**
|
|
18
|
-
* Remove a sub-name from the free set (a free private-virtual BURN → reopen its slot). No-op if
|
|
19
|
-
* the name isn't in the set (a paid sub's burn doesn't touch the allowance). Preserves order.
|
|
20
|
-
*/
|
|
21
|
-
export declare const removeFreeName: (freeNames: string[], name: string) => string[];
|
|
22
|
-
/** Parse a stored comma-hex free-name list ("" -> []). */
|
|
23
|
-
export declare const parseFreeNames: (csv: string | null | undefined) => string[];
|
|
24
|
-
/** Serialize a free-name set back to comma-hex for storage. */
|
|
25
|
-
export declare const serializeFreeNames: (freeNames: string[]) => string;
|
package/mpt/registryValue.js
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// DSH-402 — TypeScript port of the on-chain `registry_value.ak`. The MPT value at a ROOT
|
|
3
|
-
// handle key carries, alongside the WS1 label set, the SET OF NAMES of the root's currently-held
|
|
4
|
-
// FREE private virtual subs (at most `free_virtual_count`). This MUST stay byte-identical to the
|
|
5
|
-
// aiken `encode` so the off-chain `old_value`/`new_value` match what the validator reconstructs
|
|
6
|
-
// (`mpt.update` verifies the old bytes are in the trie). If these diverge, every free-virtual
|
|
7
|
-
// `mpt.update` fails on-chain.
|
|
8
|
-
//
|
|
9
|
-
// CANONICAL HOME: see ./labelSet.ts — this is the single shared definition for all Node services.
|
|
10
|
-
//
|
|
11
|
-
// Representation: free names and labels are lowercase hex strings; `encode` returns a hex string
|
|
12
|
-
// ("" = empty value). Names are sub-handle name bytes; labels are concatenated 4-byte CIP-67
|
|
13
|
-
// prefixes (each starting 0x00), so a leading 0xff marker can never collide with a label set.
|
|
14
|
-
//
|
|
15
|
-
// Encoding (mirrors `registry_value.ak`):
|
|
16
|
-
// - free_names == [] -> labels (backward compatible with WS1)
|
|
17
|
-
// - free_names != [] -> 0xff ++ serialise_data(free_names) ++ labels
|
|
18
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
-
exports.serializeFreeNames = exports.parseFreeNames = exports.removeFreeName = exports.addFreeName = exports.hasFreeName = exports.hasFreeSlot = exports.encode = void 0;
|
|
20
|
-
// CBOR header for a Plutus `Data` byte string (major type 2). Handle/sub names are CIP-67 asset
|
|
21
|
-
// names (<= 32 bytes), so a single definite-length chunk always suffices; Plutus only chunks
|
|
22
|
-
// byte strings longer than 64 bytes, which a valid handle name can never be — throw rather than
|
|
23
|
-
// emit divergent bytes for an impossible input.
|
|
24
|
-
const cborByteString = (hex) => {
|
|
25
|
-
const byteLen = hex.length / 2;
|
|
26
|
-
if (!Number.isInteger(byteLen)) {
|
|
27
|
-
throw new Error(`free name is not valid hex (odd length): ${hex}`);
|
|
28
|
-
}
|
|
29
|
-
if (byteLen < 24)
|
|
30
|
-
return (0x40 | byteLen).toString(16).padStart(2, '0') + hex;
|
|
31
|
-
if (byteLen <= 64)
|
|
32
|
-
return '58' + byteLen.toString(16).padStart(2, '0') + hex;
|
|
33
|
-
throw new Error(`free name exceeds 64 bytes (Plutus would chunk): ${hex}`);
|
|
34
|
-
};
|
|
35
|
-
// Plutus `Data` CBOR of a non-empty `List<ByteArray>` (indefinite-length array).
|
|
36
|
-
const serialiseData = (freeNames) => '9f' + freeNames.map((n) => cborByteString(n.toLowerCase())).join('') + 'ff';
|
|
37
|
-
/**
|
|
38
|
-
* Byte-identical to on-chain `registry_value.encode(free_names, labels)`.
|
|
39
|
-
* free_names == [] -> labels (an empty handle stays "", any pure-label handle is WS1-identical)
|
|
40
|
-
* free_names != [] -> "ff" ++ serialise_data(free_names) ++ labels
|
|
41
|
-
*/
|
|
42
|
-
const encode = (freeNames, labels) => {
|
|
43
|
-
const l = labels.toLowerCase();
|
|
44
|
-
return freeNames.length === 0 ? l : 'ff' + serialiseData(freeNames) + l;
|
|
45
|
-
};
|
|
46
|
-
exports.encode = encode;
|
|
47
|
-
/** A free slot is available iff the root holds fewer than the configured free count. */
|
|
48
|
-
const hasFreeSlot = (freeNames, freeVirtualCount) => freeNames.length < freeVirtualCount;
|
|
49
|
-
exports.hasFreeSlot = hasFreeSlot;
|
|
50
|
-
/** Is this sub-name one of the root's current free names? */
|
|
51
|
-
const hasFreeName = (freeNames, name) => freeNames.map((n) => n.toLowerCase()).includes(name.toLowerCase());
|
|
52
|
-
exports.hasFreeName = hasFreeName;
|
|
53
|
-
/**
|
|
54
|
-
* Add a sub-name to the free set (a free private-virtual MINT). Prepends (mirrors aiken
|
|
55
|
-
* `list.push`) and is idempotent — the prepend order is part of the encoded bytes, so it MUST
|
|
56
|
-
* match the contract's `add_free_name`.
|
|
57
|
-
*/
|
|
58
|
-
const addFreeName = (freeNames, name) => {
|
|
59
|
-
const n = name.toLowerCase();
|
|
60
|
-
const lower = freeNames.map((x) => x.toLowerCase());
|
|
61
|
-
return lower.includes(n) ? lower : [n, ...lower];
|
|
62
|
-
};
|
|
63
|
-
exports.addFreeName = addFreeName;
|
|
64
|
-
/**
|
|
65
|
-
* Remove a sub-name from the free set (a free private-virtual BURN → reopen its slot). No-op if
|
|
66
|
-
* the name isn't in the set (a paid sub's burn doesn't touch the allowance). Preserves order.
|
|
67
|
-
*/
|
|
68
|
-
const removeFreeName = (freeNames, name) => {
|
|
69
|
-
const n = name.toLowerCase();
|
|
70
|
-
return freeNames.map((x) => x.toLowerCase()).filter((x) => x !== n);
|
|
71
|
-
};
|
|
72
|
-
exports.removeFreeName = removeFreeName;
|
|
73
|
-
/** Parse a stored comma-hex free-name list ("" -> []). */
|
|
74
|
-
const parseFreeNames = (csv) => (csv ? csv.split(',').map((s) => s.trim().toLowerCase()).filter(Boolean) : []);
|
|
75
|
-
exports.parseFreeNames = parseFreeNames;
|
|
76
|
-
/** Serialize a free-name set back to comma-hex for storage. */
|
|
77
|
-
const serializeFreeNames = (freeNames) => freeNames.map((n) => n.toLowerCase()).join(',');
|
|
78
|
-
exports.serializeFreeNames = serializeFreeNames;
|