New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

eth-lattice-keyring

Package Overview
Dependencies
Maintainers
1
Versions
76
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

eth-lattice-keyring - npm Package Compare versions

Comparing version 0.4.9 to 0.5.0

194

index.js

@@ -48,2 +48,4 @@ const crypto = require('crypto');

this.page = opts.page;
if (opts.sdkState)
this.sdkState = opts.sdkState;
return Promise.resolve()

@@ -57,3 +59,2 @@ }

serialize() {
this.triedConnection = false;
return Promise.resolve({

@@ -70,2 +71,5 @@ creds: this.creds,

hdPath: this.hdPath,
sdkState: this.sdkSession ?
this.sdkSession.getStateData() :
null
})

@@ -77,7 +81,13 @@ }

isUnlocked () {
return !!this._getCurrentWalletUID()
return !!this._getCurrentWalletUID() && !!this.sdkSession;
}
// Initialize a session with the Lattice1 device using the GridPlus SDK
unlock() {
// NOTE: `bypassOnStateData=true` allows us to rehydrate a new SDK session without
// reconnecting to the target Lattice. This is only currently used for signing
// because it eliminates the need for 2 connection requests and shaves off ~4-6sec.
// We avoid passing `bypassOnStateData=true` for other calls on `unlock` to avoid
// possible edge cases related to this new functionality (it's probably fine - just
// being cautious). In the future we may remove `bypassOnStateData` entirely.
unlock(bypassOnStateData=false) {
return new Promise((resolve, reject) => {

@@ -96,6 +106,6 @@ // Force compatability. `this.accountOpts` were added after other

if (this.isUnlocked()) {
if (this.isUnlocked() && !this.forceReconnect) {
return resolve('Unlocked');
}
this._getCreds()

@@ -110,3 +120,8 @@ .then((creds) => {

})
.then(() => {
.then((includedStateData) => {
// If state data was provided and if we are authorized to
// bypass reconnecting, we can exit here.
if (includedStateData && bypassOnStateData) {
return resolve('Unlocked');
}
return this._connect();

@@ -171,35 +186,3 @@ })

getAccounts() {
return new Promise((resolve, reject) => {
const accounts = this.accounts ? this.accounts.slice() : [].slice();
// Exit without connecting?
// * If we have no credentials, just return the accounts. It shouldn't be
// possible to have addresses without credentials, i.e. it should be an
// empty array.
// * If we have already tried to connect, we don't need to do it again --
// just return the accounts. Note that this proceeds regardless of the
// connection result. If the user's device is offline then the extension
// will still unlock but the device won't be reachable until it tries to
// connect again.
if (!this._hasCreds() || this.triedConnection) {
return resolve(accounts);
}
// Since this is called when the extension unlocks, we should make sure
// we have a connection with the user's Lattice. If no connection is found
// this will attempt to create one. The error will not be handled in this
// function because the user could have their Lattice unplugged and may
// want to use a different account on MetaMask.
this._ensureCurrentWalletUID()
.then(() => {
this.triedConnection = true;
return resolve(accounts);
})
.catch((err) => {
// Rather than throw an error here, we should still unlock the
// extension and return whatever accounts we currently have.
// If we threw an error, it would lock people out of the extension
// if they could not talk to their Lattice.
this.triedConnection = true;
return resolve(accounts);
})
})
return Promise.resolve(this.accounts ? this.accounts.slice() : [].slice());
}

@@ -301,3 +284,3 @@

})
return resolve(validatingTx)
return resolve(validatingTx);
})

@@ -340,14 +323,18 @@ .catch((err) => {

}
if (!this.isUnlocked())
return reject(new Error('No connection to Lattice. Could not send request.'));
this.sdkSession.sign(req, (err, res) => {
if (err)
if (err) {
return reject(new Error(err));
if (!res.sig)
}
if (!this._syncCurrentWalletUID()) {
return reject('No active wallet.');
}
if (!res.sig) {
return reject(new Error('No signature returned'));
}
// Convert the `v` to a number. It should convert to 0 or 1
try {
let v = res.sig.v.toString('hex');
if (v.length < 2)
if (v.length < 2) {
v = `0${v}`;
}
return resolve(`0x${res.sig.r}${res.sig.s}${v}`);

@@ -381,2 +368,9 @@ } catch (err) {

getFirstPage() {
// This function gets called after the user has connected to the Lattice.
// Update a state variable to force opening of the Lattice manager window.
// If we don't do this, MetaMask will automatically start requesting addresses,
// even if the device is not reachable.
// This way the user can close the window and connect accounts from other
// wallets instead of being forced into selecting Lattice accounts
this.forceReconnect = true;
this.page = 0;

@@ -409,6 +403,11 @@ return this._getPage(0);

return new Promise((resolve, reject) => {
this._ensureCurrentWalletUID()
// Unlock and get the wallet UID. We will bypass the reconnection
// step if we are able to rehydrate an SDK session with state data.
this.unlock(true)
.then(() => {
return this.getAccounts()
return this._ensureCurrentWalletUID();
})
.then(() => {
return this.getAccounts();
})
.then((addrs) => {

@@ -422,8 +421,4 @@ // Find the signer in our current set of accounts

})
if (accountIdx === null)
if (accountIdx === null) {
return reject('Signer not present');
// Make sure the account is associated with the current wallet
if (this.accountOpts[accountIdx].walletUID !== this._getCurrentWalletUID()) {
return reject(new Error('Account on a different wallet. ' +
'Please switch to the correct wallet on your Lattice.'));
}

@@ -534,5 +529,6 @@ return resolve(accountIdx);

// We only need to setup if we don't have a deviceID
if (this._hasCreds())
if (this._hasCreds() && !this.forceReconnect)
return resolve();
// Cancel the force reconnect, if applicable
this.forceReconnect = false;
// If we are not aware of what Lattice we should be talking to,

@@ -631,14 +627,8 @@ // we need to open a window that lets the user go through the

this.sdkSession.timeout = SDK_TIMEOUT;
if (err)
if (err) {
return reject(err);
// Save the current wallet UID
const activeWallet = this.sdkSession.getActiveWallet();
if (!activeWallet || !activeWallet.uid)
return reject(new Error('No active wallet'));
const newUID = activeWallet.uid.toString('hex');
// If we fetched a walletUID that does not match our current one,
// reset accounts and update the known UID
if (newUID != this.walletUID) {
this.walletUID = newUID;
}
if (!this._syncCurrentWalletUID()) {
return reject('No active wallet.');
}
return resolve();

@@ -658,12 +648,23 @@ });

url = this.creds.endpoint
const setupData = {
name: this.appName,
baseUrl: url,
crypto,
timeout: SDK_TIMEOUT,
privKey: this._genSessionKey(),
network: this.network
let setupData;
if (this.sdkState) {
// If we have state data we can fully rehydrate the session.
setupData = {
stateData: this.sdkState
}
} else {
// If we have no state data, we need to create a session.
// Its state will be saved once the connection is established.
setupData = {
name: this.appName,
baseUrl: url,
timeout: SDK_TIMEOUT,
privKey: this._genSessionKey(),
network: this.network,
}
}
this.sdkSession = new SDK.Client(setupData);
return resolve();
// Return a boolean indicating whether we provided state data.
// If we have, we can skip `connect`.
return resolve(!!setupData.stateData);
} catch (err) {

@@ -677,10 +678,10 @@ return reject(err);

return new Promise((resolve, reject) => {
if (!this.isUnlocked())
if (!this.isUnlocked()) {
return reject('No connection to Lattice. Cannot fetch addresses.')
}
this.__fetchAddresses(n, i, (err, addrs) => {
if (err)
if (err) {
return reject(err);
else
return resolve(addrs);
}
return resolve(addrs);
})

@@ -708,5 +709,9 @@ })

return cb(err);
if (!this._syncCurrentWalletUID()) {
return cb(new Error('No active wallet.'));
}
// Sanity check -- if this returned 0 addresses, handle the error
if (addrs.length < 1)
if (addrs.length < 1) {
return cb(new Error('No addresses returned'));
}
// Return the addresses we fetched *without* updating state

@@ -723,9 +728,12 @@ if (shouldRecurse) {

return new Promise((resolve, reject) => {
if (!this.isUnlocked())
return reject(new Error('No connection to Lattice. Cannot sign transaction.'));
this.sdkSession.sign({ currency: 'ETH', data: txData }, (err, res) => {
if (err)
if (err) {
return reject(err);
if (!res.tx)
}
if (!this._syncCurrentWalletUID()) {
return reject('No active wallet.');
}
if (!res.tx) {
return reject(new Error('No transaction payload returned.'));
}
// Here we catch an edge case where the requester is asking for an EIP1559

@@ -817,8 +825,26 @@ // transaction but firmware is not updated to support it. We fallback to legacy.

_getCurrentWalletUID() {
return this.walletUID || null;
}
// The SDK has an auto-retry mechanism for all requests if a "wrong wallet"
// error gets thrown. In such a case, the SDK will re-connect to the device to
// find the new wallet UID and will then save that UID to memory and will retry
// the original request with that new wallet UID.
// Therefore, we should sync the walletUID with `this.walletUID` after each
// SDK request. This is a synchronous and fast operation.
_syncCurrentWalletUID() {
if (!this.sdkSession) {
return null;
} else if (!this.sdkSession.getActiveWallet()) {
}
const activeWallet = this.sdkSession.getActiveWallet();
if (!activeWallet || !activeWallet.uid) {
return null;
}
return this.sdkSession.getActiveWallet().uid.toString('hex');
const newUID = activeWallet.uid.toString('hex');
// If we fetched a walletUID that does not match our current one,
// reset accounts and update the known UID
if (newUID != this.walletUID) {
this.walletUID = newUID;
}
return this.walletUID;
}

@@ -825,0 +851,0 @@

{
"name": "eth-lattice-keyring",
"version": "0.4.9",
"version": "0.5.0",
"description": "Keyring for connecting to the Lattice1 hardware wallet",

@@ -24,4 +24,4 @@ "main": "index.js",

"ethereumjs-util": "^7.0.10",
"gridplus-sdk": "^0.9.7"
"gridplus-sdk": "^1.0.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