@everyprotocol/every-cli 0.1.3 → 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/.every.toml +3 -3
- package/dist/abi.js +1 -0
- package/dist/cmdgen.js +51 -139
- package/dist/cmds/balance.js +43 -0
- package/dist/cmds/config.js +46 -0
- package/dist/cmds/kind.js +14 -0
- package/dist/cmds/matter.js +82 -0
- package/dist/cmds/minter.js +31 -0
- package/dist/cmds/object.js +175 -0
- package/dist/cmds/relation.js +16 -0
- package/dist/cmds/set.js +31 -0
- package/dist/cmds/unique.js +14 -0
- package/dist/cmds/universe.js +21 -0
- package/dist/cmds/value.js +14 -0
- package/dist/{wallet.js → cmds/wallet.js} +19 -19
- package/dist/commander-patch.js +64 -0
- package/dist/config.js +18 -93
- package/dist/ethereum.js +33 -0
- package/dist/from-opts.js +161 -0
- package/dist/index.js +2 -1
- package/dist/logger.js +39 -0
- package/dist/parsers.js +59 -0
- package/dist/program.js +28 -39
- package/dist/substrate.js +24 -18
- package/dist/utils.js +144 -182
- package/package.json +4 -1
- package/dist/cmds.js +0 -132
- package/dist/matter.js +0 -96
- package/dist/mint.js +0 -78
- package/dist/options.js +0 -26
- package/dist/relate.js +0 -104
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 { walletCmd } from "./wallet.js";
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
program.addCommand(relationCmd);
|
|
34
|
-
program.addCommand(valueCmd);
|
|
35
|
-
program.addCommand(uniqueCmd);
|
|
36
|
-
program.addCommand(objectCmd);
|
|
37
|
-
program.addCommand(mintPolicyCmd);
|
|
38
|
-
program.addCommand(walletCmd);
|
|
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);
|
package/dist/substrate.js
CHANGED
|
@@ -1,19 +1,11 @@
|
|
|
1
1
|
import "@polkadot/api-augment/substrate";
|
|
2
2
|
import { decodeAddress } from "@polkadot/util-crypto";
|
|
3
3
|
import { u8aFixLength } from "@polkadot/util";
|
|
4
|
-
import "
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const promise = new Promise((res, rej) => {
|
|
9
|
-
resolve = res;
|
|
10
|
-
reject = rej;
|
|
11
|
-
});
|
|
12
|
-
return { promise, resolve, reject };
|
|
13
|
-
}
|
|
4
|
+
import * as JSON11 from "json11";
|
|
5
|
+
import columify from "columnify";
|
|
6
|
+
import { createDeferred } from "./utils.js";
|
|
7
|
+
import "./commander-patch.js";
|
|
14
8
|
export async function submitTransaction(api, tx, pair) {
|
|
15
|
-
// const pTxn = Promise.withResolvers<Transaction>();
|
|
16
|
-
// const pReceipt = Promise.withResolvers<Receipt>();
|
|
17
9
|
const pTxn = createDeferred();
|
|
18
10
|
const pReceipt = createDeferred();
|
|
19
11
|
const accountId = u8aFixLength(decodeAddress(pair.address), 256);
|
|
@@ -47,11 +39,25 @@ export async function submitTransaction(api, tx, pair) {
|
|
|
47
39
|
});
|
|
48
40
|
return await pTxn.promise;
|
|
49
41
|
}
|
|
50
|
-
export function
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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 }));
|
|
55
61
|
}
|
|
56
|
-
|
|
62
|
+
console.result(result);
|
|
57
63
|
}
|
package/dist/utils.js
CHANGED
|
@@ -1,127 +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 {
|
|
15
|
-
import
|
|
16
|
-
import { UnifiedKeystore } from "./keystore.js";
|
|
7
|
+
import { getAddress, isAddress, pad, sha256 } from "viem";
|
|
8
|
+
import { FromOpts } from "./from-opts.js";
|
|
17
9
|
export const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
18
10
|
export function version() {
|
|
19
11
|
const pkgPath = path.resolve(__dirname, "../package.json");
|
|
20
12
|
return JSON.parse(fs.readFileSync(pkgPath, "utf-8")).version;
|
|
21
13
|
}
|
|
22
|
-
export function lstrip(prefix) {
|
|
23
|
-
return function (func) {
|
|
24
|
-
return func.name.startsWith(prefix) ? func.name.substring(prefix.length).toLowerCase() : func.name;
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
export function rstrip(postfix) {
|
|
28
|
-
return function (func) {
|
|
29
|
-
return func.name.endsWith(postfix) ? func.name.slice(0, -postfix.length) : func.name;
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
export function startsWith(prefix) {
|
|
33
|
-
return function (func) {
|
|
34
|
-
return func.name.startsWith(prefix);
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
export function excludes(names) {
|
|
38
|
-
return function (func) {
|
|
39
|
-
return !names.includes(func.name);
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
export function includes(names) {
|
|
43
|
-
return function (f) {
|
|
44
|
-
return names.includes(f.name);
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
export function stringify(o) {
|
|
48
|
-
const replacer = (_key, value) => (typeof value === "bigint" ? value.toString() : value);
|
|
49
|
-
return JSON5.stringify(o, replacer);
|
|
50
|
-
}
|
|
51
|
-
export async function getClientsEth(uniConf, opts) {
|
|
52
|
-
const transport = http(uniConf.rpc);
|
|
53
|
-
const publicClient = createPublicClient({ transport });
|
|
54
|
-
const privateKey = await readPrivateKeyEth(opts);
|
|
55
|
-
const account = privateKeyToAccount(privateKey);
|
|
56
|
-
const walletClient = createWalletClient({ account, transport });
|
|
57
|
-
return { publicClient, walletClient };
|
|
58
|
-
}
|
|
59
|
-
export async function readPrivateKeyEth(opts) {
|
|
60
|
-
if (opts.privateKey) {
|
|
61
|
-
return opts.privateKey.startsWith("0x") ? opts.privateKey : `0x${opts.privateKey}`;
|
|
62
|
-
}
|
|
63
|
-
else if (opts.account) {
|
|
64
|
-
const keystorePath = resolveKeystoreFile(opts.account, opts);
|
|
65
|
-
const keystore = loadKeystore(keystorePath);
|
|
66
|
-
if (keystore.crypto || keystore.Crypto) {
|
|
67
|
-
// for Ethereum keystores
|
|
68
|
-
const password = getPassword(opts);
|
|
69
|
-
const wallet = await Wallet.fromEncryptedJson(JSON.stringify(keystore), password);
|
|
70
|
-
return wallet.privateKey;
|
|
71
|
-
}
|
|
72
|
-
else if (keystore.encoding || keystore.meta) {
|
|
73
|
-
// for Substrate keystores
|
|
74
|
-
if (keystore.meta?.isEthereum || keystore.meta?.type === "ethereum") {
|
|
75
|
-
const password = getPassword(opts);
|
|
76
|
-
const pair = decodeSubstratePair(keystore, password);
|
|
77
|
-
return bytesToHex(pair.secretKey);
|
|
78
|
-
}
|
|
79
|
-
else {
|
|
80
|
-
throw new Error("Not an Ethereum account");
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
else {
|
|
84
|
-
// Not supported for now
|
|
85
|
-
throw new Error("Unknown keystore format");
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
throw new Error(`Neither account nor private key specified`);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
14
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
93
|
-
export function
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const pt = abiParam?.type;
|
|
97
|
-
const arg = pt === "address" || pt.startsWith("bytes") || pt === "string" ? rawArg : JSON5.parse(rawArg);
|
|
98
|
-
try {
|
|
99
|
-
encodeAbiParameters([abiParam], [arg]);
|
|
100
|
-
}
|
|
101
|
-
catch (e) {
|
|
102
|
-
if (e instanceof Error) {
|
|
103
|
-
throw new Error(`invalid param ${formatAbiParameter(abiParam)}\n${e.message}`);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
return arg;
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
export function resolveKeystoreDir(options) {
|
|
110
|
-
if (options.foundry) {
|
|
111
|
-
return path.join(os.homedir(), ".foundry", "keystores");
|
|
112
|
-
}
|
|
113
|
-
if (options.dir) {
|
|
114
|
-
return options.dir;
|
|
15
|
+
export function loadJson(file) {
|
|
16
|
+
if (!fs.existsSync(file)) {
|
|
17
|
+
throw new Error(`Keystore file not found: ${file}`);
|
|
115
18
|
}
|
|
116
|
-
return
|
|
117
|
-
}
|
|
118
|
-
export function resolveKeystoreFile(name, options) {
|
|
119
|
-
const dir = resolveKeystoreDir(options);
|
|
120
|
-
return path.join(dir, name);
|
|
19
|
+
return JSON.parse(fs.readFileSync(file, "utf8"));
|
|
121
20
|
}
|
|
122
|
-
// eslint-disable-next-line
|
|
123
|
-
export function
|
|
124
|
-
const dir = resolveKeystoreDir(options);
|
|
21
|
+
// eslint-disable-next-line
|
|
22
|
+
export function saveJson(json, dir, name) {
|
|
125
23
|
if (!fs.existsSync(dir)) {
|
|
126
24
|
fs.mkdirSync(dir, { recursive: true });
|
|
127
25
|
}
|
|
@@ -130,39 +28,9 @@ export function saveKeystore(json, name, options) {
|
|
|
130
28
|
throw new Error(`File exists: ${file}`);
|
|
131
29
|
}
|
|
132
30
|
fs.writeFileSync(file, JSON.stringify(json));
|
|
133
|
-
console.log(`File saved: ${file}`);
|
|
134
31
|
}
|
|
135
32
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
136
|
-
export function
|
|
137
|
-
if (!fs.existsSync(file)) {
|
|
138
|
-
throw new Error(`Keystore file not found: ${file}`);
|
|
139
|
-
}
|
|
140
|
-
return JSON.parse(fs.readFileSync(file, "utf8"));
|
|
141
|
-
}
|
|
142
|
-
export function getPassword(opts) {
|
|
143
|
-
return opts.password
|
|
144
|
-
? opts.password
|
|
145
|
-
: opts.passwordFile
|
|
146
|
-
? fs.readFileSync(opts.passwordFile, "utf8").trim()
|
|
147
|
-
: promptSync({ sigint: true })("Password: ", { echo: "" });
|
|
148
|
-
}
|
|
149
|
-
export function getPasswordConfirm(opts) {
|
|
150
|
-
if (opts.password) {
|
|
151
|
-
return opts.password;
|
|
152
|
-
}
|
|
153
|
-
if (opts.passwordFile) {
|
|
154
|
-
return fs.readFileSync(opts.passwordFile, "utf8").trim();
|
|
155
|
-
}
|
|
156
|
-
const prompt = promptSync({ sigint: true });
|
|
157
|
-
const password = prompt("Password: ", { echo: "" });
|
|
158
|
-
const confirmation = prompt("Confirm: ", { echo: "" });
|
|
159
|
-
if (password !== confirmation) {
|
|
160
|
-
throw new Error(`Error: Passwords do not match`);
|
|
161
|
-
}
|
|
162
|
-
return password;
|
|
163
|
-
}
|
|
164
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
165
|
-
export function decodeSubstratePair(keystore, password) {
|
|
33
|
+
export function decodePairFromJson(keystore, password) {
|
|
166
34
|
const encodedRaw = keystore.encoded;
|
|
167
35
|
let encodingType = keystore.encoding.type;
|
|
168
36
|
encodingType = !Array.isArray(encodingType) ? [encodingType] : encodingType;
|
|
@@ -170,53 +38,147 @@ export function decodeSubstratePair(keystore, password) {
|
|
|
170
38
|
const decoded = decodePair(password, encoded, encodingType);
|
|
171
39
|
return decoded;
|
|
172
40
|
}
|
|
173
|
-
export function
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
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";
|
|
57
|
+
}
|
|
58
|
+
}
|
|
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
|
+
}
|
|
181
103
|
}
|
|
182
|
-
return
|
|
183
|
-
}
|
|
184
|
-
export
|
|
185
|
-
|
|
186
|
-
|
|
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
|
+
});
|
|
187
138
|
}
|
|
188
|
-
|
|
139
|
+
// scalar
|
|
140
|
+
return coerceScalar(val, type);
|
|
189
141
|
}
|
|
190
|
-
export async function
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
const password = getPassword(options);
|
|
194
|
-
const keystore = await UnifiedKeystore.fromJSON(keyData, password);
|
|
195
|
-
return keystore;
|
|
196
|
-
}
|
|
197
|
-
export function getObserverConfig(options) {
|
|
198
|
-
const conf = loadMergedConfig();
|
|
199
|
-
let observerName;
|
|
200
|
-
const DEFAULT_OBSERVER = "localnet";
|
|
201
|
-
if (options.observer) {
|
|
202
|
-
observerName = options.observer;
|
|
142
|
+
export async function substrateAction(cmd, api, fn) {
|
|
143
|
+
try {
|
|
144
|
+
return await fn(api);
|
|
203
145
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
if (!universe) {
|
|
207
|
-
throw new Error(`Universe '${options.universe}' not found in config. Available: ${Object.keys(conf.universes).join(", ")}`);
|
|
208
|
-
}
|
|
209
|
-
observerName = universe.observer;
|
|
146
|
+
catch (e /* eslint-disable-line */) {
|
|
147
|
+
cmd.error(e.message);
|
|
210
148
|
}
|
|
211
|
-
|
|
212
|
-
|
|
149
|
+
finally {
|
|
150
|
+
api.disconnect().catch(() => { });
|
|
213
151
|
}
|
|
214
|
-
|
|
215
|
-
|
|
152
|
+
}
|
|
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
|
+
};
|
|
165
|
+
}
|
|
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)");
|
|
216
173
|
}
|
|
217
|
-
const
|
|
218
|
-
if (
|
|
219
|
-
throw new Error(
|
|
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)");
|
|
220
177
|
}
|
|
221
|
-
|
|
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);
|
|
222
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.
|
|
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",
|
package/dist/cmds.js
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import { Argument, Command, Option } from "commander";
|
|
2
|
-
import { createPublicClient, http, parseEventLogs, stringify } from "viem";
|
|
3
|
-
import { getUniverseConfig } from "./config.js";
|
|
4
|
-
import { checkArguments, getClientsEth } from "./utils.js";
|
|
5
|
-
export function defaultReadFunctionOptions() {
|
|
6
|
-
const options = [];
|
|
7
|
-
options.push(new Option("-u, --universe <universe>", "universe name").default("local"));
|
|
8
|
-
options.push(new Option("--dry-run", "Simulate the command without sending a transaction"));
|
|
9
|
-
return options;
|
|
10
|
-
}
|
|
11
|
-
export function defaultWriteFunctionOptions() {
|
|
12
|
-
const options = [];
|
|
13
|
-
options.push(new Option("-u, --universe <universe>", "universe name").default("local"));
|
|
14
|
-
options.push(new Option("-k, --private-key <key>", "private key to sign the transaction"));
|
|
15
|
-
options.push(new Option("-a, --account <account>", "name of the keystore to sign the transaction"));
|
|
16
|
-
options.push(new Option("-p, --password [password]", "password to decrypt the keystore"));
|
|
17
|
-
options.push(new Option("--password-file <file>", "file containing the password to decrypt the keystore"));
|
|
18
|
-
options.push(new Option("-f, --foundry", "use keystore from Foundry directory (~/.foundry/keystores)"));
|
|
19
|
-
options.push(new Option("--dry-run", "Simulate the command without sending a transaction"));
|
|
20
|
-
return options;
|
|
21
|
-
}
|
|
22
|
-
const defaultConfig = {
|
|
23
|
-
cmdAbi: (txnAbi) => txnAbi,
|
|
24
|
-
cmdName: (cmdAbi) => cmdAbi.name,
|
|
25
|
-
cmdDescription: (cmdAbi) => cmdAbi._metadata?.notice || cmdAbi.name,
|
|
26
|
-
cmdOptions: (cmdAbi) => {
|
|
27
|
-
const read = cmdAbi.stateMutability == "view" || cmdAbi.stateMutability == "pure";
|
|
28
|
-
return read ? defaultReadFunctionOptions() : defaultWriteFunctionOptions();
|
|
29
|
-
},
|
|
30
|
-
cmdArguments: (cmdAbi) => cmdAbi.inputs.map((input) => {
|
|
31
|
-
const argDesc = cmdAbi._metadata?.params?.[input.name] || `${input.type} parameter`;
|
|
32
|
-
return new Argument(`<${input.name}>`, argDesc);
|
|
33
|
-
}),
|
|
34
|
-
cmdAction: async function (ctx) {
|
|
35
|
-
const isRead = ctx.cmdAbi.stateMutability == "view" || ctx.cmdAbi.stateMutability == "pure";
|
|
36
|
-
const opts = ctx.cmd.opts();
|
|
37
|
-
const args0 = ctx.cmd.args;
|
|
38
|
-
console.log({ args0 });
|
|
39
|
-
const { address, tag, args } = await ctx.txnPrepare(ctx);
|
|
40
|
-
const abi = [ctx.txnAbi, ...ctx.nonFuncs];
|
|
41
|
-
const functionName = ctx.txnAbi.name;
|
|
42
|
-
if (isRead) {
|
|
43
|
-
const publicClient = createPublicClient({ transport: http(ctx.conf.rpc) });
|
|
44
|
-
const result = await publicClient.readContract({ address, abi, functionName, args });
|
|
45
|
-
console.log(`Result:`, result);
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
const { publicClient, walletClient } = await getClientsEth(ctx.conf, opts);
|
|
49
|
-
const account = walletClient.account;
|
|
50
|
-
console.log({
|
|
51
|
-
isRead,
|
|
52
|
-
address: `${address} (${tag})`,
|
|
53
|
-
account: account?.address,
|
|
54
|
-
signature: ctx.txnAbi._metadata.signature,
|
|
55
|
-
args,
|
|
56
|
-
});
|
|
57
|
-
const { request } = await publicClient.simulateContract({ address, abi, functionName, args, account });
|
|
58
|
-
const hash = await walletClient.writeContract(request);
|
|
59
|
-
console.log(`Transaction sent: ${hash}`);
|
|
60
|
-
console.log("Transaction mining...");
|
|
61
|
-
const receipt = await publicClient.waitForTransactionReceipt({ hash });
|
|
62
|
-
console.log("Transaction mined");
|
|
63
|
-
if (receipt.logs && receipt.logs.length > 0) {
|
|
64
|
-
const parsedLogs = parseEventLogs({ abi, logs: receipt.logs });
|
|
65
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
66
|
-
parsedLogs.forEach((log) => {
|
|
67
|
-
console.log(" - Event", log.eventName, stringify(log.args));
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
console.log({ isRead, address: `${address} (${tag})`, signature: ctx.txnAbi._metadata.signature, args });
|
|
72
|
-
return;
|
|
73
|
-
},
|
|
74
|
-
txnPrepare: function (ctx) {
|
|
75
|
-
const args = checkArguments(ctx.cmd.args, ctx.cmdAbi);
|
|
76
|
-
return { address: ctx.conf.contracts[ctx.contract], tag: ctx.contract, args };
|
|
77
|
-
},
|
|
78
|
-
};
|
|
79
|
-
export function configureCommand(txnAbi, config) {
|
|
80
|
-
const cmdAbi = (config.cmdAbi || defaultConfig.cmdAbi)(txnAbi);
|
|
81
|
-
const name = (config.cmdName || defaultConfig.cmdName)(cmdAbi);
|
|
82
|
-
const desc = (config.cmdDescription || defaultConfig.cmdDescription)(cmdAbi);
|
|
83
|
-
const opts = (config.cmdOptions || defaultConfig.cmdOptions)(cmdAbi);
|
|
84
|
-
const args = (config.cmdArguments || defaultConfig.cmdArguments)(cmdAbi);
|
|
85
|
-
const action = async function () {
|
|
86
|
-
const ctx = {
|
|
87
|
-
conf: getUniverseConfig(this.opts()),
|
|
88
|
-
contract: config.contract,
|
|
89
|
-
cmdAbi,
|
|
90
|
-
txnAbi,
|
|
91
|
-
nonFuncs: config.nonFuncs,
|
|
92
|
-
cmd: this,
|
|
93
|
-
txnPrepare: config.txnPrepare || defaultConfig.txnPrepare,
|
|
94
|
-
};
|
|
95
|
-
await (config.cmdAction || defaultConfig.cmdAction)(ctx);
|
|
96
|
-
};
|
|
97
|
-
const cmd = new Command();
|
|
98
|
-
cmd.name(name);
|
|
99
|
-
cmd.description(desc);
|
|
100
|
-
opts.forEach((opt) => cmd.addOption(opt));
|
|
101
|
-
args.forEach((arg) => cmd.addArgument(arg));
|
|
102
|
-
cmd.action(action);
|
|
103
|
-
return cmd;
|
|
104
|
-
}
|
|
105
|
-
export class RenamingCommand extends Command {
|
|
106
|
-
nameCounts = new Map();
|
|
107
|
-
addCommand(cmd, opts) {
|
|
108
|
-
const originalName = cmd.name();
|
|
109
|
-
const uniqueName = this.getUniqueName(originalName);
|
|
110
|
-
if (originalName !== uniqueName) {
|
|
111
|
-
cmd.name(uniqueName);
|
|
112
|
-
}
|
|
113
|
-
return super.addCommand(cmd, opts);
|
|
114
|
-
}
|
|
115
|
-
addCommands(cmds) {
|
|
116
|
-
cmds.forEach((cmd) => this.addCommand(cmd));
|
|
117
|
-
return this;
|
|
118
|
-
}
|
|
119
|
-
resetCounts(name) {
|
|
120
|
-
if (name) {
|
|
121
|
-
this.nameCounts.delete(name);
|
|
122
|
-
}
|
|
123
|
-
else {
|
|
124
|
-
this.nameCounts.clear();
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
getUniqueName(baseName) {
|
|
128
|
-
const count = this.nameCounts.get(baseName) || 0;
|
|
129
|
-
this.nameCounts.set(baseName, count + 1);
|
|
130
|
-
return count === 0 ? baseName : `${baseName}${count + 1}`;
|
|
131
|
-
}
|
|
132
|
-
}
|