{t('messages.wallet-is-not-found')}
+{t(`messages.codes.${ErrorCode.FieldNotFound}`, { fieldName: 'wallet' })}
{`${t('navbar.settings')}-${t('settings.setting-tabs.wallets')}`} @@ -33,6 +33,7 @@ const WalletEditor = ({ const [t] = useTranslation() const wallet = useMemo(() => wallets.find(w => w.id === id), [id, wallets]) || { id: '', name: '' } + const usedNames = wallets.map(w => w.name).filter(n => n !== wallet.name) const editor = useWalletEditor() const { initialize } = editor @@ -42,7 +43,7 @@ const WalletEditor = ({ }, [id, initialize, wallet.name]) const inputs = useInputs(editor) - const areParamsValid = useAreParamsValid(editor.name.value) + const hint = useHint(editor.name.value, usedNames, t) const onConfirm = useOnConfirm(editor.name.value, wallet.id, history, dispatch) const goBack = useGoBack(history) @@ -56,13 +57,17 @@ const WalletEditor = ({ {
+ type: MessageType
timestamp: number
- content: string
- meta?: { [key: string]: string }
+ code?: Code
+ content?: string
+ meta?: Meta
}
interface Send {
txID: string
diff --git a/packages/neuron-ui/src/utils/const.ts b/packages/neuron-ui/src/utils/const.ts
index 1dfa352b08..ad02db9781 100644
--- a/packages/neuron-ui/src/utils/const.ts
+++ b/packages/neuron-ui/src/utils/const.ts
@@ -1,4 +1,5 @@
export const MAX_NETWORK_NAME_LENGTH = 28
+export const MAX_WALLET_NAME_LENGTH = 20
export const ADDRESS_LENGTH = 46
export const MIN_PASSWORD_LENGTH = 8
export const MAX_PASSWORD_LENGTH = 50
@@ -49,20 +50,6 @@ export const PlaceHolders = {
},
}
-export enum Message {
- NameRequired = 'messages.name-required',
- URLRequired = 'messages.url-required',
- LengthOfNameShouldBeLessThanOrEqualTo = 'messages.length-of-name-should-be-less-than-or-equal-to',
- NetworkNameUsed = 'messages.network-name-used',
- AtLeastOneAddressNeeded = 'messages.at-least-one-address-needed',
- InvalidAddress = 'messages.invalid-address',
- InvalidAmount = 'messages.invalid-amount',
- DecimalExceed = 'messages.amount-decimal-exceed',
- IsUnremovable = 'messages.is-unremovable',
- ProtocolRequired = 'messages.protocol-required',
- AmountTooSmall = 'messages.amount-too-small',
-}
-
export enum MnemonicAction {
Create = 'create',
Verify = 'verify',
@@ -77,3 +64,26 @@ export const FULL_SCREENS = [
`${Routes.WalletEditor}/`,
`${Routes.NetworkEditor}/`,
]
+
+export enum ErrorCode {
+ // Errors from RPC
+ ErrorFromRPC = -3,
+ // Errors from neuron-wallet
+ AmountNotEnough = 100,
+ AmountTooSmall = 101,
+ // Parameter validation errors from neuron-ui
+ FieldRequired = 201,
+ FieldUsed = 202,
+ FieldTooLong = 203,
+ FieldTooShort = 204,
+ FieldInvalid = 205,
+ DecimalExceed = 206,
+ NotNegative = 207,
+ ProtocolRequired = 208,
+ NoWhiteSpaces = 209,
+ FieldIrremovable = 301,
+ FailToLaunch = 302,
+ FieldNotFound = 303,
+ CameraUnavailable = 304,
+ AddressIsEmpty = 305,
+}
diff --git a/packages/neuron-ui/src/utils/formatters.ts b/packages/neuron-ui/src/utils/formatters.ts
index e178b94cd5..a1baa6241a 100644
--- a/packages/neuron-ui/src/utils/formatters.ts
+++ b/packages/neuron-ui/src/utils/formatters.ts
@@ -163,7 +163,7 @@ export const addressesToBalance = (addresses: State.Address[] = []) => {
.toString()
}
-export const outputsToTotalCapacity = (outputs: { amount: string; unit: CapacityUnit }[]) => {
+export const outputsToTotalAmount = (outputs: { amount: string; unit: CapacityUnit }[]) => {
const totalCapacity = outputs.reduce((total, cur) => {
if (Number.isNaN(+cur.amount)) {
return total
@@ -173,6 +173,16 @@ export const outputsToTotalCapacity = (outputs: { amount: string; unit: Capacity
return totalCapacity.toString()
}
+export const failureResToNotification = (res: any): State.Message => {
+ return {
+ type: 'alert',
+ timestamp: +new Date(),
+ code: res.status,
+ content: typeof res.message !== 'string' ? res.message.content : res.message,
+ meta: typeof res.message !== 'string' ? res.message.meta : undefined,
+ }
+}
+
export default {
queryFormatter,
currencyFormatter,
@@ -182,5 +192,6 @@ export default {
uniformTimeFormatter,
priceToFee,
addressesToBalance,
- outputsToTotalCapacity,
+ outputsToTotalAmount,
+ failureResToNotification,
}
diff --git a/packages/neuron-ui/src/utils/validators.ts b/packages/neuron-ui/src/utils/validators.ts
index 0f9667d913..cccd918f54 100644
--- a/packages/neuron-ui/src/utils/validators.ts
+++ b/packages/neuron-ui/src/utils/validators.ts
@@ -1,23 +1,44 @@
+import { MAX_NETWORK_NAME_LENGTH } from 'utils/const'
+/* global BigInt */
import { ckbCore } from 'services/chain'
-import { ADDRESS_LENGTH, MIN_PASSWORD_LENGTH, MAX_PASSWORD_LENGTH, MIN_AMOUNT } from './const'
+import { MIN_PASSWORD_LENGTH, MAX_PASSWORD_LENGTH, MIN_AMOUNT, MAX_DECIMAL_DIGITS, ErrorCode } from './const'
-export const verifyAddress = (address: string): boolean | string => {
- // TODO: verify address, prd required
+export const verifyAddress = (address: string): boolean => {
try {
- if (address.length !== ADDRESS_LENGTH) {
- throw new Error('Address length is incorrect')
- }
ckbCore.utils.parseAddress(address)
return true
} catch (err) {
- return err.message
+ return false
}
}
-export const verifyAmountRange = (amount: string) => {
+export const verifyAmountRange = (amount: string = '') => {
return +amount >= MIN_AMOUNT
}
+export const verifyAmount = (amount: string = '0') => {
+ if (Number.isNaN(+amount)) {
+ return { code: ErrorCode.FieldInvalid }
+ }
+ if (+amount < 0) {
+ return { code: ErrorCode.NotNegative }
+ }
+ const [, decimal = ''] = amount.split('.')
+ if (decimal.length > MAX_DECIMAL_DIGITS) {
+ return {
+ code: ErrorCode.DecimalExceed,
+ }
+ }
+ return true
+}
+
+export const verifyTotalAmount = (totalAmount: string, fee: string, balance: string) => {
+ if (+balance < 0) {
+ return false
+ }
+ return BigInt(totalAmount) + BigInt(fee) <= BigInt(balance)
+}
+
export const verifyPasswordComplexity = (password: string) => {
if (!password) {
return 'password-is-empty'
@@ -51,8 +72,61 @@ export const verifyPasswordComplexity = (password: string) => {
return true
}
+export const verifyTransactionOutputs = (items: { address: string; amount: string }[] = []) => {
+ return !items.some(item => {
+ if (item.address === '' || verifyAddress(item.address) !== true) {
+ return true
+ }
+ if (verifyAmount(item.amount) !== true || verifyAmountRange(item.amount) !== true) {
+ return true
+ }
+ return false
+ })
+}
+
+export const verifyNetworkName = (name: string, usedNames: string[]) => {
+ if (!name) {
+ return {
+ code: ErrorCode.FieldRequired,
+ }
+ }
+ if (usedNames.includes(name)) {
+ return {
+ code: ErrorCode.FieldUsed,
+ }
+ }
+ if (name.length > MAX_NETWORK_NAME_LENGTH) {
+ return {
+ code: ErrorCode.FieldTooLong,
+ }
+ }
+ return true
+}
+
+export const verifyURL = (url: string) => {
+ if (!url) {
+ return {
+ code: ErrorCode.FieldRequired,
+ }
+ }
+ if (!/^https?:\/\//.test(url)) {
+ return {
+ code: ErrorCode.ProtocolRequired,
+ }
+ }
+ if (/\s/.test(url)) {
+ return {
+ code: ErrorCode.NoWhiteSpaces,
+ }
+ }
+ return true
+}
+
export default {
verifyAddress,
verifyAmountRange,
+ verifyTotalAmount,
verifyPasswordComplexity,
+ verifyTransactionOutputs,
+ verifyNetworkName,
}
diff --git a/packages/neuron-ui/src/widgets/QRScanner/index.tsx b/packages/neuron-ui/src/widgets/QRScanner/index.tsx
index e2b3fcc942..067963af32 100644
--- a/packages/neuron-ui/src/widgets/QRScanner/index.tsx
+++ b/packages/neuron-ui/src/widgets/QRScanner/index.tsx
@@ -14,6 +14,7 @@ import jsQR from 'jsqr'
import { showErrorMessage } from 'services/remote'
import { drawPolygon } from 'utils/canvasActions'
import { verifyAddress } from 'utils/validators'
+import { ErrorCode } from 'utils/const'
interface QRScannerProps {
title: string
@@ -100,7 +101,7 @@ const QRScanner = ({ title, label, onConfirm, styles }: QRScannerProps) => {
requestAnimationFrame(tick)
})
.catch((err: Error) => {
- showErrorMessage(t('messages.camera-not-available-or-disabled'), err.message)
+ showErrorMessage(t(`messages.codes.${ErrorCode.CameraUnavailable}`), err.message)
setOpen(false)
})
}, [video, t, onConfirm, onDismiss])
diff --git a/packages/neuron-wallet/package.json b/packages/neuron-wallet/package.json
index b5ee5b3a68..cef26d0bec 100644
--- a/packages/neuron-wallet/package.json
+++ b/packages/neuron-wallet/package.json
@@ -3,7 +3,7 @@
"productName": "Neuron",
"description": "CKB Neuron Wallet",
"homepage": "https://www.nervos.org/",
- "version": "0.18.0-beta.1",
+ "version": "0.19.0-beta.0",
"private": true,
"author": {
"name": "Nervos Core Dev",
@@ -34,8 +34,8 @@
]
},
"dependencies": {
- "@nervosnetwork/ckb-sdk-core": "0.18.0",
- "@nervosnetwork/ckb-sdk-utils": "0.18.0",
+ "@nervosnetwork/ckb-sdk-core": "0.19.0",
+ "@nervosnetwork/ckb-sdk-utils": "0.19.0",
"bn.js": "4.11.8",
"chalk": "2.4.2",
"electron-log": "3.0.7",
@@ -51,7 +51,7 @@
"uuid": "3.3.2"
},
"devDependencies": {
- "@nervosnetwork/ckb-types": "0.18.0",
+ "@nervosnetwork/ckb-types": "0.19.0",
"@types/electron-devtools-installer": "2.2.0",
"@types/elliptic": "6.4.8",
"@types/sqlite3": "3.1.5",
@@ -64,7 +64,7 @@
"electron-devtools-installer": "2.2.4",
"electron-notarize": "0.1.1",
"lint-staged": "9.2.0",
- "neuron-ui": "0.18.0-beta.1",
+ "neuron-ui": "0.19.0-beta.0",
"rimraf": "2.6.3",
"spectron": "8.0.0",
"ts-transformer-imports": "0.4.3",
diff --git a/packages/neuron-wallet/src/controllers/app/options.ts b/packages/neuron-wallet/src/controllers/app/options.ts
index 5e4a57fe5b..1d337d6b57 100644
--- a/packages/neuron-wallet/src/controllers/app/options.ts
+++ b/packages/neuron-wallet/src/controllers/app/options.ts
@@ -7,14 +7,6 @@ import i18n from 'utils/i18n'
import env from 'env'
import AppController from '.'
-export enum MenuCommand {
- ShowAbout = 'show-about',
- ShowPreferences = 'show-preferences',
- OpenNervosWebsite = 'open-nervos-website',
- OpenSourceCodeRepository = 'open-sourcecode-repository',
- SetUILocale = 'set-ui-language',
-}
-
export enum URL {
Preference = '/settings/general',
CreateWallet = '/wizard/mnemonic/create',
@@ -186,4 +178,4 @@ export const contextMenuTemplate: {
},
}
-export default { MenuCommand, URL }
+export default { URL }
diff --git a/packages/neuron-wallet/src/controllers/wallets/index.ts b/packages/neuron-wallet/src/controllers/wallets/index.ts
index 6fc3c95328..0f98884eb9 100644
--- a/packages/neuron-wallet/src/controllers/wallets/index.ts
+++ b/packages/neuron-wallet/src/controllers/wallets/index.ts
@@ -371,7 +371,7 @@ export default class WalletsController {
} catch (err) {
return {
status: ResponseCode.Fail,
- msg: `Error: "${err.message}"`,
+ message: `Error: "${err.message}"`,
}
}
}
@@ -391,7 +391,7 @@ export default class WalletsController {
} catch (err) {
return {
status: ResponseCode.Fail,
- msg: `Error: "${err.message}"`,
+ message: `Error: "${err.message}"`,
}
}
}
diff --git a/packages/neuron-wallet/src/database/chain/entities/input.ts b/packages/neuron-wallet/src/database/chain/entities/input.ts
index f0c5995cb0..7b4ba19234 100644
--- a/packages/neuron-wallet/src/database/chain/entities/input.ts
+++ b/packages/neuron-wallet/src/database/chain/entities/input.ts
@@ -1,5 +1,5 @@
import { Entity, BaseEntity, Column, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'
-import { OutPoint, Input as InputInterface, CellOutPoint } from 'types/cell-types'
+import { OutPoint, Input as InputInterface } from 'types/cell-types'
import Transaction from './transaction'
/* eslint @typescript-eslint/no-unused-vars: "warn" */
@@ -42,7 +42,7 @@ export default class Input extends BaseEntity {
})
capacity: string | null = null
- public cellOutPoint(): CellOutPoint | null {
+ public previousOutput(): OutPoint | null {
if (!this.outPointTxHash || !this.outPointIndex) {
return null
}
@@ -52,13 +52,6 @@ export default class Input extends BaseEntity {
}
}
- public previousOutput(): OutPoint {
- return {
- blockHash: null,
- cell: this.cellOutPoint(),
- }
- }
-
public toInterface(): InputInterface {
return {
previousOutput: this.previousOutput(),
diff --git a/packages/neuron-wallet/src/database/chain/entities/output.ts b/packages/neuron-wallet/src/database/chain/entities/output.ts
index 2fcf41d4a9..23e5606b53 100644
--- a/packages/neuron-wallet/src/database/chain/entities/output.ts
+++ b/packages/neuron-wallet/src/database/chain/entities/output.ts
@@ -1,5 +1,5 @@
import { Entity, BaseEntity, Column, PrimaryColumn, ManyToOne } from 'typeorm'
-import { Script, OutPoint, Cell, CellOutPoint } from 'types/cell-types'
+import { Script, OutPoint, Cell } from 'types/cell-types'
import TransactionEntity from './transaction'
/* eslint @typescript-eslint/no-unused-vars: "warn" */
@@ -35,20 +35,13 @@ export default class Output extends BaseEntity {
})
status!: string
- public cellOutPoint(): CellOutPoint {
+ public outPoint(): OutPoint {
return {
txHash: this.outPointTxHash,
index: this.outPointIndex,
}
}
- public outPoint(): OutPoint {
- return {
- blockHash: null,
- cell: this.cellOutPoint(),
- }
- }
-
@ManyToOne(_type => TransactionEntity, transaction => transaction.outputs, { onDelete: 'CASCADE' })
transaction!: TransactionEntity
diff --git a/packages/neuron-wallet/src/database/chain/entities/transaction.ts b/packages/neuron-wallet/src/database/chain/entities/transaction.ts
index 865825c048..ef3c763633 100644
--- a/packages/neuron-wallet/src/database/chain/entities/transaction.ts
+++ b/packages/neuron-wallet/src/database/chain/entities/transaction.ts
@@ -11,7 +11,7 @@ import {
AfterRemove,
} from 'typeorm'
import { remote } from 'electron'
-import { Witness, OutPoint, Transaction as TransactionInterface, TransactionStatus } from 'types/cell-types'
+import { Witness, Transaction as TransactionInterface, TransactionStatus, CellDep } from 'types/cell-types'
import TxDbChangedSubject from 'models/subjects/tx-db-changed-subject'
import InputEntity from './input'
import OutputEntity from './output'
@@ -37,7 +37,12 @@ export default class Transaction extends BaseEntity {
@Column({
type: 'simple-json',
})
- deps!: OutPoint[]
+ cellDeps: CellDep[] = []
+
+ @Column({
+ type: 'simple-json',
+ })
+ headerDeps: string[] = []
@Column({
type: 'simple-json',
@@ -101,7 +106,8 @@ export default class Transaction extends BaseEntity {
return {
hash: this.hash,
version: this.version,
- deps: this.deps,
+ cellDeps: this.cellDeps,
+ headerDeps: this.headerDeps,
inputs,
outputs,
timestamp: this.timestamp,
diff --git a/packages/neuron-wallet/src/database/chain/migrations/1562038960990-AddStatusToTx.ts b/packages/neuron-wallet/src/database/chain/migrations/1562038960990-AddStatusToTx.ts
deleted file mode 100644
index 233ab2c59c..0000000000
--- a/packages/neuron-wallet/src/database/chain/migrations/1562038960990-AddStatusToTx.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import {MigrationInterface, QueryRunner, TableColumn, getConnection, In} from "typeorm";
-import TransactionEntity from '../entities/transaction'
-import { OutputStatus } from '../../../services/tx/params'
-import { TransactionStatus } from '../../../types/cell-types'
-import OutputEntity from 'database/chain/entities/output'
-
-export class AddStatusToTx1562038960990 implements MigrationInterface {
-
- public async up(queryRunner: QueryRunner): Promise {
- // TransactionStatus.Success = 'success'
- await queryRunner.query(`ALTER TABLE 'transaction' ADD COLUMN 'status' varchar NOT NULL DEFAULT 'success';`)
-
- const pendingTxHashes: string[] = (await getConnection()
- .getRepository(OutputEntity)
- .createQueryBuilder('output')
- .select(`output.outPointTxHash`, 'txHash')
- .where({
- status: OutputStatus.Sent
- })
- .getRawMany())
- .filter(output => output.txHash)
- await getConnection()
- .createQueryBuilder()
- .update(TransactionEntity)
- .set({ status: TransactionStatus.Pending })
- .where({
- hash: In(pendingTxHashes)
- })
- .execute()
-
- await queryRunner.changeColumn('transaction', 'status', new TableColumn({
- name: 'status',
- type: 'varchar',
- }))
- }
-
- public async down(queryRunner: QueryRunner): Promise {
- await queryRunner.dropColumn('transaction', 'status')
- }
-
-}
diff --git a/packages/neuron-wallet/src/database/chain/migrations/1565693320664-AddConfirmed.ts b/packages/neuron-wallet/src/database/chain/migrations/1565693320664-AddConfirmed.ts
deleted file mode 100644
index 69448a80d7..0000000000
--- a/packages/neuron-wallet/src/database/chain/migrations/1565693320664-AddConfirmed.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import {MigrationInterface, QueryRunner} from "typeorm";
-
-export class AddConfirmed1565693320664 implements MigrationInterface {
-
- public async up(queryRunner: QueryRunner): Promise {
- await queryRunner.query(`ALTER TABLE 'transaction' ADD COLUMN 'confirmed' boolean NOT NULL DEFAULT false;`)
- }
-
- public async down(queryRunner: QueryRunner): Promise {
- await queryRunner.dropColumn('transaction', 'confirmed')
- }
-
-}
diff --git a/packages/neuron-wallet/src/database/chain/migrations/1561695143591-InitMigration.ts b/packages/neuron-wallet/src/database/chain/migrations/1566959757554-InitMigration.ts
similarity index 91%
rename from packages/neuron-wallet/src/database/chain/migrations/1561695143591-InitMigration.ts
rename to packages/neuron-wallet/src/database/chain/migrations/1566959757554-InitMigration.ts
index 211327651b..af467315d0 100644
--- a/packages/neuron-wallet/src/database/chain/migrations/1561695143591-InitMigration.ts
+++ b/packages/neuron-wallet/src/database/chain/migrations/1566959757554-InitMigration.ts
@@ -1,10 +1,10 @@
import {MigrationInterface, QueryRunner} from "typeorm";
-export class InitMigration1561695143591 implements MigrationInterface {
+export class InitMigration1566959757554 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise {
await queryRunner.query(`CREATE TABLE "output" ("outPointTxHash" varchar NOT NULL, "outPointIndex" varchar NOT NULL, "capacity" varchar NOT NULL, "lock" text NOT NULL, "lockHash" varchar NOT NULL, "status" varchar NOT NULL, "transactionHash" varchar, PRIMARY KEY ("outPointTxHash", "outPointIndex"))`);
- await queryRunner.query(`CREATE TABLE "transaction" ("hash" varchar PRIMARY KEY NOT NULL, "version" varchar NOT NULL, "deps" text NOT NULL, "witnesses" text NOT NULL, "timestamp" varchar, "blockNumber" varchar, "blockHash" varchar, "description" varchar, "createdAt" varchar NOT NULL, "updatedAt" varchar NOT NULL)`);
+ await queryRunner.query(`CREATE TABLE "transaction" ("hash" varchar PRIMARY KEY NOT NULL, "version" varchar NOT NULL, "cellDeps" text NOT NULL, "headerDeps" text NOT NULL, "witnesses" text NOT NULL, "timestamp" varchar, "blockNumber" varchar, "blockHash" varchar, "description" varchar, "status" varchar NOT NULL, "createdAt" varchar NOT NULL, "updatedAt" varchar NOT NULL, "confirmed" boolean NOT NULL)`);
await queryRunner.query(`CREATE TABLE "input" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "outPointTxHash" varchar, "outPointIndex" varchar, "since" varchar NOT NULL, "lockHash" varchar, "capacity" varchar, "transactionHash" varchar)`);
await queryRunner.query(`CREATE TABLE "sync_info" ("name" varchar PRIMARY KEY NOT NULL, "value" varchar NOT NULL)`);
await queryRunner.query(`CREATE TABLE "temporary_output" ("outPointTxHash" varchar NOT NULL, "outPointIndex" varchar NOT NULL, "capacity" varchar NOT NULL, "lock" text NOT NULL, "lockHash" varchar NOT NULL, "status" varchar NOT NULL, "transactionHash" varchar, CONSTRAINT "FK_29236a0eb11fac458990882f985" FOREIGN KEY ("transactionHash") REFERENCES "transaction" ("hash") ON DELETE CASCADE ON UPDATE NO ACTION, PRIMARY KEY ("outPointTxHash", "outPointIndex"))`);
diff --git a/packages/neuron-wallet/src/database/chain/ormconfig.ts b/packages/neuron-wallet/src/database/chain/ormconfig.ts
index 98f2d75937..d7732905f5 100644
--- a/packages/neuron-wallet/src/database/chain/ormconfig.ts
+++ b/packages/neuron-wallet/src/database/chain/ormconfig.ts
@@ -9,10 +9,7 @@ import Transaction from './entities/transaction'
import Input from './entities/input'
import Output from './entities/output'
import SyncInfo from './entities/sync-info'
-
-import { InitMigration1561695143591 } from './migrations/1561695143591-InitMigration'
-import { AddStatusToTx1562038960990 } from './migrations/1562038960990-AddStatusToTx'
-import { AddConfirmed1565693320664 } from './migrations/1565693320664-AddConfirmed'
+import { InitMigration1566959757554 } from './migrations/1566959757554-InitMigration'
export const CONNECTION_NOT_FOUND_NAME = 'ConnectionNotFoundError'
@@ -32,7 +29,7 @@ const connectOptions = async (genesisBlockHash: string): Promise {
- const salt = crypto.randomBytes(32)
- const iv = crypto.randomBytes(16)
- const params = {
- n: 8192,
- r: 8,
- p: 1,
- }
+ static create = (
+ extendedPrivateKey: ExtendedPrivateKey,
+ password: string,
+ options: { salt?: Buffer; iv?: Buffer } = {}
+ ) => {
+ const salt = options.salt || crypto.randomBytes(32)
+ const iv = options.iv || crypto.randomBytes(16)
const kdfparams: KdfParams = {
dklen: 32,
salt: salt.toString('hex'),
- ...params,
+ n: 2 ** 18,
+ r: 8,
+ p: 1,
}
- const derivedKey: Buffer = crypto.scryptSync(Buffer.from(password), salt, kdfparams.dklen, {
- N: kdfparams.n,
- r: kdfparams.r,
- p: kdfparams.p,
- })
+ const derivedKey = crypto.scryptSync(password, salt, kdfparams.dklen, Keystore.scryptOptions(kdfparams))
const cipher = crypto.createCipheriv(CIPHER, derivedKey.slice(0, 16), iv)
if (!cipher) {
@@ -75,11 +72,6 @@ export default class Keystore {
cipher.update(Buffer.from(extendedPrivateKey.serialize(), 'hex')),
cipher.final(),
])
- const hash = new SHA3(256)
- const mac = hash
- .update(Buffer.concat([derivedKey.slice(16, 32), ciphertext]))
- .digest()
- .toString('hex')
return new Keystore(
{
@@ -90,7 +82,7 @@ export default class Keystore {
cipher: CIPHER,
kdf: 'scrypt',
kdfparams,
- mac,
+ mac: Keystore.mac(derivedKey, ciphertext),
},
uuid()
)
@@ -98,23 +90,9 @@ export default class Keystore {
// Decrypt and return serialized extended private key.
decrypt(password: string): string {
- const { kdfparams } = this.crypto
- const derivedKey: Buffer = crypto.scryptSync(
- Buffer.from(password),
- Buffer.from(kdfparams.salt, 'hex'),
- kdfparams.dklen,
- {
- N: kdfparams.n,
- r: kdfparams.r,
- p: kdfparams.p,
- }
- )
+ const derivedKey = this.derivedKey(password)
const ciphertext = Buffer.from(this.crypto.ciphertext, 'hex')
- const mac = new SHA3(256)
- .update(Buffer.concat([derivedKey.slice(16, 32), ciphertext]))
- .digest()
- .toString('hex')
- if (mac !== this.crypto.mac) {
+ if (Keystore.mac(derivedKey, ciphertext) !== this.crypto.mac) {
throw new IncorrectPassword()
}
const decipher = crypto.createDecipheriv(
@@ -130,22 +108,31 @@ export default class Keystore {
}
checkPassword = (password: string) => {
+ const derivedKey = this.derivedKey(password)
+ const ciphertext = Buffer.from(this.crypto.ciphertext, 'hex')
+ return Keystore.mac(derivedKey, ciphertext) === this.crypto.mac
+ }
+
+ derivedKey = (password: string) => {
const { kdfparams } = this.crypto
- const derivedKey: Buffer = crypto.scryptSync(
- Buffer.from(password),
+ return crypto.scryptSync(
+ password,
Buffer.from(kdfparams.salt, 'hex'),
kdfparams.dklen,
- {
- N: kdfparams.n,
- r: kdfparams.r,
- p: kdfparams.p,
- }
+ Keystore.scryptOptions(kdfparams)
)
- const ciphertext = Buffer.from(this.crypto.ciphertext, 'hex')
- const mac = new SHA3(256)
- .update(Buffer.concat([derivedKey.slice(16, 32), ciphertext]))
- .digest()
- .toString('hex')
- return mac === this.crypto.mac
+ }
+
+ static mac = (derivedKey: Buffer, ciphertext: Buffer) => {
+ return new Keccak(256).update(Buffer.concat([derivedKey.slice(16, 32), ciphertext])).digest('hex')
+ }
+
+ static scryptOptions = (kdfparams: KdfParams) => {
+ return {
+ N: kdfparams.n,
+ r: kdfparams.r,
+ p: kdfparams.p,
+ maxmem: 128 * (kdfparams.n + kdfparams.p + 2) * kdfparams.r,
+ }
}
}
diff --git a/packages/neuron-wallet/src/models/lock-utils.ts b/packages/neuron-wallet/src/models/lock-utils.ts
index 1c50517490..780eaf0dca 100644
--- a/packages/neuron-wallet/src/models/lock-utils.ts
+++ b/packages/neuron-wallet/src/models/lock-utils.ts
@@ -1,13 +1,15 @@
import NodeService from 'services/node'
import { OutPoint, Script, ScriptHashType } from 'types/cell-types'
import env from 'env'
-import { SystemScriptSubject } from './subjects/system-script'
+import ConvertTo from 'types/convert-to'
+import { SystemScriptSubject } from 'models/subjects/system-script'
const { core } = NodeService.getInstance()
export interface SystemScript {
codeHash: string
outPoint: OutPoint
+ hashType: ScriptHashType
}
const subscribed = (target: any, propertyName: string) => {
@@ -30,21 +32,16 @@ export default class LockUtils {
return this.systemScriptInfo
}
- const systemCell = await core.loadSystemCell()
+ const systemCell = await core.loadSecp256k1Dep()
let { codeHash } = systemCell
- const { outPoint } = systemCell
- let { blockHash } = outPoint
- let { txHash } = outPoint.cell
- const { index } = outPoint.cell
+ const { outPoint, hashType } = systemCell
+ let { txHash } = outPoint
+ const { index } = outPoint
if (!codeHash.startsWith('0x')) {
codeHash = `0x${codeHash}`
}
- if (!blockHash.startsWith('0x')) {
- blockHash = `0x${blockHash}`
- }
-
if (!txHash.startsWith('0x')) {
txHash = `0x${txHash}`
}
@@ -52,12 +49,10 @@ export default class LockUtils {
const systemScriptInfo = {
codeHash,
outPoint: {
- blockHash,
- cell: {
- txHash,
- index,
- },
+ txHash,
+ index,
},
+ hashType: hashType as ScriptHashType,
}
this.systemScriptInfo = systemScriptInfo
@@ -70,26 +65,21 @@ export default class LockUtils {
SystemScriptSubject.next({ codeHash: info.codeHash })
}
- // use SDK lockScriptToHash
- static lockScriptToHash = (lock: Script) => {
- const codeHash: string = lock!.codeHash!
- const args: string[] = lock.args!
- const { hashType } = lock
- // TODO: should support ScriptHashType.Type in the future
- const lockHash: string = core.utils.lockScriptToHash({
- codeHash,
- args,
- hashType,
- })
-
- if (lockHash.startsWith('0x')) {
- return lockHash
+ static computeScriptHash = async (script: Script): Promise => {
+ const ckbScript: CKBComponents.Script = ConvertTo.toSdkScript(script)
+ const hash: string = await (core.rpc as any).computeScriptHash(ckbScript)
+ if (!hash.startsWith('0x')) {
+ return `0x${hash}`
}
+ return hash
+ }
- return `0x${lockHash}`
+ // use SDK lockScriptToHash
+ static lockScriptToHash = async (lock: Script) => {
+ return LockUtils.computeScriptHash(lock)
}
- static async addressToLockScript(address: string, hashType: ScriptHashType = ScriptHashType.Data): Promise