@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 CHANGED
@@ -2,7 +2,7 @@
2
2
  id = 31337
3
3
  rpc = "http://127.0.0.1:8545"
4
4
  explorer = "http://127.0.0.1:8545"
5
- observer = "localnet"
5
+ observer = "dev"
6
6
 
7
7
  [universes.anvil.contracts]
8
8
  SetRegistry = "0x854C35Fd2b65fE9fcE71dddE91De8c3e1A7Dc8Ae"
@@ -11,7 +11,7 @@ KindRegistry = "0x7A8B3E5A9c227858C5917b7de8ba1684Cd868630"
11
11
  ElementRegistry = "0x8De1EE1dbAE2Ffd1CAe1e6bA83E6cAede1461507"
12
12
  ObjectMinter = "0x12CaBC370b316F247126F3Fab529Ee25e03aE226"
13
13
 
14
- [observers.localnet]
14
+ [observers.dev]
15
15
  rpc = "ws://localhost:9944"
16
- gateway = "http://every.im.local"
16
+ gateway = "http://localhost:3456"
17
17
  explorer = "http://every.im.local"
package/dist/abi.js CHANGED
@@ -11,6 +11,7 @@ export const abi = {
11
11
  omniRegistry: loadNonFuncAbiItems("OmniRegistry"),
12
12
  kindRegistry: loadNonFuncAbiItems("KindRegistry"),
13
13
  setRegistry: loadNonFuncAbiItems("SetRegistry"),
14
+ setContract: loadNonFuncAbiItems("ISet"),
14
15
  },
