From 2fbfefcf80b9e392d4b7cbd8eebb0444b2272653 Mon Sep 17 00:00:00 2001 From: Hui-Sang Kim <102507786+Hiksang@users.noreply.github.com> Date: Mon, 27 Apr 2026 23:59:16 +0900 Subject: [PATCH] =?UTF-8?q?feat(wallet):=20bump=20OWS=201.2.0=20=E2=86=92?= =?UTF-8?q?=201.3.2,=20add=20dual-curve=20import?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - @open-wallet-standard/core 1.3.2 (additive API; existing calls compatible) - wallet import: --evm/--solana flags for simultaneous secp256k1 + ed25519 import - preserves positional + --chain backward compat - input validation: positional/flag/mnemonic mutually exclusive Co-Authored-By: Claude Opus 4.7 (1M context) --- package.json | 2 +- pnpm-lock.yaml | 42 ++++++++++++++--------------- src/commands/wallet.ts | 61 +++++++++++++++++++++++++++++++++++++----- 3 files changed, 76 insertions(+), 29 deletions(-) diff --git a/package.json b/package.json index b85c855..3b634dc 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "dependencies": { "@modelcontextprotocol/sdk": "^1.27.1", "@msgpack/msgpack": "^3.1.3", - "@open-wallet-standard/core": "1.2.0", + "@open-wallet-standard/core": "1.3.2", "@solana/web3.js": "^1.98.0", "@types/react": "^19.2.14", "bs58": "^6.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fda4607..0e7f225 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,8 +15,8 @@ importers: specifier: ^3.1.3 version: 3.1.3 '@open-wallet-standard/core': - specifier: 1.2.0 - version: 1.2.0 + specifier: 1.3.2 + version: 1.3.2 '@solana/web3.js': specifier: ^1.98.0 version: 1.98.4(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6) @@ -315,28 +315,28 @@ packages: resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} engines: {node: ^14.21.3 || >=16} - '@open-wallet-standard/core-darwin-arm64@1.2.0': - resolution: {integrity: sha512-2TivIvNgm3+/+A7DpAHhgyH+Nefgm0JlHUaGoiazmKEVuUSNN9AhVArSMIVFXD0mN8Wz2cmequ+mFF3Mzhz6jw==} + '@open-wallet-standard/core-darwin-arm64@1.3.2': + resolution: {integrity: sha512-rvUsGU8eZtIMYFJ047nFKS79ajJeYCydvvh2B6bX0UUGf2NJZ4wUnxGqijxPiflz2xqzvbHXYZNzy3MIO4+fDQ==} cpu: [arm64] os: [darwin] - '@open-wallet-standard/core-darwin-x64@1.2.0': - resolution: {integrity: sha512-Kqx4ovI/b0Xs2QRnsY9n7TFzVIszjrNCbOLIUUgFBiNn75jhxTbbcNwMEBkaAu6hy5Y5qnaLdDUjpeqbqgSDfA==} + '@open-wallet-standard/core-darwin-x64@1.3.2': + resolution: {integrity: sha512-a6u3CvWZY8sC1S92AMGnO1WFlMW3m38+3/IoKzhxcFvD8rVY0OA0ebH6qzYLT96/TaouXDwmMQV6yQmb1IjfzQ==} cpu: [x64] os: [darwin] - '@open-wallet-standard/core-linux-arm64-gnu@1.2.0': - resolution: {integrity: sha512-JDrx3D1f7o7WJM6q/LE3xnYQJdz28KLWDHqyhdsBAmYxNaOYC/X48YD5dOhmD3PKR6DOqcgAMyoE58zIDU2kQA==} + '@open-wallet-standard/core-linux-arm64-gnu@1.3.2': + resolution: {integrity: sha512-wzyd7euZ5qvDr8dHf3eG2XP7iFgMmBUo35U7cWMLs6Yqjqz103SEjtMfNJEedZRb62f8P3Xhp9jdRLzaJvjk5g==} cpu: [arm64] os: [linux] - '@open-wallet-standard/core-linux-x64-gnu@1.2.0': - resolution: {integrity: sha512-zPOAly+rEhCvTQ4/aBBfBVqeg+NIpCKU6aI/Jtj73gFfnVsunJzRdWyjcSP8rYGMxN2cJi18jdqO7xTPLEW+fw==} + '@open-wallet-standard/core-linux-x64-gnu@1.3.2': + resolution: {integrity: sha512-pVtyEP8EqR3rjqdBDCRuB9Rd4xs8+11gRVtWidwPeFz5QPq3c9VGZjGQtTZoiZBHCxKaq5pTQjC78J5lVuA0hg==} cpu: [x64] os: [linux] - '@open-wallet-standard/core@1.2.0': - resolution: {integrity: sha512-6YBlPJK0TLYivSD4etD9NzZGc1qtTa4D3mAeQ+DE0wz0gkeQFTrysiRiSVK5jIel2V2HazHto1qizYTTcVVrWg==} + '@open-wallet-standard/core@1.3.2': + resolution: {integrity: sha512-Dk8bB9G5PjJfNzAqJd9WT9OfqrrSXRc3gA9+BCaY2qirlNrCkIAZCHaDIE0LnGOAaoSZizR6qnOFbukj+DTzJg==} hasBin: true '@rollup/rollup-android-arm-eabi@4.59.0': @@ -1887,24 +1887,24 @@ snapshots: '@noble/hashes@1.8.0': {} - '@open-wallet-standard/core-darwin-arm64@1.2.0': + '@open-wallet-standard/core-darwin-arm64@1.3.2': optional: true - '@open-wallet-standard/core-darwin-x64@1.2.0': + '@open-wallet-standard/core-darwin-x64@1.3.2': optional: true - '@open-wallet-standard/core-linux-arm64-gnu@1.2.0': + '@open-wallet-standard/core-linux-arm64-gnu@1.3.2': optional: true - '@open-wallet-standard/core-linux-x64-gnu@1.2.0': + '@open-wallet-standard/core-linux-x64-gnu@1.3.2': optional: true - '@open-wallet-standard/core@1.2.0': + '@open-wallet-standard/core@1.3.2': optionalDependencies: - '@open-wallet-standard/core-darwin-arm64': 1.2.0 - '@open-wallet-standard/core-darwin-x64': 1.2.0 - '@open-wallet-standard/core-linux-arm64-gnu': 1.2.0 - '@open-wallet-standard/core-linux-x64-gnu': 1.2.0 + '@open-wallet-standard/core-darwin-arm64': 1.3.2 + '@open-wallet-standard/core-darwin-x64': 1.3.2 + '@open-wallet-standard/core-linux-arm64-gnu': 1.3.2 + '@open-wallet-standard/core-linux-x64-gnu': 1.3.2 '@rollup/rollup-android-arm-eabi@4.59.0': optional: true diff --git a/src/commands/wallet.ts b/src/commands/wallet.ts index 0f418dc..5193c68 100644 --- a/src/commands/wallet.ts +++ b/src/commands/wallet.ts @@ -344,25 +344,72 @@ export function registerWalletCommands(program: Command, isJson: () => boolean) // ── import (OWS by default — imports key into encrypted vault) ── wallet - .command("import ") - .description("Import a private key into OWS encrypted vault") + .command("import [privateKey]") + .description("Import a private key into OWS encrypted vault (use --evm/--solana to import both curves at once)") .option("--name ", "Wallet alias name", "imported") - .option("--chain ", "Key type: evm (default) or solana", "evm") + .option("--chain ", "Key type for positional : evm (default) or solana", "evm") + .option("--evm ", "EVM (secp256k1) private key — use with --solana to import both curves") + .option("--solana ", "Solana (ed25519) private key — use with --evm to import both curves") .option("--mnemonic", "Import as mnemonic phrase instead of private key") .option("--legacy ", "Legacy mode: import to wallets.json (solana or evm)") - .action(async (privateKey: string, opts: { name: string; chain: string; mnemonic?: boolean; legacy?: string }) => { - // Legacy mode + .action(async (privateKey: string | undefined, opts: { name: string; chain: string; evm?: string; solana?: string; mnemonic?: boolean; legacy?: string }) => { + // Legacy mode (positional only) if (opts.legacy) { + if (!privateKey) { + const msg = "--legacy mode requires a positional "; + if (isJson()) { const { jsonError } = await import("../utils.js"); return printJson(jsonError("OWS_ERROR", msg)); } + console.error(chalk.red(`\n Error: ${msg}\n`)); + process.exit(1); + } return _legacyImport(opts.legacy, privateKey, opts.name, isJson); } + // Validation: input mode is exactly one of (positional | --evm/--solana flags | mnemonic) + const hasPositional = !!privateKey; + const hasFlagKeys = !!(opts.evm || opts.solana); + if (!hasPositional && !hasFlagKeys) { + const msg = "Provide a argument OR --evm/--solana flag(s)"; + if (isJson()) { const { jsonError } = await import("../utils.js"); return printJson(jsonError("OWS_ERROR", msg)); } + console.error(chalk.red(`\n Error: ${msg}\n`)); + process.exit(1); + } + if (hasPositional && hasFlagKeys) { + const msg = "Cannot mix positional with --evm/--solana flags. Use one input style."; + if (isJson()) { const { jsonError } = await import("../utils.js"); return printJson(jsonError("OWS_ERROR", msg)); } + console.error(chalk.red(`\n Error: ${msg}\n`)); + process.exit(1); + } + if (opts.mnemonic && hasFlagKeys) { + const msg = "--mnemonic cannot be combined with --evm/--solana"; + if (isJson()) { const { jsonError } = await import("../utils.js"); return printJson(jsonError("OWS_ERROR", msg)); } + console.error(chalk.red(`\n Error: ${msg}\n`)); + process.exit(1); + } + try { const ows = loadOws(); let w; if (opts.mnemonic) { - w = ows.importWalletMnemonic(opts.name, privateKey); + w = ows.importWalletMnemonic(opts.name, privateKey!); + } else if (opts.evm && opts.solana) { + // Dual-curve: both explicit keys (OWS 1.3+ API — both must be present) + w = ows.importWalletPrivateKey( + opts.name, + "", // ignored when both secp256k1Key and ed25519Key are provided + "", + undefined, + undefined, + opts.evm, + opts.solana, + ); + } else if (opts.evm) { + // Single EVM via flag — same as positional + --chain evm + w = ows.importWalletPrivateKey(opts.name, opts.evm, "", undefined, "evm"); + } else if (opts.solana) { + // Single Solana via flag — same as positional + --chain solana + w = ows.importWalletPrivateKey(opts.name, opts.solana, "", undefined, "solana"); } else { - w = ows.importWalletPrivateKey(opts.name, privateKey, "", undefined, opts.chain); + w = ows.importWalletPrivateKey(opts.name, privateKey!, "", undefined, opts.chain); } // Set as active wallet if none set