diff --git a/containers/Contract.integration.dockerfile b/containers/Contract.integration.dockerfile index bc0836cd..b7b022ef 100644 --- a/containers/Contract.integration.dockerfile +++ b/containers/Contract.integration.dockerfile @@ -6,12 +6,12 @@ RUN apk add --no-cache --virtual .gyp \ && npm install -g truffle ganache-cli \ && apk del .gyp WORKDIR /proj -COPY ./packages/contracts/package.json /proj/package.json +COPY ./package.json /proj/package.json RUN npm install -COPY ./packages/contracts/contracts /proj/contracts -COPY ./packages/contracts/utils /proj/utils -COPY ./packages/contracts/migrations /proj/migrations -COPY ./packages/contracts/truffle-config.js /proj/truffle-config.js +COPY ./contracts /proj/contracts +COPY ./utils /proj/utils +COPY ./migrations /proj/migrations +COPY ./truffle-config.js /proj/truffle-config.js RUN truffle compile EXPOSE 5000 RUN ganache-cli --db=/data -i 20200406 -p 5000 --deterministic --host 0.0.0.0 & sleep 5 && truffle migrate --network integrationtest diff --git a/package.json b/package.json index 2b2ddb14..8d902d7a 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,7 @@ "@types/fs-extra": "^8.1.0", "@types/hdkey": "^0.7.1", "@types/jest": "^24.0.23", + "@types/node-fetch": "^2.5.7", "@types/node-schedule": "^1.3.0", "@types/pino": "^6.0.0", "@types/prompts": "^2.0.8", diff --git a/packages/cli-wallet/package.json b/packages/cli-wallet/package.json index b83a50fa..a867813d 100644 --- a/packages/cli-wallet/package.json +++ b/packages/cli-wallet/package.json @@ -11,7 +11,7 @@ "~zk-wizard": "dist" }, "bin": { - "cli-wallet": "dist/index.js" + "cli-wallet": "dist/cli.js" }, "keywords": [ "cli" @@ -28,8 +28,9 @@ "test:ci": "jest --coverage --ci --reporters='jest-junit'", "coverage": "jest --coverage", "coverage:show": "live-server coverage", - "dev": "ts-node src/index.ts --ws ws://localhost:5000 -f", - "start": "node dist/index.js" + "dev": "ts-node src/cli.ts -f --ws ws://localhost:5000 --coordinator http://localhost:8888", + "dev:config": "ts-node src/cli.ts --config wallet.json", + "start": "node dist/cli.js" }, "dependencies": { "@nano-sql/adapter-leveldb": "^2.0.5", @@ -54,6 +55,7 @@ "tar": "^6.0.2", "web3": "^1.2.6", "web3-core": "^1.2.6", + "web3-utils": "^1.2.6", "web3-eth-contract": "^1.2.6", "yargs": "^15.3.1" }, diff --git a/packages/cli-wallet/src/app/app.ts b/packages/cli-wallet/src/app/app.ts new file mode 100644 index 00000000..88717a81 --- /dev/null +++ b/packages/cli-wallet/src/app/app.ts @@ -0,0 +1,24 @@ +import { PromptApp } from '@zkopru/utils' +import { ZkAccount } from '@zkopru/account' +import { ZkWallet } from '../zk-wallet' + +export enum AppMenu { + TOP_MENU, + ACCOUNT_DETAIL, + DEPOSIT_ETHER, + EXIT, +} + +export interface Context { + menu: AppMenu + account?: ZkAccount +} + +export default abstract class App extends PromptApp { + zkWallet: ZkWallet + + constructor(zkWallet: ZkWallet, onCancel: () => Promise) { + super(zkWallet, onCancel) + this.zkWallet = zkWallet + } +} diff --git a/packages/cli-wallet/src/app/index.ts b/packages/cli-wallet/src/app/index.ts new file mode 100644 index 00000000..47447eb3 --- /dev/null +++ b/packages/cli-wallet/src/app/index.ts @@ -0,0 +1,26 @@ +import { ZkWallet } from '../zk-wallet' +import { AppMenu, Context } from './app' +import TopMenu from './menus/top-menus' + +export async function runCliApp( + zkWallet: ZkWallet, + onError?: () => Promise, +): Promise { + const defaultOnCancel = () => { + process.exit() + } + const onCancel = onError || defaultOnCancel + let context: Context = { + menu: AppMenu.TOP_MENU, + } + const menus = {} + menus[AppMenu.TOP_MENU] = new TopMenu(zkWallet, onCancel) + while (context.menu !== AppMenu.EXIT) { + const menu = menus[context.menu] + if (menu) { + context = await menu.run(context) + } else { + break + } + } +} diff --git a/packages/cli-wallet/src/menus/account-detail-build-tx.ts b/packages/cli-wallet/src/app/menus/account-detail-build-tx.ts similarity index 100% rename from packages/cli-wallet/src/menus/account-detail-build-tx.ts rename to packages/cli-wallet/src/app/menus/account-detail-build-tx.ts diff --git a/packages/cli-wallet/src/menus/account-detail-deposit.ts b/packages/cli-wallet/src/app/menus/account-detail-deposit.ts similarity index 100% rename from packages/cli-wallet/src/menus/account-detail-deposit.ts rename to packages/cli-wallet/src/app/menus/account-detail-deposit.ts diff --git a/packages/cli-wallet/src/menus/account-detail-my-txs.ts b/packages/cli-wallet/src/app/menus/account-detail-my-txs.ts similarity index 100% rename from packages/cli-wallet/src/menus/account-detail-my-txs.ts rename to packages/cli-wallet/src/app/menus/account-detail-my-txs.ts diff --git a/packages/cli-wallet/src/menus/account-detail-my-utxos.ts b/packages/cli-wallet/src/app/menus/account-detail-my-utxos.ts similarity index 100% rename from packages/cli-wallet/src/menus/account-detail-my-utxos.ts rename to packages/cli-wallet/src/app/menus/account-detail-my-utxos.ts diff --git a/packages/cli-wallet/src/menus/account-detail-withdraw.ts b/packages/cli-wallet/src/app/menus/account-detail-withdraw.ts similarity index 100% rename from packages/cli-wallet/src/menus/account-detail-withdraw.ts rename to packages/cli-wallet/src/app/menus/account-detail-withdraw.ts diff --git a/packages/cli-wallet/src/app/menus/account-detail.ts b/packages/cli-wallet/src/app/menus/account-detail.ts new file mode 100644 index 00000000..7ea3ad50 --- /dev/null +++ b/packages/cli-wallet/src/app/menus/account-detail.ts @@ -0,0 +1,31 @@ +import chalk from 'chalk' +import App, { AppMenu, Context } from '../app' + +const { goTo, print } = App + +export default class AccountDetail extends App { + static code = AppMenu.ACCOUNT_DETAIL + + // eslint-disable-next-line class-methods-use-this + async run(context: Context): Promise { + if (!context.account) throw Error('Acocunt is not set') + const spendables = await this.zkWallet.getSpendables(context.account) + print(chalk.greenBright)( + `Ether: ${spendables.eth.divn(18).toString()} Ether`, + ) + const { choice } = await this.ask({ + type: 'select', + name: 'choice', + initial: 0, + message: 'What do you want to do?', + choices: [ + { title: 'Go to top menu', value: AppMenu.TOP_MENU }, + { + title: 'Deposit Ether to the zkopru network', + value: AppMenu.DEPOSIT_ETHER, + }, + ], + }) + return { ...goTo(context, choice) } + } +} diff --git a/packages/cli-wallet/src/menus/build-tx.ts b/packages/cli-wallet/src/app/menus/build-tx.ts similarity index 100% rename from packages/cli-wallet/src/menus/build-tx.ts rename to packages/cli-wallet/src/app/menus/build-tx.ts diff --git a/packages/cli-wallet/src/menus/select-account.ts b/packages/cli-wallet/src/app/menus/top-menus.ts similarity index 58% rename from packages/cli-wallet/src/menus/select-account.ts rename to packages/cli-wallet/src/app/menus/top-menus.ts index 02e08b63..139f0186 100644 --- a/packages/cli-wallet/src/menus/select-account.ts +++ b/packages/cli-wallet/src/app/menus/top-menus.ts @@ -1,15 +1,14 @@ -import chalk from 'chalk' import { ZkAccount } from '@zkopru/account' -import App, { Context, Menu } from '../app' +import App, { AppMenu, Context } from '../app' const { goTo } = App -export default class SelectAccount extends App { +export default class TopMenu extends App { + static code = AppMenu.TOP_MENU + + // eslint-disable-next-line class-methods-use-this async run(context: Context): Promise { - if (!context.wallet) { - throw Error(chalk.red('Wallet is not loaded')) - } - const accounts: ZkAccount[] = await context.wallet.retrieveAccounts() + const accounts: ZkAccount[] = await this.zkWallet.wallet.retrieveAccounts() const { idx } = await this.ask({ type: 'select', name: 'idx', @@ -27,10 +26,11 @@ export default class SelectAccount extends App { }) switch (idx) { case -1: - return { ...goTo(context, Menu.EXIT) } + return { ...goTo(context, AppMenu.EXIT) } default: + this.zkWallet.setAccount(idx) return { - ...goTo(context, Menu.ACCOUNT_DETAIL), + ...goTo(context, AppMenu.ACCOUNT_DETAIL), account: accounts[idx], } } diff --git a/packages/cli-wallet/src/cli.ts b/packages/cli-wallet/src/cli.ts new file mode 100644 index 00000000..45e2da08 --- /dev/null +++ b/packages/cli-wallet/src/cli.ts @@ -0,0 +1,90 @@ +#!/usr/bin/env node + +/* eslint-disable no-case-declarations */ +import yargs from 'yargs' +import fs from 'fs' +import { Config } from './configurator/configurator' +import { getZkWallet } from './configurator' +import { runCliApp } from './app' + +const { argv }: { argv: Config } = yargs + .scriptName('zk-wizard') + .usage('$0 [args]') + .options({ + fullnode: { + type: 'boolean', + default: false, + alias: 'f', + describe: 'Run a full-node zkopru wallet', + }, + develop: { + type: 'boolean', + default: false, + alias: 'd', + describe: 'Run a develop version', + }, + networkId: { + type: 'number', + alias: 'n', + default: 1, + }, + chainId: { + type: 'number', + alias: 'c', + default: 1, + }, + address: { + type: 'string', + alias: 'a', + default: '0x7C728214be9A0049e6a86f2137ec61030D0AA964', + }, + coordinator: { + type: 'string', + alias: 'r', + default: 'https://coordinator.zkopru.network', + }, + websocket: { + type: 'string', + alias: 'ws', + default: 'ws://ws.zkopru.network', + }, + keys: { + type: 'string', + default: 'keys', + describe: 'Path to store SNARK keys', + }, + db: { + type: 'string', + default: 'db', + }, + mnemonic: { + type: 'string', + default: undefined, + }, + config: { + type: 'string', + describe: 'You can save cli-wallet configuration file', + }, + }) + .help() + +const main = async () => { + let config: Config = argv + if (argv.config) { + config = { + ...JSON.parse(fs.readFileSync(argv.config).toString('utf8')), + ...argv, + } + if (!config.seedKeystore) + throw Error('You should setup the keystore in the config file') + } + console.log('config is ', config) + const zkWallet = await getZkWallet(config) + console.log('get zkwallet', zkWallet) + await runCliApp(zkWallet) +} +;(async () => { + await main() +})().catch(e => { + console.error(e) +}) diff --git a/packages/cli-wallet/src/app.ts b/packages/cli-wallet/src/configurator/configurator.ts similarity index 68% rename from packages/cli-wallet/src/app.ts rename to packages/cli-wallet/src/configurator/configurator.ts index d6ecb7ac..8528bfdd 100644 --- a/packages/cli-wallet/src/app.ts +++ b/packages/cli-wallet/src/configurator/configurator.ts @@ -2,19 +2,26 @@ import Web3 from 'web3' import { InanoSQLInstance } from '@nano-sql/core/lib/interfaces' import { ZkOPRUNode, NetworkStatus } from '@zkopru/core' import { ZkAccount, HDWallet } from '@zkopru/account' -import { ZkWizard } from '@zkopru/zk-wizard' import { WebsocketProvider } from 'web3-core' import { PromptApp } from '@zkopru/utils' +import { HDWalletSql } from '@zkopru/database' +import { ZkWallet } from '../zk-wallet' export interface Config { fullnode: boolean develop: boolean address: string - bootstrap: string + coordinator: string websocket: string keys: string db: string + config?: string mnemonic?: string + erc20?: string[] + erc721?: string[] + seedKeystore?: HDWalletSql + password?: string + accountNumber?: number } export enum Menu { @@ -24,7 +31,7 @@ export enum Menu { LOAD_DATABASE, LOAD_HDWALLET, CONFIG_TRACKING_ACCOUNT, - SELECT_ACCOUNT, + SAVE_CONFIG, SHOW_UTXOS, LOAD_NODE, NODE_SYNC, @@ -43,8 +50,10 @@ export interface Context { wallet?: HDWallet account?: ZkAccount node?: ZkOPRUNode - wizard?: ZkWizard accounts?: ZkAccount[] + zkWallet?: ZkWallet + passwordHash?: string + isInitialSetup?: boolean } -export default abstract class App extends PromptApp {} +export default abstract class Configurator extends PromptApp {} diff --git a/packages/cli-wallet/src/configurator/index.ts b/packages/cli-wallet/src/configurator/index.ts new file mode 100644 index 00000000..67519481 --- /dev/null +++ b/packages/cli-wallet/src/configurator/index.ts @@ -0,0 +1,50 @@ +#!/usr/bin/env node + +/* eslint-disable no-case-declarations */ +import { NetworkStatus } from '@zkopru/core' +import { Menu, Context, Config } from './configurator' +import Splash from './menus/splash' +import ConnectWeb3 from './menus/connect-web3' +import DownloadKeys from './menus/download-keys' +import LoadDatabase from './menus/load-database' +import LoadHDWallet from './menus/load-hdwallet' +import LoadNode from './menus/load-node' +import TrackingAccount from './menus/config-tracking-accounts' +import NodeSync from './menus/node-sync' +import SaveConfig from './menus/save-config' +import { ZkWallet } from '../zk-wallet' + +const defaultOnCancel = () => { + process.exit() +} + +export async function getZkWallet( + config: Config, + onError?: () => Promise, +): Promise { + const onCancel = onError || defaultOnCancel + let context: Context = { + menu: Menu.SPLASH, + networkStatus: NetworkStatus.STOPPED, + } + const menus = {} + menus[Menu.SPLASH] = new Splash(config, onCancel) + menus[Menu.CONNECT_WEB3] = new ConnectWeb3(config, onCancel) + menus[Menu.DOWNLOAD_KEYS] = new DownloadKeys(config, onCancel) + menus[Menu.LOAD_DATABASE] = new LoadDatabase(config, onCancel) + menus[Menu.LOAD_HDWALLET] = new LoadHDWallet(config, onCancel) + menus[Menu.CONFIG_TRACKING_ACCOUNT] = new TrackingAccount(config, onCancel) + menus[Menu.LOAD_NODE] = new LoadNode(config, onCancel) + menus[Menu.NODE_SYNC] = new NodeSync(config, onCancel) + menus[Menu.SAVE_CONFIG] = new SaveConfig(config, onCancel) + while (context.menu !== Menu.EXIT) { + const menu = menus[context.menu] + if (menu) { + context = await menu.run(context) + } else { + break + } + } + if (!context.zkWallet) throw Error('Wallet is not configured') + return context.zkWallet +} diff --git a/packages/cli-wallet/src/menus/config-tracking-accounts.ts b/packages/cli-wallet/src/configurator/menus/config-tracking-accounts.ts similarity index 63% rename from packages/cli-wallet/src/menus/config-tracking-accounts.ts rename to packages/cli-wallet/src/configurator/menus/config-tracking-accounts.ts index f40fb9e4..b8b010e7 100644 --- a/packages/cli-wallet/src/menus/config-tracking-accounts.ts +++ b/packages/cli-wallet/src/configurator/menus/config-tracking-accounts.ts @@ -1,18 +1,31 @@ import chalk from 'chalk' import { ZkAccount } from '@zkopru/account' -import App, { Context, Menu } from '../app' +import Configurator, { Context, Menu } from '../configurator' -const { print, goTo } = App +const { print, goTo } = Configurator + +export default class TrackingAccount extends Configurator { + static code = Menu.CONFIG_TRACKING_ACCOUNT -export default class TrackingAccount extends App { async run(context: Context): Promise { if (!context.wallet) { throw Error(chalk.red('Wallet is not loaded')) } print(chalk.blue)('Configure accounts to keep tracking') print(chalk.blue)('My account list') + if (this.config.accountNumber) { + await Promise.all( + Array(this.config.accountNumber).map((_, index) => + context.wallet?.createAccount(index), + ), + ) + return { ...goTo(context, Menu.SAVE_CONFIG) } + } const accounts: ZkAccount[] = await context.wallet.retrieveAccounts() accounts.forEach((account, i) => print()(`${i}: ${account.address}`)) + if (!context.isInitialSetup) { + return { ...goTo(context, Menu.SAVE_CONFIG), accounts } + } const { idx } = await this.ask({ type: 'select', name: 'idx', @@ -35,7 +48,7 @@ export default class TrackingAccount extends App { reRun = await this.run(context) return reRun case 1: - return { ...goTo(context, Menu.LOAD_NODE), accounts } + return { ...goTo(context, Menu.SAVE_CONFIG), accounts } default: return { ...goTo(context, Menu.EXIT), accounts } } diff --git a/packages/cli-wallet/src/menus/connect-web3.ts b/packages/cli-wallet/src/configurator/menus/connect-web3.ts similarity index 61% rename from packages/cli-wallet/src/menus/connect-web3.ts rename to packages/cli-wallet/src/configurator/menus/connect-web3.ts index 37490d73..662cb902 100644 --- a/packages/cli-wallet/src/menus/connect-web3.ts +++ b/packages/cli-wallet/src/configurator/menus/connect-web3.ts @@ -1,15 +1,20 @@ import chalk from 'chalk' import Web3 from 'web3' -import App, { Context, Menu } from '../app' +import Configurator, { Context, Menu } from '../configurator' -const { print, goTo } = App +const { print, goTo } = Configurator + +export default class ConnectWeb3 extends Configurator { + static code = Menu.CONNECT_WEB3 -export default class ConnectWeb3 extends App { async run(context: Context): Promise { print(chalk.blue)('Connecting to the Ethereum network') - const provider = new Web3.providers.WebsocketProvider(this.config.websocket, { - reconnect: { auto: true }, - }) + const provider = new Web3.providers.WebsocketProvider( + this.config.websocket, + { + reconnect: { auto: true }, + }, + ) const web3 = new Web3(provider) async function waitConnection() { return new Promise(res => { diff --git a/packages/cli-wallet/src/menus/download-keys.ts b/packages/cli-wallet/src/configurator/menus/download-keys.ts similarity index 89% rename from packages/cli-wallet/src/menus/download-keys.ts rename to packages/cli-wallet/src/configurator/menus/download-keys.ts index 0ca2f067..c8cdeca5 100644 --- a/packages/cli-wallet/src/menus/download-keys.ts +++ b/packages/cli-wallet/src/configurator/menus/download-keys.ts @@ -4,9 +4,9 @@ import fs from 'fs-extra' import tar from 'tar' import { SingleBar } from 'cli-progress' import { https } from 'follow-redirects' -import App, { Context, Menu } from '../app' +import Configurator, { Context, Menu } from '../configurator' -const { print, goTo } = App +const { print, goTo } = Configurator export const downloadKeys = async (url: string, path: string) => { return new Promise((resolve, reject) => { @@ -41,7 +41,9 @@ export const downloadKeys = async (url: string, path: string) => { }) } -export default class DownloadKeys extends App { +export default class DownloadKeys extends Configurator { + static code = Menu.DOWNLOAD_KEYS + async run(context: Context): Promise { print(chalk.blue)('Downloading keys') const pwd = path.join(process.cwd(), this.config.keys) diff --git a/packages/cli-wallet/src/menus/load-database.ts b/packages/cli-wallet/src/configurator/menus/load-database.ts similarity index 91% rename from packages/cli-wallet/src/menus/load-database.ts rename to packages/cli-wallet/src/configurator/menus/load-database.ts index c06d69ca..7a2b8271 100644 --- a/packages/cli-wallet/src/menus/load-database.ts +++ b/packages/cli-wallet/src/configurator/menus/load-database.ts @@ -6,9 +6,9 @@ import { InanoSQLInstance, nSQL } from '@nano-sql/core' import { schema, ChainConfig } from '@zkopru/database' import { InanoSQLAdapter } from '@nano-sql/core/lib/interfaces' import { L1Contract } from '@zkopru/core' -import App, { Context, Menu } from '../app' +import Configurator, { Context, Menu } from '../configurator' -const { print, goTo } = App +const { print, goTo } = Configurator async function initDB({ name, @@ -69,9 +69,7 @@ async function initDB({ }) .exec()) as ChainConfig[] zkopruId = createResult[0].id - console.log('create result', createResult[0]) } else { - console.log('query result', queryResult[0]) zkopruId = queryResult[0].id } return { @@ -80,7 +78,9 @@ async function initDB({ } } -export default class LoadDatabase extends App { +export default class LoadDatabase extends Configurator { + static code = Menu.LOAD_DATABASE + async run(context: Context): Promise { print(chalk.blue)('Loading database') if (!context.web3) { diff --git a/packages/cli-wallet/src/menus/load-hdwallet.ts b/packages/cli-wallet/src/configurator/menus/load-hdwallet.ts similarity index 74% rename from packages/cli-wallet/src/menus/load-hdwallet.ts rename to packages/cli-wallet/src/configurator/menus/load-hdwallet.ts index 4c932b6a..8def57d5 100644 --- a/packages/cli-wallet/src/menus/load-hdwallet.ts +++ b/packages/cli-wallet/src/configurator/menus/load-hdwallet.ts @@ -2,11 +2,13 @@ import chalk from 'chalk' import { HDWallet, ZkAccount } from '@zkopru/account' import { validateMnemonic, wordlists } from 'bip39' import { HDWalletSql } from '@zkopru/database' -import App, { Context, Menu } from '../app' +import Configurator, { Context, Menu } from '../configurator' -const { print, goTo } = App +const { print, goTo } = Configurator + +export default class LoadHDWallet extends Configurator { + static code = Menu.LOAD_HDWALLET -export default class LoadHDWallet extends App { async run(context: Context): Promise { if (!context.db) { throw Error('Database is not loaded') @@ -16,8 +18,13 @@ export default class LoadHDWallet extends App { } const { web3, db } = context const wallet = new HDWallet(web3, db) - const existingWallets = await wallet.list() - if (existingWallets.length === 0) { + let existingWallets!: HDWalletSql[] + if (!this.config.seedKeystore) { + existingWallets = await wallet.list() + } + const createNewWallet: boolean = + !this.config.seedKeystore && existingWallets.length === 0 + if (createNewWallet) { let mnemonic: string if (this.config.mnemonic) { print()('Using imported mnemonic words') @@ -97,16 +104,29 @@ export default class LoadHDWallet extends App { return result } } - const { password } = await this.ask({ - type: 'password', - name: 'password', - message: 'Type password', - }) - await wallet.init(mnemonic, password) + let confirmed = false + let confirmedPassword!: string + do { + const { password } = await this.ask({ + type: 'password', + name: 'password', + message: 'password', + }) + const { retyped } = await this.ask({ + type: 'password', + name: 'retyped', + message: 'confirm password', + }) + confirmed = password === retyped + confirmedPassword = password + } while (!confirmed) + await wallet.init(mnemonic, confirmedPassword) } } else { let existing!: HDWalletSql - if (existingWallets.length === 1) { + if (this.config.seedKeystore) { + existing = this.config.seedKeystore + } else if (existingWallets.length === 1) { existing = existingWallets[0] as HDWalletSql } else if (existingWallets.length > 1) { const { idx } = await this.ask({ @@ -127,11 +147,13 @@ export default class LoadHDWallet extends App { } existing = existingWallets[idx] } - const { password } = await this.ask({ - type: 'password', - name: 'password', - message: 'Type password', - }) + const { password } = this.config.password + ? this.config + : await this.ask({ + type: 'password', + name: 'password', + message: 'Type password', + }) try { await wallet.load(existing, password) } catch (err) { @@ -146,6 +168,10 @@ export default class LoadHDWallet extends App { const account = await wallet.createAccount(0) accounts = [account] } - return { ...goTo(context, Menu.CONFIG_TRACKING_ACCOUNT), wallet } + return { + ...goTo(context, Menu.CONFIG_TRACKING_ACCOUNT), + wallet, + isInitialSetup: createNewWallet, + } } } diff --git a/packages/cli-wallet/src/menus/load-node.ts b/packages/cli-wallet/src/configurator/menus/load-node.ts similarity index 84% rename from packages/cli-wallet/src/menus/load-node.ts rename to packages/cli-wallet/src/configurator/menus/load-node.ts index 5329bdb4..6e1103ed 100644 --- a/packages/cli-wallet/src/menus/load-node.ts +++ b/packages/cli-wallet/src/configurator/menus/load-node.ts @@ -5,11 +5,13 @@ import { LightNode, HttpBootstrapHelper, } from '@zkopru/core' -import App, { Context, Menu } from '../app' +import Configurator, { Context, Menu } from '../configurator' -const { print, goTo } = App +const { print, goTo } = Configurator + +export default class LoadNode extends Configurator { + static code = Menu.LOAD_NODE -export default class LoadNode extends App { // eslint-disable-next-line class-methods-use-this async run(context: Context): Promise { if (!context.provider) throw Error('Websocket provider does not exist') @@ -19,7 +21,7 @@ export default class LoadNode extends App { throw Error('Websocket provider is not connected') let node: ZkOPRUNode const { provider, db, accounts } = context - const { address, bootstrap } = this.config + const { address, coordinator: bootstrap } = this.config if (this.config.fullnode) { node = await FullNode.new({ provider, @@ -47,7 +49,6 @@ export default class LoadNode extends App { print(chalk.blue)(`Bootstrap light node from ${bootstrap}`) await node.bootstrap() } - node.startSync() return { ...goTo(context, Menu.NODE_SYNC), node } } } diff --git a/packages/cli-wallet/src/menus/node-sync.ts b/packages/cli-wallet/src/configurator/menus/node-sync.ts similarity index 76% rename from packages/cli-wallet/src/menus/node-sync.ts rename to packages/cli-wallet/src/configurator/menus/node-sync.ts index 2e261299..f3343921 100644 --- a/packages/cli-wallet/src/menus/node-sync.ts +++ b/packages/cli-wallet/src/configurator/menus/node-sync.ts @@ -1,14 +1,17 @@ import chalk from 'chalk' import { NetworkStatus } from '@zkopru/core' -import App, { Context, Menu } from '../app' +import Configurator, { Context, Menu } from '../configurator' -const { print, goTo } = App +const { print, goTo } = Configurator + +export default class NodeSync extends Configurator { + static code = Menu.NODE_SYNC -export default class NodeSync extends App { // eslint-disable-next-line class-methods-use-this async run(context: Context): Promise { const { node } = context if (!node) throw Error('ZKOPRU node is not defined') + print(chalk.blue)('Synchronizing... ') return new Promise((res, rej) => { node.synchronizer.on('status', (status: NetworkStatus) => { switch (status) { @@ -17,10 +20,10 @@ export default class NodeSync extends App { break case NetworkStatus.LIVE: print(chalk.green)('ZKOPRU network is on live') - res(goTo(context, Menu.SELECT_ACCOUNT)) + res(goTo(context, Menu.SAVE_CONFIG)) break case NetworkStatus.ON_SYNCING: - print(chalk.green)('Synchronizing ZKOPRU network') + print(chalk.blue)('Synchronizing ZKOPRU network') break case NetworkStatus.FULLY_SYNCED: print(chalk.green)('Synchronizing is fully synced') @@ -35,6 +38,7 @@ export default class NodeSync extends App { break } }) + node.startSync() }) } } diff --git a/packages/cli-wallet/src/configurator/menus/save-config.ts b/packages/cli-wallet/src/configurator/menus/save-config.ts new file mode 100644 index 00000000..0c851121 --- /dev/null +++ b/packages/cli-wallet/src/configurator/menus/save-config.ts @@ -0,0 +1,71 @@ +import chalk from 'chalk' +import path from 'path' +import fs from 'fs' +import { HDWalletSql } from '@zkopru/database' +import Configurator, { Context, Menu } from '../configurator' + +const { print, goTo } = Configurator + +export default class SaveConfig extends Configurator { + static code = Menu.SAVE_CONFIG + + async run(context: Context): Promise { + if (!context.isInitialSetup) return { ...goTo(context, Menu.LOAD_NODE) } + + const { save } = await this.ask({ + type: 'confirm', + initial: true, + name: 'save', + message: 'Do you want to save this configuration?', + }) + if (!save) { + return { ...goTo(context, Menu.LOAD_NODE) } + } + let exported = false + let seedKeystore!: HDWalletSql + if (!context.wallet) throw Error('Wallet is not configured') + do { + const { password } = await this.ask({ + type: 'password', + name: 'password', + message: 'Type your password', + }) + try { + seedKeystore = context.wallet.export(password) + exported = true + } catch (err) { + exported = false + } + } while (!exported) + let pathConfirmed = false + let configPath!: string + do { + const { filePath } = await this.ask({ + type: 'text', + name: 'filePath', + initial: `${path.resolve(path.join('wallet.json'))}`, + message: 'Save to', + }) + configPath = filePath + if (!fs.existsSync(filePath)) pathConfirmed = true + else { + const { overwrite } = await this.ask({ + type: 'confirm', + initial: false, + name: 'overwrite', + message: + 'You may overwrite exising config file. Do you want to overwrite?', + }) + pathConfirmed = overwrite + } + } while (!pathConfirmed) + const newConfig = { + ...this.config, + seedKeystore, + accountNumber: context.accounts?.length, + } + fs.writeFileSync(configPath, JSON.stringify(newConfig)) + print(chalk.blue)('Successfully created wallet.json') + return { ...goTo(context, Menu.LOAD_NODE) } + } +} diff --git a/packages/cli-wallet/src/configurator/menus/splash.ts b/packages/cli-wallet/src/configurator/menus/splash.ts new file mode 100644 index 00000000..74fb62fc --- /dev/null +++ b/packages/cli-wallet/src/configurator/menus/splash.ts @@ -0,0 +1,18 @@ +import chalk from 'chalk' +import figlet from 'figlet' +import Configurator, { Context, Menu } from '../configurator' + +const { print, goTo } = Configurator + +export default class Splash extends Configurator { + static code = Menu.SPLASH + + // eslint-disable-next-line class-methods-use-this + async run(context: Context): Promise { + print(chalk.cyan)(figlet.textSync('ZK', 'Isometric3')) + print(chalk.cyan)(figlet.textSync('OPRU', 'Isometric3')) + print(chalk.cyan)('\n =========================') + print(chalk.cyan)(figlet.textSync('wallet', 'Small')) + return goTo(context, Menu.CONNECT_WEB3) + } +} diff --git a/packages/cli-wallet/src/index.ts b/packages/cli-wallet/src/index.ts deleted file mode 100644 index 6d398cf3..00000000 --- a/packages/cli-wallet/src/index.ts +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/env node - -/* eslint-disable no-case-declarations */ -import yargs from 'yargs' -import { NetworkStatus } from '@zkopru/core' -import { Menu, Context, Config } from './app' -import Splash from './menus/splash' -import ConnectWeb3 from './menus/connect-web3' -import DownloadKeys from './menus/download-keys' -import LoadDatabase from './menus/load-database' -import LoadHDWallet from './menus/load-hdwallet' -import LoadNode from './menus/load-node' -import SelectAccount from './menus/select-account' -import TrackingAccount from './menus/config-tracking-accounts' -import NodeSync from './menus/node-sync' - -const { argv }: { argv: Config } = yargs - .scriptName('zk-wizard') - .usage('$0 [args]') - .options({ - fullnode: { - type: 'boolean', - default: false, - alias: 'f', - describe: 'Run a full-node zkopru wallet', - }, - develop: { - type: 'boolean', - default: false, - alias: 'd', - describe: 'Run a develop version', - }, - networkId: { - type: 'number', - alias: 'n', - default: 1, - }, - chainId: { - type: 'number', - alias: 'c', - default: 1, - }, - address: { - type: 'string', - alias: 'a', - default: '0x7C728214be9A0049e6a86f2137ec61030D0AA964', - }, - bootstrap: { - type: 'string', - alias: 'b', - default: 'https://bootstrap.zkopru.network', - }, - websocket: { - type: 'string', - alias: 'ws', - default: 'ws://ws.zkopru.network', - }, - keys: { - type: 'string', - default: 'keys', - describe: 'Path to store SNARK keys', - }, - db: { - type: 'string', - default: 'db', - }, - mnemonic: { - type: 'string', - default: undefined, - }, - }) - .help() - -const onCancel = () => { - process.exit() -} - -const main = async () => { - let app: Context = { menu: Menu.SPLASH, networkStatus: NetworkStatus.STOPPED } - const menus = {} - menus[Menu.SPLASH] = new Splash(argv, onCancel) - menus[Menu.CONNECT_WEB3] = new ConnectWeb3(argv, onCancel) - menus[Menu.DOWNLOAD_KEYS] = new DownloadKeys(argv, onCancel) - menus[Menu.LOAD_DATABASE] = new LoadDatabase(argv, onCancel) - menus[Menu.LOAD_HDWALLET] = new LoadHDWallet(argv, onCancel) - menus[Menu.CONFIG_TRACKING_ACCOUNT] = new TrackingAccount(argv, onCancel) - menus[Menu.LOAD_NODE] = new LoadNode(argv, onCancel) - menus[Menu.NODE_SYNC] = new NodeSync(argv, onCancel) - menus[Menu.SELECT_ACCOUNT] = new SelectAccount(argv, onCancel) - while (app.menu !== Menu.EXIT) { - const menu = menus[app.menu] - if (menu) { - app = await menu.run(app) - } else { - break - } - } - onCancel() -} -;(async () => { - await main() -})().catch(e => { - console.error(e) -}) diff --git a/packages/cli-wallet/src/menus/account-detail.ts b/packages/cli-wallet/src/menus/account-detail.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/cli-wallet/src/menus/splash.ts b/packages/cli-wallet/src/menus/splash.ts deleted file mode 100644 index d4545572..00000000 --- a/packages/cli-wallet/src/menus/splash.ts +++ /dev/null @@ -1,13 +0,0 @@ -import chalk from 'chalk' -import figlet from 'figlet' -import App, { Context, Menu } from '../app' - -const { print, goTo } = App - -export default class Splash extends App { - // eslint-disable-next-line class-methods-use-this - async run(context: Context): Promise { - print(chalk.cyan)(figlet.textSync('ZKOPRU', 'Isometric3')) - return goTo(context, Menu.CONNECT_WEB3) - } -} diff --git a/packages/cli-wallet/src/menus/top-menus.ts b/packages/cli-wallet/src/menus/top-menus.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/cli-wallet/src/zk-wallet.ts b/packages/cli-wallet/src/zk-wallet.ts new file mode 100644 index 00000000..3e68be59 --- /dev/null +++ b/packages/cli-wallet/src/zk-wallet.ts @@ -0,0 +1,288 @@ +import { Utxo, Note, UtxoStatus, Sum } from '@zkopru/transaction' +import { Field, F, Point } from '@zkopru/babyjubjub' +import { schema, UtxoSql } from '@zkopru/database' +import { InanoSQLInstance } from '@nano-sql/core' +import { HDWallet, ZkAccount } from '@zkopru/account' +import { ZkOPRUNode, L1Contract } from '@zkopru/core' +import { logger } from '@zkopru/utils' + +export interface Balance { + eth: string + + erc20: { [addr: string]: string } + + erc721: { [addr: string]: string } +} + +export class ZkWallet { + zkopruId: string + + db: InanoSQLInstance + + wallet: HDWallet + + account: ZkAccount + + node: ZkOPRUNode + + accounts: ZkAccount[] + + erc20: string[] + + erc721: string[] + + cached: { + layer1: { + balance?: Balance + nfts?: string[] + } + } + + constructor({ + zkopruId, + db, + wallet, + account, + node, + accounts, + erc20, + erc721, + }: { + zkopruId: string + db: InanoSQLInstance + wallet: HDWallet + account: ZkAccount + node: ZkOPRUNode + accounts: ZkAccount[] + erc20: string[] + erc721: string[] + }) { + this.zkopruId = zkopruId + this.db = db + this.wallet = wallet + this.node = node + this.accounts = accounts + this.account = account + this.erc20 = erc20 + this.erc721 = erc721 + this.cached = { + layer1: {}, + } + } + + setAccount(account: number | ZkAccount) { + if (typeof account === 'number') { + this.account = this.accounts[account] + } else { + this.account = account + } + } + + async getSpendableUtxos(account: ZkAccount): Promise { + const utxoSqls: UtxoSql[] = (await this.db + .selectTable(schema.utxo.name) + .presetQuery('getSpendables', { + zkopru: this.zkopruId, + pubKeys: [account.pubKey.toHex()], + }) + .exec()) as UtxoSql[] + const utxos: Utxo[] = [] + utxoSqls.forEach(obj => { + if (!obj.eth) throw Error('should have Ether data') + if (!obj.pubKey) throw Error('should have pubkey data') + if (!(account.pubKey.toHex() === obj.pubKey)) + throw Error('should have same pubkey') + if (!obj.salt) throw Error('should have salt data') + if (!(obj.status === UtxoStatus.NON_INCLUDED || obj.status === undefined)) + throw Error('should have undefined status or NON_INCLUDED status') + + let note!: Note + if (!obj.tokenAddr) { + note = Note.newEtherNote({ + eth: obj.eth, + pubKey: account.pubKey, + salt: obj.salt, + }) + } else if (obj.erc20Amount) { + note = Note.newERC20Note({ + eth: obj.eth, + pubKey: account.pubKey, + salt: obj.salt, + tokenAddr: obj.tokenAddr, + erc20Amount: obj.erc20Amount, + }) + } else if (obj.nft) { + note = Note.newNFTNote({ + eth: obj.eth, + pubKey: account.pubKey, + salt: obj.salt, + tokenAddr: obj.tokenAddr, + nft: obj.nft, + }) + } else { + throw Error('Not enough data to recover utxo') + } + utxos.push(Utxo.from(note)) + }) + return utxos + } + + async getSpendables(account: ZkAccount): Promise { + const utxos: Utxo[] = await this.getSpendableUtxos(account) + const assets = Sum.from(utxos) + return assets + } + + async getLayer1Assets( + account: ZkAccount, + erc20Addrs?: string[], + erc721Addrs?: string[], + ): Promise { + const balance: Balance = { + eth: '0', + erc20: {}, + erc721: {}, + } + const promises: (() => Promise)[] = [] + const { web3 } = this.node.l1Contract + promises.push(async () => { + balance.eth = await web3.eth.getBalance(account.address) + }) + if (erc20Addrs) { + promises.push( + ...erc20Addrs.map(addr => async () => { + balance.erc20[addr] = await L1Contract.asIERC20(web3, addr) + .methods.balanceOf(account.address) + .call() + }), + ) + } + if (erc721Addrs) { + promises.push( + ...erc721Addrs.map(addr => async () => { + balance.erc721[addr] = await L1Contract.asIERC721(web3, addr) + .methods.balanceOf(account.address) + .call() + }), + ) + } + await Promise.all(promises.map(task => task())) + this.cached.layer1.balance = balance + return balance + } + + async listLayer1Nfts( + account: ZkAccount, + erc721Addr: string, + balance: number, + ): Promise { + const promises: (() => Promise)[] = [] + const nfts: string[] = [] + const { web3 } = this.node.l1Contract + // 0x4f6ccce7 = tokenOfOwnerByIndex func sig + const supportEnumeration = await L1Contract.asIERC721(web3, erc721Addr) + .methods.supportsInterface('0x4f6ccce7') + .call() + if (supportEnumeration) { + promises.push( + ...Array(balance) + .fill(0) + .map((_, i) => async () => { + nfts[i] = await L1Contract.asIERC721Enumerable(web3, erc721Addr) + .methods.tokenOfOwnerByIndex(account.address, i) + .call() + }), + ) + await Promise.all(promises.map(task => task())) + return nfts + } + logger.error('It does not support tokenOfOwnerByIndex() interface') + return [] + } + + async depositEther(eth: F, fee: F, to?: Point) { + if (!this.cached.layer1.balance) { + logger.error('fetch balance first') + return + } + if ( + Field.strictFrom(this.cached.layer1.balance.eth).lt( + Field.strictFrom(eth).add(Field.strictFrom(fee)), + ) + ) { + logger.error('Not enough Ether') + return + } + const note = Note.newEtherNote({ + eth, + pubKey: to || this.account.pubKey, + }) + await this.deposit(note, Field.strictFrom(fee)) + } + + async depositERC20(eth: F, addr: string, amount: F, fee: F, to?: Point) { + if (!this.cached.layer1.balance) { + logger.error('fetch balance first') + return + } + if ( + Field.strictFrom(this.cached.layer1.balance.eth).lt( + Field.strictFrom(eth).add(Field.strictFrom(fee)), + ) + ) { + logger.error('Not enough Ether') + return + } + if ( + Field.strictFrom(this.cached.layer1.balance.erc20[addr]).lt( + Field.strictFrom(amount), + ) + ) { + logger.error('Not enough ERC20 balance') + return + } + const note = Note.newERC20Note({ + eth, + pubKey: to || this.account.pubKey, + tokenAddr: addr, + erc20Amount: amount, + }) + await this.deposit(note, Field.strictFrom(fee)) + } + + async depositERC721(eth: F, addr: string, nft: F, fee: F, to?: Point) { + if (!this.cached.layer1.balance) { + logger.error('fetch balance first') + return + } + if ( + Field.strictFrom(this.cached.layer1.balance.eth).lt( + Field.strictFrom(eth).add(Field.strictFrom(fee)), + ) + ) { + logger.error('Not enough Ether') + return + } + const note = Note.newNFTNote({ + eth, + pubKey: to || this.account.pubKey, + tokenAddr: addr, + nft, + }) + await this.deposit(note, Field.strictFrom(fee)) + } + + private async deposit(note: Note, fee: Field) { + await this.node.l1Contract.user.methods + .deposit( + note.eth.toString(), + note.salt.toString(), + note.tokenAddr.toHex(20), + note.erc20Amount.toString(), + note.nft.toString(), + [note.pubKey.x.toString(), note.pubKey.y.toString()], + fee.toString(), + ) + .send({ from: this.account.address }) + } +} diff --git a/packages/cli-wallet/wallet.json b/packages/cli-wallet/wallet.json new file mode 100644 index 00000000..8605a987 --- /dev/null +++ b/packages/cli-wallet/wallet.json @@ -0,0 +1 @@ +{"_":[],"fullnode":true,"f":true,"develop":false,"d":false,"ws":"ws://localhost:5000","websocket":"ws://localhost:5000","coordinator":"http://localhost:8888","r":"http://localhost:8888","networkId":1,"n":1,"network-id":1,"chainId":1,"c":1,"chain-id":1,"address":"0x7C728214be9A0049e6a86f2137ec61030D0AA964","a":"0x7C728214be9A0049e6a86f2137ec61030D0AA964","keys":"keys","db":"db","$0":"zk-wizard","seedKeystore":{"ciphertext":"f34047785c14c5b1b87ce540c1bbd0bdb748f7ddf95fdf95d2d1e462de1dde98cf7815e280084111567fc3aac24225aa","iv":"188e2d6b2c7f7a6fecc9d850aa3a8914","algorithm":"aes-256-cbc","keylen":32,"kdf":"scrypt","kdfParams":{"N":16384,"r":8,"p":1},"salt":"9950f726377129f30ad64e5f56e5a4077765ecf433e677481f9ce141c474e011"},"accountNumber":3} \ No newline at end of file diff --git a/packages/database/src/chain-schema.ts b/packages/database/src/chain-schema.ts index 64b5c35e..5627bded 100644 --- a/packages/database/src/chain-schema.ts +++ b/packages/database/src/chain-schema.ts @@ -6,6 +6,7 @@ export enum NodeType { } export interface L1Config { + genesisBlock: string utxoTreeDepth: number withdrawalTreeDepth: number nullifierTreeDepth: number diff --git a/yarn.lock b/yarn.lock index 700f23ab..50a54195 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1751,6 +1751,14 @@ dependencies: "@types/node" "*" +"@types/node-fetch@^2.5.7": + version "2.5.7" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.7.tgz#20a2afffa882ab04d44ca786449a276f9f6bbf3c" + integrity sha512-o2WVNf5UhWRkxlf6eq+jMZDu7kjgpgJfl4xVNlvryc95O/6F2ld8ztKX+qu+Rjyet93WAWm5LjeX9H5FGkODvw== + dependencies: + "@types/node" "*" + form-data "^3.0.0" + "@types/node-schedule@^1.3.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@types/node-schedule/-/node-schedule-1.3.0.tgz#100f69078e74d736d59433fc4634ff49d0a9142d" @@ -1977,12 +1985,12 @@ mz "^2.5.0" "@zkopru/account@file:packages/account": - version "0.0.1" + version "0.0.3" dependencies: "@nano-sql/core" "^2.3.7" - "@zkopru/babyjubjub" "file:../../../.cache/yarn/v6/npm-@zkopru-account-0.0.1-e1de4d80-c9ad-4fa4-be7e-27258c76ffbc-1589800833134/node_modules/@zkopru/babyjubjub" - "@zkopru/database" "file:../../../.cache/yarn/v6/npm-@zkopru-account-0.0.1-e1de4d80-c9ad-4fa4-be7e-27258c76ffbc-1589800833134/node_modules/@zkopru/database" - "@zkopru/utils" "file:../../../.cache/yarn/v6/npm-@zkopru-account-0.0.1-e1de4d80-c9ad-4fa4-be7e-27258c76ffbc-1589800833134/node_modules/@zkopru/utils" + "@zkopru/babyjubjub" "file:../../../.cache/yarn/v6/npm-@zkopru-account-0.0.3-132ecf22-5630-4f2c-b161-56f1312ba6d5-1590065442516/node_modules/@zkopru/babyjubjub" + "@zkopru/database" "file:../../../.cache/yarn/v6/npm-@zkopru-account-0.0.3-132ecf22-5630-4f2c-b161-56f1312ba6d5-1590065442516/node_modules/@zkopru/database" + "@zkopru/utils" "file:../../../.cache/yarn/v6/npm-@zkopru-account-0.0.3-132ecf22-5630-4f2c-b161-56f1312ba6d5-1590065442516/node_modules/@zkopru/utils" bip39 "^3.0.2" hdkey "^1.1.1" web3 "^1.2.6" @@ -1990,7 +1998,7 @@ web3-eth-accounts "^1.2.6" "@zkopru/babyjubjub@file:packages/babyjubjub": - version "0.0.1" + version "0.0.3" dependencies: big-integer "^1.6.48" blake-hash "^1.1.0" @@ -2000,7 +2008,7 @@ web3-utils "^1.2.6" "@zkopru/contracts@file:packages/contracts": - version "0.0.1" + version "0.0.3" dependencies: "@openzeppelin/contracts" "3.0.1" bn.js "^5.1.1" @@ -2009,40 +2017,47 @@ web3-eth-contract "^1.2.6" "@zkopru/coordinator@file:packages/coordinator": - version "0.0.1" + version "0.0.3" dependencies: + "@nano-sql/adapter-leveldb" "^2.0.5" "@nano-sql/core" "^2.3.7" - "@zkopru/babyjubjub" "file:../../../.cache/yarn/v6/npm-@zkopru-coordinator-0.0.1-3ce2bec6-1446-49ac-99dd-428026d3955b-1589800833141/node_modules/@zkopru/babyjubjub" - "@zkopru/contracts" "file:../../../.cache/yarn/v6/npm-@zkopru-coordinator-0.0.1-3ce2bec6-1446-49ac-99dd-428026d3955b-1589800833141/node_modules/@zkopru/contracts" - "@zkopru/core" "file:../../../.cache/yarn/v6/npm-@zkopru-coordinator-0.0.1-3ce2bec6-1446-49ac-99dd-428026d3955b-1589800833141/node_modules/@zkopru/core" - "@zkopru/transaction" "file:../../../.cache/yarn/v6/npm-@zkopru-coordinator-0.0.1-3ce2bec6-1446-49ac-99dd-428026d3955b-1589800833141/node_modules/@zkopru/transaction" - "@zkopru/tree" "file:../../../.cache/yarn/v6/npm-@zkopru-coordinator-0.0.1-3ce2bec6-1446-49ac-99dd-428026d3955b-1589800833141/node_modules/@zkopru/tree" - "@zkopru/utils" "file:../../../.cache/yarn/v6/npm-@zkopru-coordinator-0.0.1-3ce2bec6-1446-49ac-99dd-428026d3955b-1589800833141/node_modules/@zkopru/utils" + "@zkopru/babyjubjub" "file:../../../.cache/yarn/v6/npm-@zkopru-coordinator-0.0.3-f3888ee5-d16d-41ce-9f6e-9121f9eec6f0-1590065442522/node_modules/@zkopru/babyjubjub" + "@zkopru/contracts" "file:../../../.cache/yarn/v6/npm-@zkopru-coordinator-0.0.3-f3888ee5-d16d-41ce-9f6e-9121f9eec6f0-1590065442522/node_modules/@zkopru/contracts" + "@zkopru/core" "file:../../../.cache/yarn/v6/npm-@zkopru-coordinator-0.0.3-f3888ee5-d16d-41ce-9f6e-9121f9eec6f0-1590065442522/node_modules/@zkopru/core" + "@zkopru/transaction" "file:../../../.cache/yarn/v6/npm-@zkopru-coordinator-0.0.3-f3888ee5-d16d-41ce-9f6e-9121f9eec6f0-1590065442522/node_modules/@zkopru/transaction" + "@zkopru/tree" "file:../../../.cache/yarn/v6/npm-@zkopru-coordinator-0.0.3-f3888ee5-d16d-41ce-9f6e-9121f9eec6f0-1590065442522/node_modules/@zkopru/tree" + "@zkopru/utils" "file:../../../.cache/yarn/v6/npm-@zkopru-coordinator-0.0.3-f3888ee5-d16d-41ce-9f6e-9121f9eec6f0-1590065442522/node_modules/@zkopru/utils" big-integer "^1.6.48" + bip39 "^3.0.2" bn.js "^5.1.1" + chalk "^4.0.0" express "^4.17.1" + figlet "^1.4.0" + fs-extra "^9.0.0" node-schedule "^1.3.2" + prompts "^2.3.2" snarkjs "^0.1.25" web3 "^1.2.6" web3-core "^1.2.6" web3-core-subscriptions "^1.2.6" web3-utils "^1.2.6" + yargs "^15.3.1" "@zkopru/core@file:packages/core": - version "0.0.1" + version "0.0.3" dependencies: "@nano-sql/core" "^2.3.7" - "@zkopru/account" "file:../../../.cache/yarn/v6/npm-@zkopru-core-0.0.1-f8309e8c-f3ea-4803-9ea0-bed19efe6441-1589800833135/node_modules/@zkopru/account" - "@zkopru/babyjubjub" "file:../../../.cache/yarn/v6/npm-@zkopru-core-0.0.1-f8309e8c-f3ea-4803-9ea0-bed19efe6441-1589800833135/node_modules/@zkopru/babyjubjub" - "@zkopru/contracts" "file:../../../.cache/yarn/v6/npm-@zkopru-core-0.0.1-f8309e8c-f3ea-4803-9ea0-bed19efe6441-1589800833135/node_modules/@zkopru/contracts" - "@zkopru/database" "file:../../../.cache/yarn/v6/npm-@zkopru-core-0.0.1-f8309e8c-f3ea-4803-9ea0-bed19efe6441-1589800833135/node_modules/@zkopru/database" - "@zkopru/transaction" "file:../../../.cache/yarn/v6/npm-@zkopru-core-0.0.1-f8309e8c-f3ea-4803-9ea0-bed19efe6441-1589800833135/node_modules/@zkopru/transaction" - "@zkopru/tree" "file:../../../.cache/yarn/v6/npm-@zkopru-core-0.0.1-f8309e8c-f3ea-4803-9ea0-bed19efe6441-1589800833135/node_modules/@zkopru/tree" - "@zkopru/utils" "file:../../../.cache/yarn/v6/npm-@zkopru-core-0.0.1-f8309e8c-f3ea-4803-9ea0-bed19efe6441-1589800833135/node_modules/@zkopru/utils" + "@zkopru/account" "file:../../../.cache/yarn/v6/npm-@zkopru-core-0.0.3-5da0e665-6d69-4265-af8e-b7643cfa4617-1590065442517/node_modules/@zkopru/account" + "@zkopru/babyjubjub" "file:../../../.cache/yarn/v6/npm-@zkopru-core-0.0.3-5da0e665-6d69-4265-af8e-b7643cfa4617-1590065442517/node_modules/@zkopru/babyjubjub" + "@zkopru/contracts" "file:../../../.cache/yarn/v6/npm-@zkopru-core-0.0.3-5da0e665-6d69-4265-af8e-b7643cfa4617-1590065442517/node_modules/@zkopru/contracts" + "@zkopru/database" "file:../../../.cache/yarn/v6/npm-@zkopru-core-0.0.3-5da0e665-6d69-4265-af8e-b7643cfa4617-1590065442517/node_modules/@zkopru/database" + "@zkopru/transaction" "file:../../../.cache/yarn/v6/npm-@zkopru-core-0.0.3-5da0e665-6d69-4265-af8e-b7643cfa4617-1590065442517/node_modules/@zkopru/transaction" + "@zkopru/tree" "file:../../../.cache/yarn/v6/npm-@zkopru-core-0.0.3-5da0e665-6d69-4265-af8e-b7643cfa4617-1590065442517/node_modules/@zkopru/tree" + "@zkopru/utils" "file:../../../.cache/yarn/v6/npm-@zkopru-core-0.0.3-5da0e665-6d69-4265-af8e-b7643cfa4617-1590065442517/node_modules/@zkopru/utils" async-lock "^1.2.2" big-integer "^1.6.48" bn.js "^5.1.1" - ffjavascript "^0.0.5" + ffjavascript "^0.1.3" node-fetch "^2.6.0" snarkjs "^0.1.27" web3 "^1.2.6" @@ -2052,21 +2067,21 @@ winston "^3.2.1" "@zkopru/database@file:packages/database": - version "0.0.1" + version "0.0.3" dependencies: "@nano-sql/core" "^2.3.7" - "@zkopru/babyjubjub" "file:../../../.cache/yarn/v6/npm-@zkopru-database-0.0.1-c751da18-83c5-4553-a2f7-54c90d36979b-1589800833133/node_modules/@zkopru/babyjubjub" - "@zkopru/transaction" "file:../../../.cache/yarn/v6/npm-@zkopru-database-0.0.1-c751da18-83c5-4553-a2f7-54c90d36979b-1589800833133/node_modules/@zkopru/transaction" + "@zkopru/babyjubjub" "file:../../../.cache/yarn/v6/npm-@zkopru-database-0.0.3-489ad99f-0c3e-4978-835b-c11d462a9973-1590065442514/node_modules/@zkopru/babyjubjub" + "@zkopru/transaction" "file:../../../.cache/yarn/v6/npm-@zkopru-database-0.0.3-489ad99f-0c3e-4978-835b-c11d462a9973-1590065442514/node_modules/@zkopru/transaction" big-integer "^1.6.48" bn.js "^5.1.1" web3-core "^1.2.6" web3-utils "^1.2.6" "@zkopru/transaction@file:packages/transaction": - version "0.0.1" + version "0.0.3" dependencies: - "@zkopru/babyjubjub" "file:../../../.cache/yarn/v6/npm-@zkopru-transaction-0.0.1-e0ca32ce-cd72-46f3-ab27-5569d551cae8-1589800833136/node_modules/@zkopru/babyjubjub" - "@zkopru/utils" "file:../../../.cache/yarn/v6/npm-@zkopru-transaction-0.0.1-e0ca32ce-cd72-46f3-ab27-5569d551cae8-1589800833136/node_modules/@zkopru/utils" + "@zkopru/babyjubjub" "file:../../../.cache/yarn/v6/npm-@zkopru-transaction-0.0.3-32e1c6d2-df04-4b81-9977-7b5e7726659b-1590065442520/node_modules/@zkopru/babyjubjub" + "@zkopru/utils" "file:../../../.cache/yarn/v6/npm-@zkopru-transaction-0.0.3-32e1c6d2-df04-4b81-9977-7b5e7726659b-1590065442520/node_modules/@zkopru/utils" big-integer "^1.6.48" chacha20 "^0.1.4" circomlib "^0.1.1" @@ -2074,12 +2089,12 @@ web3-utils "^1.2.6" "@zkopru/tree@file:packages/tree": - version "0.0.1" + version "0.0.3" dependencies: "@nano-sql/core" "^2.3.7" - "@zkopru/babyjubjub" "file:../../../.cache/yarn/v6/npm-@zkopru-tree-0.0.1-a9fd28c6-a902-485b-8e0b-4ab525a06023-1589800833140/node_modules/@zkopru/babyjubjub" - "@zkopru/database" "file:../../../.cache/yarn/v6/npm-@zkopru-tree-0.0.1-a9fd28c6-a902-485b-8e0b-4ab525a06023-1589800833140/node_modules/@zkopru/database" - "@zkopru/transaction" "file:../../../.cache/yarn/v6/npm-@zkopru-tree-0.0.1-a9fd28c6-a902-485b-8e0b-4ab525a06023-1589800833140/node_modules/@zkopru/transaction" + "@zkopru/babyjubjub" "file:../../../.cache/yarn/v6/npm-@zkopru-tree-0.0.3-ca3686f8-c616-4f78-8978-2cb8f743662c-1590065442520/node_modules/@zkopru/babyjubjub" + "@zkopru/database" "file:../../../.cache/yarn/v6/npm-@zkopru-tree-0.0.3-ca3686f8-c616-4f78-8978-2cb8f743662c-1590065442520/node_modules/@zkopru/database" + "@zkopru/transaction" "file:../../../.cache/yarn/v6/npm-@zkopru-tree-0.0.3-ca3686f8-c616-4f78-8978-2cb8f743662c-1590065442520/node_modules/@zkopru/transaction" async-lock "^1.2.2" big-integer "^1.6.48" bn.js "^5.1.1" @@ -2087,7 +2102,7 @@ web3-utils "^1.2.6" "@zkopru/utils@file:packages/utils": - version "0.0.1" + version "0.0.3" dependencies: bn.js "^5.1.1" circom_runtime "^0.0.3" @@ -2096,22 +2111,21 @@ node-docker-api "^1.1.22" pino "^6.2.0" pino-pretty "^4.0.0" + prompts "^2.3.2" snarkjs "^0.1.25" tar "^6.0.2" web3-utils "^1.2.6" "@zkopru/zk-wizard@file:packages/zk-wizard": - version "0.0.1" + version "0.0.3" dependencies: - "@nano-sql/core" "^2.3.7" - "@zkopru/account" "file:../../../.cache/yarn/v6/npm-@zkopru-zk-wizard-0.0.1-633e8abc-ca6e-494e-98ba-0ffb50370975-1589800833139/node_modules/@zkopru/account" - "@zkopru/babyjubjub" "file:../../../.cache/yarn/v6/npm-@zkopru-zk-wizard-0.0.1-633e8abc-ca6e-494e-98ba-0ffb50370975-1589800833139/node_modules/@zkopru/babyjubjub" - "@zkopru/contracts" "file:../../../.cache/yarn/v6/npm-@zkopru-zk-wizard-0.0.1-633e8abc-ca6e-494e-98ba-0ffb50370975-1589800833139/node_modules/@zkopru/contracts" - "@zkopru/core" "file:../../../.cache/yarn/v6/npm-@zkopru-zk-wizard-0.0.1-633e8abc-ca6e-494e-98ba-0ffb50370975-1589800833139/node_modules/@zkopru/core" - "@zkopru/database" "file:../../../.cache/yarn/v6/npm-@zkopru-zk-wizard-0.0.1-633e8abc-ca6e-494e-98ba-0ffb50370975-1589800833139/node_modules/@zkopru/database" - "@zkopru/transaction" "file:../../../.cache/yarn/v6/npm-@zkopru-zk-wizard-0.0.1-633e8abc-ca6e-494e-98ba-0ffb50370975-1589800833139/node_modules/@zkopru/transaction" - "@zkopru/tree" "file:../../../.cache/yarn/v6/npm-@zkopru-zk-wizard-0.0.1-633e8abc-ca6e-494e-98ba-0ffb50370975-1589800833139/node_modules/@zkopru/tree" - "@zkopru/utils" "file:../../../.cache/yarn/v6/npm-@zkopru-zk-wizard-0.0.1-633e8abc-ca6e-494e-98ba-0ffb50370975-1589800833139/node_modules/@zkopru/utils" + "@zkopru/account" "file:../../../.cache/yarn/v6/npm-@zkopru-zk-wizard-0.0.3-c6cf7392-2d60-4d29-852b-1b483ee54573-1590065442521/node_modules/@zkopru/account" + "@zkopru/babyjubjub" "file:../../../.cache/yarn/v6/npm-@zkopru-zk-wizard-0.0.3-c6cf7392-2d60-4d29-852b-1b483ee54573-1590065442521/node_modules/@zkopru/babyjubjub" + "@zkopru/contracts" "file:../../../.cache/yarn/v6/npm-@zkopru-zk-wizard-0.0.3-c6cf7392-2d60-4d29-852b-1b483ee54573-1590065442521/node_modules/@zkopru/contracts" + "@zkopru/core" "file:../../../.cache/yarn/v6/npm-@zkopru-zk-wizard-0.0.3-c6cf7392-2d60-4d29-852b-1b483ee54573-1590065442521/node_modules/@zkopru/core" + "@zkopru/transaction" "file:../../../.cache/yarn/v6/npm-@zkopru-zk-wizard-0.0.3-c6cf7392-2d60-4d29-852b-1b483ee54573-1590065442521/node_modules/@zkopru/transaction" + "@zkopru/tree" "file:../../../.cache/yarn/v6/npm-@zkopru-zk-wizard-0.0.3-c6cf7392-2d60-4d29-852b-1b483ee54573-1590065442521/node_modules/@zkopru/tree" + "@zkopru/utils" "file:../../../.cache/yarn/v6/npm-@zkopru-zk-wizard-0.0.3-c6cf7392-2d60-4d29-852b-1b483ee54573-1590065442521/node_modules/@zkopru/utils" big-integer "^1.6.48" circom_runtime "^0.0.3" ffjavascript "^0.1.2" @@ -2158,14 +2172,6 @@ abstract-leveldown@^6.2.1: level-supports "~1.0.0" xtend "~4.0.0" -abstract-leveldown@~6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.1.1.tgz#f44bad5862d71c7b418110d7698ac25bedf24396" - integrity sha512-7fK/KySVqzKIomdhkSWzX4YBQhzkzEMbWSiaB6mSN9e+ZdV3KEeKxia/8xQzCkATA5xnnukdP88cFR0D2FsFXw== - dependencies: - level-concat-iterator "~2.0.0" - xtend "~4.0.0" - abstract-leveldown@~6.2.1: version "6.2.3" resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.2.3.tgz#036543d87e3710f2528e47040bc3261b77a9a8eb" @@ -3673,7 +3679,7 @@ columnify@^1.5.4: strip-ansi "^3.0.0" wcwidth "^1.0.0" -combined-stream@^1.0.6, combined-stream@~1.0.6: +combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== @@ -5523,13 +5529,6 @@ ffjavascript@0.1.2: dependencies: big-integer "^1.6.48" -ffjavascript@^0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/ffjavascript/-/ffjavascript-0.0.5.tgz#244d242b74299fef736b697ff4df9cda1a26fbbe" - integrity sha512-7je6PydOWLDUj3vU8JeCUgeezg4yrG/6qjlukQNuPHeeavnM4REcrN9LA2+xtqIMIPdx/wdUkPMQpixsz+CdIw== - dependencies: - big-integer "^1.6.48" - ffjavascript@^0.1.2, ffjavascript@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/ffjavascript/-/ffjavascript-0.1.3.tgz#75d5397f5da0af977d6f38b60301d4de25f17040" @@ -5802,6 +5801,15 @@ form-data@^2.2.0: combined-stream "^1.0.6" mime-types "^2.1.12" +form-data@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.0.tgz#31b7e39c85f1355b7139ee0c647cf0de7f83c682" + integrity sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + form-data@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" @@ -10919,15 +10927,6 @@ rlp@^2.2.3: dependencies: bn.js "^4.11.1" -rocksdb@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/rocksdb/-/rocksdb-4.1.0.tgz#79c2cb716ffb9b317bdb48f80d1985410179ecac" - integrity sha512-NtjezNMuxk9NsC1kGybZ8Y9eWKqAohug88xbtxCwb5n7MhDDgtKJuL7VYUk8s8Q9U4Mzolt026k3hD8eHtoUvQ== - dependencies: - abstract-leveldown "~6.1.1" - napi-macros "~2.0.0" - node-gyp-build "~4.1.0" - rsvp@^4.8.4: version "4.8.5" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734"