@everyprotocol/every-cli 0.1.2 → 0.1.4

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/dist/logger.js ADDED
@@ -0,0 +1,39 @@
1
+ import * as fs from "fs";
2
+ import { stringify as j11 } from "json11";
3
+ import path from "path";
4
+ export class Logger {
5
+ quiet;
6
+ json;
7
+ constructor(opts = {}) {
8
+ this.quiet = opts.quiet ?? !!opts.json;
9
+ this.json = opts.json ?? false;
10
+ }
11
+ log(...args) {
12
+ if (!this.quiet)
13
+ console.error(...args);
14
+ }
15
+ warn(...args) {
16
+ if (!this.quiet)
17
+ console.error("[warn]", ...args);
18
+ }
19
+ error(...args) {
20
+ console.error("[error]", ...args);
21
+ }
22
+ result(data) {
23
+ const opts = {
24
+ quote: `"`,
25
+ quoteNames: true,
26
+ withBigInt: false,
27
+ };
28
+ if (this.json) {
29
+ if (typeof this.json === "string") {
30
+ const dir = path.dirname(this.json);
31
+ fs.mkdirSync(dir, { recursive: true });
32
+ fs.writeFileSync(this.json, j11(data, opts));
33
+ }
34
+ else {
35
+ console.log(j11(data, opts)); // stdout
36
+ }
37
+ }
38
+ }
39
+ }
@@ -0,0 +1,59 @@
1
+ import { u8aFixLength } from "@polkadot/util";
2
+ import { decodeAddress } from "@polkadot/util-crypto";
3
+ import { InvalidArgumentError } from "commander";
4
+ export function parseBigInt(arg) {
5
+ try {
6
+ return BigInt(arg);
7
+ }
8
+ catch (e /* eslint-disable-line */) {
9
+ throw new InvalidArgumentError("invalid bigint");
10
+ }
11
+ }
12
+ export function parseAccountId(address) {
13
+ try {
14
+ return u8aFixLength(decodeAddress(address), 256);
15
+ }
16
+ catch (e /* eslint-disable-line */) {
17
+ throw new InvalidArgumentError("invalid account ID");
18
+ }
19
+ }
20
+ export function parseNode4(arg) {
21
+ const parts = arg.split(".");
22
+ let [data, grant, set, id] = [0n, 0n, 0n, 0n];
23
+ if (parts.length == 2) {
24
+ set = BigInt(parts[0]);
25
+ id = BigInt(parts[1]);
26
+ }
27
+ else if (parts.length == 3) {
28
+ grant = BigInt(parts[0]);
29
+ set = BigInt(parts[1]);
30
+ id = BigInt(parts[2]);
31
+ }
32
+ else if (parts.length == 4) {
33
+ data = BigInt(parts[0]);
34
+ grant = BigInt(parts[1]);
35
+ set = BigInt(parts[2]);
36
+ id = BigInt(parts[3]);
37
+ }
38
+ else {
39
+ throw new InvalidArgumentError("invalid Node4");
40
+ }
41
+ return (data << 192n) | (grant << 128n) | (set << 64n) | id;
42
+ }
43
+ export function parseNode3(arg) {
44
+ const parts = arg.split(".");
45
+ let [grant, set, id] = [0n, 0n, 0n];
46
+ if (parts.length == 2) {
47
+ set = BigInt(parts[0]);
48
+ id = BigInt(parts[1]);
49
+ }
50
+ else if (parts.length == 3) {
51
+ grant = BigInt(parts[0]);
52
+ set = BigInt(parts[1]);
53
+ id = BigInt(parts[2]);
54
+ }
55
+ else {
56
+ throw new InvalidArgumentError("invalid Node3");
57
+ }
58
+ return (grant << 128n) | (set << 64n) | id;
59
+ }
package/dist/program.js CHANGED
@@ -1,41 +1,30 @@
1
1
  import { Command } from "commander";
2
- import { generateCommands } from "./cmdgen.js";
3
- import { RenamingCommand } from "./cmds.js";
4
2
  import { version } from "./utils.js";
