diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ec62c7..5ae30d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to the "ultra-cpp" extension will be documented in this file. +## 1.3.9 + +- Fix issue where wallet could not be destroyed properly. +- Fix issue where wallet could not be created again after being destroyed. +- Added 'Wallet - Create Key' command + ## 1.3.8 - Fix extension path issues. diff --git a/README.md b/README.md index 3305d45..c137764 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,8 @@ The wallet service allows you to store private keys inside of VSCode's global st - Keep the wallet unlocked to easily sign transactions, and view keys. - Ultra: Wallet - Lock - Lock the wallet. +- Ultra: Wallet - Create Key + - Create a key, and print it to console. ## Previews diff --git a/package-lock.json b/package-lock.json index b974faf..31d5d4e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,19 @@ { "name": "ultra-cpp", - "version": "1.3.1", + "version": "1.3.9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ultra-cpp", - "version": "1.3.1", + "version": "1.3.9", "dependencies": { "@types/node-fetch": "^2.6.4", "@ultraos/contract-builder": "^1.0.4", + "@wharfkit/antelope": "^0.7.2", "eosjs": "^22.1.0", "eosjs-ecc": "^4.0.7", + "glob": "^8.1.0", "node-fetch": "^2.6.11" }, "devDependencies": { @@ -23,13 +25,22 @@ "@typescript-eslint/parser": "^5.59.8", "@vscode/test-electron": "^2.3.2", "elliptic": "^6.5.4", - "glob": "^8.1.0", "typescript": "^5.1.3" }, "engines": { "vscode": "^1.70.0" } }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/@babel/runtime": { "version": "7.6.0", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.0.tgz", @@ -494,6 +505,28 @@ "node": ">=16" } }, + "node_modules/@wharfkit/antelope": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@wharfkit/antelope/-/antelope-0.7.2.tgz", + "integrity": "sha512-5HvP9xHxCXPiJqz2eKMWQ6BOWuzCByk8S4PvnNZ6R3ds+mHZO+9idYksCHSqy3iiJX63tsP2ctuIjl/jFUuT1Q==", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "elliptic": "^6.5.4", + "hash.js": "^1.0.0", + "tslib": "^2.0.3" + } + }, + "node_modules/@wharfkit/antelope/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/@wharfkit/antelope/node_modules/tslib": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz", + "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==" + }, "node_modules/acorn": { "version": "8.8.2", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", @@ -617,8 +650,7 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/base-x": { "version": "3.0.9", @@ -1485,14 +1517,12 @@ "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "node_modules/glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -1524,7 +1554,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -1533,7 +1562,6 @@ "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -1775,7 +1803,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -2155,7 +2182,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "dependencies": { "wrappy": "1" } @@ -2175,18 +2201,18 @@ } }, "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, "peer": true, "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "type-check": "^0.4.0" }, "engines": { "node": ">= 0.8.0" @@ -2531,9 +2557,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -2818,16 +2844,6 @@ "node": ">= 8" } }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -2847,8 +2863,7 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/yallist": { "version": "4.0.0", diff --git a/package.json b/package.json index d8ca440..da38225 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "repository": { "url": "https://github.com/Stuyk/ultra-cpp-extension" }, - "version": "1.3.8", + "version": "1.3.9", "engines": { "vscode": "^1.70.0" }, @@ -85,6 +85,11 @@ "command": "ultra.lockWallet", "title": "Wallet - Lock", "category": "Ultra" + }, + { + "command": "ultra.createKey", + "title": "Wallet - Create Key", + "category": "Ultra" } ], "snippets": [ @@ -123,9 +128,10 @@ "dependencies": { "@types/node-fetch": "^2.6.4", "@ultraos/contract-builder": "^1.0.4", + "@wharfkit/antelope": "^0.7.2", "eosjs": "^22.1.0", "eosjs-ecc": "^4.0.7", - "node-fetch": "^2.6.11", - "glob": "^8.1.0" + "glob": "^8.1.0", + "node-fetch": "^2.6.11" } -} \ No newline at end of file +} diff --git a/src/commands/addKeyToWallet.ts b/src/commands/addKeyToWallet.ts index d07614e..fed04c9 100644 --- a/src/commands/addKeyToWallet.ts +++ b/src/commands/addKeyToWallet.ts @@ -6,7 +6,8 @@ let disposable: vscode.Disposable; async function register() { disposable = vscode.commands.registerCommand(Service.command.commandNames.addKeyToWallet, async () => { - if (!Service.wallet.exists()) { + const walletExists = await Service.wallet.exists(); + if (!walletExists) { vscode.window.showErrorMessage('Wallet does not exist. Create a wallet first!'); return; } diff --git a/src/commands/apiFlows/getAbi.ts b/src/commands/apiFlows/getAbi.ts new file mode 100644 index 0000000..f3b6eaa --- /dev/null +++ b/src/commands/apiFlows/getAbi.ts @@ -0,0 +1,37 @@ +import * as vscode from 'vscode'; +import fetch from 'node-fetch'; +import * as Utility from '../../utility/index'; + +const endpoint = '/v1/chain/get_abi'; + +export async function start(api: string) { + const accountName = await Utility.quickInput.create({ title: 'Account Name', value: '', placeHolder: 'ultra' }); + + if (!accountName) { + vscode.window.showWarningMessage(`Account name was not provided. Query cancelled.`); + return; + } + + const options = { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: `{"account_name":"${accountName}","json":true}`, + }; + + const outputChannel = Utility.outputChannel.get(); + outputChannel.show(); + outputChannel.appendLine(endpoint); + + const response = await fetch(api + endpoint, options).catch((err) => { + outputChannel.appendLine(err); + return undefined; + }); + + if (!response || !response.ok) { + vscode.window.showWarningMessage(`Failed to fetch data`); + return; + } + + const data = await response.json(); + outputChannel.appendLine(JSON.stringify(data, null, 2)); +} diff --git a/src/commands/createKey.ts b/src/commands/createKey.ts new file mode 100644 index 0000000..344c6da --- /dev/null +++ b/src/commands/createKey.ts @@ -0,0 +1,74 @@ +import * as vscode from 'vscode'; +import * as Utility from '../utility/index'; +import * as Service from '../service/index'; +import * as wharfkit from '@wharfkit/antelope'; + +let disposable: vscode.Disposable; + +async function register() { + disposable = vscode.commands.registerCommand(Service.command.commandNames.createKey, async () => { + const keyType = await Utility.quickPick.create({ + title: 'Choose Key Version', + items: [ + { label: 'K1', description: 'K1' }, + { label: 'R1', description: 'R1' }, + { label: 'WA', description: 'WA' }, + ], + placeholder: 'Choose a key version. K1 is considered default.', + }); + + if (!keyType) { + return; + } + + const privateKey = wharfkit.PrivateKey.generate(keyType); + const publicKeyType = await Utility.quickPick.create({ + title: 'Choose Public Key Type', + items: [ + { label: 'Standard', description: 'standard' }, + { label: 'Legacy', description: 'legacy' }, + ], + placeholder: 'Choose a public key version. Legacy starts with "EOS"', + }); + + const ready = await Utility.quickPick.create({ + title: 'Keys will be printed to console, are you ready to view them?', + items: [ + { label: 'Yes', description: 'yes' }, + { label: 'No', description: 'no' }, + ], + placeholder: 'Read above carefully before selecting an answer.', + }); + + if (ready === 'no') { + vscode.window.showWarningMessage('Declined showing keys after generation.'); + return; + } + + const output = Utility.outputChannel.get(); + + if (keyType === 'K1') { + output.appendLine(`Private: ${privateKey.toWif()}`); + } else { + output.appendLine(`Private: ${privateKey.toString()}`); + } + + if (publicKeyType === 'standard') { + output.appendLine(`Public: ${privateKey.toPublic().toString()}`); + } else { + output.appendLine(`Public: ${privateKey.toPublic().toLegacyString()}`); + } + + output.show(); + }); + + const context = await Utility.context.get(); + context.subscriptions.push(disposable); + return () => { + if (disposable) { + disposable.dispose(); + } + }; +} + +Service.command.register('createKey', register); diff --git a/src/commands/createWallet.ts b/src/commands/createWallet.ts index f8ba475..0d51c2a 100644 --- a/src/commands/createWallet.ts +++ b/src/commands/createWallet.ts @@ -6,7 +6,8 @@ let disposable: vscode.Disposable; async function register() { disposable = vscode.commands.registerCommand(Service.command.commandNames.createWallet, async () => { - if (Service.wallet.exists()) { + const walletExists = await Service.wallet.exists(); + if (walletExists) { vscode.window.showInformationMessage('Wallet already exists!'); return; } diff --git a/src/commands/destroyWallet.ts b/src/commands/destroyWallet.ts index 3923f34..bb0195f 100644 --- a/src/commands/destroyWallet.ts +++ b/src/commands/destroyWallet.ts @@ -6,7 +6,8 @@ let disposable: vscode.Disposable; async function register() { disposable = vscode.commands.registerCommand(Service.command.commandNames.destroyWallet, async () => { - if (!Service.wallet.exists()) { + const walletExists = await Service.wallet.exists(); + if (!walletExists) { vscode.window.showInformationMessage('No wallet available.'); return; } diff --git a/src/commands/index.ts b/src/commands/index.ts index 4039ccc..26477c1 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -1,5 +1,6 @@ import './api'; import './buildContract'; +import './createKey'; import './deployContract'; import './installHeaders'; import './scaffoldContract'; diff --git a/src/commands/showWalletPublicKeys.ts b/src/commands/showWalletPublicKeys.ts index daea88c..e6eedbc 100644 --- a/src/commands/showWalletPublicKeys.ts +++ b/src/commands/showWalletPublicKeys.ts @@ -6,7 +6,8 @@ let disposable: vscode.Disposable; async function register() { disposable = vscode.commands.registerCommand(Service.command.commandNames.showWalletPublicKeys, async () => { - if (!Service.wallet.exists()) { + const walletExists = await Service.wallet.exists(); + if (!walletExists) { vscode.window.showInformationMessage('No wallet available.'); return; } diff --git a/src/commands/unlockWallet.ts b/src/commands/unlockWallet.ts index 7f8a2ad..5ec3225 100644 --- a/src/commands/unlockWallet.ts +++ b/src/commands/unlockWallet.ts @@ -6,7 +6,8 @@ let disposable: vscode.Disposable; async function register() { disposable = vscode.commands.registerCommand(Service.command.commandNames.unlockWallet, async () => { - if (!Service.wallet.exists()) { + const walletExists = await Service.wallet.exists(); + if (!walletExists) { vscode.window.showInformationMessage('No wallet available.'); return; } diff --git a/src/service/command.ts b/src/service/command.ts index 3fa502a..8ee1637 100644 --- a/src/service/command.ts +++ b/src/service/command.ts @@ -13,6 +13,7 @@ export const commandNames = { lockWallet: 'ultra.lockWallet', transact: 'ultra.transact', deployContract: 'ultra.deployContract', + createKey: 'ultra.createKey', }; const commands: { [key: string]: Function } = {}; diff --git a/src/service/wallet.ts b/src/service/wallet.ts index db52475..3194c2c 100644 --- a/src/service/wallet.ts +++ b/src/service/wallet.ts @@ -145,8 +145,9 @@ export async function listPublicKeys(password: string | undefined) { outputChannel.appendLine(']'); } -export function exists() { - return typeof Utility.state.get(walletKeyName) !== 'undefined'; +export async function exists() { + const res = await Utility.state.get(walletKeyName); + return res ? true : false; } export async function clear() { diff --git a/src/statusbars/wallet.ts b/src/statusbars/wallet.ts new file mode 100644 index 0000000..f3cf46f --- /dev/null +++ b/src/statusbars/wallet.ts @@ -0,0 +1,49 @@ +import * as vscode from 'vscode'; +import * as Service from '../service/index'; + +let disposableStatusBar: vscode.StatusBarItem; + +function register() { + disposableStatusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 0); + setAsLocked(); + disposableStatusBar.show(); +} + +export function showStatusBar() { + if (!disposableStatusBar) { + register(); + } + + disposableStatusBar.show(); +} + +export function hideStatusBar() { + if (!disposableStatusBar) { + register(); + } + + disposableStatusBar.hide(); +} + +export function setAsLocked() { + disposableStatusBar.text = '$(lock) Wallet'; + disposableStatusBar.command = Service.command.commandNames.unlockWallet; + disposableStatusBar.tooltip = 'Unlock Wallet'; + disposableStatusBar.backgroundColor = undefined; +} + +export function setAsUnlocked() { + disposableStatusBar.text = '$(unlock) Wallet'; + disposableStatusBar.command = Service.command.commandNames.lockWallet; + disposableStatusBar.tooltip = 'Lock Wallet'; + disposableStatusBar.backgroundColor = new vscode.ThemeColor('statusBarItem.errorBackground'); +} + +export function dispose() { + if (!disposableStatusBar) { + return; + } + + disposableStatusBar.dispose(); + disposableStatusBar = undefined; +}