Socket
Socket
Sign inDemoInstall

eth-dcent-keyring

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

eth-dcent-keyring - npm Package Compare versions

Comparing version 0.1.3 to 0.2.0

237

index.js
const { EventEmitter } = require('events')
const { TransactionFactory } = require('@ethereumjs/tx')
const ethUtil = require('ethereumjs-util')
const Transaction = require('ethereumjs-tx')
const DcentConnector = require('dcent-web-connector')
const { getFullPath, getCoinType } = require('./scripts/util')

@@ -10,7 +9,11 @@ const DefaultKeyPathString = `m/44'/60'/0'/0/0`

const DCENT_TIMEOUT = 60000
const DcentResult = require('./dcent-result')
const DcentResult = {
SUCCESS: 'success',
ERROR: 'error',
}
let LOG
if (process.env.NODE_ENV !== 'production') {
LOG = console.log.bind(console, '[LOG]')
// LOG = console.log.bind(console, '[LOG]')
LOG = () => {}
} else {

@@ -20,2 +23,64 @@ LOG = () => {}

const splitPath = path => {
return path.split('/').filter(item => item.trim() !== '')
}
const hardenedIdx = [1, 2, 3]
const isHardened = idx => {
return hardenedIdx.includes(idx)
}
const getFullPath = (path, idx) => {
const pieces = splitPath(path)
let fullpath = 'm'
for (let i = 1; i < 6; i++) {
if (i < pieces.length) {
fullpath += `/${pieces[i]}`
} else if (i === pieces.length) {
fullpath += `/${idx}`
} else {
fullpath += `/0`
}
if (isHardened(i) && !fullpath.endsWith("'")) {
fullpath += "'"
}
}
return fullpath
}
const coinType = DcentConnector.coinType
const getCoinType = path => {
let type
switch (/m\/44'\/(\d+)'/g.exec(path)[1]) {
case '0':
type = coinType.BITCOIN
break
case '1':
type = coinType.BITCOIN_TESTNET
break
case '60':
type = coinType.ETHEREUM
break
case '137':
type = coinType.RSK
break
case '144':
type = coinType.RIPPLE
break
case '22':
type = coinType.MONACOIN
break
case '8217':
type = coinType.KLAYTN
break
default:
throw new Error('Not Supported path')
}
return type
}
function isOldStyleEthereumjsTx (tx) {
return typeof tx.getChainId === 'function'
}
class DcentKeyring extends EventEmitter {

@@ -168,5 +233,42 @@ constructor (opts = {}) {

signTransaction (address, tx) {
const txObj = this._generateTxObj(tx)
LOG('signTransaction - address', address)
LOG('signTransaction - tx', txObj)
if (isOldStyleEthereumjsTx(tx)) { // old style transaction
tx.v = ethUtil.bufferToHex(tx.getChainId())
tx.r = '0x00'
tx.s = '0x00'
return this._signTransaction(address, tx.getChainId(), tx)
}
return this._signTransaction(
address,
tx.common.chainIdBN().toNumber(),
tx
)
}
_signTransaction (address, chainId, tx) {
let transaction
if (isOldStyleEthereumjsTx(tx)) {
// legacy transaction from ethereumjs-tx package has no .toJSON() function,
// so we need to convert to hex-strings manually manually
transaction = {
to: this._normalize(tx.to),
value: this._normalize(tx.value),
data: this._normalize(tx.data),
chainId,
nonce: this._normalize(tx.nonce),
gasLimit: this._normalize(tx.gasLimit),
gasPrice: this._normalize(tx.gasPrice),
}
} else {
transaction = {
...tx.toJSON(),
chainId,
to: this._normalize(tx.to),
}
}
transaction.nonce = (transaction.nonce === '0x') ? '0x0' : transaction.nonce
transaction.value = (transaction.value === '0x') ? '0x0' : transaction.value
return new Promise((resolve, reject) => {

@@ -177,22 +279,36 @@ this.unlock()

this.coinType,
txObj.nonce,
txObj.gasPrice,
txObj.gasLimit,
txObj.to,
txObj.value,
txObj.data,
transaction.nonce,
transaction.gasPrice,
transaction.gasLimit,
transaction.to,
transaction.value,
transaction.data,
this.path, // key path
txObj.chainId
transaction.chainId
).then((response) => {
LOG('response - ', response)
if (response.header.status === DcentResult.SUCCESS) {
tx.v = response.body.parameter.sign_v
tx.r = response.body.parameter.sign_r
tx.s = response.body.parameter.sign_s
const signedTx = new Transaction(tx)
const parameter = response.body.parameter
const signedBuffer = Buffer.from(parameter.signed, 'hex')
const tempTx = TransactionFactory.fromSerializedData(signedBuffer)
const addressSignedWith = ethUtil.toChecksumAddress(`0x${signedTx.from.toString('hex')}`)
let signedTx = tx
if (isOldStyleEthereumjsTx(tx)) {
signedTx.v = Buffer.from(ethUtil.stripHexPrefix(parameter.sign_v), 'hex')
signedTx.r = Buffer.from(ethUtil.stripHexPrefix(parameter.sign_r), 'hex')
signedTx.s = Buffer.from(ethUtil.stripHexPrefix(parameter.sign_s), 'hex')
} else {
signedTx = tempTx
}
const addressSignedWith = ethUtil.toChecksumAddress(
ethUtil.addHexPrefix(
tempTx.getSenderAddress().toString('hex'),
),
)
const correctAddress = ethUtil.toChecksumAddress(address)
if (addressSignedWith !== correctAddress) {
reject(new Error('signature doesnt match the right address'))
reject(new Error("signature doesn't match the right address"))
}
LOG('signedTx - ', signedTx)
resolve(signedTx)

@@ -204,4 +320,5 @@ } else if (response.body.error) {

}
}).catch((e) => {
if (e.body.error) {
if (e && e.body && e.body.error) {
reject(new Error(`${e.body.error.code} - ${e.body.error.message}`))

@@ -222,2 +339,3 @@ } else {

})
}

@@ -272,3 +390,40 @@

// Waiting on dcent to enable this
return Promise.reject(new Error('Not supported on this device'))
LOG('signPersonalMessage - withAccount', withAccount)
LOG('signTypedData - typedData', typedData)
return new Promise((resolve, reject) => {
this.unlock()
.then((_) => {
DcentConnector.getEthereumSignedTypedData(
typedData,
this.path
).then((response) => {
if (response.header.status === DcentResult.SUCCESS) {
if (response.body.parameter.address !== ethUtil.toChecksumAddress(withAccount)) {
reject(new Error('signature doesnt match the right address'))
}
resolve(response.body.parameter.sign)
} else if (response.body.error) {
reject(new Error(`${response.body.error.code} - ${response.body.error.message}`))
} else {
reject(new Error(`Unknown error - ${response}`))
}
}).catch((e) => {
if (e.body.error) {
reject(new Error(`${e.body.error.code} - ${e.body.error.message}`))
} else {
reject(new Error(`Unknown error - ${e}`))
}
}).finally((_) => {
DcentConnector.popupWindowClose()
})
}).catch((e) => {
if (e && e.body && e.body.error) {
reject(new Error(`${e.body.error.code} - ${e.body.error.message}`))
} else {
reject(new Error(`Unknown error - ${e}`))
}
})
})
}

@@ -289,15 +444,2 @@

/* PRIVATE METHODS */
_generateTxObj (tx) {
const txObj = {}
txObj.nonce = this._normalize(tx.nonce)
txObj.nonce = (txObj.nonce === '0x') ? '0x0' : txObj.nonce
txObj.gasPrice = this._normalize(tx.gasPrice)
txObj.gasLimit = this._normalize(tx.gasLimit)
txObj.to = this._normalize(tx.to)
txObj.value = this._normalize(tx.value)
txObj.value = (txObj.value === '0x') ? '0x0' : txObj.value
txObj.data = this._normalize(tx.data)
txObj.chainId = tx._chainId
return txObj
}

@@ -308,27 +450,2 @@ _normalize (buf) {

// _addressFromIndex (pathBase, i) {
// const dkey = this.hdk.derive(`${pathBase}/${i}`)
// const address = ethUtil
// .publicToAddress(dkey.publicKey, true)
// .toString('hex')
// return ethUtil.toChecksumAddress(address)
// }
// _pathFromAddress (address) {
// const checksummedAddress = ethUtil.toChecksumAddress(address)
// let index = this.paths[checksummedAddress]
// if (typeof index === 'undefined') {
// for (let i = 0; i < MAX_INDEX; i++) {
// if (checksummedAddress === this._addressFromIndex(pathBase, i)) {
// index = i
// break
// }
// }
// }
// if (typeof index === 'undefined') {
// throw new Error('Unknown address')
// }
// return `${this.hdPath}/${index}`
// }
}

@@ -335,0 +452,0 @@

{
"name": "eth-dcent-keyring",
"version": "0.1.3",
"version": "0.2.0",
"description": "A MetaMask compatible keyring, for D'CENT hardware wallets",
"main": "index.js",
"files": [
"index.js"
],
"scripts": {
"test": "npm run lint && mocha",
"test": "yarn lint && mocha",
"lint": "./node_modules/.bin/eslint . --ext .js",

@@ -32,9 +35,8 @@ "lint:fix": "./node_modules/.bin/eslint --fix . --ext .js"

"dependencies": {
"dcent-web-connector": "^0.8.2",
"eth-sig-util": "^1.4.2",
"ethereumjs-tx": "^1.3.4",
"ethereumjs-util": "^5.1.5",
"events": "^2.0.0"
"@ethereumjs/tx": "3.2.1",
"ethereumjs-util": "7.0.9",
"dcent-web-connector": "^0.10.5"
},
"devDependencies": {
"@lavamoat/allow-scripts": "^1.0.6",
"assert": "^1.4.1",

@@ -49,4 +51,8 @@ "babel-eslint": "^8.0.0",

"eslint-plugin-mocha": "^5.0.0",
"ethereumjs-tx": "^1.3.4",
"mocha": "^5.0.4"
},
"engines": {
"node": ">=12.0.0"
}
}

@@ -7,6 +7,13 @@ # eth-dcent-keyring

- Because the keys are stored in the device, operations that rely on the device will fail if there is no D'CENT device attached, or a different D'CENT device is attached.
- It does not support `signTypedData` or `exportAccount` methods, because D'CENT devices do not support these operations.
- It does not support `exportAccount` methods, because D'CENT devices do not support these operations.
- It works the firmware version 1.3.0+ for D'CENT Biometric device
- It returns only one account.
## Install
Run the following command:
```
yarn add eth-dcent-keyring
```
## Testing

@@ -16,3 +23,5 @@ Run the following command:

```
npm run test
yarn
yarn test
```

@@ -19,0 +28,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc