diff --git a/ormconfig-address.json b/ormconfig-address.json deleted file mode 100644 index 89b3d7e5ca..0000000000 --- a/ormconfig-address.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "type": "sqlite", - "synchronize": false, - "migrationsRun": true, - "logging": true, - "database": "address-dev.sqlite", - "entities": [ - "packages/neuron-wallet/dist/database/address/entities/**/*.js" - ], - "migrations": [ - "packages/neuron-wallet/dist/database/address/migrations/**/*.js" - ], - "subscribers": [ - "packages/neuron-wallet/dist/database/address/subscriber/**/*.js" - ], - "cli": { - "entitiesDir": "packages/neuron-wallet/src/database/address/entities", - "migrationsDir": "packages/neuron-wallet/src/database/address/migrations", - "subscribersDir": "packages/neuron-wallet/src/database/address/subscriber" - } -} diff --git a/package.json b/package.json index e4d3b62edf..cca3c7e96c 100644 --- a/package.json +++ b/package.json @@ -34,8 +34,7 @@ "test:e2e": "yarn build && ./scripts/copy-ui-files.sh && lerna run --parallel test:e2e", "lint": "lerna run --stream lint", "postinstall": "lerna run rebuild:nativemodules", - "db:chain": "node ./node_modules/.bin/typeorm", - "db:address": "node ./node_modules/.bin/typeorm --config ormconfig-address.json" + "db:chain": "node ./node_modules/.bin/typeorm" }, "husky": { "hooks": { diff --git a/packages/neuron-wallet/package.json b/packages/neuron-wallet/package.json index 1530c36f10..f490580768 100644 --- a/packages/neuron-wallet/package.json +++ b/packages/neuron-wallet/package.json @@ -21,7 +21,7 @@ "start:dev": "yarn run build && electron .", "build": "ttsc && ncp ./src/startup/sync-block-task/index.html ./dist/startup/sync-block-task/index.html", "clean": "rimraf dist/*", - "test": "jest --color", + "test": "jest --color --runInBand", "test:e2e": "jest --config jest.e2e.config.js --color", "lint": "eslint --fix --ext .ts,.js src", "precommit": "lint-staged", diff --git a/packages/neuron-wallet/src/controllers/app/index.ts b/packages/neuron-wallet/src/controllers/app/index.ts index e5e404d159..6a0ed85bd5 100644 --- a/packages/neuron-wallet/src/controllers/app/index.ts +++ b/packages/neuron-wallet/src/controllers/app/index.ts @@ -6,6 +6,7 @@ import env from 'env' import { updateApplicationMenu } from './menu' import logger from 'utils/logger' import { subscribe } from './subscribe' +import WalletService from 'services/wallets' const app = electronApp || (remote && remote.app) @@ -65,6 +66,8 @@ export default class AppController { this.mainWindow.show() this.mainWindow.focus() logger.info('The main window is ready to show') + + WalletService.getInstance().generateAddressesIfNecessary() } else { logger.error('The main window is not initialized on ready to show') } diff --git a/packages/neuron-wallet/src/controllers/wallets.ts b/packages/neuron-wallet/src/controllers/wallets.ts index a8aa816d5b..0491f7952d 100644 --- a/packages/neuron-wallet/src/controllers/wallets.ts +++ b/packages/neuron-wallet/src/controllers/wallets.ts @@ -134,7 +134,7 @@ export default class WalletsController { keystore, }) - await walletsService.generateAddressesById(wallet.id, isImporting) + walletsService.generateAddressesById(wallet.id, isImporting) return { status: ResponseCode.Success, @@ -294,26 +294,24 @@ export default class WalletsController { } public static async getAllAddresses(id: string) { - const addresses = await AddressService.allAddressesByWalletId(id).then(addrs => - addrs.map( - ({ - address, - blake160: identifier, - addressType: type, - txCount, - balance, - description = '', - addressIndex: index = '', - }) => ({ - address, - identifier, - type, - txCount, - description, - balance, - index, - }) - ) + const addresses = AddressService.allAddressesByWalletId(id).map( + ({ + address, + blake160: identifier, + addressType: type, + txCount, + balance, + description = '', + addressIndex: index = '', + }) => ({ + address, + identifier, + type, + txCount, + description, + balance, + index, + }) ) return { status: ResponseCode.Success, @@ -501,7 +499,7 @@ export default class WalletsController { const walletService = WalletsService.getInstance() const wallet = walletService.get(walletID) - await AddressService.updateDescription(wallet.id, address, description) + AddressService.updateDescription(wallet.id, address, description) return { status: ResponseCode.Success, diff --git a/packages/neuron-wallet/src/database/address/address-dao.ts b/packages/neuron-wallet/src/database/address/address-dao.ts new file mode 100644 index 0000000000..c2b48409e6 --- /dev/null +++ b/packages/neuron-wallet/src/database/address/address-dao.ts @@ -0,0 +1,244 @@ +import { remote } from 'electron' +import { AddressType } from 'models/keys/address' +import { TransactionsService } from 'services/tx' +import CellsService from 'services/cells' +import LockUtils from 'models/lock-utils' +import { TransactionStatus } from 'types/cell-types' +import { OutputStatus } from 'services/tx/params' +import NodeService from 'services/node' +import Store from 'models/store' +import AddressDbChangedSubject from 'models/subjects/address-db-changed-subject' + +export enum AddressVersion { + Testnet = 'testnet', + Mainnet = 'mainnet', +} + +export interface Address { + walletId: string + address: string + path: string + addressType: AddressType + addressIndex: number + txCount: number + liveBalance: string + sentBalance: string + pendingBalance: string + balance: string + blake160: string + version: AddressVersion + description?: string + isImporting?: boolean | undefined +} + +export default class AddressDao { + public static create = (addresses: Address[]): Address[] => { + const result = addresses.map(address => { + address.txCount = address.txCount || 0 + address.liveBalance = address.liveBalance || '0' + address.sentBalance = address.sentBalance || '0' + address.pendingBalance = address.pendingBalance || '0' + address.balance = (BigInt(address.liveBalance) + BigInt(address.sentBalance)).toString() + return address + }) + return AddressStore.add(result) + } + + public static getAll(): Address[] { + return AddressStore.getAll() + } + + // txCount include all txs in db + // liveBalance means balance of OutputStatus.Live cells (already in chain and not spent) + // sentBalance means balance of OutputStatus.Sent cells (sent to me but not committed) + // pendingBalance means balance of OutputStatus.Pending cells (sent from me, but not committed) + // so the final balance is (liveBalance + sentBalance - pendingBalance) + // balance is the balance of the cells those who don't hold data or type script + public static updateTxCountAndBalance = async ( + address: string, + url: string = NodeService.getInstance().core.rpc.node.url + ): Promise => { + const all = AddressStore.getAll() + const toUpdate = all.filter(value => { + return value.address === address + }) + const others = all.filter(value => { + return value.address !== address + }) + + const txCount: number = await TransactionsService.getCountByAddressAndStatus(address, [ + TransactionStatus.Pending, + TransactionStatus.Success, + ], url) + const lockUtils = new LockUtils(await LockUtils.systemScript(url)) + const result = await Promise.all( + toUpdate.map(async entity => { + const item = entity + item.txCount = txCount + const lockHashes: string[] = lockUtils.addressToAllLockHashes(item.address) + item.liveBalance = await CellsService.getBalance(lockHashes, OutputStatus.Live) + item.sentBalance = await CellsService.getBalance(lockHashes, OutputStatus.Sent) + item.pendingBalance = await CellsService.getBalance(lockHashes, OutputStatus.Pending) + item.balance = (BigInt(item.liveBalance) + BigInt(item.sentBalance)).toString() + return item + }) + ) + + AddressStore.updateAll(toUpdate.concat(others)) + return result + } + + public static nextUnusedAddress(walletId: string, version: AddressVersion): Address | undefined { + const addresses = AddressStore.getAll().filter(value => { + return value.walletId === walletId + && value.version === version + && value.addressType == AddressType.Receiving + && value.txCount === 0 + }) + return addresses.sort((lhs, rhs) => { + return lhs.addressIndex < rhs.addressIndex ? 1 : -1 + })[0] + } + + public static nextUnusedChangeAddress(walletId: string, version: AddressVersion): Address | undefined { + const addresses = AddressStore.getAll().filter(value => { + return value.walletId === walletId + && value.version === version + && value.addressType == AddressType.Change + && value.txCount === 0 + }) + return addresses.sort((lhs, rhs) => { + return lhs.addressIndex < rhs.addressIndex ? 1 : -1 + })[0] + } + + public static allAddresses(version: AddressVersion): Address[] { + const all = AddressStore.getAll() + return all.filter(value => { + return value.version === version + }) + } + + public static allAddressesByWalletId(walletId: string, version: AddressVersion): Address[] { + return AddressStore.getAll() + .filter(value => value.walletId === walletId && value.version === version) + .sort((lhs, rhs) => { + return lhs.addressType - rhs.addressType || lhs.addressIndex - rhs.addressIndex + }) + } + + public static usedAddressesByWalletId(walletId: string, version: AddressVersion): Address[] { + const all = AddressStore.getAll() + return all.filter(value => { + return value.walletId === walletId + && value.version === version + && value.txCount !== 0 + }) + } + + public static findByAddress(address: string, walletId: string): Address | undefined { + return AddressStore.getAll().find(value => { + return value.address === address && value.walletId == walletId + }) + } + + public static findByAddresses(addresses: string[]): Address[] { + return AddressStore.getAll().filter(value => { + return addresses.includes(value.address) + }) + } + + public static maxAddressIndex(walletId: string, addressType: AddressType, version: AddressVersion): Address | undefined { + const addresses = AddressStore.getAll().filter(value => { + return value.walletId === walletId + && value.addressType === addressType + && value.version === version + }) + return addresses.sort((lhs, rhs) => { + return lhs.addressIndex > rhs.addressIndex ? -1 : 1 + })[0] + } + + public static updateDescription(walletId: string, address: string, description: string): Address | undefined { + const item = AddressDao.findByAddress(address, walletId) + if (!item) { + return undefined + } + item.description = description + return AddressStore.update(item) + } + + public static deleteByWalletId(walletId: string): Address[] { + const all = AddressStore.getAll() + const toKeep = all.filter(value => { + return value.walletId !== walletId + }) + const deleted = all.filter(value => { + return value.walletId === walletId + }) + AddressStore.updateAll(toKeep) + + return deleted + } + + public static updateAll(addresses: Address[]) { + AddressStore.updateAll(addresses) + } + + public static deleteAll() { + AddressStore.updateAll([]) + } +} + +const isRenderer = process && process.type === 'renderer' +const addressDbChangedSubject = isRenderer + ? remote.require('./models/subjects/address-db-changed-subject').default.getSubject() + : AddressDbChangedSubject.getSubject() + +/// Persist all addresses as array in `addresses/index.json`. +class AddressStore { + static MODULE_NAME = 'addresses' + static ROOT_KEY = 'addresses' + static store = new Store(AddressStore.MODULE_NAME, 'index.json', '{}') + + static getAll(): Address[] { + const root = AddressStore.store.readSync(AddressStore.ROOT_KEY) + return root || [] + } + + static updateAll(addresses: Address[]) { + AddressStore.store.writeSync(AddressStore.ROOT_KEY, addresses) + AddressStore.changed() + } + + static add(addresses: Address[]): Address[] { + const all = AddressStore.getAll() + for (let address of addresses) { + all.push(address) + } + + AddressStore.updateAll(all) + + return addresses + } + + static update(address: Address): Address { + const all = AddressStore.getAll() + const exist = all.findIndex(value => { + return value.walletId === address.walletId && value.address === address.address + }) + if (exist !== -1) { + all[exist] = address + } else { + all.push(address) + } + + AddressStore.updateAll(all) + + return address + } + + static changed() { + addressDbChangedSubject.next("Updated") + } +} diff --git a/packages/neuron-wallet/src/database/address/dao.ts b/packages/neuron-wallet/src/database/address/dao.ts deleted file mode 100644 index b6eed992c4..0000000000 --- a/packages/neuron-wallet/src/database/address/dao.ts +++ /dev/null @@ -1,245 +0,0 @@ -import { Not, In } from 'typeorm' -import { AddressType } from 'models/keys/address' -import { TransactionsService } from 'services/tx' -import CellsService from 'services/cells' -import LockUtils from 'models/lock-utils' -import { TransactionStatus } from 'types/cell-types' -import { OutputStatus } from 'services/tx/params' -import AddressEntity, { AddressVersion } from './entities/address' -import { getConnection } from './ormconfig' -import NodeService from 'services/node' - -export interface Address { - walletId: string - address: string - path: string - addressType: AddressType - addressIndex: number - txCount: number - liveBalance: string - sentBalance: string - pendingBalance: string - balance: string - blake160: string - version: AddressVersion - description?: string - isImporting?: boolean | undefined -} - -export default class AddressDao { - public static create = async (addresses: Address[]): Promise => { - const addressEntities: AddressEntity[] = addresses.map(address => { - const addressEntity = new AddressEntity() - addressEntity.walletId = address.walletId - addressEntity.address = address.address - addressEntity.path = address.path - addressEntity.addressType = address.addressType - addressEntity.addressIndex = address.addressIndex - addressEntity.txCount = address.txCount || 0 - addressEntity.blake160 = address.blake160 - addressEntity.version = address.version - addressEntity.liveBalance = address.liveBalance || '0' - addressEntity.sentBalance = address.sentBalance || '0' - addressEntity.pendingBalance = address.pendingBalance || '0' - return addressEntity - }) - - return getConnection().manager.save(addressEntities) - } - - // txCount include all txs in db - // liveBalance means balance of OutputStatus.Live cells (already in chain and not spent) - // sentBalance means balance of OutputStatus.Sent cells (sent to me but not committed) - // pendingBalance means balance of OutputStatus.Pending cells (sent from me, but not committed) - // so the final balance is (liveBalance + sentBalance - pendingBalance) - // balance is the balance of the cells those who don't hold data or type script - public static updateTxCountAndBalance = async ( - address: string, - url: string = NodeService.getInstance().core.rpc.node.url - ): Promise => { - const addressEntities = await getConnection() - .getRepository(AddressEntity) - .find({ - address, - }) - - const txCount: number = await TransactionsService.getCountByAddressAndStatus(address, [ - TransactionStatus.Pending, - TransactionStatus.Success, - ], url) - const lockUtils = new LockUtils(await LockUtils.systemScript(url)) - const entities = await Promise.all( - addressEntities.map(async entity => { - const addressEntity = entity - addressEntity.txCount = txCount - const lockHashes: string[] = lockUtils.addressToAllLockHashes(addressEntity.address) - addressEntity.liveBalance = await CellsService.getBalance(lockHashes, OutputStatus.Live) - addressEntity.sentBalance = await CellsService.getBalance(lockHashes, OutputStatus.Sent) - addressEntity.pendingBalance = await CellsService.getBalance(lockHashes, OutputStatus.Pending) - return addressEntity - }) - ) - - return getConnection().manager.save(entities) - } - - public static nextUnusedAddress = async ( - walletId: string, - version: AddressVersion - ): Promise => { - const addressEntity = await getConnection() - .getRepository(AddressEntity) - .createQueryBuilder('address') - .where({ - walletId, - version, - addressType: AddressType.Receiving, - txCount: 0, - }) - .orderBy('address.addressIndex', 'ASC') - .getOne() - - return addressEntity - } - - public static nextUnusedChangeAddress = async ( - walletId: string, - version: AddressVersion - ): Promise => { - const addressEntity = await getConnection() - .getRepository(AddressEntity) - .createQueryBuilder('address') - .where({ - walletId, - version, - addressType: AddressType.Change, - txCount: 0, - }) - .orderBy('address.addressIndex', 'ASC') - .getOne() - - return addressEntity - } - - public static allAddresses = async (version: AddressVersion): Promise => { - const addressEntities = await getConnection() - .getRepository(AddressEntity) - .createQueryBuilder('address') - .where({ - version, - }) - .getMany() - - return addressEntities - } - - public static allAddressesByWalletId = async ( - walletId: string, - version: AddressVersion - ): Promise => { - const addressEntities = await getConnection() - .getRepository(AddressEntity) - .createQueryBuilder('address') - .where({ - walletId, - version, - }) - .getMany() - - return addressEntities - } - - public static usedAddressesByWalletId = async ( - walletId: string, - version: AddressVersion - ): Promise => { - const addressEntities = await getConnection() - .getRepository(AddressEntity) - .createQueryBuilder('address') - .where({ - walletId, - version, - txCount: Not(0), - }) - .getMany() - - return addressEntities - } - - public static findByAddress = async (address: string, walletId: string): Promise => { - const addressEntity = await getConnection() - .getRepository(AddressEntity) - .createQueryBuilder('address') - .where({ - address, - walletId, - }) - .getOne() - - return addressEntity - } - - public static findByAddresses = async (addresses: string[]) => { - const addressEntities = await getConnection() - .getRepository(AddressEntity) - .createQueryBuilder('address') - .where({ - address: In(addresses), - }) - .getMany() - return addressEntities - } - - public static maxAddressIndex = async ( - walletId: string, - addressType: AddressType, - version: AddressVersion - ): Promise => { - const addressEntity = await getConnection() - .getRepository(AddressEntity) - .createQueryBuilder('address') - .where({ - walletId, - addressType, - version, - }) - .orderBy('address.addressIndex', 'DESC') - .getOne() - - if (!addressEntity) { - return undefined - } - - return addressEntity - } - - public static updateDescription = async (walletId: string, address: string, description: string) => { - const addressEntity = await getConnection() - .getRepository(AddressEntity) - .createQueryBuilder('address') - .where({ - walletId, - address, - }) - .getOne() - - if (!addressEntity) { - return undefined - } - addressEntity.description = description - return getConnection().manager.save(addressEntity) - } - - public static deleteByWalletId = async (walletId: string) => { - const addresses = await getConnection() - .getRepository(AddressEntity) - .createQueryBuilder('address') - .where({ - walletId, - }) - .getMany() - const result = addresses.map(addr => addr.toInterface()) - await getConnection().manager.remove(addresses) - return result - } -} diff --git a/packages/neuron-wallet/src/database/address/entities/address.ts b/packages/neuron-wallet/src/database/address/entities/address.ts deleted file mode 100644 index 1cdd995d60..0000000000 --- a/packages/neuron-wallet/src/database/address/entities/address.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { remote } from 'electron' -import { Entity, BaseEntity, PrimaryColumn, Column, AfterInsert, AfterUpdate, AfterRemove } from 'typeorm' -import { AddressType } from 'models/keys/address' -import AddressDbChangedSubject from 'models/subjects/address-db-changed-subject' -import { Address as AddressInterface } from '../dao' - -export enum AddressVersion { - Testnet = 'testnet', - Mainnet = 'mainnet', -} - -const isRenderer = process && process.type === 'renderer' -const addressDbChangedSubject = isRenderer - ? remote.require('./models/subjects/address-db-changed-subject').default.getSubject() - : AddressDbChangedSubject.getSubject() - -@Entity() -export default class Address extends BaseEntity { - @PrimaryColumn({ - type: 'varchar', - }) - address!: string - - @PrimaryColumn({ - type: 'varchar', - }) - walletId!: string - - @Column({ - type: 'varchar', - }) - path!: string - - @Column({ - type: 'int', - }) - addressType!: AddressType - - @Column({ - type: 'int', - }) - addressIndex!: number - - @Column({ - type: 'int', - }) - txCount!: number - - @Column({ - type: 'varchar', - }) - blake160!: string - - @Column({ - type: 'varchar', - }) - version!: AddressVersion - - @Column({ - type: 'varchar', - nullable: true, - }) - description?: string - - @Column({ - type: 'varchar', - }) - liveBalance: string = '0' - - @Column() - sentBalance: string = '0' - - @Column() - pendingBalance: string = '0' - - public balance = (): string => { - return (BigInt(this.liveBalance) + BigInt(this.sentBalance)).toString() - } - - public toInterface = (): AddressInterface => { - return { - address: this.address, - walletId: this.walletId, - path: this.path, - addressType: this.addressType, - addressIndex: this.addressIndex, - txCount: this.txCount, - blake160: this.blake160, - version: this.version, - liveBalance: this.liveBalance, - sentBalance: this.sentBalance, - pendingBalance: this.pendingBalance, - balance: this.balance(), - description: this.description, - } - } - - @AfterInsert() - emitInsert() { - this.changed('AfterInsert') - } - - @AfterUpdate() - emitUpdate() { - this.changed('AfterUpdate') - } - - @AfterRemove() - emitRemove() { - this.changed('AfterRemove') - } - - private changed = (event: string) => { - addressDbChangedSubject.next(event) - } -} diff --git a/packages/neuron-wallet/src/database/address/migrations/1561461669542-AddAddress.ts b/packages/neuron-wallet/src/database/address/migrations/1561461669542-AddAddress.ts deleted file mode 100644 index 34bccf8ae8..0000000000 --- a/packages/neuron-wallet/src/database/address/migrations/1561461669542-AddAddress.ts +++ /dev/null @@ -1,13 +0,0 @@ -import {MigrationInterface, QueryRunner} from "typeorm"; - -export class AddAddress1561461669542 implements MigrationInterface { - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`CREATE TABLE "address" ("address" varchar NOT NULL, "walletId" varchar NOT NULL, "path" varchar NOT NULL, "addressType" integer NOT NULL, "addressIndex" integer NOT NULL, "txCount" integer NOT NULL, "blake160" varchar NOT NULL, "version" varchar NOT NULL, "description" varchar, "balance" varchar NOT NULL, PRIMARY KEY ("address", "walletId"))`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE "address"`); - } - -} diff --git a/packages/neuron-wallet/src/database/address/migrations/1562126909151-extendBalance.ts b/packages/neuron-wallet/src/database/address/migrations/1562126909151-extendBalance.ts deleted file mode 100644 index 516d5befbc..0000000000 --- a/packages/neuron-wallet/src/database/address/migrations/1562126909151-extendBalance.ts +++ /dev/null @@ -1,24 +0,0 @@ -import {MigrationInterface, QueryRunner, TableColumn} from "typeorm"; - -export class extendBalance1562126909151 implements MigrationInterface { - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE 'address' ADD COLUMN 'sentBalance' varchar NOT NULL DEFAULT '0';`) - await queryRunner.query(`ALTER TABLE 'address' ADD COLUMN 'pendingBalance' varchar NOT NULL DEFAULT '0';`) - - await queryRunner.changeColumn('address', 'balance', new TableColumn({ - name: 'liveBalance', - type: 'varchar', - })) - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.dropColumn('address', 'sentBalance') - await queryRunner.dropColumn('address', 'pendingBalance') - await queryRunner.changeColumn('address', 'liveBalance', new TableColumn({ - name: 'balance', - type: 'varchar', - })) - } - -} diff --git a/packages/neuron-wallet/src/database/address/migrations/1567485550388-AddTotalBalance.ts b/packages/neuron-wallet/src/database/address/migrations/1567485550388-AddTotalBalance.ts deleted file mode 100644 index 03b3e5df9b..0000000000 --- a/packages/neuron-wallet/src/database/address/migrations/1567485550388-AddTotalBalance.ts +++ /dev/null @@ -1,17 +0,0 @@ -import {MigrationInterface, QueryRunner, TableColumn} from "typeorm"; - -export class AddTotalBalance1567485550388 implements MigrationInterface { - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.addColumn('address', new TableColumn({ - name: 'totalBalance', - type: 'varchar', - default: '0', - })) - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.dropColumn('address', 'totalBalance') - } - -} diff --git a/packages/neuron-wallet/src/database/address/migrations/1573458655136-RemoveTotalBalance.ts b/packages/neuron-wallet/src/database/address/migrations/1573458655136-RemoveTotalBalance.ts deleted file mode 100644 index 4bc22a5710..0000000000 --- a/packages/neuron-wallet/src/database/address/migrations/1573458655136-RemoveTotalBalance.ts +++ /dev/null @@ -1,17 +0,0 @@ -import {MigrationInterface, QueryRunner, TableColumn} from "typeorm"; - -export class RemoveTotalBalance1573458655136 implements MigrationInterface { - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.dropColumn('address', 'totalBalance') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.addColumn('address', new TableColumn({ - name: 'totalBalance', - type: 'varchar', - default: '0', - })) - } - -} diff --git a/packages/neuron-wallet/src/database/address/ormconfig.ts b/packages/neuron-wallet/src/database/address/ormconfig.ts deleted file mode 100644 index 3aa6ee695a..0000000000 --- a/packages/neuron-wallet/src/database/address/ormconfig.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { createConnection, getConnection as ormGetConnection } from 'typeorm' -import { SqliteConnectionOptions } from 'typeorm/driver/sqlite/SqliteConnectionOptions' -import path from 'path' - -import env from 'env' - -import Address from './entities/address' - -import { AddAddress1561461669542 } from './migrations/1561461669542-AddAddress' -import { extendBalance1562126909151 } from './migrations/1562126909151-extendBalance' -import { AddTotalBalance1567485550388 } from './migrations/1567485550388-AddTotalBalance' -import { RemoveTotalBalance1573458655136 } from './migrations/1573458655136-RemoveTotalBalance' - -const dbPath = path.join(env.fileBasePath, 'address.sqlite') - -const connectionName = 'address' - -const connectOptions = (): SqliteConnectionOptions => { - const database = env.isTestMode ? ':memory:' : dbPath - return { - name: connectionName, - type: 'sqlite', - database, - entities: [Address], - migrations: [ - AddAddress1561461669542, - extendBalance1562126909151, - AddTotalBalance1567485550388, - RemoveTotalBalance1573458655136, - ], - synchronize: false, - migrationsRun: true, - logging: ['error'], - } -} - -export const getConnection = () => { - return ormGetConnection(connectionName) -} - -const setBusyTimeout = async () => { - await getConnection().manager.query(`PRAGMA busy_timeout = 3000;`) -} - -export const initConnection = async () => { - const connectionOptions = connectOptions() - await createConnection(connectionOptions) - await setBusyTimeout() -} - -export default initConnection diff --git a/packages/neuron-wallet/src/database/chain/ormconfig.ts b/packages/neuron-wallet/src/database/chain/ormconfig.ts index 030e4eed5e..c5730b278f 100644 --- a/packages/neuron-wallet/src/database/chain/ormconfig.ts +++ b/packages/neuron-wallet/src/database/chain/ormconfig.ts @@ -32,7 +32,7 @@ const connectOptions = async (genesisBlockHash: string): Promise { const url: string = addressesList[addressesList.length - 1].url const uniqueAddresses = [...new Set(addresses)] const addrs = await AddressService.updateTxCountAndBalances(uniqueAddresses, url) - const walletIds: string[] = addrs.map(addr => addr.walletId).filter((value, idx, a) => a.indexOf(value) === idx) - await Promise.all( - walletIds.map(async id => { - const wallet = WalletService.getInstance().get(id) - const accountExtendedPublicKey: AccountExtendedPublicKey = wallet.accountExtendedPublicKey() - // set isImporting to undefined means unknown - await AddressService.checkAndGenerateSave(id, accountExtendedPublicKey, undefined, 20, 10) - }) - ) + const walletIds: string[] = addrs.map(addr => (addr as Address).walletId).filter((value, idx, a) => a.indexOf(value) === idx) + for (const id of walletIds) { + const wallet = WalletService.getInstance().get(id) + const accountExtendedPublicKey: AccountExtendedPublicKey = wallet.accountExtendedPublicKey() + // set isImporting to undefined means unknown + AddressService.checkAndGenerateSave(id, accountExtendedPublicKey, undefined, 20, 10) + } }) } diff --git a/packages/neuron-wallet/src/main.ts b/packages/neuron-wallet/src/main.ts index 550f1588eb..bb62cfe71e 100644 --- a/packages/neuron-wallet/src/main.ts +++ b/packages/neuron-wallet/src/main.ts @@ -1,7 +1,6 @@ import { app } from 'electron' import AppController from 'controllers/app' -import initConnection from 'database/address/ormconfig' import createSyncBlockTask from 'startup/sync-block-task/create' import { changeLanguage } from 'utils/i18n' @@ -10,7 +9,6 @@ const appController = new AppController() app.on('ready', async () => { changeLanguage(app.getLocale()) - await initConnection() createSyncBlockTask() appController.openWindow() diff --git a/packages/neuron-wallet/src/models/subjects/address-created-subject.ts b/packages/neuron-wallet/src/models/subjects/address-created-subject.ts index 40f5ab3fc9..63ff7968cd 100644 --- a/packages/neuron-wallet/src/models/subjects/address-created-subject.ts +++ b/packages/neuron-wallet/src/models/subjects/address-created-subject.ts @@ -1,5 +1,5 @@ import { ReplaySubject } from 'rxjs' -import { Address } from 'database/address/dao' +import { Address } from 'database/address/address-dao' export default class AddressCreatedSubject { static subject = new ReplaySubject(100) diff --git a/packages/neuron-wallet/src/services/addresses.ts b/packages/neuron-wallet/src/services/addresses.ts index 101d19cafc..5c479c4df3 100644 --- a/packages/neuron-wallet/src/services/addresses.ts +++ b/packages/neuron-wallet/src/services/addresses.ts @@ -2,8 +2,7 @@ import { AddressPrefix } from '@nervosnetwork/ckb-sdk-utils' import { AccountExtendedPublicKey } from 'models/keys/key' import Address, { AddressType } from 'models/keys/address' import LockUtils from 'models/lock-utils' -import AddressDao, { Address as AddressInterface } from 'database/address/dao' -import AddressEntity, { AddressVersion } from 'database/address/entities/address' +import AddressDao, { Address as AddressInterface, AddressVersion } from 'database/address/address-dao' import AddressCreatedSubject from 'models/subjects/address-created-subject' import NodeService from './node' import ChainInfo from 'models/chain-info' @@ -18,12 +17,12 @@ export interface AddressMetaInfo { } export default class AddressService { - public static isAddressUsed = async (address: string, walletId: string): Promise => { - const addressEntity = await AddressDao.findByAddress(address, walletId) + public static isAddressUsed = (address: string, walletId: string): boolean => { + const addressEntity = AddressDao.findByAddress(address, walletId) return !!addressEntity } - public static generateAndSave = async ( + public static generateAndSave = ( walletId: string, extendedKey: AccountExtendedPublicKey, isImporting: boolean | undefined, @@ -46,7 +45,7 @@ export default class AddressService { ...addresses.testnetChange, ...addresses.mainnetChange, ] - await AddressDao.create(allAddresses) + AddressDao.create(allAddresses) // TODO: notify address created and pass addressWay AddressService.notifyAddressCreated(allAddresses, isImporting) @@ -64,7 +63,7 @@ export default class AddressService { AddressCreatedSubject.getSubject().next(addrs) } - public static checkAndGenerateSave = async ( + public static checkAndGenerateSave = ( walletId: string, extendedKey: AccountExtendedPublicKey, isImporting: boolean | undefined, @@ -72,8 +71,8 @@ export default class AddressService { changeAddressCount: number = 10 ) => { const addressVersion = AddressService.getAddressVersion() - const maxIndexReceivingAddress = await AddressDao.maxAddressIndex(walletId, AddressType.Receiving, addressVersion) - const maxIndexChangeAddress = await AddressDao.maxAddressIndex(walletId, AddressType.Change, addressVersion) + const maxIndexReceivingAddress = AddressDao.maxAddressIndex(walletId, AddressType.Receiving, addressVersion) + const maxIndexChangeAddress = AddressDao.maxAddressIndex(walletId, AddressType.Change, addressVersion) if ( maxIndexReceivingAddress !== undefined && maxIndexReceivingAddress.txCount === 0 && @@ -95,16 +94,13 @@ export default class AddressService { ) } - public static updateTxCountAndBalances = async ( - addresses: string[], - url: string = NodeService.getInstance().core.rpc.node.url - ) => { - let addrs: AddressEntity[] = [] + public static updateTxCountAndBalances = async (addresses: string[], url: string = NodeService.getInstance().core.rpc.node.url) => { + let result: Address[] = [] for (const address of addresses) { - const ads = await AddressDao.updateTxCountAndBalance(address, url) - addrs = addrs.concat(ads) + const updatedAddress = await AddressDao.updateTxCountAndBalance(address, url) + result = result.concat(updatedAddress) } - return addrs + return result } // Generate both receiving and change addresses. @@ -194,59 +190,52 @@ export default class AddressService { return [testnetAddressInfo, mainnetAddressInfo] } - public static nextUnusedAddress = async (walletId: string): Promise => { + public static nextUnusedAddress = (walletId: string): AddressInterface | undefined => { const version = AddressService.getAddressVersion() - const addressEntity = await AddressDao.nextUnusedAddress(walletId, version) + const addressEntity = AddressDao.nextUnusedAddress(walletId, version) if (!addressEntity) { return undefined } - return addressEntity.toInterface() + return addressEntity } - public static nextUnusedChangeAddress = async (walletId: string): Promise => { + public static nextUnusedChangeAddress = (walletId: string): AddressInterface | undefined => { const version = AddressService.getAddressVersion() - const addressEntity = await AddressDao.nextUnusedChangeAddress(walletId, version) + const addressEntity = AddressDao.nextUnusedChangeAddress(walletId, version) if (!addressEntity) { return undefined } - return addressEntity.toInterface() + return addressEntity } - public static allAddresses = async (): Promise => { + public static allAddresses = (): AddressInterface[] => { const version = AddressService.getAddressVersion() - const addressEntities = await AddressDao.allAddresses(version) - - return addressEntities.map(addr => addr.toInterface()) + return AddressDao.allAddresses(version) } - public static allAddressesByWalletId = async (walletId: string): Promise => { + public static allAddressesByWalletId = (walletId: string): AddressInterface[] => { const version = AddressService.getAddressVersion() - const addressEntities = await AddressDao.allAddressesByWalletId(walletId, version) - - return addressEntities.map(addr => addr.toInterface()) + return AddressDao.allAddressesByWalletId(walletId, version) } - public static usedAddresses = async (walletId: string): Promise => { + public static usedAddresses = (walletId: string): AddressInterface[] => { const version = AddressService.getAddressVersion() - const addressEntities = await AddressDao.usedAddressesByWalletId(walletId, version) - - return addressEntities.map(addr => addr.toInterface()) + return AddressDao.usedAddressesByWalletId(walletId, version) } - public static updateDescription = async (walletId: string, address: string, description: string) => { + public static updateDescription = (walletId: string, address: string, description: string): AddressInterface | undefined => { return AddressDao.updateDescription(walletId, address, description) } - public static deleteByWalletId = async (walletId: string) => { + public static deleteByWalletId = (walletId: string): AddressInterface[] => { return AddressDao.deleteByWalletId(walletId) } - public static findByAddresses = async (addresses: string[]) => { - const entities = await AddressDao.findByAddresses(addresses) - return entities.map(entity => entity.toInterface()) + public static findByAddresses = (addresses: string[]): AddressInterface[] => { + return AddressDao.findByAddresses(addresses) } private static getAddressVersion = (): AddressVersion => { diff --git a/packages/neuron-wallet/src/services/wallets.ts b/packages/neuron-wallet/src/services/wallets.ts index 490cc3550e..9bfea2d62a 100644 --- a/packages/neuron-wallet/src/services/wallets.ts +++ b/packages/neuron-wallet/src/services/wallets.ts @@ -7,7 +7,7 @@ import LockUtils from 'models/lock-utils' import { TransactionWithoutHash, Input, OutPoint, WitnessArgs } from 'types/cell-types' import ConvertTo from 'types/convert-to' import { WalletNotFound, IsRequired, UsedName } from 'exceptions' -import { Address as AddressInterface } from 'database/address/dao' +import { Address as AddressInterface } from 'database/address/address-dao' import Keychain from 'models/keys/keychain' import AddressDbChangedSubject from 'models/subjects/address-db-changed-subject' import AddressesUsedSubject from 'models/subjects/addresses-used-subject' @@ -173,15 +173,22 @@ export default class WalletService { return FileKeystoreWallet.fromJSON(wallet) } - public generateAddressesById = async ( + public generateAddressesIfNecessary = () => { + for (const wallet of this.getAll()) { + if (AddressService.allAddressesByWalletId(wallet.id).length === 0) { + this.generateAddressesById(wallet.id, false) + } + } + } + + public generateAddressesById = ( id: string, isImporting: boolean, receivingAddressCount: number = 20, changeAddressCount: number = 10 ) => { - const wallet: Wallet = this.get(id) - const accountExtendedPublicKey: AccountExtendedPublicKey = wallet.accountExtendedPublicKey() - await AddressService.checkAndGenerateSave( + const accountExtendedPublicKey: AccountExtendedPublicKey = this.get(id).accountExtendedPublicKey() + AddressService.checkAndGenerateSave( id, accountExtendedPublicKey, isImporting, @@ -190,18 +197,6 @@ export default class WalletService { ) } - public generateCurrentWalletAddresses = async ( - isImporting: boolean, - receivingAddressCount: number = 20, - changeAddressCount: number = 10 - ) => { - const wallet: Wallet | undefined = this.getCurrent() - if (!wallet) { - return undefined - } - return this.generateAddressesById(wallet.id, isImporting, receivingAddressCount, changeAddressCount) - } - public create = (props: WalletProperties) => { if (!props) { throw new IsRequired('wallet property') @@ -269,7 +264,7 @@ export default class WalletService { this.listStore.writeSync(this.walletsKey, newWallets) wallet.deleteKeystore() - const addressInterfaces = await AddressService.deleteByWalletId(id) + const addressInterfaces = AddressService.deleteByWalletId(id) this.deindexAddresses(addressInterfaces.map(addr => addr.address)) } @@ -280,7 +275,7 @@ export default class WalletService { if (addressesWithEnvPrefix.length === 0) { return } - const addrs: string[] = (await AddressService.findByAddresses(addressesWithEnvPrefix)).map(addr => addr.address) + const addrs: string[] = AddressService.findByAddresses(addressesWithEnvPrefix).map(addr => addr.address) const deindexAddresses: string[] = addresses.filter(item => addrs.indexOf(item) < 0); // only deindex if no same wallet if (deindexAddresses.length !== 0) { @@ -362,7 +357,7 @@ export default class WalletService { const txHash = core.utils.rawTransactionToHash(ConvertTo.toSdkTxWithoutHash(tx)) - const addressInfos = await this.getAddressInfos(walletID) + const addressInfos = this.getAddressInfos(walletID) const paths = addressInfos.map(info => info.path) const pathAndPrivateKeys = this.getPrivateKeys(wallet, paths, password) const findPrivateKey = (blake160: string) => { @@ -459,12 +454,12 @@ export default class WalletService { fee: string = '0', feeRate: string = '0', ): Promise => { - const wallet = await this.get(walletID) + const wallet = this.get(walletID) if (!wallet) { throw new WalletNotFound(walletID) } - const addressInfos = await this.getAddressInfos(walletID) + const addressInfos = this.getAddressInfos(walletID) const addresses: string[] = addressInfos.map(info => info.address) @@ -475,7 +470,7 @@ export default class WalletService { capacity: BigInt(item.capacity).toString(), })) - const changeAddress: string = await this.getChangeAddress() + const changeAddress: string = this.getChangeAddress() const tx: TransactionWithoutHash = await TransactionGenerator.generateTx( lockHashes, @@ -494,20 +489,20 @@ export default class WalletService { fee: string = '0', feeRate: string = '0', ): Promise => { - const wallet = await this.get(walletID) + const wallet = this.get(walletID) if (!wallet) { throw new WalletNotFound(walletID) } - const addressInfos = await this.getAddressInfos(walletID) + const addressInfos = this.getAddressInfos(walletID) const addresses: string[] = addressInfos.map(info => info.address) const lockHashes: string[] = new LockUtils(await LockUtils.systemScript()).addressesToAllLockHashes(addresses) - const address = await AddressesService.nextUnusedAddress(walletID) + const address = AddressesService.nextUnusedAddress(walletID) - const changeAddress: string = await this.getChangeAddress() + const changeAddress: string = this.getChangeAddress() const tx = await TransactionGenerator.generateDepositTx( lockHashes, @@ -527,7 +522,7 @@ export default class WalletService { fee: string = '0', feeRate: string = '0' ): Promise => { - const wallet = await this.get(walletID) + const wallet = this.get(walletID) if (!wallet) { throw new WalletNotFound(walletID) } @@ -543,7 +538,7 @@ export default class WalletService { throw new TransactionIsNotCommittedYet() } - const addressInfos = await this.getAddressInfos(walletID) + const addressInfos = this.getAddressInfos(walletID) const addresses: string[] = addressInfos.map(info => info.address) @@ -772,12 +767,12 @@ export default class WalletService { } public computeCycles = async (walletID: string = '', capacities: string): Promise => { - const wallet = await this.get(walletID) + const wallet = this.get(walletID) if (!wallet) { throw new WalletNotFound(walletID) } - const addressInfos = await this.getAddressInfos(walletID) + const addressInfos = this.getAddressInfos(walletID) const addresses: string[] = addressInfos.map(info => info.address) @@ -790,7 +785,7 @@ export default class WalletService { } // path is a BIP44 full path such as "m/44'/309'/0'/0/0" - public getAddressInfos = async (walletID: string): Promise => { + public getAddressInfos = (walletID: string): AddressInterface[] => { const wallet = this.get(walletID) if (!wallet) { throw new WalletNotFound(walletID) @@ -798,10 +793,9 @@ export default class WalletService { return AddressService.allAddressesByWalletId(walletID) } - public getChangeAddress = async (): Promise => { + public getChangeAddress = (): string => { const walletId = this.getCurrent()!.id - const addr = await AddressService.nextUnusedChangeAddress(walletId) - return addr!.address + return AddressService.nextUnusedChangeAddress(walletId)!.address } public signWitness = ( diff --git a/packages/neuron-wallet/src/startup/sync-block-task/create.ts b/packages/neuron-wallet/src/startup/sync-block-task/create.ts index a3220e1a12..1c856cbe84 100644 --- a/packages/neuron-wallet/src/startup/sync-block-task/create.ts +++ b/packages/neuron-wallet/src/startup/sync-block-task/create.ts @@ -12,7 +12,7 @@ import DataUpdateSubject from 'models/subjects/data-update' export { genesisBlockHash } const updateAllAddressesTxCount = async (url: string) => { - const addresses = (await AddressService.allAddresses()).map(addr => addr.address) + const addresses = AddressService.allAddresses().map(addr => addr.address) await AddressService.updateTxCountAndBalances(addresses, url) } diff --git a/packages/neuron-wallet/src/startup/sync-block-task/indexer.ts b/packages/neuron-wallet/src/startup/sync-block-task/indexer.ts index cb1331ba7c..87f4b91b62 100644 --- a/packages/neuron-wallet/src/startup/sync-block-task/indexer.ts +++ b/packages/neuron-wallet/src/startup/sync-block-task/indexer.ts @@ -2,7 +2,7 @@ import { remote } from 'electron' import AddressService from 'services/addresses' import LockUtils from 'models/lock-utils' import IndexerQueue, { LockHashInfo } from 'services/indexer/queue' -import { Address } from 'database/address/dao' +import { Address } from 'database/address/address-dao' import initConnection from 'database/chain/ormconfig' import ChainInfo from 'models/chain-info' @@ -12,7 +12,7 @@ const { nodeService, addressCreatedSubject, walletCreatedSubject } = remote.requ // maybe should call this every time when new address generated // load all addresses and convert to lockHashes export const loadAddressesAndConvert = async (nodeURL: string): Promise => { - const addresses: string[] = (await AddressService.allAddresses()).map(addr => addr.address) + const addresses: string[] = AddressService.allAddresses().map(addr => addr.address) const lockUtils = new LockUtils(await LockUtils.loadSystemScript(nodeURL)) return lockUtils.addressesToAllLockHashes(addresses) } diff --git a/packages/neuron-wallet/src/startup/sync-block-task/sync.ts b/packages/neuron-wallet/src/startup/sync-block-task/sync.ts index decb81948f..fdac5e0682 100644 --- a/packages/neuron-wallet/src/startup/sync-block-task/sync.ts +++ b/packages/neuron-wallet/src/startup/sync-block-task/sync.ts @@ -2,7 +2,7 @@ import { remote } from 'electron' import AddressService from 'services/addresses' import LockUtils from 'models/lock-utils' import BlockListener from 'services/sync/block-listener' -import { Address } from 'database/address/dao' +import { Address } from 'database/address/address-dao' import initConnection from 'database/chain/ormconfig' import ChainInfo from 'models/chain-info' @@ -21,7 +21,7 @@ export interface LockHashInfo { // load all addresses and convert to lockHashes export const loadAddressesAndConvert = async (nodeURL: string): Promise => { const lockUtils = new LockUtils(await LockUtils.systemScript(nodeURL)) - const addresses = (await AddressService.allAddresses()).map(addr => addr.address) + const addresses = AddressService.allAddresses().map(addr => addr.address) return lockUtils.addressesToAllLockHashes(addresses) } diff --git a/packages/neuron-wallet/src/startup/sync-block-task/task.ts b/packages/neuron-wallet/src/startup/sync-block-task/task.ts index 9b7d4abc98..31c0226e0f 100644 --- a/packages/neuron-wallet/src/startup/sync-block-task/task.ts +++ b/packages/neuron-wallet/src/startup/sync-block-task/task.ts @@ -1,5 +1,4 @@ import { remote } from 'electron' -import { initConnection as initAddressConnection } from 'database/address/ormconfig' import AddressesUsedSubject from 'models/subjects/addresses-used-subject' import { register as registerTxStatusListener } from 'listeners/tx-status' import { register as registerAddressListener } from 'listeners/address' @@ -31,7 +30,6 @@ export const testIndexer = async (url: string): Promise => { } export const run = async () => { - await initAddressConnection() databaseInitSubject.subscribe(async (params: DatabaseInitParams) => { const { network, genesisBlockHash, chain } = params if (network && genesisBlockHash.startsWith('0x')) { diff --git a/packages/neuron-wallet/tests/database/address/balance.test.ts b/packages/neuron-wallet/tests/database/address/balance.test.ts index 3abb13f16f..15811932de 100644 --- a/packages/neuron-wallet/tests/database/address/balance.test.ts +++ b/packages/neuron-wallet/tests/database/address/balance.test.ts @@ -1,21 +1,9 @@ -import AddressEntity, { AddressVersion } from '../../../src/database/address/entities/address' import { AddressType } from '../../../src/models/keys/address' -import initConnection, { getConnection } from '../../../src/database/address/ormconfig' -import AddressDao, { Address } from '../../../src/database/address/dao' +import AddressDao, { Address, AddressVersion } from '../../../src/database/address/address-dao' describe('balance', () => { - beforeAll(async () => { - await initConnection() - }) - - afterAll(async () => { - await getConnection().close() - }) - - beforeEach(async () => { - const connection = getConnection() - await connection.dropDatabase() - await connection.synchronize() + beforeEach(() => { + AddressDao.deleteAll() }) const generateAddress = ( @@ -43,24 +31,24 @@ describe('balance', () => { it('balance = live + sent - pending', async () => { const address = generateAddress('1000', '100', '300') - const addrs: AddressEntity[] = await AddressDao.create([address]) + const addrs: Address[] = await AddressDao.create([address]) const addr = addrs[0] - expect(addr.balance()).toEqual((1000 + 100).toString()) + expect(addr.balance).toEqual((1000 + 100).toString()) }) it('the balance returned by the toInterface() is correct', async () => { const address = generateAddress('1000', '100', '300') - const addrs: AddressEntity[] = await AddressDao.create([address]) + const addrs: Address[] = AddressDao.create([address]) const addr = addrs[0] - expect(addr.toInterface().balance).toEqual((1000 + 100).toString()) + expect(addr.balance).toEqual((1000 + 100).toString()) }) it('sent to others', async () => { // have 1000, sent to others 200, and refund 800 const addresses = [generateAddress('0', '0', '1000'), generateAddress('0', '800', '0')] - const addrs: AddressEntity[] = await AddressDao.create(addresses) - const balance: bigint = addrs.map(addr => BigInt(addr.balance())).reduce((result, c) => result + c, BigInt(0)) + const addrs: Address[] = await AddressDao.create(addresses) + const balance: bigint = addrs.map(addr => BigInt(addr.balance)).reduce((result, c) => result + c, BigInt(0)) expect(balance).toEqual(BigInt(800)) }) @@ -72,8 +60,8 @@ describe('balance', () => { generateAddress('0', '200', '0'), generateAddress('0', '800', '0'), ] - const addrs: AddressEntity[] = await AddressDao.create(addresses) - const balance: bigint = addrs.map(addr => BigInt(addr.balance())).reduce((result, c) => result + c, BigInt(0)) + const addrs: Address[] = await AddressDao.create(addresses) + const balance: bigint = addrs.map(addr => BigInt(addr.balance)).reduce((result, c) => result + c, BigInt(0)) expect(balance).toEqual(BigInt(1000)) }) @@ -82,8 +70,8 @@ describe('balance', () => { // have 1000, sent to others 200, and refund 790, with 10 shannon fee const addresses = [generateAddress('0', '0', '1000'), generateAddress('0', '790', '0')] - const addrs: AddressEntity[] = await AddressDao.create(addresses) - const balance: bigint = addrs.map(addr => BigInt(addr.balance())).reduce((result, c) => result + c, BigInt(0)) + const addrs: Address[] = await AddressDao.create(addresses) + const balance: bigint = addrs.map(addr => BigInt(addr.balance)).reduce((result, c) => result + c, BigInt(0)) expect(balance).toEqual(BigInt(790)) }) @@ -96,8 +84,8 @@ describe('balance', () => { generateAddress('0', '790', '0'), ] - const addrs: AddressEntity[] = await AddressDao.create(addresses) - const balance: bigint = addrs.map(addr => BigInt(addr.balance())).reduce((result, c) => result + c, BigInt(0)) + const addrs: Address[] = await AddressDao.create(addresses) + const balance: bigint = addrs.map(addr => BigInt(addr.balance)).reduce((result, c) => result + c, BigInt(0)) expect(balance).toEqual(BigInt(990)) }) diff --git a/packages/neuron-wallet/tests/database/address/dao.test.ts b/packages/neuron-wallet/tests/database/address/dao.test.ts index 2f05b462d5..5044459f74 100644 --- a/packages/neuron-wallet/tests/database/address/dao.test.ts +++ b/packages/neuron-wallet/tests/database/address/dao.test.ts @@ -1,7 +1,5 @@ -import AddressEntity, { AddressVersion } from '../../../src/database/address/entities/address' import { AddressType } from '../../../src/models/keys/address' -import initConnection, { getConnection } from '../../../src/database/address/ormconfig' -import AddressDao, { Address } from '../../../src/database/address/dao' +import AddressDao, { Address, AddressVersion } from '../../../src/database/address/address-dao' describe('Address Dao tests', () => { const address: Address = { @@ -49,27 +47,14 @@ describe('Address Dao tests', () => { version: AddressVersion.Testnet, } - beforeAll(async () => { - await initConnection() + beforeEach(() => { + AddressDao.deleteAll() }) - afterAll(async () => { - await getConnection().close() - }) - - beforeEach(async () => { - const connection = getConnection() - await connection.dropDatabase() - await connection.synchronize() - }) - - it('create', async () => { - await AddressDao.create([address]) + it('create', () => { + AddressDao.create([address]) - const all = await getConnection() - .getRepository(AddressEntity) - .createQueryBuilder('address') - .getMany() + const all = AddressDao.getAll() expect(all.length).toEqual(1) expect(all[0].address).toEqual(address.address) @@ -89,64 +74,64 @@ describe('Address Dao tests', () => { // expect(dao.txCount).toEqual(getCountByAddress) // }) - it('nextUnusedAddress', async () => { - await AddressDao.create([address, usedAddress]) + it('nextUnusedAddress', () => { + AddressDao.create([address, usedAddress]) - const addr = await AddressDao.nextUnusedAddress('1', AddressVersion.Testnet) + const addr = AddressDao.nextUnusedAddress('1', AddressVersion.Testnet) expect(addr!.address).toEqual(address.address) - const usedAddr = await AddressDao.nextUnusedAddress('2', AddressVersion.Testnet) + const usedAddr = AddressDao.nextUnusedAddress('2', AddressVersion.Testnet) expect(usedAddr).toBe(undefined) - const mainnetAddr = await AddressDao.nextUnusedAddress('1', AddressVersion.Mainnet) + const mainnetAddr = AddressDao.nextUnusedAddress('1', AddressVersion.Mainnet) expect(mainnetAddr).toBe(undefined) }) - it('nextUnusedChangeAddress', async () => { - await AddressDao.create([address, usedAddress, changeAddress]) + it('nextUnusedChangeAddress', () => { + AddressDao.create([address, usedAddress, changeAddress]) - const addr = await AddressDao.nextUnusedChangeAddress('1', AddressVersion.Testnet) + const addr = AddressDao.nextUnusedChangeAddress('1', AddressVersion.Testnet) expect(addr!.address).toEqual(changeAddress.address) - const usedAddr = await AddressDao.nextUnusedAddress('2', AddressVersion.Testnet) + const usedAddr = AddressDao.nextUnusedAddress('2', AddressVersion.Testnet) expect(usedAddr).toBe(undefined) - const mainnetAddr = await AddressDao.nextUnusedAddress('1', AddressVersion.Mainnet) + const mainnetAddr = AddressDao.nextUnusedAddress('1', AddressVersion.Mainnet) expect(mainnetAddr).toBe(undefined) }) - it('allAddresses', async () => { - await AddressDao.create([address, usedAddress]) + it('allAddresses', () => { + AddressDao.create([address, usedAddress]) - const all = await AddressDao.allAddresses(AddressVersion.Testnet) + const all = AddressDao.allAddresses(AddressVersion.Testnet) - const allMainnet = await AddressDao.allAddresses(AddressVersion.Mainnet) + const allMainnet = AddressDao.allAddresses(AddressVersion.Mainnet) expect(all.length).toEqual(2) expect(allMainnet.length).toEqual(0) }) - it('allAddressesByWalletId', async () => { - await AddressDao.create([address, usedAddress]) + it('allAddressesByWalletId', () => { + AddressDao.create([address, usedAddress]) - const all = await AddressDao.allAddressesByWalletId('1', AddressVersion.Testnet) + const all = AddressDao.allAddressesByWalletId('1', AddressVersion.Testnet) expect(all.length).toEqual(1) }) - it('usedAddressByWalletId', async () => { - await AddressDao.create([address, usedAddress]) + it('usedAddressByWalletId', () => { + AddressDao.create([address, usedAddress]) - const walletOne = await AddressDao.usedAddressesByWalletId('1', AddressVersion.Testnet) + const walletOne = AddressDao.usedAddressesByWalletId('1', AddressVersion.Testnet) expect(walletOne.length).toEqual(0) - const walletTwo = await AddressDao.usedAddressesByWalletId('2', AddressVersion.Testnet) + const walletTwo = AddressDao.usedAddressesByWalletId('2', AddressVersion.Testnet) expect(walletTwo.length).toEqual(1) }) - it('findByAddress', async () => { - await AddressDao.create([address, usedAddress]) + it('findByAddress', () => { + AddressDao.create([address, usedAddress]) - const one = await AddressDao.findByAddress(address.address, address.walletId) + const one = AddressDao.findByAddress(address.address, address.walletId) expect(one!.address).toEqual(address.address) }) diff --git a/packages/neuron-wallet/tests/services/address.test.ts b/packages/neuron-wallet/tests/services/address.test.ts index 2fae0cdda5..a06ff9be13 100644 --- a/packages/neuron-wallet/tests/services/address.test.ts +++ b/packages/neuron-wallet/tests/services/address.test.ts @@ -1,7 +1,5 @@ import AddressService from '../../src/services/addresses' -import initConnection, { getConnection } from '../../src/database/address/ormconfig' -import AddressEntity, { AddressVersion } from '../../src/database/address/entities/address' -import AddressDao, { Address } from '../../src/database/address/dao' +import AddressDao, { Address, AddressVersion } from '../../src/database/address/address-dao' import { AddressType } from '../../src/models/keys/address' import { AccountExtendedPublicKey } from '../../src/models/keys/key' @@ -88,117 +86,98 @@ describe('Key tests with db', () => { version: AddressVersion.Testnet, } - beforeAll(async () => { - await initConnection() + beforeEach(() => { + AddressDao.deleteAll() }) - afterAll(async () => { - await getConnection().close() - }) - - beforeEach(async () => { - const connection = getConnection() - await connection.dropDatabase() - await connection.synchronize() - }) - - const generate = async (id: string = walletId) => { - await AddressService.generateAndSave(id, extendedKey, undefined, 0, 0, 2, 1) + const generate = (id: string = walletId) => { + AddressService.generateAndSave(id, extendedKey, undefined, 0, 0, 2, 1) } - const checkAndGenerate = async (id: string = walletId) => { - await AddressService.checkAndGenerateSave(id, extendedKey, undefined, 2, 1) + const checkAndGenerate = (id: string = walletId) => { + AddressService.checkAndGenerateSave(id, extendedKey, undefined, 2, 1) } - it('generateAndSave', async () => { - await generate() + it('generateAndSave', () => { + generate() - const all = await getConnection() - .getRepository(AddressEntity) - .createQueryBuilder('address') - .getMany() + const all = AddressDao.getAll() expect(all.length).toEqual((2 + 1) * 2) }) - it('checkAndGenerateSave', async () => { - await generate() + it('checkAndGenerateSave', () => { + generate() - const all = await getConnection() - .getRepository(AddressEntity) - .createQueryBuilder('address') - .getMany() + const all = AddressDao.getAll() const usedAll = all - .filter(one => one.addressType === AddressType.Receiving) .map(one => { - const entity = one - entity.txCount = 1 - return entity + if (one.addressType === AddressType.Receiving) { + const entity = one + entity.txCount = 1 + return entity + } else { + return one + } }) - await getConnection().manager.save(usedAll) + AddressDao.updateAll(usedAll) - await checkAndGenerate() + checkAndGenerate() - const final = await getConnection() - .getRepository(AddressEntity) - .createQueryBuilder('address') - .getMany() + const final = AddressDao.getAll() expect(final.length).toEqual((2 + 1) * 2 * 2) }) - it('generateAndSave with two wallet', async () => { - await generate() - await generate('2') - const all = await getConnection() - .getRepository(AddressEntity) - .createQueryBuilder('address') - .getMany() + it('generateAndSave with two wallet', () => { + generate() + generate('2') + const all = AddressDao.getAll() expect(all.length).toEqual((2 + 1) * 2 * 2) }) - it('isAddressUsed', async () => { - await AddressDao.create([address, usedAddress]) - const used = await AddressService.isAddressUsed(address.address, walletId) + it('isAddressUsed', () => { + AddressDao.create([address, usedAddress]) + const used = AddressService.isAddressUsed(address.address, walletId) expect(used).toBe(true) }) - it('nextUnusedAddress', async () => { - await AddressDao.create([address, usedAddress, changeAddress]) - const addr = await AddressService.nextUnusedAddress(walletId) - const addrDao = await AddressDao.nextUnusedAddress(walletId, AddressVersion.Testnet) - expect(addr).toEqual(addrDao && addrDao.toInterface()) + it('nextUnusedAddress', () => { + AddressDao.create([address, usedAddress, changeAddress]) + const addr = AddressService.nextUnusedAddress(walletId) + const addrDao = AddressDao.nextUnusedAddress(walletId, AddressVersion.Testnet) + expect(addr).toEqual(addrDao) }) - it('nextUnusedChangeAddress', async () => { - await AddressDao.create([address, usedAddress, changeAddress]) - const addr = await AddressService.nextUnusedChangeAddress(walletId) - const addrDao = await AddressDao.nextUnusedChangeAddress(walletId, AddressVersion.Testnet) - expect(addr).toEqual(addrDao && addrDao.toInterface()) + it('nextUnusedChangeAddress', () => { + AddressDao.create([address, usedAddress, changeAddress]) + const addr = AddressService.nextUnusedChangeAddress(walletId) + const addrDao = AddressDao.nextUnusedChangeAddress(walletId, AddressVersion.Testnet) + expect(addr).toEqual(addrDao) }) - it('allAddresses', async () => { - await generate() - await generate('2') - const all = await AddressService.allAddresses() + it('allAddresses', () => { + generate() + generate('2') + const all = AddressService.allAddresses() expect(all.length).toEqual(6) }) - it('allAddressesByWalletId', async () => { - await generate() - await generate('2') - const all = await AddressService.allAddressesByWalletId(walletId) + it('allAddressesByWalletId', () => { + generate() + generate('2') + const all = AddressService.allAddressesByWalletId(walletId) expect(all.length).toEqual(3) }) - it('usedAddress', async () => { - await AddressDao.create([address, usedAddress]) + it('usedAddress', () => { + AddressDao.create([address, usedAddress]) - const addr = await AddressService.usedAddresses(walletId) + const addr = AddressService.usedAddresses(walletId) expect(addr).toEqual([]) - const addr2 = await AddressService.usedAddresses('2') + const addr2 = AddressService.usedAddresses('2') expect(addr2).not.toEqual([]) }) }) diff --git a/packages/neuron-wallet/tests/services/wallets.test.ts b/packages/neuron-wallet/tests/services/wallets.test.ts index 81c01a53a5..0478b44101 100644 --- a/packages/neuron-wallet/tests/services/wallets.test.ts +++ b/packages/neuron-wallet/tests/services/wallets.test.ts @@ -3,13 +3,6 @@ import Keystore from '../../src/models/keys/keystore' import Keychain from '../../src/models/keys/keychain' import { mnemonicToSeedSync } from '../../src/models/keys/mnemonic' import { ExtendedPrivateKey, AccountExtendedPublicKey } from '../../src/models/keys/key' -import AddressService from '../../src/services/addresses' - -const mockDeleteAddressByWalletId = () => { - const mockDeleteAddress = jest.fn() - mockDeleteAddress.mockReturnValue(undefined) - AddressService.deleteByWalletId = mockDeleteAddress.bind(AddressService) -} describe('wallet service', () => { let walletService: WalletService @@ -121,7 +114,6 @@ describe('wallet service', () => { }) it('delete wallet', () => { - mockDeleteAddressByWalletId() const w1 = walletService.create(wallet1) walletService.create(wallet2) expect(walletService.getAll().length).toBe(2) @@ -154,7 +146,6 @@ describe('wallet service', () => { }) it('delete current wallet', () => { - mockDeleteAddressByWalletId() const w1 = walletService.create(wallet1) const w2 = walletService.create(wallet2) walletService.delete(w1.id) @@ -164,7 +155,6 @@ describe('wallet service', () => { }) it('delete none current wallet', () => { - mockDeleteAddressByWalletId() const w1 = walletService.create(wallet1) const w2 = walletService.create(wallet2) walletService.delete(w2.id)