Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fabo/cross network ledger #3338

Merged
merged 21 commits into from
Jan 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/fabo_cross-network-ledger
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[Added] [#3392](https://github.com/cosmos/lunie/issues/3392) Use Ledger across networks @faboweb
13 changes: 12 additions & 1 deletion config.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,16 @@ export default {
graphqlHost: graphql,

e2e: process.env.VUE_APP_E2E || false,
enableTxAPI: process.env.VUE_APP_ENABLE_TX_API === "true" || false
enableTxAPI: process.env.VUE_APP_ENABLE_TX_API === "true" || false,

bech32Prefixes: {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be received from the API. I will create an issue.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"cosmos-hub-mainnet": "cosmos",
"cosmos-hub-testnet": "cosmos",
"regen-testnet": "xrn:",
"regen-mainnet": "xrn:",
"terra-testnet": "terra",
"terra-mainnet": "terra",
"emoney-testnet": "emoney",
"emoney-mainnet": "emoney"
}
}
3 changes: 0 additions & 3 deletions src/ActionModal/components/ActionModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -700,9 +700,6 @@ export default {
this.submissionError = `${this.submissionErrorPrefix}: ${error.message}.`
this.trackEvent(`event`, `failed-submit`, this.title, error.message)
this.$apollo.queries.overview.refetch()
},
async connectLedger() {
await this.$store.dispatch(`connectLedgerApp`)
}
},
validations() {
Expand Down
2 changes: 1 addition & 1 deletion src/ActionModal/utils/ActionManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ function toMicroAtomString(amount) {
return String(uatoms(amount))
}

// // limitation of the block, so we pick the top 5 rewards and inform the user.
// limitation of the Ledger Nano S, so we pick the top 5 rewards and inform the user.
function getTop5RewardsValidators(bondDenom, rewards) {
// Compares the amount in a [address1, {denom: amount}] array
const byBalance = (a, b) => b.amount - a.amount
Expand Down
7 changes: 5 additions & 2 deletions src/components/common/AppMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ import TmBtn from "common/TmBtn"
import TmFormMsg from "common/TmFormMsg"
import { mapGetters, mapState } from "vuex"
import { atoms, viewDenom, shortDecimals } from "scripts/num.js"
import { showAddressOnLedger } from "scripts/ledger"
export default {
name: `app-menu`,
components: {
Expand All @@ -180,7 +181,8 @@ export default {
shortDecimals
},
data: () => ({
ledgerAddressError: undefined
ledgerAddressError: undefined,
showAddressOnLedgerFn: showAddressOnLedger
}),
computed: {
...mapState([`session`]),
Expand All @@ -202,10 +204,11 @@ export default {
async showAddressOnLedger() {
if (this.messageTimeout) {
clearTimeout(this.messageTimeout)
this.messageTimeout = undefined
}
this.ledgerAddressError = undefined
try {
await this.$store.dispatch("showAddressOnLedger")
await this.showAddressOnLedgerFn(this.network)
} catch (error) {
this.ledgerAddressError = error.message
this.messageTimeout = setTimeout(
Expand Down
7 changes: 5 additions & 2 deletions src/components/common/TmSessionHardware.vue
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,11 @@

<script>
import TmBtn from "common/TmBtn"
import { mapState } from "vuex"
import { mapState, mapGetters } from "vuex"
import HardwareState from "common/TmHardwareState"
import SessionFrame from "common/SessionFrame"
import { getAddressFromLedger } from "scripts/ledger"

export default {
name: `session-hardware`,
components: {
Expand All @@ -106,6 +108,7 @@ export default {
}),
computed: {
...mapState([`session`]),
...mapGetters({ networkId: `network` }),
submitCaption() {
return {
connect: "Sign In",
Expand All @@ -132,7 +135,7 @@ export default {
this.status = `detect`
this.address = null
try {
this.address = await this.$store.dispatch(`connectLedgerApp`)
this.address = await getAddressFromLedger(this.networkId)
this.$router.push(`/`)
} catch ({ message }) {
this.status = `connect`
Expand Down
16 changes: 0 additions & 16 deletions src/scripts/blocks-throttle.js

This file was deleted.

70 changes: 70 additions & 0 deletions src/scripts/ledger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import config from "src/../config"

function parseLedgerErrors(error) {
// TODO move this error rewrite into the ledger lib
/* istanbul ignore next: specific error rewrite */
if (error.message.trim().startsWith("Device is already open")) {
throw new Error(
"Something went wrong connecting to your Ledger. Please refresh your page and try again."
)
}
throw error
}

export const getAddressFromLedger = async network => {
const ledger = await getLedgerConnector(network)

try {
const address = await ledger.getCosmosAddress() // TODO this should become `getAddress` to also work for not Cosmos networks

return address
} catch (err) {
parseLedgerErrors(err)
} finally {
// cleanup. if we leave this open, the next connection will brake for HID
// TODO move this into the leder lib
ledger.cosmosApp.transport.close()
}
}

export async function showAddressOnLedger(network) {
const ledger = await getLedgerConnector(network)

try {
await ledger.confirmLedgerAddress()
} catch (err) {
parseLedgerErrors(err)
} finally {
// cleanup. if we leave this open, the next connection will brake for HID
// TODO move this into the leder lib
ledger.cosmosApp.transport.close()
}
}

async function getLedgerConnector(network) {
switch (network) {
case "cosmos-hub-mainnet":
case "cosmos-hub-testnet":
case "regen-testnet":
case "regen-mainnet":
case "terra-testnet":
case "terra-mainnet": {
const { default: Ledger } = await import("@lunie/cosmos-ledger")

const HDPATH = [44, 118, 0, 0, 0]
const ledger = new Ledger(
{
testModeAllowed: config.testModeAllowed
},
HDPATH,
config.bech32Prefixes[network]
)

return ledger
}
default:
throw new Error(
"Lunie doesn't support connecting to the Ledger for this network."
)
}
}
1 change: 0 additions & 1 deletion src/vuex/modules/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ export default opts => ({
notifications: require(`./notifications.js`).default(opts),
session: require(`./session.js`).default(opts),
keystore: require(`./keystore.js`).default(opts),
ledger: require(`./ledger.js`).default(opts),
extension: require(`./extension.js`).default(opts),
signup: require(`./signup.js`).default(opts),
recover: require(`./recover.js`).default(opts)
Expand Down
16 changes: 4 additions & 12 deletions src/vuex/modules/keystore.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { track } from "scripts/google-analytics"
import config from "src/../config"

export default () => {
const state = {
accounts: [],
error: null,
// import into state to be able to test easier
externals: {
track
track,
config
}
}

Expand Down Expand Up @@ -73,18 +75,8 @@ export default () => {
// creates a cosmos addres for the network desired
function getCosmosAddressCreator(network) {
return async seedPhrase => {
const bech32Prefixes = {
"cosmos-hub-mainnet": "cosmos",
"cosmos-hub-testnet": "cosmos",
"regen-testnet": "xrn:",
"regen-mainnet": "xrn:",
"terra-testnet": "terra",
"terra-mainnet": "terra",
"emoney-testnet": "emoney",
"emoney-mainnet": "emoney"
}
const { getNewWalletFromSeed } = await import("@lunie/cosmos-keys")
return getNewWalletFromSeed(seedPhrase, bech32Prefixes[network])
return getNewWalletFromSeed(seedPhrase, config.bech32Prefixes[network])
}
}

Expand Down
64 changes: 0 additions & 64 deletions src/vuex/modules/ledger.js

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -244,13 +244,6 @@ describe(`ActionModal`, () => {
expect(wrapper.find(`#password`).exists()).toBe(false)
})

it(`should dispatch connectLedgerApp`, () => {
const $store = { dispatch: jest.fn() }
const self = { $store }
ActionModal.methods.connectLedger.call(self)
expect($store.dispatch).toHaveBeenCalledWith(`connectLedgerApp`)
})

describe(`should show the action modal`, () => {
describe(`when user has logged in`, () => {
const signMethods = ["local", "ledger", "extension", "explore"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ describe(`UndelegationModal`, () => {
$store
},
propsData: {
sourceValidator: validator
sourceValidator: validator,
targetValidator: validator2
}
})
wrapper.setData({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ exports[`UndelegationModal should display undelegation modal form 1`] = `
notifymessage="[object Object]"
rewards=""
submissionerrorprefix="Unstaking failed"
targetvalidator="[object Object]"
title="Unstake"
transactiondata="[object Object]"
validate="function () { [native code] }"
Expand Down
29 changes: 22 additions & 7 deletions tests/unit/specs/components/common/AppMenu.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,21 +69,21 @@ describe(`AppMenu`, () => {

it(`shows a warning if showing address on Ledger fails`, async () => {
const self = {
$store: {
dispatch: jest.fn(() => Promise.reject(new Error("Expected Error")))
}
showAddressOnLedgerFn: jest.fn(() =>
Promise.reject(new Error("Expected Error"))
)
}
await AppMenu.methods.showAddressOnLedger.call(self)
expect(self.$store.dispatch).toHaveBeenCalledWith("showAddressOnLedger")
expect(self.showAddressOnLedgerFn).toHaveBeenCalled()
expect(self.ledgerAddressError).toBe("Expected Error")
})

it(`clears the warning if showing address on Ledger fails after a while`, async () => {
jest.useFakeTimers()
const self = {
$store: {
dispatch: jest.fn(() => Promise.reject(new Error("Expected Error")))
}
showAddressOnLedgerFn: jest.fn(() =>
Promise.reject(new Error("Expected Error"))
)
}
await AppMenu.methods.showAddressOnLedger.call(self)

Expand All @@ -92,4 +92,19 @@ describe(`AppMenu`, () => {

jest.useRealTimers()
})

it(`clears the warning timeout if user intents to show address on Ledger again`, async () => {
jest.useFakeTimers()
const self = {
showAddressOnLedgerFn: jest.fn(() =>
Promise.reject(new Error("Expected Error"))
)
}
await AppMenu.methods.showAddressOnLedger.call(self)
expect(self.messageTimeout).toBeDefined()
AppMenu.methods.showAddressOnLedger.call(self)
expect(self.messageTimeout).toBeUndefined()

jest.useRealTimers()
})
})
Loading