diff --git a/packages/cli/.gitignore b/packages/cli/.gitignore index 2f7cb8a7..68bf3735 100644 --- a/packages/cli/.gitignore +++ b/packages/cli/.gitignore @@ -1,5 +1,3 @@ build/ dist/ docs/ - -selftest_userprofile_db/ diff --git a/packages/cli/README.md b/packages/cli/README.md index 40da3cca..c40c677a 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -64,9 +64,8 @@ const sendTokensMsg: types.MsgSend = { }, }; -const signBytes = makeSignBytes([sendTokensMsg], defaultFee, defaultNetworkId, memo, account) as SignableBytes; -const rawSignature = await wallet.createTransactionSignature(signer, signBytes, PrehashType.Sha256); -const signature = encodeSecp256k1Signature(signer.pubkey.data, rawSignature); +const signBytes = makeSignBytes([sendTokensMsg], defaultFee, defaultNetworkId, memo, account); +const signature = encodeSecp256k1Signature(pen.pubkey, await pen.createSignature(signBytes)); const signedTx: types.StdTx = { msg: [sendTokensMsg], fee: defaultFee, diff --git a/packages/cli/examples/local_faucet.ts b/packages/cli/examples/local_faucet.ts index 2b6c6522..21199c9c 100644 --- a/packages/cli/examples/local_faucet.ts +++ b/packages/cli/examples/local_faucet.ts @@ -12,10 +12,7 @@ const defaultFee: types.StdFee = { const faucetMnemonic = "economy stock theory fatal elder harbor betray wasp final emotion task crumble siren bottom lizard educate guess current outdoor pair theory focus wife stone"; -const faucetPath = HdPaths.cosmos(0); const faucetAddress = "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6"; -const wallet = Secp256k1HdWallet.fromMnemonic(faucetMnemonic); -const signer = await wallet.createIdentity("unused_value" as ChainId, faucetPath); - +const pen = await Secp256k1Pen.fromMnemonic(faucetMnemonic); const client = new RestClient(defaultHttpUrl); diff --git a/packages/cli/package.json b/packages/cli/package.json index 826a6326..156d8d11 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -34,16 +34,13 @@ ], "dependencies": { "@cosmwasm/sdk": "^0.0.3", - "@iov/bcp": "^2.0.0-alpha.7", "@iov/crypto": "^2.0.0-alpha.7", "@iov/encoding": "^2.0.0-alpha.7", - "@iov/keycontrol": "^2.0.0-alpha.7", "@iov/utils": "^2.0.0-alpha.7", "argparse": "^1.0.10", "babylon": "^6.18.0", "colors": "^1.3.3", "diff": "^4", - "leveldown": "^5.0.0", "recast": "^0.18.0", "ts-node": "^8", "typescript": "~3.7" diff --git a/packages/cli/src/cli.ts b/packages/cli/src/cli.ts index 57ecd587..d39287a9 100644 --- a/packages/cli/src/cli.ts +++ b/packages/cli/src/cli.ts @@ -38,28 +38,16 @@ export function main(originalArgs: readonly string[]): void { } const imports = new Map([ - ["@cosmwasm/sdk", ["encodeSecp256k1Signature", "makeSignBytes", "marshalTx", "types", "RestClient"]], [ - "@iov/bcp", + "@cosmwasm/sdk", [ - "Address", - "Algorithm", - "ChainId", - "Nonce", - "PrehashType", - "PubkeyBytes", - "SendTransaction", - "SignableBytes", - "TokenTicker", - "TransactionId", - // block info - "BlockInfoPending", - "BlockInfoSucceeded", - "BlockInfoFailed", - "BlockInfo", - "isBlockInfoPending", - "isBlockInfoSucceeded", - "isBlockInfoFailed", + "encodeSecp256k1Signature", + "makeSignBytes", + "marshalTx", + "Pen", + "RestClient", + "Secp256k1Pen", + "types", ], ], [ @@ -90,20 +78,6 @@ export function main(originalArgs: readonly string[]): void { "Uint64", ], ], - [ - "@iov/keycontrol", - [ - "Ed25519HdWallet", - "HdPaths", - "Keyring", - "Secp256k1HdWallet", - "UserProfile", - "Wallet", - "WalletId", - "WalletImplementationIdString", - "WalletSerializationString", - ], - ], ["@iov/utils", ["sleep"]], ]); @@ -111,8 +85,6 @@ export function main(originalArgs: readonly string[]): void { console.info(colors.yellow("Available imports:")); console.info(colors.yellow(" * http")); console.info(colors.yellow(" * https")); - console.info(colors.yellow(" * leveldown")); - console.info(colors.yellow(" * levelup")); console.info(colors.yellow(" * from long")); console.info(colors.yellow(" - Long")); for (const moduleName of imports.keys()) { @@ -128,8 +100,6 @@ export function main(originalArgs: readonly string[]): void { console.info(colors.yellow(" - toHex")); let init = ` - import leveldown = require('leveldown'); - import levelup from "levelup"; import * as http from 'http'; import * as https from 'https'; import Long from "long"; @@ -151,11 +121,11 @@ export function main(originalArgs: readonly string[]): void { const hexHash = toHex(hash); export class NewDummyClass {}; - const profile = new UserProfile(); - const wallet = profile.addWallet(Ed25519HdWallet.fromMnemonic("degree tackle suggest window test behind mesh extra cover prepare oak script")); - const db = levelup(leveldown('./selftest_userprofile_db')); - await profile.storeIn(db, "secret passwd"); - const profileFromDb = await UserProfile.loadFrom(db, "secret passwd"); + const pen = await Secp256k1Pen.fromMnemonic( + "zebra slush diet army arrest purpose hawk source west glimpse custom record", + ); + const data = Encoding.toAscii("foo bar"); + const signature = await pen.createSignature(data); console.info("Done testing, will exit now."); process.exit(0); diff --git a/packages/sdk/package.json b/packages/sdk/package.json index a05d2ce8..55a04c7f 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -43,7 +43,5 @@ "axios": "^0.19.0" }, "devDependencies": { - "@iov/bcp": "^2.0.0-alpha.7", - "@iov/keycontrol": "^2.0.0-alpha.7" } } diff --git a/packages/sdk/src/index.ts b/packages/sdk/src/index.ts index 2b01f294..8ac4d6f7 100644 --- a/packages/sdk/src/index.ts +++ b/packages/sdk/src/index.ts @@ -4,4 +4,5 @@ export { CosmosBech32Prefix, decodeBech32Pubkey, encodeAddress, isValidAddress } export { unmarshalTx } from "./decoding"; export { encodeSecp256k1Signature, makeSignBytes, marshalTx } from "./encoding"; export { RestClient, TxsResponse } from "./restclient"; +export { makeCosmoshubPath, Pen, PrehashType, Secp256k1Pen } from "./pen"; export { types }; diff --git a/packages/sdk/src/pen.spec.ts b/packages/sdk/src/pen.spec.ts new file mode 100644 index 00000000..7ea39cee --- /dev/null +++ b/packages/sdk/src/pen.spec.ts @@ -0,0 +1,46 @@ +import { Secp256k1, Secp256k1Signature, Sha256 } from "@iov/crypto"; +import { Encoding } from "@iov/encoding"; + +import { Secp256k1Pen } from "./pen"; + +const { fromHex } = Encoding; + +describe("Sec256k1Pen", () => { + it("can be constructed", async () => { + const pen = await Secp256k1Pen.fromMnemonic( + "zebra slush diet army arrest purpose hawk source west glimpse custom record", + ); + expect(pen).toBeTruthy(); + }); + + describe("pubkey", () => { + it("returns compressed pubkey", async () => { + // special sign fit simple patrol salute grocery chicken wheat radar tonight ceiling + // m/44'/118'/0'/0/0 + // pubkey: 02baa4ef93f2ce84592a49b1d729c074eab640112522a7a89f7d03ebab21ded7b6 + const pen = await Secp256k1Pen.fromMnemonic( + "special sign fit simple patrol salute grocery chicken wheat radar tonight ceiling", + ); + expect(pen.pubkey).toEqual( + fromHex("02baa4ef93f2ce84592a49b1d729c074eab640112522a7a89f7d03ebab21ded7b6"), + ); + }); + }); + + describe("createSignature", () => { + it("creates correct signatures", async () => { + const pen = await Secp256k1Pen.fromMnemonic( + "special sign fit simple patrol salute grocery chicken wheat radar tonight ceiling", + ); + const data = Encoding.toAscii("foo bar"); + const signature = await pen.createSignature(data); + + const valid = await Secp256k1.verifySignature( + new Secp256k1Signature(signature.slice(0, 32), signature.slice(32, 64)), + new Sha256(data).digest(), + pen.pubkey, + ); + expect(valid).toEqual(true); + }); + }); +}); diff --git a/packages/sdk/src/pen.ts b/packages/sdk/src/pen.ts new file mode 100644 index 00000000..f50d2465 --- /dev/null +++ b/packages/sdk/src/pen.ts @@ -0,0 +1,86 @@ +import { + Bip39, + EnglishMnemonic, + Secp256k1, + Sha256, + Sha512, + Slip10, + Slip10Curve, + Slip10RawIndex, +} from "@iov/crypto"; + +export type PrehashType = "sha256" | "sha512" | null; + +/** + * A pen is the most basic tool you can think of for signing. It works + * everywhere and can be used intuitively by everyone. However, it does not + * come with a great amount of features. End of semi suitable metaphor. + * + * This wraps a single keypair and allows for signing. + * + * Non-goals of this types are: multi account support, persistency, data migrations, + * obfuscation of sensitive data. + */ +export interface Pen { + readonly pubkey: Uint8Array; + readonly createSignature: (signBytes: Uint8Array, prehashType?: PrehashType) => Promise; +} + +function prehash(bytes: Uint8Array, type: PrehashType): Uint8Array { + switch (type) { + case null: + return new Uint8Array([...bytes]); + case "sha256": + return new Sha256(bytes).digest(); + case "sha512": + return new Sha512(bytes).digest(); + default: + throw new Error("Unknown prehash type"); + } +} + +/** + * The Cosmoshub derivation path in the form `m/44'/118'/0'/0/a` + * with 0-based account index `a`. + */ +export function makeCosmoshubPath(a: number): readonly Slip10RawIndex[] { + return [ + Slip10RawIndex.hardened(44), + Slip10RawIndex.hardened(118), + Slip10RawIndex.hardened(0), + Slip10RawIndex.normal(0), + Slip10RawIndex.normal(a), + ]; +} + +export class Secp256k1Pen implements Pen { + public static async fromMnemonic( + mnemonic: string, + hdPath: readonly Slip10RawIndex[] = makeCosmoshubPath(0), + ): Promise { + const seed = await Bip39.mnemonicToSeed(new EnglishMnemonic(mnemonic)); + const { privkey } = Slip10.derivePath(Slip10Curve.Secp256k1, seed, hdPath); + const uncompressed = (await Secp256k1.makeKeypair(privkey)).pubkey; + return new Secp256k1Pen(privkey, Secp256k1.compressPubkey(uncompressed)); + } + + public readonly pubkey: Uint8Array; + private readonly privkey: Uint8Array; + + private constructor(privkey: Uint8Array, pubkey: Uint8Array) { + this.privkey = privkey; + this.pubkey = pubkey; + } + + /** + * Creates a fixed length encoding of the signature parameters r (32 bytes) and s (32 bytes). + */ + public async createSignature( + signBytes: Uint8Array, + prehashType: PrehashType = "sha256", + ): Promise { + const message = prehash(signBytes, prehashType); + const signature = await Secp256k1.createSignature(message, this.privkey); + return new Uint8Array([...signature.r(32), ...signature.s(32)]); + } +} diff --git a/packages/sdk/src/restclient.spec.ts b/packages/sdk/src/restclient.spec.ts index 405b780e..e3f9541b 100644 --- a/packages/sdk/src/restclient.spec.ts +++ b/packages/sdk/src/restclient.spec.ts @@ -1,12 +1,11 @@ /* eslint-disable @typescript-eslint/camelcase */ -import { ChainId, Identity, PrehashType, SignableBytes } from "@iov/bcp"; import { Random } from "@iov/crypto"; import { Bech32, Encoding } from "@iov/encoding"; -import { HdPaths, Secp256k1HdWallet } from "@iov/keycontrol"; import { encodeSecp256k1Signature, makeSignBytes, marshalTx } from "./encoding"; import { leb128Encode } from "./leb128.spec"; import { Attribute, Log, parseLogs } from "./logs"; +import { Pen, Secp256k1Pen } from "./pen"; import { PostTxsResponse, RestClient } from "./restclient"; import contract from "./testdata/contract.json"; import cosmoshub from "./testdata/cosmoshub.json"; @@ -28,7 +27,6 @@ const httpUrl = "http://localhost:1317"; const defaultNetworkId = "testing"; const faucetMnemonic = "economy stock theory fatal elder harbor betray wasp final emotion task crumble siren bottom lizard educate guess current outdoor pair theory focus wife stone"; -const faucetPath = HdPaths.cosmos(0); const faucetAddress = "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6"; const emptyAddress = "cosmos1ltkhnmdcqemmd2tkhnx7qx66tq7e0wykw2j85k"; @@ -96,11 +94,7 @@ function findAttribute(logs: readonly Log[], eventType: "message" | "transfer", return out; } -async function uploadContract( - client: RestClient, - wallet: Secp256k1HdWallet, - signer: Identity, -): Promise { +async function uploadContract(client: RestClient, pen: Pen): Promise { const memo = "My first contract on chain"; const theMsg: MsgStoreCode = { type: "wasm/store-code", @@ -122,17 +116,15 @@ async function uploadContract( }; const account = (await client.authAccounts(faucetAddress)).result.value; - const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account) as SignableBytes; - const rawSignature = await wallet.createTransactionSignature(signer, signBytes, PrehashType.Sha256); - const signature = encodeSecp256k1Signature(signer.pubkey.data, rawSignature); + const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account); + const signature = encodeSecp256k1Signature(pen.pubkey, await pen.createSignature(signBytes)); const signedTx = makeSignedTx(theMsg, fee, memo, signature); return client.postTx(marshalTx(signedTx)); } async function instantiateContract( client: RestClient, - wallet: Secp256k1HdWallet, - signer: Identity, + pen: Pen, codeId: number, beneficiaryAddress: string, transferAmount: readonly Coin[], @@ -161,17 +153,15 @@ async function instantiateContract( }; const account = (await client.authAccounts(faucetAddress)).result.value; - const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account) as SignableBytes; - const rawSignature = await wallet.createTransactionSignature(signer, signBytes, PrehashType.Sha256); - const signature = encodeSecp256k1Signature(signer.pubkey.data, rawSignature); + const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account); + const signature = encodeSecp256k1Signature(pen.pubkey, await pen.createSignature(signBytes)); const signedTx = makeSignedTx(theMsg, fee, memo, signature); return client.postTx(marshalTx(signedTx)); } async function executeContract( client: RestClient, - wallet: Secp256k1HdWallet, - signer: Identity, + pen: Pen, contractAddress: string, ): Promise { const memo = "Time for action"; @@ -195,9 +185,8 @@ async function executeContract( }; const account = (await client.authAccounts(faucetAddress)).result.value; - const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account) as SignableBytes; - const rawSignature = await wallet.createTransactionSignature(signer, signBytes, PrehashType.Sha256); - const signature = encodeSecp256k1Signature(signer.pubkey.data, rawSignature); + const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account); + const signature = encodeSecp256k1Signature(pen.pubkey, await pen.createSignature(signBytes)); const signedTx = makeSignedTx(theMsg, fee, memo, signature); return client.postTx(marshalTx(signedTx)); } @@ -240,8 +229,7 @@ describe("RestClient", () => { describe("post", () => { it("can send tokens", async () => { pendingWithoutCosmos(); - const wallet = Secp256k1HdWallet.fromMnemonic(faucetMnemonic); - const signer = await wallet.createIdentity("abc" as ChainId, faucetPath); + const pen = await Secp256k1Pen.fromMnemonic(faucetMnemonic); const memo = "My first contract on chain"; const theMsg: MsgSend = { @@ -271,9 +259,8 @@ describe("RestClient", () => { const client = new RestClient(httpUrl); const account = (await client.authAccounts(faucetAddress)).result.value; - const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account) as SignableBytes; - const rawSignature = await wallet.createTransactionSignature(signer, signBytes, PrehashType.Sha256); - const signature = encodeSecp256k1Signature(signer.pubkey.data, rawSignature); + const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account); + const signature = encodeSecp256k1Signature(pen.pubkey, await pen.createSignature(signBytes)); const signedTx = makeSignedTx(theMsg, fee, memo, signature); const result = await client.postTx(marshalTx(signedTx)); // console.log("Raw log:", result.raw_log); @@ -282,8 +269,7 @@ describe("RestClient", () => { it("can upload, instantiate and execute wasm", async () => { pendingWithoutCosmos(); - const wallet = Secp256k1HdWallet.fromMnemonic(faucetMnemonic); - const signer = await wallet.createIdentity("abc" as ChainId, faucetPath); + const pen = await Secp256k1Pen.fromMnemonic(faucetMnemonic); const client = new RestClient(httpUrl); const transferAmount: readonly Coin[] = [ @@ -303,7 +289,7 @@ describe("RestClient", () => { // upload { // console.log("Raw log:", result.raw_log); - const result = await uploadContract(client, wallet, signer); + const result = await uploadContract(client, pen); expect(result.code).toBeFalsy(); const logs = parseSuccess(result.raw_log); const codeIdAttr = findAttribute(logs, "message", "code_id"); @@ -316,14 +302,7 @@ describe("RestClient", () => { // instantiate { - const result = await instantiateContract( - client, - wallet, - signer, - codeId, - beneficiaryAddress, - transferAmount, - ); + const result = await instantiateContract(client, pen, codeId, beneficiaryAddress, transferAmount); expect(result.code).toBeFalsy(); // console.log("Raw log:", result.raw_log); const logs = parseSuccess(result.raw_log); @@ -338,7 +317,7 @@ describe("RestClient", () => { // execute { - const result = await executeContract(client, wallet, signer, contractAddress); + const result = await executeContract(client, pen, contractAddress); expect(result.code).toBeFalsy(); // console.log("Raw log:", result.raw_log); const [firstLog] = parseSuccess(result.raw_log); @@ -356,8 +335,7 @@ describe("RestClient", () => { describe("query", () => { it("can list upload code", async () => { pendingWithoutCosmos(); - const wallet = Secp256k1HdWallet.fromMnemonic(faucetMnemonic); - const signer = await wallet.createIdentity("abc" as ChainId, faucetPath); + const pen = await Secp256k1Pen.fromMnemonic(faucetMnemonic); const client = new RestClient(httpUrl); // check with contracts were here first to compare @@ -366,7 +344,7 @@ describe("RestClient", () => { const numExisting = existingInfos.length; // upload data - const result = await uploadContract(client, wallet, signer); + const result = await uploadContract(client, pen); expect(result.code).toBeFalsy(); const logs = parseSuccess(result.raw_log); const codeIdAttr = findAttribute(logs, "message", "code_id"); @@ -387,8 +365,7 @@ describe("RestClient", () => { it("can list contracts and get info", async () => { pendingWithoutCosmos(); - const wallet = Secp256k1HdWallet.fromMnemonic(faucetMnemonic); - const signer = await wallet.createIdentity("abc" as ChainId, faucetPath); + const pen = await Secp256k1Pen.fromMnemonic(faucetMnemonic); const client = new RestClient(httpUrl); const beneficiaryAddress = makeRandomAddress(); const transferAmount: readonly Coin[] = [ @@ -404,7 +381,7 @@ describe("RestClient", () => { if (existingInfos.length > 0) { codeId = existingInfos[existingInfos.length - 1].id; } else { - const uploaded = await uploadContract(client, wallet, signer); + const uploaded = await uploadContract(client, pen); expect(uploaded.code).toBeFalsy(); const uploadLogs = parseSuccess(uploaded.raw_log); const codeIdAttr = findAttribute(uploadLogs, "message", "code_id"); @@ -414,14 +391,7 @@ describe("RestClient", () => { // create new instance and compare before and after const existingContracts = await client.listContractAddresses(); - const result = await instantiateContract( - client, - wallet, - signer, - codeId, - beneficiaryAddress, - transferAmount, - ); + const result = await instantiateContract(client, pen, codeId, beneficiaryAddress, transferAmount); expect(result.code).toBeFalsy(); const logs = parseSuccess(result.raw_log); const contractAddressAttr = findAttribute(logs, "message", "contract_address"); diff --git a/packages/sdk/types/index.d.ts b/packages/sdk/types/index.d.ts index 18324a0a..a341b70c 100644 --- a/packages/sdk/types/index.d.ts +++ b/packages/sdk/types/index.d.ts @@ -3,4 +3,5 @@ export { CosmosBech32Prefix, decodeBech32Pubkey, encodeAddress, isValidAddress } export { unmarshalTx } from "./decoding"; export { encodeSecp256k1Signature, makeSignBytes, marshalTx } from "./encoding"; export { RestClient, TxsResponse } from "./restclient"; +export { makeCosmoshubPath, Pen, PrehashType, Secp256k1Pen } from "./pen"; export { types }; diff --git a/packages/sdk/types/pen.d.ts b/packages/sdk/types/pen.d.ts new file mode 100644 index 00000000..08a3f8d8 --- /dev/null +++ b/packages/sdk/types/pen.d.ts @@ -0,0 +1,31 @@ +import { Slip10RawIndex } from "@iov/crypto"; +export declare type PrehashType = "sha256" | "sha512" | null; +/** + * A pen is the most basic tool you can think of for signing. It works + * everywhere and can be used intuitively by everyone. However, it does not + * come with a great amount of features. End of semi suitable metaphor. + * + * This wraps a single keypair and allows for signing. + * + * Non-goals of this types are: multi account support, persistency, data migrations, + * obfuscation of sensitive data. + */ +export interface Pen { + readonly pubkey: Uint8Array; + readonly createSignature: (signBytes: Uint8Array, prehashType?: PrehashType) => Promise; +} +/** + * The Cosmoshub derivation path in the form `m/44'/118'/0'/0/a` + * with 0-based account index `a`. + */ +export declare function makeCosmoshubPath(a: number): readonly Slip10RawIndex[]; +export declare class Secp256k1Pen implements Pen { + static fromMnemonic(mnemonic: string, hdPath?: readonly Slip10RawIndex[]): Promise; + readonly pubkey: Uint8Array; + private readonly privkey; + private constructor(); + /** + * Creates a fixed length encoding of the signature parameters r (32 bytes) and s (32 bytes). + */ + createSignature(signBytes: Uint8Array, prehashType?: PrehashType): Promise; +} diff --git a/tslint.json b/tslint.json index f2c54d8c..1e301e42 100644 --- a/tslint.json +++ b/tslint.json @@ -4,6 +4,7 @@ "jsRules": {}, "rules": { "array-type": [true, "array"], + "await-promise": true, "callable-types": false, "comment-format": [true, "check-space"], "curly": false, diff --git a/yarn.lock b/yarn.lock index b93ac1be..634f4e2f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4898,15 +4898,6 @@ level-supports@~1.0.0: dependencies: xtend "^4.0.2" -leveldown@^5.0.0: - version "5.4.1" - resolved "https://registry.yarnpkg.com/leveldown/-/leveldown-5.4.1.tgz#83a8fdd9bb52b1ed69be2ef59822b6cdfcdb51ec" - integrity sha512-3lMPc7eU3yj5g+qF1qlALInzIYnkySIosR1AsUKFjL9D8fYbTLuENBAeDRZXIG4qeWOAyqRItOoLu2v2avWiMA== - dependencies: - abstract-leveldown "~6.2.1" - napi-macros "~2.0.0" - node-gyp-build "~4.1.0" - levelup@^4.0.0: version "4.3.2" resolved "https://registry.yarnpkg.com/levelup/-/levelup-4.3.2.tgz#31c5b1b29f146d1d35d692e01a6da4d28fa55ebd" @@ -5517,11 +5508,6 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" -napi-macros@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.0.0.tgz#2b6bae421e7b96eb687aa6c77a7858640670001b" - integrity sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg== - natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -5556,11 +5542,6 @@ node-fetch@^2.3.0, node-fetch@^2.5.0: resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== -node-gyp-build@~4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.1.1.tgz#d7270b5d86717068d114cc57fff352f96d745feb" - integrity sha512-dSq1xmcPDKPZ2EED2S6zw/b9NKsqzXRE6dVr8TVQnI3FJOTteUMuqF3Qqs6LZg+mLGYJWqQzMbIjMtJqTv87nQ== - node-gyp@^5.0.2: version "5.0.7" resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-5.0.7.tgz#dd4225e735e840cf2870e4037c2ed9c28a31719e"