5
- import { genWalletCommands } from "./wallet.js";
6
- import { genMatterCommand } from "./matter.js";
7
- function buildProgram() {
8
- const subCmds = generateCommands();
9
- const kindCmd = new RenamingCommand().name("kind").description("manage kinds").addCommands(subCmds.kind);
10
- const setCmd = new RenamingCommand().name("set").description("manage sets").addCommands(subCmds.set);
11
- const relationCmd = new RenamingCommand()
12
- .name("relation")
13
- .description("manage relations")
14
- .addCommands(subCmds.relation);
15
- const uniqueCmd = new RenamingCommand().name("unique").description("manage uniques").addCommands(subCmds.unique);
16
- const valueCmd = new RenamingCommand().name("value").description("manage values").addCommands(subCmds.value);
17
- const objectCmd = new RenamingCommand()
18
- .name("object")
19
- .description("create and interact with objects")
20
- .addCommands(subCmds.object);
21
- const mintPolicyCmd = new RenamingCommand()
22
- .name("mintpolicy")
23
- .description("manage mint policies")
24
- .addCommands(subCmds.mintpolicy);
25
- const program = new Command()
26
- .name("every")
27
- .description("CLI for interacting with Every Protocol")
28
- .version(version())
29
- .showHelpAfterError(true);
30
- program.addCommand(kindCmd);
31
- program.addCommand(setCmd);
32
- program.addCommand(relationCmd);
33
- program.addCommand(uniqueCmd);
34
- program.addCommand(valueCmd);
35
- program.addCommand(objectCmd);
36
- program.addCommand(mintPolicyCmd);
37
- program.addCommand(genWalletCommands());
38
- program.addCommand(genMatterCommand());
39
- return program;
40
- }
41
- export const program = buildProgram();
3
+ import { walletCmd } from "./cmds/wallet.js";
4
+ import { matterCmd } from "./cmds/matter.js";
5
+ import { balanceCmd } from "./cmds/balance.js";
6
+ import { configCmd } from "./cmds/config.js";
7
+ import { kindCmd } from "./cmds/kind.js";
8
+ import { valueCmd } from "./cmds/value.js";
9
+ import { uniqueCmd } from "./cmds/unique.js";
10
+ import { relationCmd } from "./cmds/relation.js";
11
+ import { setCmd } from "./cmds/set.js";
12
+ import { objectCmd } from "./cmds/object.js";
13
+ import { minterCmd } from "./cmds/minter.js";
14
+ import { universeCmd } from "./cmds/universe.js";
15
+ export const program = new Command("every")
16
+ .description("CLI for interacting with Every Protocol")
17
+ .version(version())
18
+ .showHelpAfterError(true)
19
+ .addCommand(universeCmd)
20
+ .addCommand(matterCmd)
21
+ .addCommand(setCmd)
22
+ .addCommand(kindCmd)
23
+ .addCommand(relationCmd)
24
+ .addCommand(valueCmd)
25
+ .addCommand(uniqueCmd)
26
+ .addCommand(objectCmd)
27
+ .addCommand(minterCmd)
28
+ .addCommand(balanceCmd)
29
+ .addCommand(walletCmd)
30
+ .addCommand(configCmd);
@@ -0,0 +1,63 @@
1
+ import "@polkadot/api-augment/substrate";
2
+ import { decodeAddress } from "@polkadot/util-crypto";
3
+ import { u8aFixLength } from "@polkadot/util";
4
+ import * as JSON11 from "json11";
5
+ import columify from "columnify";
6
+ import { createDeferred } from "./utils.js";
7
+ import "./commander-patch.js";
8
+ export async function submitTransaction(api, tx, pair) {
9
+ const pTxn = createDeferred();
10
+ const pReceipt = createDeferred();
11
+ const accountId = u8aFixLength(decodeAddress(pair.address), 256);
12
+ const nonce = await api.rpc.system.accountNextIndex(accountId);
13
+ const unsub = await tx.signAndSend(pair, { nonce }, (result) => {
14
+ const { status, txHash, events, dispatchError } = result;
15
+ if (dispatchError) {
16
+ if (dispatchError.isModule) {
17
+ const meta = api.registry.findMetaError(dispatchError.asModule);
18
+ const msg = `${meta.section}.${meta.name}${meta.docs.length ? `: ${meta.docs.join(" ")}` : ""}`;
19
+ unsub();
20
+ pReceipt.reject(new Error(`DispatchError: ${msg}`));
21
+ }
22
+ else {
23
+ unsub();
24
+ pReceipt.reject(new Error(dispatchError.toString()));
25
+ }
26
+ }
27
+ if (status.isReady) {
28
+ pTxn.resolve({ txHash: txHash.toHex(), receipt: pReceipt.promise });
29
+ }
30
+ if (status.isFinalized) {
31
+ unsub();
32
+ pReceipt.resolve({
33
+ txHash: txHash.toHex(),
34
+ blockHash: status.asFinalized.toHex(),
35
+ events: events,
36
+ result,
37
+ });
38
+ }
39
+ });
40
+ return await pTxn.promise;
41
+ }
42
+ export async function submitSubTxUI(api, tx, pair, console) {
43
+ console.log(`Transaction submitting...`);
44
+ const txn = await submitTransaction(api, tx, pair);
45
+ console.log(`Transaction submitted: ${txn.txHash}`);
46
+ console.log("Waiting for confirmation...");
47
+ const r = await txn.receipt;
48
+ const header = await api.rpc.chain.getHeader(r.blockHash);
49
+ console.log(`Confirmed in: block ${header.number}, hash ${header.hash}`);
50
+ const events = r.events.map((e, i) => [i, e.event.method, JSON11.stringify(e.event.data.toJSON())]);
51
+ const result = r.events.map((e) => {
52
+ const event = {
53
+ event: e.event.method,
54
+ data: e.event.data.toJSON(),
55
+ };
56
+ return event;
57
+ });
58
+ if (events.length > 0) {
59
+ console.log(`Events`);
60
+ console.log(columify(events, { showHeaders: false }));
61
+ }
62
+ console.result(result);
63
+ }
package/dist/utils.js CHANGED
@@ -1,125 +1,25 @@
1
- import { bytesToHex, createPublicClient, createWalletClient, encodeAbiParameters, http, } from "viem";
2
- import { formatAbiParameter } from "abitype";
3
1
  import fs from "fs";
