Use ledger subprovider
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -89,7 +89,7 @@ packages/order-watcher/src/generated_contract_wrappers/
|
||||
packages/order-utils/src/generated_contract_wrappers/
|
||||
packages/migrations/src/1.0.0/contract_wrappers
|
||||
packages/migrations/src/2.0.0/contract_wrappers
|
||||
packages/migrations/src/2.0.0-beta-kovan/contract_wrappers
|
||||
packages/migrations/src/2.0.0-beta-testnet/contract_wrappers
|
||||
|
||||
# solc-bin in sol-compiler
|
||||
packages/sol-compiler/solc_bin/
|
||||
|
@@ -17,23 +17,23 @@
|
||||
"tslint --project . --exclude **/src/v2/contract_wrappers/**/* --exclude **/src/v1/contract_wrappers/**/*",
|
||||
"migrate:v1": "run-s build compile:v1 script:migrate:v1",
|
||||
"migrate:v2": "run-s build compile:v2 script:migrate:v2",
|
||||
"migrate:v2-beta-kovan": "run-s build compile:v2-beta-kovan script:migrate:v2-beta-kovan",
|
||||
"migrate:v2-beta-testnet": "run-s build compile:v2-beta-testnet script:migrate:v2-beta-testnet",
|
||||
"script:migrate:v1": "node ./lib/migrate.js --contracts-version 1.0.0",
|
||||
"script:migrate:v2": "node ./lib/migrate.js --contracts-version 2.0.0",
|
||||
"script:migrate:v2-beta-kovan": "node ./lib/migrate.js --contracts-version 2.0.0-beta-kovan",
|
||||
"script:migrate:v2-beta-testnet": "node ./lib/migrate.js --contracts-version 2.0.0-beta-testnet",
|
||||
"generate_contract_wrappers": "run-p generate_contract_wrappers:*",
|
||||
"generate_contract_wrappers:v1":
|
||||
"abi-gen --abis ${npm_package_config_abis_v1} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/1.0.0/contract_wrappers --backend ethers",
|
||||
"generate_contract_wrappers:v2":
|
||||
"abi-gen --abis ${npm_package_config_abis_v2} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/2.0.0/contract_wrappers --backend ethers",
|
||||
"generate_contract_wrappers:v2-beta-kovan":
|
||||
"abi-gen --abis ${npm_package_config_abis_v2BetaKovan} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/2.0.0-beta-kovan/contract_wrappers --backend ethers",
|
||||
"generate_contract_wrappers:v2-beta-testnet":
|
||||
"abi-gen --abis ${npm_package_config_abis_v2BetaTestnet} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/2.0.0-beta-testnet/contract_wrappers --backend ethers",
|
||||
"compile:v1":
|
||||
"sol-compiler --artifacts-dir artifacts/1.0.0 --contracts Exchange_v1,DummyERC20Token,ZRXToken,WETH9,TokenTransferProxy_v1,MultiSigWallet,MultiSigWalletWithTimeLock,MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress,TokenRegistry",
|
||||
"compile:v2":
|
||||
"sol-compiler --artifacts-dir artifacts/2.0.0 --contracts ERC20Token,DummyERC20Token,ERC721Token,DummyERC721Token,ERC20Proxy,ERC721Proxy,Exchange,MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress,ZRXToken,WETH9,IWallet,IValidator",
|
||||
"compile:v2-beta-kovan":
|
||||
"sol-compiler --artifacts-dir artifacts/2.0.0-beta-kovan --contracts AssetProxyOwner,ERC20Proxy,ERC721Proxy,Exchange"
|
||||
"compile:v2-beta-testnet":
|
||||
"sol-compiler --artifacts-dir artifacts/2.0.0-beta-testnet --contracts AssetProxyOwner,ERC20Proxy,ERC721Proxy,Exchange"
|
||||
},
|
||||
"config": {
|
||||
"abis": {
|
||||
@@ -41,7 +41,7 @@
|
||||
"artifacts/1.0.0/@(DummyERC20Token|TokenTransferProxy_v1|Exchange_v1|TokenRegistry|MultiSigWallet|MultiSigWalletWithTimeLock|MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress|TokenRegistry|ZRXToken|WETH9).json",
|
||||
"v2":
|
||||
"artifacts/2.0.0/@(ERC20Token|DummyERC20Token|ERC721Token|DummyERC721Token|ERC20Proxy|ERC721Proxy|Exchange|AssetProxyOwner|ZRXToken|WETH9|IWallet|IValidator).json",
|
||||
"v2BetaKovan": "artifacts/2.0.0-beta-kovan/@(ERC20Proxy|ERC721Proxy|Exchange|AssetProxyOwner).json"
|
||||
"v2BetaTestnet": "artifacts/2.0.0-beta-testnet/@(ERC20Proxy|ERC721Proxy|Exchange|AssetProxyOwner).json"
|
||||
}
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
@@ -62,12 +62,18 @@
|
||||
"@0xproject/base-contract": "^0.3.4",
|
||||
"@0xproject/order-utils": "^1.0.0",
|
||||
"@0xproject/sol-compiler": "^0.5.2",
|
||||
"@0xproject/subproviders": "^0.10.4",
|
||||
"@0xproject/typescript-typings": "^0.4.1",
|
||||
"@0xproject/utils": "^0.7.1",
|
||||
"@0xproject/web3-wrapper": "^0.7.1",
|
||||
"@ledgerhq/hw-app-eth": "^4.3.0",
|
||||
"ethereum-types": "^0.0.1",
|
||||
"ethers": "3.0.22",
|
||||
"lodash": "^4.17.4"
|
||||
"lodash": "^4.17.4",
|
||||
"web3-provider-engine": "^14.0.4"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@ledgerhq/hw-transport-node-hid": "^4.3.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
2
packages/migrations/src/1.0.0/migration.ts
vendored
2
packages/migrations/src/1.0.0/migration.ts
vendored
@@ -2,7 +2,7 @@ import { BigNumber, NULL_BYTES } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import { Provider, TxData } from 'ethereum-types';
|
||||
|
||||
import { ArtifactWriter } from '../artifact_writer';
|
||||
import { ArtifactWriter } from '../utils/artifact_writer';
|
||||
import { erc20TokenInfo } from '../utils/token_info';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
|
@@ -1,13 +0,0 @@
|
||||
import { ContractArtifact } from '@0xproject/sol-compiler';
|
||||
|
||||
import * as AssetProxyOwner from '../../artifacts/2.0.0-beta-kovan/AssetProxyOwner.json';
|
||||
import * as ERC20Proxy from '../../artifacts/2.0.0-beta-kovan/ERC20Proxy.json';
|
||||
import * as ERC721Proxy from '../../artifacts/2.0.0-beta-kovan/ERC721Proxy.json';
|
||||
import * as Exchange from '../../artifacts/2.0.0-beta-kovan/Exchange.json';
|
||||
|
||||
export const artifacts = {
|
||||
AssetProxyOwner: (AssetProxyOwner as any) as ContractArtifact,
|
||||
Exchange: (Exchange as any) as ContractArtifact,
|
||||
ERC20Proxy: (ERC20Proxy as any) as ContractArtifact,
|
||||
ERC721Proxy: (ERC721Proxy as any) as ContractArtifact,
|
||||
};
|
13
packages/migrations/src/2.0.0-beta-testnet/artifacts.ts
Normal file
13
packages/migrations/src/2.0.0-beta-testnet/artifacts.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { ContractArtifact } from '@0xproject/sol-compiler';
|
||||
|
||||
import * as AssetProxyOwner from '../../artifacts/2.0.0-beta-testnet/AssetProxyOwner.json';
|
||||
import * as ERC20Proxy from '../../artifacts/2.0.0-beta-testnet/ERC20Proxy.json';
|
||||
import * as ERC721Proxy from '../../artifacts/2.0.0-beta-testnet/ERC721Proxy.json';
|
||||
import * as Exchange from '../../artifacts/2.0.0-beta-testnet/Exchange.json';
|
||||
|
||||
export const artifacts = {
|
||||
AssetProxyOwner: (AssetProxyOwner as any) as ContractArtifact,
|
||||
Exchange: (Exchange as any) as ContractArtifact,
|
||||
ERC20Proxy: (ERC20Proxy as any) as ContractArtifact,
|
||||
ERC721Proxy: (ERC721Proxy as any) as ContractArtifact,
|
||||
};
|
@@ -1,25 +1,25 @@
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import { Provider, TxData } from 'ethereum-types';
|
||||
|
||||
import { ArtifactWriter } from '../artifact_writer';
|
||||
import { ArtifactWriter } from '../utils/artifact_writer';
|
||||
|
||||
import { constants } from '../utils/constants';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
import { constants } from './constants';
|
||||
import { AssetProxyOwnerContract } from './contract_wrappers/asset_proxy_owner';
|
||||
import { ERC20ProxyContract } from './contract_wrappers/e_r_c20_proxy';
|
||||
import { ERC721ProxyContract } from './contract_wrappers/e_r_c721_proxy';
|
||||
import { ExchangeContract } from './contract_wrappers/exchange';
|
||||
|
||||
/**
|
||||
* Custom migrations should be defined in this function. This will be called with the CLI 'migrate:v2' command.
|
||||
* Custom migrations should be defined in this function. This will be called with the CLI 'migrate:v2-beta-testnet' command.
|
||||
* Migrations could be written to run in parallel, but if you want contract addresses to be created deterministically,
|
||||
* the migration should be written to run synchronously.
|
||||
* @param provider Web3 provider instance.
|
||||
* @param artifactsDir The directory with compiler artifact files.
|
||||
* @param txDefaults Default transaction values to use when deploying contracts.
|
||||
*/
|
||||
export const runV2BetaKovanMigrationsAsync = async (
|
||||
export const runV2TestnetMigrationsAsync = async (
|
||||
provider: Provider,
|
||||
artifactsDir: string,
|
||||
txDefaults: Partial<TxData>,
|
||||
@@ -43,18 +43,19 @@ export const runV2BetaKovanMigrationsAsync = async (
|
||||
artifactsWriter.saveArtifact(exchange);
|
||||
|
||||
// Register AssetProxies in Exchange
|
||||
const oldAssetProxy = constants.NULL_ADDRESS;
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await exchange.registerAssetProxy.sendTransactionAsync(
|
||||
constants.ERC20_PROXY_ID,
|
||||
erc20proxy.address,
|
||||
constants.NULL_ADDRESS,
|
||||
oldAssetProxy,
|
||||
),
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await exchange.registerAssetProxy.sendTransactionAsync(
|
||||
constants.ERC721_PROXY_ID,
|
||||
erc721proxy.address,
|
||||
constants.NULL_ADDRESS,
|
||||
oldAssetProxy,
|
||||
),
|
||||
);
|
||||
|
2
packages/migrations/src/2.0.0/migration.ts
vendored
2
packages/migrations/src/2.0.0/migration.ts
vendored
@@ -3,7 +3,7 @@ import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import { Provider, TxData } from 'ethereum-types';
|
||||
|
||||
import { ArtifactWriter } from '../artifact_writer';
|
||||
import { ArtifactWriter } from '../utils/artifact_writer';
|
||||
import { erc20TokenInfo, erc721TokenInfo } from '../utils/token_info';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
|
23
packages/migrations/src/globals.d.ts
vendored
23
packages/migrations/src/globals.d.ts
vendored
@@ -4,3 +4,26 @@ declare module '*.json' {
|
||||
export default json;
|
||||
/* tslint:enable */
|
||||
}
|
||||
|
||||
declare module '@ledgerhq/hw-app-eth' {
|
||||
class Eth {
|
||||
public transport: LedgerTransport;
|
||||
constructor(transport: LedgerTransport);
|
||||
public getAddress(
|
||||
path: string,
|
||||
boolDisplay?: boolean,
|
||||
boolChaincode?: boolean,
|
||||
): Promise<{ publicKey: string; address: string; chainCode: string }>;
|
||||
public signTransaction(path: string, rawTxHex: string): Promise<ECSignatureString>;
|
||||
public getAppConfiguration(): Promise<{ arbitraryDataEnabled: number; version: string }>;
|
||||
public signPersonalMessage(path: string, messageHex: string): Promise<ECSignature>;
|
||||
}
|
||||
export default Eth;
|
||||
}
|
||||
|
||||
declare module '@ledgerhq/hw-transport-node-hid' {
|
||||
export default class TransportNodeHid implements LedgerTransport {
|
||||
public static create(): Promise<LedgerTransport>;
|
||||
public close(): Promise<void>;
|
||||
}
|
||||
}
|
||||
|
@@ -1,3 +1,3 @@
|
||||
export { runV1MigrationsAsync } from './1.0.0/migration';
|
||||
export { runV2MigrationsAsync } from './2.0.0/migration';
|
||||
export { runV2BetaKovanMigrationsAsync } from './2.0.0-beta-kovan/migration';
|
||||
export { runV2TestnetMigrationsAsync } from './2.0.0-beta-testnet/migration';
|
||||
|
@@ -6,13 +6,15 @@ import { Provider } from 'ethereum-types';
|
||||
import * as yargs from 'yargs';
|
||||
|
||||
import { runV1MigrationsAsync } from './1.0.0/migration';
|
||||
import { runV2BetaKovanMigrationsAsync } from './2.0.0-beta-kovan/migration';
|
||||
import { runV2TestnetMigrationsAsync } from './2.0.0-beta-testnet/migration';
|
||||
import { runV2MigrationsAsync } from './2.0.0/migration';
|
||||
|
||||
import { providerFactory } from './utils/provider_factory';
|
||||
|
||||
enum ContractVersions {
|
||||
V1 = '1.0.0',
|
||||
V2 = '2.0.0',
|
||||
V2BetaKovan = '2.0.0-beta-kovan',
|
||||
V2Testnet = '2.0.0-beta-testnet',
|
||||
}
|
||||
const args = yargs.argv;
|
||||
|
||||
@@ -24,17 +26,24 @@ const args = yargs.argv;
|
||||
};
|
||||
const contractsVersion = args.contractsVersion;
|
||||
const artifactsDir = `artifacts/${contractsVersion}`;
|
||||
if (contractsVersion === ContractVersions.V1) {
|
||||
await runV1MigrationsAsync(provider, artifactsDir, txDefaults);
|
||||
} else if (contractsVersion === ContractVersions.V2) {
|
||||
await runV2MigrationsAsync(provider, artifactsDir, txDefaults);
|
||||
} else {
|
||||
const web3Wrapper = new Web3Wrapper(provider);
|
||||
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||
const kovanTxDefaults = {
|
||||
from: accounts[0],
|
||||
};
|
||||
await runV2BetaKovanMigrationsAsync(provider, artifactsDir, kovanTxDefaults);
|
||||
switch (contractsVersion) {
|
||||
case ContractVersions.V1:
|
||||
await runV1MigrationsAsync(provider, artifactsDir, txDefaults);
|
||||
break;
|
||||
case ContractVersions.V2:
|
||||
await runV2MigrationsAsync(provider, artifactsDir, txDefaults);
|
||||
break;
|
||||
case ContractVersions.V2Testnet:
|
||||
const ledgerProvider = await providerFactory.getLedgerProviderAsync();
|
||||
const web3Wrapper = new Web3Wrapper(ledgerProvider);
|
||||
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||
const testnetTxDefaults = {
|
||||
from: accounts[0],
|
||||
};
|
||||
await runV2TestnetMigrationsAsync(ledgerProvider, artifactsDir, testnetTxDefaults);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unsupported contract version: ${contractsVersion}`);
|
||||
}
|
||||
process.exit(0);
|
||||
})().catch(err => {
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import { ECSignature } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
|
||||
export interface ERC20Token {
|
||||
@@ -27,3 +28,38 @@ export enum ContractName {
|
||||
EtherDelta = 'EtherDelta',
|
||||
Arbitrage = 'Arbitrage',
|
||||
}
|
||||
|
||||
export interface LedgerCommunicationClient {
|
||||
close: () => Promise<void>;
|
||||
}
|
||||
|
||||
export interface LedgerGetAddressResult {
|
||||
address: string;
|
||||
publicKey: string;
|
||||
chainCode: string;
|
||||
}
|
||||
|
||||
export interface ECSignatureString {
|
||||
v: string;
|
||||
r: string;
|
||||
s: string;
|
||||
}
|
||||
|
||||
export interface LedgerGetAddressResult {
|
||||
address: string;
|
||||
publicKey: string;
|
||||
chainCode: string;
|
||||
}
|
||||
|
||||
export interface LedgerEthereumClient {
|
||||
// shouldGetChainCode is defined as `true` instead of `boolean` because other types rely on the assumption
|
||||
// that we get back the chain code and we don't have dependent types to express it properly
|
||||
getAddress: (
|
||||
derivationPath: string,
|
||||
askForDeviceConfirmation: boolean,
|
||||
shouldGetChainCode: true,
|
||||
) => Promise<LedgerGetAddressResult>;
|
||||
signTransaction: (derivationPath: string, rawTxHex: string) => Promise<ECSignatureString>;
|
||||
signPersonalMessage: (derivationPath: string, messageHex: string) => Promise<ECSignature>;
|
||||
transport: LedgerCommunicationClient;
|
||||
}
|
||||
|
@@ -8,7 +8,8 @@ export const constants = {
|
||||
],
|
||||
ASSET_PROXY_OWNER_TIMELOCK: new BigNumber(0),
|
||||
ASSET_PROXY_OWNER_CONFIRMATIONS: new BigNumber(1),
|
||||
ERC20_PROXY_ID: new BigNumber(0),
|
||||
ERC721_PROXY_ID: new BigNumber(1),
|
||||
ERC20_PROXY_ID: '0xf47261b0',
|
||||
ERC721_PROXY_ID: '0x08e937fa',
|
||||
NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
|
||||
RPC_URL: 'http://localhost:8545',
|
||||
};
|
37
packages/migrations/src/utils/provider_factory.ts
Normal file
37
packages/migrations/src/utils/provider_factory.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { LedgerSubprovider } from '@0xproject/subproviders';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import Eth from '@ledgerhq/hw-app-eth';
|
||||
import TransportNodeHid from '@ledgerhq/hw-transport-node-hid';
|
||||
import { Provider } from 'ethereum-types';
|
||||
import ProviderEngine = require('web3-provider-engine');
|
||||
import RpcSubprovider = require('web3-provider-engine/subproviders/rpc');
|
||||
|
||||
import { LedgerEthereumClient } from '../types';
|
||||
|
||||
import { constants } from './constants';
|
||||
|
||||
async function ledgerEthereumNodeJsClientFactoryAsync(): Promise<LedgerEthereumClient> {
|
||||
const ledgerConnection = await TransportNodeHid.create();
|
||||
const ledgerEthClient = new Eth(ledgerConnection);
|
||||
return ledgerEthClient;
|
||||
}
|
||||
export const providerFactory = {
|
||||
async getLedgerProviderAsync(): Promise<Provider> {
|
||||
const provider = new ProviderEngine();
|
||||
provider.addProvider(
|
||||
new RpcSubprovider({
|
||||
rpcUrl: constants.RPC_URL,
|
||||
}),
|
||||
);
|
||||
const web3Wrapper = new Web3Wrapper(provider);
|
||||
const networkId = await web3Wrapper.getNetworkIdAsync();
|
||||
const ledgerWalletConfigs = {
|
||||
networkId,
|
||||
ledgerEthereumClientFactoryAsync: ledgerEthereumNodeJsClientFactoryAsync,
|
||||
};
|
||||
const ledgerSubprovider = new LedgerSubprovider(ledgerWalletConfigs);
|
||||
provider.addProvider(ledgerSubprovider);
|
||||
provider.start();
|
||||
return provider;
|
||||
},
|
||||
};
|
10
yarn.lock
10
yarn.lock
@@ -330,7 +330,7 @@
|
||||
|
||||
"@types/mocha@^5.2.2":
|
||||
version "5.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.3.tgz#11f3a5629d67cd444fa6c94536576244e6a52ea9"
|
||||
resolved "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.3.tgz#11f3a5629d67cd444fa6c94536576244e6a52ea9"
|
||||
|
||||
"@types/nock@^9.1.2":
|
||||
version "9.1.3"
|
||||
@@ -2899,7 +2899,7 @@ copyfiles@^1.2.0:
|
||||
|
||||
copyfiles@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/copyfiles/-/copyfiles-2.0.0.tgz#bbd78bb78e8fd6db5c67adf54249317b24560f2a"
|
||||
resolved "https://registry.npmjs.org/copyfiles/-/copyfiles-2.0.0.tgz#bbd78bb78e8fd6db5c67adf54249317b24560f2a"
|
||||
dependencies:
|
||||
glob "^7.0.5"
|
||||
minimatch "^3.0.3"
|
||||
@@ -4073,7 +4073,7 @@ ethereum-common@^0.0.18:
|
||||
|
||||
ethereum-types@^0.0.2:
|
||||
version "0.0.2"
|
||||
resolved "https://registry.yarnpkg.com/ethereum-types/-/ethereum-types-0.0.2.tgz#6ef6faf46a24697cbf66b6c8a0ecf2095ce58c38"
|
||||
resolved "https://registry.npmjs.org/ethereum-types/-/ethereum-types-0.0.2.tgz#6ef6faf46a24697cbf66b6c8a0ecf2095ce58c38"
|
||||
dependencies:
|
||||
"@types/node" "^8.0.53"
|
||||
bignumber.js "~4.1.0"
|
||||
@@ -10215,7 +10215,7 @@ run-queue@^1.0.0, run-queue@^1.0.3:
|
||||
|
||||
run-s@^0.0.0:
|
||||
version "0.0.0"
|
||||
resolved "https://registry.yarnpkg.com/run-s/-/run-s-0.0.0.tgz#599912be20c00ba7698655c9936d075d31b71754"
|
||||
resolved "https://registry.npmjs.org/run-s/-/run-s-0.0.0.tgz#599912be20c00ba7698655c9936d075d31b71754"
|
||||
|
||||
rustbn.js@~0.1.1:
|
||||
version "0.1.2"
|
||||
@@ -13168,7 +13168,7 @@ yargs@^10.0.3:
|
||||
|
||||
yargs@^11.0.0:
|
||||
version "11.0.0"
|
||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.0.0.tgz#c052931006c5eee74610e5fc0354bedfd08a201b"
|
||||
resolved "https://registry.npmjs.org/yargs/-/yargs-11.0.0.tgz#c052931006c5eee74610e5fc0354bedfd08a201b"
|
||||
dependencies:
|
||||
cliui "^4.0.0"
|
||||
decamelize "^1.1.1"
|
||||
|
Reference in New Issue
Block a user