@1sat/cli 0.0.1
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/bin/1sat +0 -0
- package/package.json +32 -0
- package/src/args.ts +100 -0
- package/src/cli.ts +105 -0
- package/src/commands/action.ts +79 -0
- package/src/commands/config.ts +109 -0
- package/src/commands/identity.ts +133 -0
- package/src/commands/init.ts +172 -0
- package/src/commands/locks.ts +126 -0
- package/src/commands/opns.ts +73 -0
- package/src/commands/ordinals.ts +355 -0
- package/src/commands/social.ts +56 -0
- package/src/commands/sweep.ts +54 -0
- package/src/commands/tokens.ts +194 -0
- package/src/commands/tx.ts +65 -0
- package/src/commands/wallet.ts +218 -0
- package/src/config.ts +97 -0
- package/src/context.ts +63 -0
- package/src/help.ts +117 -0
- package/src/keys.ts +88 -0
- package/src/output.ts +82 -0
package/bin/1sat
ADDED
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@1sat/cli",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "CLI for 1Sat Ordinals SDK",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./src/cli.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"1sat": "./src/cli.ts"
|
|
9
|
+
},
|
|
10
|
+
"files": ["src", "bin"],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "bun build ./src/cli.ts --compile --outfile=bin/1sat --external pg --external pg-native --external pg-query-stream --external tedious --external oracledb --external mysql",
|
|
13
|
+
"dev": "bun run src/cli.ts",
|
|
14
|
+
"lint": "biome check src"
|
|
15
|
+
},
|
|
16
|
+
"keywords": ["1sat", "bsv", "ordinals", "cli"],
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@1sat/actions": "0.0.52",
|
|
20
|
+
"@1sat/client": "0.0.15",
|
|
21
|
+
"@1sat/types": "0.0.13",
|
|
22
|
+
"@1sat/wallet-node": "0.0.11",
|
|
23
|
+
"@bsv/sdk": "^2.0.4",
|
|
24
|
+
"chalk": "^5.0.0",
|
|
25
|
+
"@clack/prompts": "^0.8.0",
|
|
26
|
+
"bitcoin-backup": "^0.0.8"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/bun": "^1.3.9",
|
|
30
|
+
"typescript": "^5.9.3"
|
|
31
|
+
}
|
|
32
|
+
}
|
package/src/args.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Argument parsing utilities for the 1sat CLI.
|
|
3
|
+
*
|
|
4
|
+
* Pure manual parsing - no frameworks. Follows clawnet pattern.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export interface GlobalFlags {
|
|
8
|
+
json: boolean
|
|
9
|
+
quiet: boolean
|
|
10
|
+
yes: boolean
|
|
11
|
+
chain: 'main' | 'test'
|
|
12
|
+
help: boolean
|
|
13
|
+
version: boolean
|
|
14
|
+
rest: string[]
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Parse global flags from raw argv, returning structured flags and remaining args.
|
|
19
|
+
*/
|
|
20
|
+
export function parseGlobalFlags(args: string[]): GlobalFlags {
|
|
21
|
+
let json = false
|
|
22
|
+
let quiet = false
|
|
23
|
+
let yes = false
|
|
24
|
+
let chain: 'main' | 'test' = 'main'
|
|
25
|
+
let help = false
|
|
26
|
+
let version = false
|
|
27
|
+
const rest: string[] = []
|
|
28
|
+
const skip = new Set<number>()
|
|
29
|
+
|
|
30
|
+
for (let i = 0; i < args.length; i++) {
|
|
31
|
+
if (skip.has(i)) continue
|
|
32
|
+
|
|
33
|
+
const arg = args[i]
|
|
34
|
+
|
|
35
|
+
switch (arg) {
|
|
36
|
+
case '--json':
|
|
37
|
+
json = true
|
|
38
|
+
break
|
|
39
|
+
case '--quiet':
|
|
40
|
+
case '-q':
|
|
41
|
+
quiet = true
|
|
42
|
+
break
|
|
43
|
+
case '--yes':
|
|
44
|
+
case '-y':
|
|
45
|
+
yes = true
|
|
46
|
+
break
|
|
47
|
+
case '--chain': {
|
|
48
|
+
const value = args[i + 1]
|
|
49
|
+
if (value === 'main' || value === 'test') {
|
|
50
|
+
chain = value
|
|
51
|
+
skip.add(i + 1)
|
|
52
|
+
} else {
|
|
53
|
+
throw new Error(
|
|
54
|
+
`Invalid chain value: ${value}. Must be 'main' or 'test'.`,
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
break
|
|
58
|
+
}
|
|
59
|
+
case '--help':
|
|
60
|
+
case '-h':
|
|
61
|
+
help = true
|
|
62
|
+
break
|
|
63
|
+
case '--version':
|
|
64
|
+
case '-v':
|
|
65
|
+
version = true
|
|
66
|
+
break
|
|
67
|
+
default:
|
|
68
|
+
rest.push(arg)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return { json, quiet, yes, chain, help, version, rest }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Extract a named flag value from args.
|
|
77
|
+
* Returns the value following the flag, or undefined if not found.
|
|
78
|
+
*/
|
|
79
|
+
export function extractFlag(args: string[], flag: string): string | undefined {
|
|
80
|
+
const idx = args.indexOf(flag)
|
|
81
|
+
if (idx === -1 || idx + 1 >= args.length) return undefined
|
|
82
|
+
return args[idx + 1]
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Check if a boolean flag is present.
|
|
87
|
+
*/
|
|
88
|
+
export function hasFlag(args: string[], flag: string): boolean {
|
|
89
|
+
return args.includes(flag)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Extract positional arguments, skipping flag indices.
|
|
94
|
+
*/
|
|
95
|
+
export function extractPositional(
|
|
96
|
+
args: string[],
|
|
97
|
+
skipIndices: Set<number>,
|
|
98
|
+
): string[] {
|
|
99
|
+
return args.filter((arg, i) => !arg.startsWith('--') && !skipIndices.has(i))
|
|
100
|
+
}
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 1sat CLI - Command-line interface for 1Sat Ordinals SDK.
|
|
5
|
+
*
|
|
6
|
+
* Pure Bun CLI with manual arg parsing. No frameworks.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { parseGlobalFlags } from './args'
|
|
10
|
+
import { handleActionCommand } from './commands/action'
|
|
11
|
+
import { handleConfigCommand } from './commands/config'
|
|
12
|
+
import { handleIdentityCommand } from './commands/identity'
|
|
13
|
+
import { handleInitCommand } from './commands/init'
|
|
14
|
+
import { handleLocksCommand } from './commands/locks'
|
|
15
|
+
import { handleOpnsCommand } from './commands/opns'
|
|
16
|
+
import { handleOrdinalsCommand } from './commands/ordinals'
|
|
17
|
+
import { handleSocialCommand } from './commands/social'
|
|
18
|
+
import { handleSweepCommand } from './commands/sweep'
|
|
19
|
+
import { handleTokensCommand } from './commands/tokens'
|
|
20
|
+
import { handleTxCommand } from './commands/tx'
|
|
21
|
+
import { handleWalletCommand } from './commands/wallet'
|
|
22
|
+
import { printHelp, printVersion } from './help'
|
|
23
|
+
import { formatError } from './output'
|
|
24
|
+
|
|
25
|
+
const rawArgs = process.argv.slice(2)
|
|
26
|
+
|
|
27
|
+
async function main(): Promise<void> {
|
|
28
|
+
const flags = parseGlobalFlags(rawArgs)
|
|
29
|
+
|
|
30
|
+
if (flags.version) {
|
|
31
|
+
printVersion()
|
|
32
|
+
process.exit(0)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const [command, ...rest] = flags.rest
|
|
36
|
+
|
|
37
|
+
if (!command || flags.help) {
|
|
38
|
+
printHelp()
|
|
39
|
+
process.exit(0)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
switch (command) {
|
|
43
|
+
case 'init':
|
|
44
|
+
await handleInitCommand(rest, flags)
|
|
45
|
+
break
|
|
46
|
+
|
|
47
|
+
case 'config':
|
|
48
|
+
await handleConfigCommand(rest, flags)
|
|
49
|
+
break
|
|
50
|
+
|
|
51
|
+
case 'wallet':
|
|
52
|
+
await handleWalletCommand(rest, flags)
|
|
53
|
+
break
|
|
54
|
+
|
|
55
|
+
case 'ordinals':
|
|
56
|
+
await handleOrdinalsCommand(rest, flags)
|
|
57
|
+
break
|
|
58
|
+
|
|
59
|
+
case 'tokens':
|
|
60
|
+
await handleTokensCommand(rest, flags)
|
|
61
|
+
break
|
|
62
|
+
|
|
63
|
+
case 'locks':
|
|
64
|
+
await handleLocksCommand(rest, flags)
|
|
65
|
+
break
|
|
66
|
+
|
|
67
|
+
case 'identity':
|
|
68
|
+
await handleIdentityCommand(rest, flags)
|
|
69
|
+
break
|
|
70
|
+
|
|
71
|
+
case 'social':
|
|
72
|
+
await handleSocialCommand(rest, flags)
|
|
73
|
+
break
|
|
74
|
+
|
|
75
|
+
case 'opns':
|
|
76
|
+
await handleOpnsCommand(rest, flags)
|
|
77
|
+
break
|
|
78
|
+
|
|
79
|
+
case 'sweep':
|
|
80
|
+
await handleSweepCommand(rest, flags)
|
|
81
|
+
break
|
|
82
|
+
|
|
83
|
+
case 'action':
|
|
84
|
+
await handleActionCommand(rest, flags)
|
|
85
|
+
break
|
|
86
|
+
|
|
87
|
+
case 'tx':
|
|
88
|
+
await handleTxCommand(rest, flags)
|
|
89
|
+
break
|
|
90
|
+
|
|
91
|
+
case 'help':
|
|
92
|
+
printHelp()
|
|
93
|
+
break
|
|
94
|
+
|
|
95
|
+
default:
|
|
96
|
+
console.error(formatError(`Unknown command: ${command}`))
|
|
97
|
+
printHelp()
|
|
98
|
+
process.exit(1)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
main().catch((err) => {
|
|
103
|
+
console.error(formatError(`Error: ${err.message}`))
|
|
104
|
+
process.exit(1)
|
|
105
|
+
})
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic action executor.
|
|
3
|
+
*
|
|
4
|
+
* Run any registered action by name with JSON input.
|
|
5
|
+
* Useful for scripting and testing.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { actionRegistry } from '@1sat/actions'
|
|
9
|
+
import type { GlobalFlags } from '../args'
|
|
10
|
+
import { loadContext } from '../context'
|
|
11
|
+
import { loadKey, resolvePassword } from '../keys'
|
|
12
|
+
import { fatal, output } from '../output'
|
|
13
|
+
|
|
14
|
+
export async function handleActionCommand(
|
|
15
|
+
args: string[],
|
|
16
|
+
opts: GlobalFlags,
|
|
17
|
+
): Promise<void> {
|
|
18
|
+
const [actionName, jsonInput] = args
|
|
19
|
+
|
|
20
|
+
if (!actionName) {
|
|
21
|
+
// List available actions
|
|
22
|
+
const actions = actionRegistry.list()
|
|
23
|
+
if (opts.json) {
|
|
24
|
+
output(
|
|
25
|
+
actions.map((a) => ({
|
|
26
|
+
name: a.meta.name,
|
|
27
|
+
description: a.meta.description,
|
|
28
|
+
category: a.meta.category,
|
|
29
|
+
})),
|
|
30
|
+
opts,
|
|
31
|
+
)
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
console.log('\nRegistered actions:\n')
|
|
36
|
+
const grouped = new Map<string, typeof actions>()
|
|
37
|
+
for (const action of actions) {
|
|
38
|
+
const cat = action.meta.category
|
|
39
|
+
if (!grouped.has(cat)) grouped.set(cat, [])
|
|
40
|
+
grouped.get(cat)!.push(action)
|
|
41
|
+
}
|
|
42
|
+
for (const [category, categoryActions] of grouped) {
|
|
43
|
+
console.log(` ${category}:`)
|
|
44
|
+
for (const a of categoryActions) {
|
|
45
|
+
console.log(` ${a.meta.name.padEnd(30)} ${a.meta.description}`)
|
|
46
|
+
}
|
|
47
|
+
console.log()
|
|
48
|
+
}
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const action = actionRegistry.get(actionName)
|
|
53
|
+
if (!action) {
|
|
54
|
+
fatal(
|
|
55
|
+
`Unknown action: ${actionName}\n\nRun '1sat action' to list available actions.`,
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
let input: unknown = {}
|
|
60
|
+
if (jsonInput) {
|
|
61
|
+
try {
|
|
62
|
+
input = JSON.parse(jsonInput)
|
|
63
|
+
} catch {
|
|
64
|
+
fatal(`Invalid JSON input: ${jsonInput}`)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const privateKey = await loadKey(resolvePassword())
|
|
69
|
+
const { ctx, destroy } = await loadContext(privateKey, {
|
|
70
|
+
chain: opts.chain,
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
const result = await action.execute(ctx, input)
|
|
75
|
+
output(result, opts)
|
|
76
|
+
} finally {
|
|
77
|
+
await destroy()
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config command - show, set, and locate configuration.
|
|
3
|
+
*
|
|
4
|
+
* Subcommands:
|
|
5
|
+
* show - Display current configuration
|
|
6
|
+
* set - Set a configuration value
|
|
7
|
+
* path - Print config directory path
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { GlobalFlags } from '../args'
|
|
11
|
+
import {
|
|
12
|
+
type OneSatCliConfig,
|
|
13
|
+
getConfigDir,
|
|
14
|
+
getConfigFile,
|
|
15
|
+
loadConfig,
|
|
16
|
+
updateConfig,
|
|
17
|
+
} from '../config'
|
|
18
|
+
import { printCommandHelp } from '../help'
|
|
19
|
+
import {
|
|
20
|
+
fatal,
|
|
21
|
+
formatLabel,
|
|
22
|
+
formatSuccess,
|
|
23
|
+
formatValue,
|
|
24
|
+
output,
|
|
25
|
+
printKeyValue,
|
|
26
|
+
} from '../output'
|
|
27
|
+
|
|
28
|
+
const SETTABLE_KEYS: Array<keyof OneSatCliConfig> = [
|
|
29
|
+
'chain',
|
|
30
|
+
'dataDir',
|
|
31
|
+
'remoteStorageUrl',
|
|
32
|
+
'storageIdentityKey',
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
export async function handleConfigCommand(
|
|
36
|
+
args: string[],
|
|
37
|
+
opts: GlobalFlags,
|
|
38
|
+
): Promise<void> {
|
|
39
|
+
const [subcommand, ...rest] = args
|
|
40
|
+
|
|
41
|
+
switch (subcommand) {
|
|
42
|
+
case 'show':
|
|
43
|
+
return configShow(opts)
|
|
44
|
+
case 'set':
|
|
45
|
+
return configSet(rest, opts)
|
|
46
|
+
case 'path':
|
|
47
|
+
return configPath(opts)
|
|
48
|
+
default:
|
|
49
|
+
printCommandHelp('config', {
|
|
50
|
+
show: 'Display current configuration',
|
|
51
|
+
set: 'Set a config value (e.g. 1sat config set chain test)',
|
|
52
|
+
path: 'Print config directory path',
|
|
53
|
+
})
|
|
54
|
+
if (subcommand && subcommand !== 'help') {
|
|
55
|
+
process.exit(1)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function configShow(opts: GlobalFlags): void {
|
|
61
|
+
const config = loadConfig()
|
|
62
|
+
|
|
63
|
+
if (opts.json) {
|
|
64
|
+
output(config, opts)
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
console.log()
|
|
69
|
+
printKeyValue({
|
|
70
|
+
chain: config.chain,
|
|
71
|
+
dataDir: config.dataDir,
|
|
72
|
+
remoteStorageUrl: config.remoteStorageUrl ?? '(not set)',
|
|
73
|
+
storageIdentityKey: config.storageIdentityKey ?? '(not set)',
|
|
74
|
+
})
|
|
75
|
+
console.log()
|
|
76
|
+
console.log(
|
|
77
|
+
` ${formatLabel('config file:')} ${formatValue(getConfigFile())}`,
|
|
78
|
+
)
|
|
79
|
+
console.log()
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function configSet(args: string[], opts: GlobalFlags): void {
|
|
83
|
+
const [key, value] = args
|
|
84
|
+
|
|
85
|
+
if (!key || !value) {
|
|
86
|
+
fatal(
|
|
87
|
+
`Usage: 1sat config set <key> <value>\n\nSettable keys: ${SETTABLE_KEYS.join(', ')}`,
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (!SETTABLE_KEYS.includes(key as keyof OneSatCliConfig)) {
|
|
92
|
+
fatal(
|
|
93
|
+
`Unknown config key: ${key}\n\nSettable keys: ${SETTABLE_KEYS.join(', ')}`,
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Validate specific keys
|
|
98
|
+
if (key === 'chain' && value !== 'main' && value !== 'test') {
|
|
99
|
+
fatal("chain must be 'main' or 'test'")
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const updated = updateConfig({ [key]: value })
|
|
103
|
+
output(opts.json ? updated : formatSuccess(`Set ${key} = ${value}`), opts)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function configPath(opts: GlobalFlags): void {
|
|
107
|
+
const dir = getConfigDir()
|
|
108
|
+
output(opts.json ? { path: dir } : dir, opts)
|
|
109
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Identity commands - create, info, sign, verify.
|
|
3
|
+
*
|
|
4
|
+
* BAP (Bitcoin Attestation Protocol) identity management.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { publishIdentity, signBsm } from '@1sat/actions'
|
|
8
|
+
import type { GlobalFlags } from '../args'
|
|
9
|
+
import { extractFlag } from '../args'
|
|
10
|
+
import { loadContext } from '../context'
|
|
11
|
+
import { printCommandHelp } from '../help'
|
|
12
|
+
import { loadKey, resolvePassword } from '../keys'
|
|
13
|
+
import { fatal, output, printKeyValue } from '../output'
|
|
14
|
+
|
|
15
|
+
export async function handleIdentityCommand(
|
|
16
|
+
args: string[],
|
|
17
|
+
opts: GlobalFlags,
|
|
18
|
+
): Promise<void> {
|
|
19
|
+
const [subcommand, ...rest] = args
|
|
20
|
+
|
|
21
|
+
switch (subcommand) {
|
|
22
|
+
case 'create':
|
|
23
|
+
return identityCreate(rest, opts)
|
|
24
|
+
case 'info':
|
|
25
|
+
return identityInfo(rest, opts)
|
|
26
|
+
case 'sign':
|
|
27
|
+
return identitySign(rest, opts)
|
|
28
|
+
case 'verify':
|
|
29
|
+
return identityVerify(rest, opts)
|
|
30
|
+
default:
|
|
31
|
+
printCommandHelp('identity', {
|
|
32
|
+
create: 'Create/publish a BAP identity',
|
|
33
|
+
info: 'Show BAP identity information',
|
|
34
|
+
sign: 'Sign a message with identity key (--message <text>)',
|
|
35
|
+
verify:
|
|
36
|
+
'Verify a signed message (--message <text> --sig <sig> --address <addr>)',
|
|
37
|
+
})
|
|
38
|
+
if (subcommand && subcommand !== 'help') {
|
|
39
|
+
process.exit(1)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function identityCreate(
|
|
45
|
+
_args: string[],
|
|
46
|
+
opts: GlobalFlags,
|
|
47
|
+
): Promise<void> {
|
|
48
|
+
const privateKey = await loadKey(resolvePassword())
|
|
49
|
+
const { ctx, destroy } = await loadContext(privateKey, {
|
|
50
|
+
chain: opts.chain,
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
const result = await publishIdentity.execute(ctx, {})
|
|
55
|
+
|
|
56
|
+
if (result.error) {
|
|
57
|
+
fatal(result.error)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
output(result, opts)
|
|
61
|
+
} finally {
|
|
62
|
+
await destroy()
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function identityInfo(
|
|
67
|
+
_args: string[],
|
|
68
|
+
opts: GlobalFlags,
|
|
69
|
+
): Promise<void> {
|
|
70
|
+
const privateKey = await loadKey(resolvePassword())
|
|
71
|
+
const { ctx, destroy } = await loadContext(privateKey, {
|
|
72
|
+
chain: opts.chain,
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
const { publicKey } = await ctx.wallet.getPublicKey({
|
|
77
|
+
protocolID: [1, 'bap'],
|
|
78
|
+
keyID: '1',
|
|
79
|
+
counterparty: 'self',
|
|
80
|
+
forSelf: true,
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
if (opts.json) {
|
|
84
|
+
output({ identityKey: publicKey }, opts)
|
|
85
|
+
} else {
|
|
86
|
+
printKeyValue('Identity Key', publicKey)
|
|
87
|
+
}
|
|
88
|
+
} finally {
|
|
89
|
+
await destroy()
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function identitySign(args: string[], opts: GlobalFlags): Promise<void> {
|
|
94
|
+
const message = extractFlag(args, '--message')
|
|
95
|
+
|
|
96
|
+
if (!message) fatal('Missing --message <text>')
|
|
97
|
+
|
|
98
|
+
const privateKey = await loadKey(resolvePassword())
|
|
99
|
+
const { ctx, destroy } = await loadContext(privateKey, {
|
|
100
|
+
chain: opts.chain,
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
const result = await signBsm.execute(ctx, { message })
|
|
105
|
+
|
|
106
|
+
if (result.error) {
|
|
107
|
+
fatal(result.error)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
output(result, opts)
|
|
111
|
+
} finally {
|
|
112
|
+
await destroy()
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async function identityVerify(
|
|
117
|
+
args: string[],
|
|
118
|
+
_opts: GlobalFlags,
|
|
119
|
+
): Promise<void> {
|
|
120
|
+
const message = extractFlag(args, '--message')
|
|
121
|
+
const sig = extractFlag(args, '--sig')
|
|
122
|
+
const address = extractFlag(args, '--address')
|
|
123
|
+
|
|
124
|
+
if (!message) fatal('Missing --message <text>')
|
|
125
|
+
if (!sig) fatal('Missing --sig <signature>')
|
|
126
|
+
if (!address) fatal('Missing --address <addr>')
|
|
127
|
+
|
|
128
|
+
// BSM verification doesn't need a wallet context — it's pure crypto
|
|
129
|
+
// Use @bsv/sdk BSM.verify directly
|
|
130
|
+
fatal(
|
|
131
|
+
'identity verify is not yet implemented (needs direct BSM.verify integration)',
|
|
132
|
+
)
|
|
133
|
+
}
|