4
2
  import path from "path";
5
- import { Wallet } from "ethers";
6
- import { privateKeyToAccount } from "viem/accounts";
7
- import promptSync from "prompt-sync";
8
- import os from "os";
9
- import JSON5 from "json5";
10
3
  import { fileURLToPath } from "url";
11
4
  import { isHex, hexToU8a } from "@polkadot/util";
12
5
  import { base64Decode } from "@polkadot/util-crypto/base64";
13
6
  import { decodePair } from "@polkadot/keyring/pair/decode";
14
- import Keyring from "@polkadot/keyring";
7
+ import { getAddress, isAddress, pad, sha256 } from "viem";
8
+ import { FromOpts } from "./from-opts.js";
15
9
  export const __dirname = path.dirname(fileURLToPath(import.meta.url));
16
10
  export function version() {
17
11
  const pkgPath = path.resolve(__dirname, "../package.json");
18
12
  return JSON.parse(fs.readFileSync(pkgPath, "utf-8")).version;
19
13
  }
20
- export function lstrip(prefix) {
21
- return function (func) {
22
- return func.name.startsWith(prefix) ? func.name.substring(prefix.length).toLowerCase() : func.name;
23
- };
24
- }
25
- export function rstrip(postfix) {
26
- return function (func) {
27
- return func.name.endsWith(postfix) ? func.name.slice(0, -postfix.length) : func.name;
28
- };
29
- }
30
- export function startsWith(prefix) {
31
- return function (func) {
32
- return func.name.startsWith(prefix);
33
- };
34
- }
35
- export function excludes(names) {
36
- return function (func) {
37
- return !names.includes(func.name);
38
- };
39
- }
40
- export function includes(names) {
41
- return function (f) {
42
- return names.includes(f.name);
43
- };
44
- }
45
- export function stringify(o) {
46
- const replacer = (_key, value) => (typeof value === "bigint" ? value.toString() : value);
47
- return JSON5.stringify(o, replacer);
48
- }
49
- export async function getClientsEth(uniConf, opts) {
50
- const transport = http(uniConf.rpc);
51
- const publicClient = createPublicClient({ transport });
52
- const privateKey = await readPrivateKeyEth(opts);
53
- const account = privateKeyToAccount(privateKey);
54
- const walletClient = createWalletClient({ account, transport });
55
- return { publicClient, walletClient };
56
- }
57
- export async function readPrivateKeyEth(opts) {
58
- if (opts.privateKey) {
59
- return opts.privateKey.startsWith("0x") ? opts.privateKey : `0x${opts.privateKey}`;
60
- }
61
- else if (opts.account) {
62
- const keystorePath = resolveKeystoreFile(opts.account, opts);
63
- const keystore = loadKeystore(keystorePath);
64
- if (keystore.crypto || keystore.Crypto) {
65
- // for Ethereum keystores
66
- const password = getPassword(opts);
67
- const wallet = await Wallet.fromEncryptedJson(JSON.stringify(keystore), password);
68
- return wallet.privateKey;
69
- }
70
- else if (keystore.encoding || keystore.meta) {
71
- // for Substrate keystores
72
- if (keystore.meta?.isEthereum || keystore.meta?.type === "ethereum") {
73
- const password = getPassword(opts);
74
- const pair = decodeSubstratePair(keystore, password);
75
- return bytesToHex(pair.secretKey);
76
- }
77
- else {
78
- throw new Error("Not an Ethereum account");
79
- }
80
- }
81
- else {
82
- // Not supported for now
83
- throw new Error("Unknown keystore format");
84
- }
85
- }
86
- else {
87
- throw new Error(`Neither account nor private key specified`);
88
- }
89
- }
90
14
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
91
- export function checkArguments(raw, func) {
92
- return raw.map((rawArg, index) => {
93
- const abiParam = func.inputs[index];
94
- const pt = abiParam?.type;
95
- const arg = pt === "address" || pt.startsWith("bytes") || pt === "string" ? rawArg : JSON5.parse(rawArg);
96
- try {
97
- encodeAbiParameters([abiParam], [arg]);
98
- }
99
- catch (e) {
100
- if (e instanceof Error) {
101
- throw new Error(`invalid param ${formatAbiParameter(abiParam)}\n${e.message}`);
102
- }
103
- }
104
- return arg;
105
- });
106
- }
107
- export function resolveKeystoreDir(options) {
108
- if (options.foundry) {
109
- return path.join(os.homedir(), ".foundry", "keystores");
110
- }
111
- if (options.dir) {
112
- return options.dir;
15
+ export function loadJson(file) {
16
+ if (!fs.existsSync(file)) {
17
+ throw new Error(`Keystore file not found: ${file}`);
113
18
  }
114
- return path.join(os.homedir(), ".every", "keystores");
115
- }
116
- export function resolveKeystoreFile(name, options) {
117
- const dir = resolveKeystoreDir(options);
118
- return path.join(dir, name);
19
+ return JSON.parse(fs.readFileSync(file, "utf8"));
119
20
  }
120
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
121
- export function saveKeystore(json, name, options) {
122
- const dir = resolveKeystoreDir(options);
21
+ // eslint-disable-next-line
22
+ export function saveJson(json, dir, name) {
123
23
  if (!fs.existsSync(dir)) {
124
24
  fs.mkdirSync(dir, { recursive: true });
125
25
  }
@@ -128,54 +28,157 @@ export function saveKeystore(json, name, options) {
128
28
  throw new Error(`File exists: ${file}`);
129
29
  }
130
30
  fs.writeFileSync(file, JSON.stringify(json));
131
- console.log(`File saved: ${file}`);
132
31
  }
133
32
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
134
- export function loadKeystore(file) {
135
- if (!fs.existsSync(file)) {
136
- throw new Error(`Keystore file not found: ${file}`);
33
+ export function decodePairFromJson(keystore, password) {
34
+ const encodedRaw = keystore.encoded;
35
+ let encodingType = keystore.encoding.type;
36
+ encodingType = !Array.isArray(encodingType) ? [encodingType] : encodingType;
37
+ const encoded = isHex(encodedRaw) ? hexToU8a(encodedRaw) : base64Decode(encodedRaw);
38
+ const decoded = decodePair(password, encoded, encodingType);
39
+ return decoded;
40
+ }
41
+ export function guessContentType(filePath) {
42
+ const ext = path.extname(filePath).toLowerCase();
43
+ switch (ext) {
44
+ case ".txt":
45
+ return "text/plain";
46
+ case ".json":
47
+ return "application/json";
48
+ case ".wasm":
49
+ return "application/wasm";
50
+ case ".jpg":
51
+ case ".jpeg":
52
+ return "image/jpeg";
53
+ case ".png":
54
+ return "image/png";
55
+ default:
56
+ return "application/octet-stream";
137
57
  }
138
- return JSON.parse(fs.readFileSync(file, "utf8"));
139
58
  }
140
- export function getPassword(opts) {
141
- return opts.password
142
- ? opts.password
143
- : opts.passwordFile
144
- ? fs.readFileSync(opts.passwordFile, "utf8").trim()
145
- : promptSync({ sigint: true })("Password: ", { echo: "" });
59
+ export function createDeferred() {
60
+ let resolve;
61
+ let reject;
62
+ const promise = new Promise((res, rej) => {
63
+ resolve = res;
64
+ reject = rej;
65
+ });
66
+ return { promise, resolve, reject };
67
+ }
68
+ const isArrayType = (t) => /\[[^\]]*\]$/.test(t);
69
+ const isTupleType = (t) => t.startsWith("tuple");
70
+ const elemType = (t) => t.replace(/\[[^\]]*\]$/, "");
71
+ // const fmtInputs = (ins: ReadonlyArray<Pick<AbiParameter, "name" | "type">>) =>
72
+ // ins.map((i) => (i.name ? `${i.type} ${i.name}` : i.type)).join(", ");
73
+ function hasComponents(p) {
74
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
75
+ return p.components !== "undefined";
76
+ }
77
+ function coerceScalar(val, type) {
78
+ const base = elemType(type);
79
+ if (base === "address") {
80
+ if (!isAddress(val))
81
+ throw new Error(`Invalid address: ${val}`);
82
+ return getAddress(val);
83
+ }
84
+ if (base === "bool") {
85
+ if (!/^(true|false)$/i.test(val))
86
+ throw new Error(`Invalid bool: ${val}`);
87
+ return /^true$/i.test(val);
88
+ }
89
+ if (base === "string")
90
+ return val;
91
+ if (base.startsWith("bytes")) {
92
+ if (!/^0x[0-9a-fA-F]*$/.test(val))
93
+ throw new Error(`Invalid ${base} (expect 0x...)`);
94
+ return val;
95
+ }
96
+ if (base.startsWith("uint") || base.startsWith("int")) {
97
+ try {
98
+ return val.startsWith("0x") ? BigInt(val) : BigInt(val);
99
+ }
100
+ catch {
101
+ throw new Error(`Invalid ${base}: ${val}`);
102
+ }
103
+ }
104
+ return val;
105
+ }
106
+ export function coerceValue(val, param) {
107
+ const { type } = param;
108
+ // arrays: expect JSON array; recurse on element type (preserve components if tuple[])
109
+ if (isArrayType(type)) {
110
+ const arr = JSON.parse(val);
111
+ if (!Array.isArray(arr))
112
+ throw new Error(`Expected array for ${type}`);
113
+ // build element param (carry tuple components if present)
114
+ const inner = hasComponents(param)
115
+ ? { ...param, type: elemType(type), components: param.components }
116
+ : { ...param, type: elemType(type) };
117
+ return arr.map((v) => coerceValue(typeof v === "string" ? v : JSON.stringify(v), inner));
118
+ }
119
+ // tuples: need components
120
+ if (isTupleType(type)) {
121
+ if (!hasComponents(param) || param.components.length === 0) {
122
+ throw new Error(`Tuple components missing for ${type}`);
123
+ }
124
+ const tup = JSON.parse(val);
125
+ if (Array.isArray(tup)) {
126
+ if (tup.length !== param.components.length) {
127
+ throw new Error(`Tuple length mismatch: expected ${param.components.length}, got ${tup.length}`);
128
+ }
129
+ return param.components.map((c, i) => coerceValue(typeof tup[i] === "string" ? tup[i] : JSON.stringify(tup[i]), c));
130
+ }
131
+ // object by names
132
+ return param.components.map((c) => {
133
+ const v = tup[c.name];
134
+ if (v === undefined)
135
+ throw new Error(`Tuple field missing: ${c.name}`);
136
+ return coerceValue(typeof v === "string" ? v : JSON.stringify(v), c);
137
+ });
138
+ }
139
+ // scalar
140
+ return coerceScalar(val, type);
146
141
  }
147
- export function getPasswordConfirm(opts) {
148
- if (opts.password) {
149
- return opts.password;
142
+ export async function substrateAction(cmd, api, fn) {
143
+ try {
144
+ return await fn(api);
150
145
  }
151
- if (opts.passwordFile) {
152
- return fs.readFileSync(opts.passwordFile, "utf8").trim();
146
+ catch (e /* eslint-disable-line */) {
147
+ cmd.error(e.message);
153
148
  }
154
- const prompt = promptSync({ sigint: true });
155
- const password = prompt("Password: ", { echo: "" });
156
- const confirmation = prompt("Confirm: ", { echo: "" });
157
- if (password !== confirmation) {
158
- throw new Error(`Error: Passwords do not match`);
149
+ finally {
150
+ api.disconnect().catch(() => { });
159
151
  }
160
- return password;
161
152
  }
162
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
163
- export function decodeSubstratePair(keystore, password) {
164
- const encodedRaw = keystore.encoded;
165
- let encodingType = keystore.encoding.type;
166
- encodingType = !Array.isArray(encodingType) ? [encodingType] : encodingType;
167
- const encoded = isHex(encodedRaw) ? hexToU8a(encodedRaw) : base64Decode(encodedRaw);
168
- const decoded = decodePair(password, encoded, encodingType);
169
- return decoded;
153
+ export function wrapSubAction(fn) {
154
+ // eslint-disable-next-line
155
+ return async function (...args) {
156
+ const api = await FromOpts.getSubstrateApi(this.opts());
157
+ try {
158
+ // keep Commander’s `this` binding and pass api first
159
+ return await fn.call(this, api, ...args);
160
+ }
161
+ finally {
162
+ await api.disconnect().catch(() => { });
163
+ }
164
+ };
170
165
  }
171
- export function getSubstrateAccountPair(flags) {
172
- const keyFile = resolveKeystoreFile(flags.account, flags);
173
- const keyData = loadKeystore(keyFile);
174
- const keyring = new Keyring();
175
- const pair = keyring.createFromJson(keyData);
176
- if (pair.isLocked) {
177
- const password = getPassword(flags);
178
- pair.unlock(password);
166
+ export function loadBinary(file) {
167
+ const buf = fs.readFileSync(file);
168
+ return buf;
169
+ }
170
+ export function computeMatterHash(form, mime, blob) {
171
+ if (!Number.isInteger(form) || form < 0 || form > 255) {
172
+ throw new Error("form must be uint8 (0..255)");
173
+ }
174
+ const mimeUTF8 = new TextEncoder().encode(mime);
175
+ if (mimeUTF8.length <= 0 || mimeUTF8.length > 31) {
176
+ throw new Error("form must be uint8 (0..255)");
179
177
  }
180
- return pair;
178
+ const msg = new Uint8Array(1 + 31 + blob.length);
179
+ msg[0] = form & 0xff;
180
+ msg.set(pad(mimeUTF8, { size: 32, dir: "right" }), 1);
181
+ msg.set(blob, 32);
182
+ // SHA256(form:1 || mime:31 || blob:var)
183
+ return sha256(msg);
181
184
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@everyprotocol/every-cli",
3
3
  "type": "module",
4
- "version": "0.1.2",
4
+ "version": "0.1.4",
5
5
  "files": [
6
6
  "dist/",
7
7
  "abis/",
@@ -15,6 +15,7 @@
15
15
  "devDependencies": {
16
16
  "@eslint/js": "^9.26.0",
17
17
  "@types/bun": "latest",
18
+ "@types/columnify": "^1.5.4",
18
19
  "@types/lodash-es": "^4.17.12",
19
20
  "@types/prompt-sync": "^4.2.3",
20
21
  "@typescript-eslint/eslint-plugin": "^8.32.1",
@@ -32,8 +33,10 @@
32
33
  "@polkadot/keyring": "^13.5.2",
33
34
  "@polkadot/util": "^13.5.2",
34
35
  "@polkadot/util-crypto": "^13.5.2",
36
+ "columnify": "^1.6.0",
35
37
  "commander": "^13.1.0",
36
38
  "ethers": "^6.14.0",
39
+ "json11": "^2.0.2",
37
40
  "json5": "^2.2.3",
38
41
  "lodash-es": "^4.17.21",
39
42
  "prompt-sync": "^4.2.0",