-
-
Notifications
You must be signed in to change notification settings - Fork 50
bump eth-sig-util
version to 5.0.2, stop inheriting from eth-simple-keyring
#70
Changes from all commits
7647b42
003ca4f
58289d1
08e8583
06966d1
84a160e
5baae87
623290e
089278c
dadd8a8
d0c577e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,33 @@ | ||
const { hdkey } = require('ethereumjs-wallet'); | ||
const SimpleKeyring = require('@metamask/eth-simple-keyring'); | ||
const { keccak256 } = require('ethereum-cryptography/keccak'); | ||
const { | ||
stripHexPrefix, | ||
privateToPublic, | ||
publicToAddress, | ||
ecsign, | ||
arrToBufArr, | ||
} = require('@ethereumjs/util'); | ||
const bip39 = require('@metamask/scure-bip39'); | ||
const { wordlist } = require('@metamask/scure-bip39/dist/wordlists/english'); | ||
const { normalize } = require('@metamask/eth-sig-util'); | ||
const { | ||
concatSig, | ||
decrypt, | ||
getEncryptionPublicKey, | ||
normalize, | ||
personalSign, | ||
signTypedData, | ||
SignTypedDataVersion, | ||
} = require('@metamask/eth-sig-util'); | ||
|
||
// Options: | ||
const hdPathString = `m/44'/60'/0'/0`; | ||
const type = 'HD Key Tree'; | ||
|
||
class HdKeyring extends SimpleKeyring { | ||
class HdKeyring { | ||
/* PUBLIC METHODS */ | ||
constructor(opts = {}) { | ||
super(); | ||
this.type = type; | ||
this._wallets = []; | ||
this.deserialize(opts); | ||
} | ||
|
||
|
@@ -126,7 +141,130 @@ class HdKeyring extends SimpleKeyring { | |
); | ||
} | ||
|
||
/* PRIVATE METHODS */ | ||
/* BASE KEYRING METHODS */ | ||
|
||
// returns an address specific to an app | ||
async getAppKeyAddress(address, origin) { | ||
if (!origin || typeof origin !== 'string') { | ||
throw new Error(`'origin' must be a non-empty string`); | ||
} | ||
const wallet = this._getWalletForAccount(address, { | ||
withAppKeyOrigin: origin, | ||
}); | ||
const appKeyAddress = normalize( | ||
publicToAddress(wallet.publicKey).toString('hex'), | ||
); | ||
return appKeyAddress; | ||
} | ||
|
||
// exportAccount should return a hex-encoded private key: | ||
async exportAccount(address, opts = {}) { | ||
const wallet = this._getWalletForAccount(address, opts); | ||
return wallet.privateKey.toString('hex'); | ||
} | ||
|
||
// tx is an instance of the ethereumjs-transaction class. | ||
async signTransaction(address, tx, opts = {}) { | ||
const privKey = this._getPrivateKeyFor(address, opts); | ||
const signedTx = tx.sign(privKey); | ||
// Newer versions of Ethereumjs-tx are immutable and return a new tx object | ||
return signedTx === undefined ? tx : signedTx; | ||
} | ||
|
||
// For eth_sign, we need to sign arbitrary data: | ||
async signMessage(address, data, opts = {}) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like we dropped the |
||
const message = stripHexPrefix(data); | ||
const privKey = this._getPrivateKeyFor(address, opts); | ||
const msgSig = ecsign(Buffer.from(message, 'hex'), privKey); | ||
const rawMsgSig = concatSig(msgSig.v, msgSig.r, msgSig.s); | ||
return rawMsgSig; | ||
} | ||
|
||
// For personal_sign, we need to prefix the message: | ||
async signPersonalMessage(address, msgHex, opts = {}) { | ||
const privKey = this._getPrivateKeyFor(address, opts); | ||
const privateKey = Buffer.from(privKey, 'hex'); | ||
const sig = personalSign({ privateKey, data: msgHex }); | ||
return sig; | ||
} | ||
|
||
// For eth_decryptMessage: | ||
async decryptMessage(withAccount, encryptedData) { | ||
const wallet = this._getWalletForAccount(withAccount); | ||
const { privateKey } = wallet; | ||
const sig = decrypt({ privateKey, encryptedData }); | ||
return sig; | ||
} | ||
|
||
// personal_signTypedData, signs data along with the schema | ||
async signTypedData( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like the |
||
withAccount, | ||
typedData, | ||
opts = { version: SignTypedDataVersion.V1 }, | ||
) { | ||
// Treat invalid versions as "V1" | ||
const version = Object.keys(SignTypedDataVersion).includes(opts.version) | ||
? opts.version | ||
: SignTypedDataVersion.V1; | ||
|
||
const privateKey = this._getPrivateKeyFor(withAccount, opts); | ||
return signTypedData({ privateKey, data: typedData, version }); | ||
} | ||
|
||
removeAccount(address) { | ||
if ( | ||
!this._wallets | ||
.map((w) => normalize(w.getAddress().toString('hex'))) | ||
.includes(address.toLowerCase()) | ||
) { | ||
throw new Error(`Address ${address} not found in this keyring`); | ||
} | ||
|
||
this._wallets = this._wallets.filter( | ||
(w) => | ||
normalize(w.getAddress().toString('hex')) !== address.toLowerCase(), | ||
); | ||
} | ||
|
||
// get public key for nacl | ||
async getEncryptionPublicKey(withAccount, opts = {}) { | ||
const privKey = this._getPrivateKeyFor(withAccount, opts); | ||
const publicKey = getEncryptionPublicKey(privKey); | ||
return publicKey; | ||
} | ||
|
||
_getPrivateKeyFor(address, opts = {}) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Worth noting that this was renamed as well, to have an underscore |
||
if (!address) { | ||
throw new Error('Must specify address.'); | ||
} | ||
const wallet = this._getWalletForAccount(address, opts); | ||
return wallet.privateKey; | ||
} | ||
|
||
_getWalletForAccount(account, opts = {}) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Noting for other reviewers, this method has changed from returning a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like this change was what brought in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
yes good catch There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well actually we want to use |
||
const address = normalize(account); | ||
let wallet = this._wallets.find((w) => { | ||
return ( | ||
normalize(w.getAddress().toString('hex')) === address.toLowerCase() | ||
); | ||
}); | ||
if (!wallet) { | ||
throw new Error('HD Keyring - Unable to find matching address.'); | ||
} | ||
|
||
if (opts.withAppKeyOrigin) { | ||
const { privateKey } = wallet; | ||
const appKeyOriginBuffer = Buffer.from(opts.withAppKeyOrigin, 'utf8'); | ||
const appKeyBuffer = Buffer.concat([privateKey, appKeyOriginBuffer]); | ||
const appKeyPrivateKey = arrToBufArr(keccak256(appKeyBuffer, 256)); | ||
const appKeyPublicKey = privateToPublic(appKeyPrivateKey); | ||
wallet = { privateKey: appKeyPrivateKey, publicKey: appKeyPublicKey }; | ||
} | ||
|
||
return wallet; | ||
} | ||
|
||
/* PRIVATE / UTILITY METHODS */ | ||
|
||
/** | ||
* Sets appropriate properties for the keyring based on the given | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're dropping
EventEmitter
here as well.Seems appropriate, we aren't using any event emitter functionality here. Just noting it for the changelog.