15
16
  funcs: {
16
17
  kindRegistry: loadFuncAbiItems("IKindRegistry"),
package/dist/cmdgen.js CHANGED
@@ -1,144 +1,56 @@
1
+ import { Argument, Command } from "commander";
1
2
  import { createPublicClient, http } from "viem";
2
- import { configureCommand } from "./cmds.js";
3
- import JSON5 from "json5";
4
- import { rstrip, excludes, includes, lstrip, startsWith, checkArguments } from "./utils.js";
5
- import { replaceAbiParamAt, insertAbiParamAt, abi } from "./abi.js";
6
- import { genMintCommand } from "./mint.js";
7
- import { genRelateCommand, genUnrelateCommand } from "./relate.js";
8
- export function generateCommands() {
9
- const kind = abi.funcs.kindRegistry
10
- .map(AbiToCommand({ contract: "KindRegistry", nonFuncs: abi.nonFuncs.kindRegistry, cmdName: lstrip("kind") }))
11
- .sort(byPreferredOrder);
12
- const set = [
13
- ...abi.funcs.setRegistryAdmin.map(AbiToCommand(setRegistryAdminCmdConfig)),
14
- ...abi.funcs.setRegistry
15
- .filter(excludes(["setRegister", "setUpdate", "setTouch", "setUpgrade"]))
16
- .map(AbiToCommand({ contract: "SetRegistry", nonFuncs: abi.nonFuncs.setRegistry, cmdName: lstrip("set") })),
17
- ].sort(byPreferredOrder);
18
- const relation = abi.funcs.omniRegistry
19
- .filter(startsWith("relation"))
20
- .map(AbiToCommand({
21
- contract: "OmniRegistry",
22
- nonFuncs: abi.nonFuncs.omniRegistry,
23
- cmdName: lstrip("relation"),
24
- }))
25
- .sort(byPreferredOrder);
26
- const unique = abi.funcs.elemRegistry
27
- .filter(startsWith("unique"))
28
- .map(AbiToCommand({ contract: "ElementRegistry", nonFuncs: abi.nonFuncs.elemRegistry, cmdName: lstrip("unique") }))
29
- .sort(byPreferredOrder);
30
- const value = abi.funcs.elemRegistry
31
- .filter(startsWith("value"))
32
- .map(AbiToCommand({ contract: "ElementRegistry", nonFuncs: abi.nonFuncs.elemRegistry, cmdName: lstrip("value") }))
33
- .sort(byPreferredOrder);
34
- const object = [
35
- genMintCommand(),
36
- genRelateCommand(),
37
- genUnrelateCommand(),
38
- // write functions
39
- ...abi.funcs.setContract
40
- .filter(includes("update,upgrade,touch,transfer".split(",")))
41
- .map(AbiToCommand(setContractObjectCmdConfig)),
42
- // read functions
43
- ...abi.funcs.setContract
44
- .filter(excludes("update,upgrade,touch,transfer,uri,supportsInterface".split(",")))
45
- .map(AbiToCommand(setContractObjectCmdConfig)),
46
- ...abi.funcs.setContract
47
- .filter(includes("uri".split(",")))
48
- .map(AbiToCommand({ ...setContractObjectCmdConfig, txnPrepare: objectUriTxnPrepare })),
49
- ].sort(byPreferredOrder);
50
- const mintpolicy = [
51
- ...abi.funcs.objectMinterAdmin.map(AbiToCommand(objectMinterAdminCmdConfig)),
52
- ...abi.funcs.objectMinter
53
- .filter(startsWith("mintPolicy"))
54
- .filter(excludes("mintPolicyAdd,mintPolicyEnable,mintPolicyDisable".split(",")))
55
- .map(AbiToCommand({ contract: "ObjectMinter", nonFuncs: abi.nonFuncs.objectMinter, cmdName: lstrip("mintPolicy") })),
56
- ].sort(byPreferredOrder);
57
- return { kind, set, relation, unique, value, mintpolicy, object };
58
- }
59
- const setContractObjectCmdConfig = {
60
- contract: "ISet",
61
- nonFuncs: [],
62
- cmdAbi: function (txnAbi) {
63
- return replaceAbiParamAt(txnAbi, 0, {
64
- name: "sid",
65
- type: "string",
66
- doc: "Scoped Object ID (in form of set.id, e.g., 17.1)",
67
- });
68
- },
69
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
70
- txnPrepare: async function (ctx) {
71
- const rawArgs = checkArguments(ctx.cmd.args, ctx.cmdAbi);
72
- const [set, id] = rawArgs[0].split(".");
73
- const args = [JSON5.parse(id), ...rawArgs.slice(1)];
74
- const publicClient = createPublicClient({ transport: http(ctx.conf.rpc) });
75
- const address = (await publicClient.readContract({
76
- address: ctx.conf.contracts["SetRegistry"],
77
- abi: abi.setContract,
78
- functionName: "setContract",
79
- args: [set],
80
- }));
81
- return { address: address, tag: ctx.contract, args };
82
- },
83
- };
84
- const objectUriTxnPrepare = async function (ctx) {
85
- const rawArgs = checkArguments(ctx.cmd.args, ctx.cmdAbi);
86
- // const [set, id] = rawArgs[0].split(".");
87
- const set = rawArgs[0].split(".")[0];
88
- const publicClient = createPublicClient({ transport: http(ctx.conf.rpc) });
89
- const address = (await publicClient.readContract({
90
- address: ctx.conf.contracts["SetRegistry"],
91
- abi: abi.setContract,
92
- functionName: "setContract",
93
- args: [set],
94
- }));
95
- return { address: address, tag: ctx.contract, args: [] };
3
+ import { submitSimulation } from "./ethereum.js";
4
+ import { Logger } from "./logger.js";
5
+ import { outputOptions, universe, writeOptions } from "./commander-patch.js";
6
+ import { FromOpts } from "./from-opts.js";
7
+ import { coerceValue } from "./utils.js";
8
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9
+ const getReadAction = (config, funName, abiFunc, abi) => async function readAction() {
10
+ const opts = this.opts();
11
+ const conf = FromOpts.getUniverseConfig(opts);
12
+ const address = await config.getContract(conf, this.args, abiFunc);
13
+ const args = (config.getFuncArgs ?? CommandGenDefaults.getFuncArgs)(this.args, abiFunc);
14
+ const console = new Logger(opts);
15
+ const publicClient = createPublicClient({ transport: http(conf.rpc) });
16
+ const result = await publicClient.readContract({ address, abi, functionName: funName, args });
17
+ console.log(result);
18
+ console.result(result);
96
19
  };
97
- const setRegistryAdminCmdConfig = {
98
- contract: "ISetRegistryAdmin",
99
- nonFuncs: abi.nonFuncs.setRegistry,
100
- cmdName: rstrip("Set"),
101
- cmdAbi: function (txnAbi) {
102
- return insertAbiParamAt(txnAbi, 0, {
103
- name: "contract",
104
- type: "address",
105
- doc: "address of the set contract",
106
- });
107
- },
108
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
109
- txnPrepare: async function (ctx) {
110
- const raw = checkArguments(ctx.cmd.args, ctx.cmdAbi);
111
- const address = raw[0];
112
- const args = raw.slice(1);
113
- return { address, tag: ctx.contract, args };
114
- },
20
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
21
+ const getWriteAction = (config, funcName, abiFunc, abi) => async function writeAction() {
22
+ const opts = this.opts();
23
+ const args = (config.getFuncArgs ?? CommandGenDefaults.getFuncArgs)(this.args, abiFunc);
24
+ const { publicClient, walletClient, conf } = await FromOpts.toWriteEthereum(opts);
25
+ const address = config.getContract(conf, this.args, abiFunc);
26
+ const account = walletClient.account;
27
+ const simulation = { address, abi, functionName: funcName, args, account };
28
+ await submitSimulation(simulation, publicClient, walletClient, new Logger(opts));
115
29
  };
116
- const objectMinterAdminCmdConfig = {
117
- contract: "IObjectMinterAdmin",
118
- nonFuncs: abi.nonFuncs.objectMinter,
119
- cmdName: rstrip("MintPolicy"),
120
- cmdAbi: function (txnAbi) {
121
- return insertAbiParamAt(txnAbi, 0, {
122
- name: "contract",
123
- type: "address",
124
- doc: "address of the contract",
125
- });
126
- },
127
- txnPrepare: async function (ctx) {
128
- const raw = checkArguments(ctx.cmd.args, ctx.cmdAbi);
129
- const address = raw[0];
130
- const args = raw.slice(1);
131
- return { address, tag: ctx.contract, args };
132
- },
30
+ export const getCommandGen = (config) => function genCmd(cmdName) {
31
+ const { getFuncName, getAbiFuncs, getAbiNonFuncs } = config;
32
+ const funcName = getFuncName(cmdName);
33
+ const abiFuncs = getAbiFuncs(funcName);
34
+ const abiNonFuncs = getAbiNonFuncs(funcName);
35
+ // console.log(funcName, abiFuncs);
36
+ const abiFuncDoc = abiFuncs[0];
37
+ const description = abiFuncDoc._metadata?.notice || "";
38
+ const isRead = abiFuncDoc.stateMutability == "view" || abiFuncDoc.stateMutability == "pure";
39
+ const options = isRead ? [universe, ...outputOptions] : [...writeOptions, ...outputOptions];
40
+ const args = (config.getCmdArgs ?? CommandGenDefaults.getCmdArgs)(abiFuncDoc);
41
+ const abiContract = [...abiFuncs, ...abiNonFuncs];
42
+ const action = isRead
43
+ ? getReadAction(config, funcName, abiFuncDoc, abiContract)
44
+ : getWriteAction(config, funcName, abiFuncDoc, abiContract);
45
+ return new Command(cmdName).description(description).addOptions(options).addArguments(args).action(action);
133
46
  };
134
- function AbiToCommand(conf) {
135
- return (txnAbi) => configureCommand(txnAbi, conf);
136
- }
137
- function byPreferredOrder(a, b) {
138
- const ORDER_MAP = new Map("mint,register,update,upgrade,touch,transfer,relate,unrelate,owner,descriptor,elements,revision,sota,snapshot,status,admint,contract,rule,uri"
139
- .split(",")
140
- .map((name, index) => [name, index]));
141
- const aIndex = ORDER_MAP.get(a.name()) ?? Infinity;
142
- const bIndex = ORDER_MAP.get(b.name()) ?? Infinity;
143
- return aIndex - bIndex;
47
+ export function makeFuncName(cmdName, prefix) {
48
+ return `${prefix}${cmdName[0].toUpperCase()}${cmdName.slice(1)}`;
144
49
  }
50
+ export const CommandGenDefaults = {
51
+ getFuncArgs: (args, abiFunc) => args.map((arg, i) => coerceValue(arg, abiFunc.inputs[i])),
52
+ getCmdArgs: (abiFunc) => abiFunc.inputs.map((input) => {
53
+ const desc = abiFunc._metadata?.params?.[input.name] || `${input.type} parameter`;
54
+ return new Argument(`<${input.name}>`, desc);
55
+ }),
56
+ };
@@ -0,0 +1,43 @@
1
+ import { Command } from "commander";
2
+ import "@polkadot/api-augment/substrate";
3
+ import * as JSON11 from "json11";
4
+ import columify from "columnify";
5
+ import { u8aFixLength } from "@polkadot/util";
6
+ import { decodeAddress } from "@polkadot/util-crypto";
7
+ import { submitSubTxUI } from "../substrate.js";
8
+ import { network } from "../commander-patch.js";
9
+ import { Logger } from "../logger.js";
10
+ const balanceQueryCmd = new Command("query")
11
+ .description("Query account balance")
12
+ .argument("<address>", "Account address (SS58 or 0x hex)")
13
+ .addOption(network)
14
+ .addOutputOptions()
15
+ .subReadAction(async function (api, address) {
16
+ const accountId = u8aFixLength(decodeAddress(address), 256);
17
+ const accountInfo = (await api.query.system.account(accountId));
18
+ const symbol = api.registry.chainTokens[0];
19
+ const free = accountInfo.data.free.toBigInt();
20
+ const reserved = accountInfo.data.reserved.toBigInt();
21
+ const frozen = accountInfo.data.frozen.toBigInt();
22
+ const balance = { free, reserved, frozen };
23
+ const result = { address, symbol, balance };
24
+ const console = new Logger(this.opts());
25
+ console.log(columify([[symbol, JSON11.stringify(balance)]], { showHeaders: false }));
26
+ console.result(result);
27
+ });
28
+ const balanceTransferCmd = new Command("transfer")
29
+ .description("Transfer balance to account")
30
+ .argument("<address>", "Recipient account address (SS58 or 0x hex)")
31
+ .argument("<amount>", "Amount in base units")
32
+ .addOption(network)
33
+ .addKeystoreOptions()
34
+ .addOutputOptions()
35
+ .subWriteAction(async function (api, pair, address, amount) {
36
+ const tx = api.tx.balances.transferKeepAlive(address, amount);
37
+ const console = new Logger(this.opts());
38
+ await submitSubTxUI(api, tx, pair, console);
39
+ });
40
+ export const balanceCmd = new Command("balance")
41
+ .description("manage balances")
42
+ .addCommand(balanceQueryCmd)
43
+ .addCommand(balanceTransferCmd);
@@ -0,0 +1,46 @@
1
+ import { Command } from "commander";
2
+ import { _loadMergedConfig } from "../config.js";
3
+ const configShowCmd = new Command("show")
4
+ .description("show mreged configuration")
5
+ .option("-u, --universe <universe>", "Show config of this universe only")
6
+ .option("-n, --network <network>", "Show config of this network only")
7
+ .action(async (opts) => {
8
+ const [config] = _loadMergedConfig();
9
+ const universe = opts.universe
10
+ ? (config.universes?.[opts.universe] ??
11
+ (() => {
12
+ throw new Error(`config for universe ${opts.universe} not found`);
13
+ })())
14
+ : undefined;
15
+ const network = opts.network
16
+ ? (config.observers?.[opts.network] ??
17
+ (() => {
18
+ throw new Error(`config for network ${opts.network} not found`);
19
+ })())
20
+ : undefined;
21
+ let result;
22
+ if (universe && !network) {
23
+ result = universe;
24
+ }
25
+ else if (network && !universe) {
26
+ result = network;
27
+ }
28
+ else if (universe && network) {
29
+ result = {
30
+ [opts.universe]: universe,
31
+ [opts.network]: network,
32
+ };
33
+ }
34
+ else {
35
+ result = config;
36
+ }
37
+ console.log(JSON.stringify(result, null, 2));
38
+ });
39
+ const configFilesCmd = new Command("files").description("list configuration files searched").action(async () => {
40
+ const [, files] = _loadMergedConfig();
41
+ files.forEach((f) => console.log(f));
42
+ });
43
+ export const configCmd = new Command("config")
44
+ .description("view merged configuration and source files")
45
+ .addCommand(configShowCmd)
46
+ .addCommand(configFilesCmd);
@@ -0,0 +1,14 @@
1
+ import { Command } from "commander";
2
+ import { abi } from "../abi.js";
3
+ import { getCommandGen, makeFuncName } from "../cmdgen.js";
4
+ const cmdGenConfig = {
5
+ getFuncName: (cmdName) => makeFuncName(cmdName, `kind`),
6
+ getAbiFuncs: (funcName) => abi.funcs.kindRegistry.filter((i) => i.name == funcName),
7
+ // eslint-disable-next-line
8
+ getAbiNonFuncs: (funcName) => abi.nonFuncs.kindRegistry,
9
+ // eslint-disable-next-line
10
+ getContract: (conf, args, abiFunc) => conf.contracts.KindRegistry,
11
+ };
12
+ const cmdGen = getCommandGen(cmdGenConfig);
13
+ const subCmds = "register,upgrade,touch,transfer,owner,descriptor,snapshot".split(",");
14
+ export const kindCmd = new Command("kind").description("manage kinds").addCommands(subCmds.map(cmdGen));
@@ -0,0 +1,82 @@
1
+ import { Command } from "commander";
2
+ import "@polkadot/api-augment/substrate";
3
+ import * as fs from "fs";
4
+ import * as JSON11 from "json11";
5
+ import columify from "columnify";
6
+ import { computeMatterHash, guessContentType, loadBinary } from "../utils.js";
7
+ import { submitTransaction } from "../substrate.js";
8
+ import { network } from "../commander-patch.js";
9
+ import { Logger } from "../logger.js";
10
+ const matterRegisterCmd = new Command("register")
11
+ .description("Register matter on the Substrate chain")
12
+ .argument("<files...>", "Paths of matter blob files")
13
+ .option("--mime <string>", "Matter mime")
14
+ .option("--form <number>", "Matter form", "1")
15
+ .addOption(network)
16
+ .addKeystoreOptions()
17
+ .addOutputOptions()
18
+ .subWriteAction(async function (api, pair, files) {
19
+ const opts = this.opts();
20
+ const console = new Logger(opts);
21
+ const materials = [];
22
+ for (const file of files) {
23
+ const [filePath, form_, mime_] = file.split(":");
24
+ const form = Number(form_ ?? opts.form ?? "1");
25
+ const mime = mime_ || opts.mime || guessContentType(filePath);
26
+ materials.push({ filePath, form, mime });
27
+ }
28
+ const txns = [];
29
+ for (const { filePath, form, mime } of materials) {
30
+ const content = fs.readFileSync(filePath);
31
+ console.log(`Register matter: form=${form} mime=${mime} blob=${content.length}B ${filePath}`);
32
+ const contentRaw = api.createType("Raw", content, content.length);
33
+ const call = api.tx.every.matterRegister(form, mime, contentRaw);
34
+ console.log(`Transaction submitting...`);
35
+ const txn = await submitTransaction(api, call, pair);
36
+ console.log(`Transaction submitted: ${txn.txHash}`);
37
+ txns.push({ txn, filePath });
38
+ }
39
+ console.log("Waiting for confirmation...");
40
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
41
+ const result = [];
42
+ for (const { txn, filePath } of txns) {
43
+ const r = await txn.receipt;
44
+ const header = await api.rpc.chain.getHeader(r.blockHash);
45
+ console.log(`Transaction confirmed: ${txn.txHash} ${filePath}`);
46
+ console.log(`Confirmed in: block ${header.number}, hash ${header.hash}`);
47
+ const events = r.events.map((e) => [e.event.method, JSON11.stringify(e.event.data.toJSON())]);
48
+ const receipt = r.events.map((e) => ({ event: e.event.method, data: e.event.data.toJSON() }));
49
+ console.log(columify(events, { showHeaders: false }));
50
+ result.push({
51
+ file: filePath,
52
+ transaction: txn.txHash,
53
+ events: receipt,
54
+ });
55
+ }
56
+ console.result(result);
57
+ });
58
+ const matterHashCmd = new Command("hash")
59
+ .description("Register matter on the Substrate chain")
60
+ .argument("<files...>", "Paths of matter blob files")
61
+ .option("--mime <string>", "Matter mime")
62
+ .option("--form <number>", "Matter form", "1")
63
+ .addOutputOptions()
64
+ .action(async function (files) {
65
+ const opts = this.opts();
66
+ const console = new Logger(opts);
67
+ const matters = [];
68
+ for (const file of files) {
69
+ const [path, form_, mime_] = file.split(":");
70
+ const form = Number(form_ ?? opts.form ?? "1");
71
+ const mime = mime_ || opts.mime || guessContentType(path);
72
+ const blob = loadBinary(path);
73
+ const hash = computeMatterHash(form, mime, blob);
74
+ matters.push({ hash, form, mime, blob: blob.length, path });
75
+ }
76
+ console.log(columify(matters));
77
+ console.result(matters);
78
+ });
79
+ export const matterCmd = new Command("matter")
80
+ .description("matter utilities")
81
+ .addCommand(matterRegisterCmd)
82
+ .addCommand(matterHashCmd);
@@ -0,0 +1,31 @@
1
+ import { Argument, Command } from "commander";
2
+ import { abi } from "../abi.js";
3
+ import { CommandGenDefaults, getCommandGen, makeFuncName } from "../cmdgen.js";
4
+ const adminCmdConfig = {
5
+ getFuncName: (cmdName) => `${cmdName}MintPolicy`,
6
+ getAbiFuncs: (funcName) => abi.funcs.objectMinterAdmin.filter((i) => i.name == funcName),
7
+ // eslint-disable-next-line
8
+ getAbiNonFuncs: (funcName) => abi.nonFuncs.objectMinter,
9
+ // eslint-disable-next-line
10
+ getContract: (conf, args, abiFunc) => args[0],
11
+ // eslint-disable-next-line
12
+ getFuncArgs: (args, abiFunc) => args.slice(1),
13
+ getCmdArgs: (abiFunc) => [
14
+ new Argument(`<contract>`, "address of the set contract"),
15
+ ...CommandGenDefaults.getCmdArgs(abiFunc),
16
+ ],
17
+ };
18
+ const userCmdConfig = {
19
+ getFuncName: (cmdName) => makeFuncName(cmdName, `mintPolicy`),
20
+ getAbiFuncs: (funcName) => abi.funcs.objectMinter.filter((i) => i.name == funcName),
21
+ // eslint-disable-next-line
22
+ getAbiNonFuncs: (funcName) => abi.nonFuncs.objectMinter,
23
+ // eslint-disable-next-line
24
+ getContract: (conf, args, abiFunc) => conf.contracts.ObjectMinter,
25
+ };
26
+ const adminCmds = "add,enable,disable".split(",");
27
+ const userCmds = "count,get,search".split(",");
28
+ export const minterCmd = new Command("minter")
29
+ .description("manage mint policies")
30
+ .addCommands(adminCmds.map(getCommandGen(adminCmdConfig)))
31
+ .addCommands(userCmds.map(getCommandGen(userCmdConfig)));
@@ -0,0 +1,175 @@
1
+ import { Argument, Command } from "commander";
2
+ import { createPublicClient, http, parseUnits } from "viem";
3
+ import { parseAbiItem, erc1155Abi, erc721Abi } from "viem";
4
+ import { abi } from "../abi.js";
5
+ import { submitSimulation } from "../ethereum.js";
6
+ import { Logger } from "../logger.js";
7
+ import { parseBigInt, parseNode3, parseNode4 } from "../parsers.js";
8
+ import { CommandGenDefaults, getCommandGen } from "../cmdgen.js";
9
+ import { FromOpts } from "../from-opts.js";
10
+ import { coerceValue } from "../utils.js";
11
+ const objectRelateCmd = new Command()
12
+ .name("relate")
13
+ .description("Link a tail object to a head object through a relation")
14
+ .addWriteOptions()
15
+ .argument("<tail>", "tail node, in form of [[data.]grant.]set.id", parseNode4)
16
+ .argument("<rel>", "relation ID", parseBigInt)
17
+ .argument("<head>", "head node in form of [grant.]set.id, ", parseNode3)
18
+ .action(async function () {
19
+ await relateAction(this, "relate");
20
+ });
21
+ const objectUnrelateCmd = new Command()
22
+ .name("unrelate")
23
+ .description("Unlinks a tail object from a head object")
24
+ .addWriteOptions()
25
+ .argument("<tail>", "tail node, in form of [[data.]grant.]set.id", parseNode4)
26
+ .argument("<rel>", "relation ID", parseBigInt)
27
+ .argument("<head>", "head node in form of [grant.]set.id, ", parseNode3)
28
+ .action(async function () {
29
+ await relateAction(this, "unrelate");
30
+ });
31
+ const objectMintCmd = new Command()
32
+ .name("mint")
33
+ .description("Mint an object via the object minter or directly from the set")
34
+ .option("--to <address>", "specify the recipient")
35
+ .option("--value <amount>", "the amount of ETH to send together", "0")
36
+ .option("--auth <data>", "authorization data for a permissioned mint", "0x")
37
+ .option("--policy <index>", "the index number of the mint policy", "0")
38
+ .option("--no-minter", "mint directly from set contract instead of using ObjectMinter")
39
+ .addWriteOptions()
40
+ .argument("<sid>", "scoped object ID, in form of set.id (e.g., 17.1)")
41
+ .argument("[data]", "additional input data", "0x")
42
+ .action(mintAction);
43
+ const objectSendCmd = new Command("send")
44
+ .description("Call a function by signature (dry-run: prints calldata)")
45
+ .option("--sig <sig>", "Function signature, e.g. 'transfer(address,uint256)'")
46
+ .argument("<args...>", "Function arguments (arrays/tuples as JSON)")
47
+ .addWriteOptions()
48
+ .action(sendAction);
49
+ const cmdGenConfig = {
50
+ getFuncName: (cmdName) => cmdName,
51
+ getAbiFuncs: (funcName) => abi.funcs.setContract.filter((i) => i.name == funcName),
52
+ // eslint-disable-next-line
53
+ getAbiNonFuncs: (funcName) => [...abi.nonFuncs.setContract],
54
+ // eslint-disable-next-line
55
+ getContract: async function (conf, args, abiFunc) {
56
+ const publicClient = createPublicClient({ transport: http(conf.rpc) });
57
+ const address = await publicClient.readContract({
58
+ address: conf.contracts.SetRegistry,
59
+ abi: abi.setContract,
60
+ functionName: "setContract",
61
+ args: [args[0].set],
62
+ });
63
+ return address;
64
+ },
65
+ // eslint-disable-next-line
66
+ getFuncArgs: function (args, abiFunc) {
67
+ return abiFunc.name == "uri" ? args.slice(1) : [args[0].id, ...args.slice(1)];
68
+ },
69
+ getCmdArgs: function (abiFunc) {
70
+ const sid = new Argument(`<sid>`, "sid of the object");
71
+ const args0 = CommandGenDefaults.getCmdArgs(abiFunc);
72
+ return abiFunc.name == "uri" ? [sid] : [sid, ...args0.slice(1)];
73
+ },
74
+ };
75
+ const cmdGen = getCommandGen(cmdGenConfig);
76
+ const writeCmds = "upgrade,touch,transfer".split(",");
77
+ const readCmds = "owner,descriptor,snapshot,uri".split(",");
78
+ export const objectCmd = new Command("object")
79
+ .description("manage objects")
80
+ .addCommands(writeCmds.map(cmdGen))
81
+ .addCommand(objectMintCmd)
82
+ .addCommand(objectRelateCmd)
83
+ .addCommand(objectUnrelateCmd)
84
+ .addCommand(objectSendCmd)
85
+ .addCommands(readCmds.map(cmdGen));
86
+ async function mintAction() {
87
+ const opts = this.opts();
88
+ const args0 = this.args;
89
+ const { publicClient, walletClient, conf } = await FromOpts.toWriteEthereum(opts);
90
+ const setRegistry = conf.contracts["SetRegistry"];
91
+ const account = walletClient.account;
92
+ const [set, id] = args0[0].split(".");
93
+ const setContract = (await publicClient.readContract({
94
+ address: setRegistry,
95
+ abi: abi.setContract,
96
+ functionName: "setContract",
97
+ args: [BigInt(set)],
98
+ }));
99
+ const value = parseUnits(opts.value || "0", 18);
100
+ const recipientAddress = (opts.to || account.address);
101
+ const mintData = (args0[1] || "0x");
102
+ const simulation = opts.minter
103
+ ? {
104
+ address: conf.contracts["ObjectMinter"],
105
+ abi: abi.mint,
106
+ functionName: "mint",
107
+ args: [recipientAddress, setContract, BigInt(id), mintData, opts.auth || "0x", Number(opts.policy || "0")],
108
+ account,
109
+ value,
110
+ }
111
+ : {
112
+ address: setContract,
113
+ abi: abi.create,
114
+ functionName: "create",
115
+ args: [recipientAddress, BigInt(id), mintData],
116
+ account,
117
+ value,
118
+ };
119
+ await submitSimulation(simulation, publicClient, walletClient, new Logger(opts));
120
+ }
121
+ async function relateAction(cmd, functionName) {
122
+ const opts = cmd.opts();
123
+ const { publicClient, walletClient, conf } = await FromOpts.toWriteEthereum(opts);
124
+ const address = conf.contracts["OmniRegistry"];
125
+ const simulation = {
126
+ address,
127
+ abi: abi.relation,
128
+ functionName,
129
+ args: cmd.args,
130
+ account: walletClient.account,
131
+ };
132
+ await submitSimulation(simulation, publicClient, walletClient, new Logger(opts));
133
+ }
134
+ async function sendAction() {
135
+ const opts = this.opts();
136
+ const args0 = this.args;
137
+ const { sig } = this.opts();
138
+ if (!sig) {
139
+ console.error("Error: --sig is required (e.g. --sig 'transfer(address,uint256)')");
140
+ this.exitOverride();
141
+ return;
142
+ }
143
+ const item = parseAbiItem(`function ${sig}`);
144
+ if (item.type !== "function")
145
+ throw new Error(`Not a function signature: ${sig}`);
146
+ const abiFunc = item;
147
+ const params = abiFunc.inputs ?? [];
148
+ if (args0.length !== params.length)
149
+ throw new Error(`Argument count mismatch: expected ${params.length}, got ${args0.length}`);
150
+ const sidIndex = params.findIndex((p) => p.type == "uint64");
151
+ if (sidIndex == -1)
152
+ throw new Error("SID type(uint64) not found in signature");
153
+ const [setId, objectId] = args0[sidIndex].split(".");
154
+ args0[sidIndex] = objectId;
155
+ const args = args0.map((a, i) => coerceValue(a, params[i]));
156
+ const { publicClient, walletClient, conf } = await FromOpts.toWriteEthereum(opts);
157
+ const setRegistry = conf.contracts["SetRegistry"];
158
+ const account = walletClient.account;
159
+ const setContract = (await publicClient.readContract({
160
+ address: setRegistry,
161
+ abi: abi.funcs.setRegistry,
162
+ functionName: "setContract",
163
+ args: [BigInt(setId)],
164
+ }));
165
+ const value = parseUnits(opts.value ?? "0", 18);
166
+ const simulation = {
167
+ address: setContract,
168
+ abi: [abiFunc, ...abi.nonFuncs.setContract, ...erc1155Abi, ...erc721Abi],
169
+ functionName: abiFunc.name,
170
+ args: args,
171
+ account,
172
+ value,
173
+ };
174
+ await submitSimulation(simulation, publicClient, walletClient, new Logger(opts));
175
+ }
@@ -0,0 +1,16 @@
1
+ import { Command } from "commander";
2
+ import { abi } from "../abi.js";
3
+ import { getCommandGen, makeFuncName } from "../cmdgen.js";
4
+ const cmdGenConfig = {
5
+ getFuncName: (cmdName) => makeFuncName(cmdName, `relation`),
6
+ getAbiFuncs: (funcName) => abi.funcs.omniRegistry.filter((i) => i.name == funcName),
7
+ // eslint-disable-next-line
8
+ getAbiNonFuncs: (funcName) => abi.nonFuncs.omniRegistry,
9
+ // eslint-disable-next-line
10
+ getContract: (conf, args, abiFunc) => conf.contracts.OmniRegistry,
11
+ // eslint-disable-next-line
12
+ getFuncArgs: (args, abiFunc) => args,
13
+ };
14
+ const cmdGen = getCommandGen(cmdGenConfig);
15
+ const subCmds = "register,upgrade,touch,transfer,owner,descriptor,snapshot,rule,admit".split(",");
16
+ export const relationCmd = new Command("relation").description("manage relations").addCommands(subCmds.map(cmdGen));