Skip to content

Commit 166ec41

Browse files
committed
app: UI fixes and translation
1 parent 7068d1d commit 166ec41

10 files changed

Lines changed: 100 additions & 32 deletions

File tree

src/app/lib/ledger.test.ts

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { DerivationPathLegacy, DerivationPathAdr8, Ledger, LedgerSigner } from './ledger'
1+
import { DerivationPathTypeLegacy, DerivationPathTypeAdr8, Ledger, LedgerSigner } from './ledger'
22
import OasisApp from '@oasisprotocol/ledger'
33
import { WalletError, WalletErrors } from 'types/errors'
44
import { Wallet, WalletType } from 'app/state/wallet/types'
@@ -18,34 +18,46 @@ describe('Ledger Library', () => {
1818
describe('Ledger', () => {
1919
it('enumerateAccounts should pass when Oasis App is open', async () => {
2020
mockAppIsOpen('Oasis')
21-
const accounts = Ledger.enumerateAccounts({} as any, DerivationPathLegacy, 0)
21+
const accounts = Ledger.enumerateAccounts({} as any, DerivationPathTypeLegacy, 0)
2222
await expect(accounts).resolves.toEqual([])
2323
})
2424
it('enumerateAccounts should pass when Oasis App is open', async () => {
2525
mockAppIsOpen('Oasis')
26-
const accounts = Ledger.enumerateAccounts({} as any, DerivationPathAdr8, 0)
26+
const accounts = Ledger.enumerateAccounts({} as any, DerivationPathTypeAdr8, 0)
2727
await expect(accounts).resolves.toEqual([])
2828
})
2929

3030
it('Should catch "Oasis App is not open"', async () => {
3131
mockAppIsOpen('BOLOS')
32-
const accountsMainMenu = Ledger.enumerateAccounts({} as any, DerivationPathLegacy, 0)
32+
const accountsMainMenu = Ledger.enumerateAccounts({} as any, DerivationPathTypeLegacy, 0)
3333
await expect(accountsMainMenu).rejects.toThrowError(WalletError)
3434
await expect(accountsMainMenu).rejects.toHaveProperty('type', WalletErrors.LedgerOasisAppIsNotOpen)
3535

3636
mockAppIsOpen('Ethereum')
37-
const accountsEth = Ledger.enumerateAccounts({} as any, DerivationPathLegacy, 0)
37+
const accountsEth = Ledger.enumerateAccounts({} as any, DerivationPathTypeLegacy, 0)
3838
await expect(accountsEth).rejects.toThrowError(WalletError)
3939
await expect(accountsEth).rejects.toHaveProperty('type', WalletErrors.LedgerOasisAppIsNotOpen)
4040
})
4141

42-
it('Should enumerate and return the accounts', async () => {
42+
it('Should enumerate and return adr8 accounts', async () => {
4343
mockAppIsOpen('Oasis')
4444
const pubKey: jest.Mock<any> = OasisApp.prototype.publicKey
4545
pubKey.mockResolvedValueOnce({ return_code: 0x9000, pk: Buffer.from(new Uint8Array([1, 2, 3])) })
4646
pubKey.mockResolvedValueOnce({ return_code: 0x9000, pk: Buffer.from(new Uint8Array([4, 5, 6])) })
4747

48-
const accounts = await Ledger.enumerateAccounts({} as any, DerivationPathLegacy, 2)
48+
const accounts = await Ledger.enumerateAccounts({} as any, DerivationPathTypeAdr8, 2)
49+
expect(accounts).toHaveLength(2)
50+
expect(accounts).toContainEqual({ path: [44, 474, 0], publicKey: new Uint8Array([1, 2, 3]) })
51+
expect(accounts).toContainEqual({ path: [44, 474, 1], publicKey: new Uint8Array([4, 5, 6]) })
52+
})
53+
54+
it('Should enumerate and return legacy accounts', async () => {
55+
mockAppIsOpen('Oasis')
56+
const pubKey: jest.Mock<any> = OasisApp.prototype.publicKey
57+
pubKey.mockResolvedValueOnce({ return_code: 0x9000, pk: Buffer.from(new Uint8Array([1, 2, 3])) })
58+
pubKey.mockResolvedValueOnce({ return_code: 0x9000, pk: Buffer.from(new Uint8Array([4, 5, 6])) })
59+
60+
const accounts = await Ledger.enumerateAccounts({} as any, DerivationPathTypeLegacy, 2)
4961
expect(accounts).toHaveLength(2)
5062
expect(accounts).toContainEqual({ path: [44, 474, 0, 0, 0], publicKey: new Uint8Array([1, 2, 3]) })
5163
expect(accounts).toContainEqual({ path: [44, 474, 0, 0, 1], publicKey: new Uint8Array([4, 5, 6]) })
@@ -56,7 +68,7 @@ describe('Ledger Library', () => {
5668
const pubKey: jest.Mock<any> = OasisApp.prototype.publicKey
5769
pubKey.mockResolvedValueOnce({ return_code: 0x6804 })
5870

59-
const accounts = Ledger.enumerateAccounts({} as any, DerivationPathLegacy)
71+
const accounts = Ledger.enumerateAccounts({} as any, DerivationPathTypeLegacy)
6072
await expect(accounts).rejects.toThrowError(WalletError)
6173
await expect(accounts).rejects.toHaveProperty('type', WalletErrors.LedgerCannotOpenOasisApp)
6274
})
@@ -66,7 +78,7 @@ describe('Ledger Library', () => {
6678
const pubKey: jest.Mock<any> = OasisApp.prototype.publicKey
6779
pubKey.mockResolvedValueOnce({ return_code: 0x6400 })
6880

69-
const accounts = Ledger.enumerateAccounts({} as any, DerivationPathLegacy)
81+
const accounts = Ledger.enumerateAccounts({} as any, DerivationPathTypeLegacy)
7082
await expect(accounts).rejects.toThrowError(WalletError)
7183
await expect(accounts).rejects.toHaveProperty('type', WalletErrors.LedgerAppVersionNotSupported)
7284
})
@@ -76,7 +88,7 @@ describe('Ledger Library', () => {
7688
const pubKey: jest.Mock<any> = OasisApp.prototype.publicKey
7789
pubKey.mockResolvedValueOnce({ return_code: -1, error_message: 'unknown dummy error' })
7890

79-
const accounts = Ledger.enumerateAccounts({} as any, DerivationPathLegacy)
91+
const accounts = Ledger.enumerateAccounts({} as any, DerivationPathTypeLegacy)
8092
await expect(accounts).rejects.toThrowError(WalletError)
8193
await expect(accounts).rejects.toThrow(/unknown dummy error/)
8294
await expect(accounts).rejects.toHaveProperty('type', WalletErrors.LedgerUnknownError)
@@ -116,7 +128,7 @@ describe('Ledger Library', () => {
116128

117129
const signer = new LedgerSigner({
118130
type: WalletType.Ledger,
119-
path: Ledger.mustGetPath(DerivationPathLegacy, 0),
131+
path: Ledger.mustGetPath(DerivationPathTypeAdr8, 0),
120132
publicKey: 'aabbcc',
121133
} as Wallet)
122134

src/app/lib/ledger.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { WalletError, WalletErrors } from 'types/errors'
55
import { hex2uint } from './helpers'
66
import type Transport from '@ledgerhq/hw-transport'
77

8-
export const DerivationPathAdr8 = 'adr8';
9-
export const DerivationPathLegacy = 'legacy';
8+
export const DerivationPathTypeAdr8 = 'adr8';
9+
export const DerivationPathTypeLegacy = 'legacy';
1010

1111
interface Response {
1212
return_code: number
@@ -39,9 +39,9 @@ const successOrThrow = (response: Response, message: string) => {
3939
export class Ledger {
4040
public static mustGetPath(pathType: string, i: number) {
4141
switch (pathType) {
42-
case DerivationPathAdr8:
42+
case DerivationPathTypeAdr8:
4343
return [44, 474, i];
44-
case DerivationPathLegacy:
44+
case DerivationPathTypeLegacy:
4545
return [44, 474, 0, 0, i];
4646
}
4747

src/app/pages/OpenWalletPage/Features/FromLedger/index.tsx

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { ErrorFormatter } from 'app/components/ErrorFormatter'
77
import { LedgerStepFormatter } from 'app/components/LedgerStepFormatter'
88
import { ResponsiveLayer } from 'app/components/ResponsiveLayer'
99
import { Account } from 'app/components/Toolbar/Features/AccountSelector'
10-
import { DerivationPathAdr8, DerivationPathLegacy } from 'app/lib/ledger'
10+
import { DerivationPathTypeAdr8, DerivationPathTypeLegacy } from 'app/lib/ledger'
1111
import { ledgerActions, useLedgerSlice } from 'app/state/ledger'
1212
import { selectLedger, selectSelectedLedgerAccounts } from 'app/state/ledger/selectors'
1313
import { LedgerAccount, LedgerStep } from 'app/state/ledger/types'
@@ -105,22 +105,37 @@ export function FromLedgerModal(props: FromLedgerModalProps) {
105105
const error = ledger.error
106106
const selectedAccounts = useSelector(selectSelectedLedgerAccounts)
107107
const dispatch = useDispatch()
108+
const [initDerivationPathType, derivationPathSetValue] = useState(DerivationPathTypeAdr8);
109+
110+
const derivationPathTypes = [
111+
{
112+
label: t('ledger.derivationPathType.adr8', 'ADR 8 derivation path'),
113+
value: DerivationPathTypeAdr8,
114+
},
115+
{
116+
label: t('ledger.derivationPathType.legacy', 'Legacy derivation path'),
117+
value: DerivationPathTypeLegacy,
118+
},
119+
];
108120

109121
const openAccounts = () => {
110122
dispatch(walletActions.openWalletsFromLedger(selectedAccounts))
111123
}
112124

125+
const onChangeDerivationPathType = (arg: any) => {
126+
derivationPathSetValue(arg.value)
127+
dispatch(ledgerActions.enumerateAccounts(arg.value))
128+
}
129+
113130
useEffect(() => {
114-
dispatch(ledgerActions.enumerateAccounts())
131+
dispatch(ledgerActions.enumerateAccounts(initDerivationPathType))
115132
return () => {
116133
dispatch(ledgerActions.clear())
117134
}
118135
}, [dispatch, ledgerActions])
119136

120137
const cancelDisabled = ledger.step === LedgerStep.Done || error ? false : true
121138
const confirmDisabled = ledger.step !== LedgerStep.Done || selectedAccounts.length === 0
122-
// TODO
123-
const [value, setValue] = useState('');
124139

125140
return (
126141
<ResponsiveLayer position="center" modal>
@@ -130,9 +145,12 @@ export function FromLedgerModal(props: FromLedgerModalProps) {
130145
</Heading>
131146
<Select
132147
id='DerivationPathSelect'
133-
options={[ DerivationPathAdr8, DerivationPathLegacy ]}
134-
value={DerivationPathAdr8}
135-
onChange={({ value: nextValue }) => setValue(nextValue)}
148+
labelKey="label"
149+
margin={{ bottom: 'small', top: 'none' }}
150+
onChange={onChangeDerivationPathType}
151+
options={derivationPathTypes}
152+
value={initDerivationPathType}
153+
valueKey={{ key: 'value', reduce: true }}
136154
/>
137155
{ledger.step && ledger.step !== LedgerStep.Done && (
138156
<Box direction="row" gap="medium" alignContent="center">

src/app/state/ledger/index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ const slice = createSlice({
1313
reducers: {
1414
clear(state, action: PayloadAction<void>) {
1515
state.accounts = []
16+
state.derivationPathType = undefined
1617
state.error = undefined
1718
},
18-
enumerateAccounts(state, action: PayloadAction<void>) {
19+
enumerateAccounts(state, action: PayloadAction<string>) {
1920
state.step = undefined
21+
state.derivationPathType = action.payload
2022
state.accounts = []
2123
},
2224
toggleAccount(state, action: PayloadAction<number>) {
@@ -29,6 +31,10 @@ const slice = createSlice({
2931
setStep(state, action: PayloadAction<LedgerStep>) {
3032
state.step = action.payload
3133
},
34+
setDerivationPathType(state, action: PayloadAction<string>) {
35+
state.derivationPathType = action.payload
36+
state.accounts = []
37+
},
3238
operationFailed(state, action: PayloadAction<ErrorPayload>) {
3339
state.error = action.payload
3440
state.step = undefined

src/app/state/ledger/saga.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
// import { take, call, put, select, takeLatest } from 'redux-saga/effects';
2+
import type Transport from '@ledgerhq/hw-transport'
23
import TransportWebUSB from '@ledgerhq/hw-transport-webusb'
34
import * as oasis from '@oasisprotocol/client'
45
import { publicKeyToAddress, uint2hex } from 'app/lib/helpers'
5-
import {DerivationPathAdr8, Ledger, LedgerSigner} from 'app/lib/ledger'
6+
import { Ledger, LedgerSigner } from 'app/lib/ledger'
67
import { OasisTransaction } from 'app/lib/transaction'
78
import { all, call, put, select, takeEvery } from 'typed-redux-saga'
89
import { ErrorPayload, WalletError, WalletErrors } from 'types/errors'
910

1011
import { ledgerActions } from '.'
1112
import { selectChainContext } from '../network/selectors'
1213
import { getBalance } from '../wallet/saga'
14+
import { selectDerivationPathType } from "./selectors";
1315
import { LedgerAccount, LedgerStep } from './types'
14-
import type Transport from '@ledgerhq/hw-transport'
1516

1617
function* setStep(step: LedgerStep) {
1718
yield* put(ledgerActions.setStep(step))
@@ -41,8 +42,11 @@ function* enumerateAccounts() {
4142
transport = yield* getUSBTransport()
4243

4344
yield* setStep(LedgerStep.LoadingAccounts)
44-
// TODO: Pick the selected derivation path.
45-
const accounts = yield* call(Ledger.enumerateAccounts, transport, DerivationPathAdr8)
45+
const derivationPathType = yield* select(selectDerivationPathType)
46+
if (!derivationPathType) {
47+
throw new WalletError(WalletErrors.LedgerNoDerivationPathTypeProvided, 'No derivation path type provided')
48+
}
49+
const accounts = yield* call(Ledger.enumerateAccounts, transport, derivationPathType)
4650

4751
const balances = yield* all(accounts.map(a => call(getBalance, a.publicKey)))
4852
const addresses = yield* all(accounts.map(a => call(publicKeyToAddress, a.publicKey)))

src/app/state/ledger/selectors.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const selectSlice = (state: RootState) => state.ledger || initialState
77

88
export const selectError = createSelector([selectSlice], state => state.error)
99
export const selectLedger = createSelector([selectSlice], state => state)
10+
export const selectDerivationPathType = createSelector([selectSlice], state => state.derivationPathType)
1011
export const selectLedgerAccounts = createSelector([selectSlice], state => state.accounts)
1112
export const selectSelectedLedgerAccounts = createSelector([selectLedgerAccounts], state =>
1213
state.filter(a => a.selected),

src/app/state/ledger/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export enum LedgerStep {
1919

2020
export interface LedgerState {
2121
accounts: LedgerAccount[]
22+
derivationPathType?: string
2223
step?: LedgerStep
2324
error?: ErrorPayload
2425
}

src/locales/en/translation.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,10 @@
182182
"loadingAccounts": "Loading account details",
183183
"loadingBalances": "Loading balance details",
184184
"done": "Done"
185+
},
186+
"derivationPathType": {
187+
"adr8": "ADR 8 derivation path",
188+
"legacy": "Legacy derivation path"
185189
}
186190
},
187191
"transaction": {

src/locales/fr/translation.json

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@
4242
"ledger": {
4343
"selectWallets": "Sélectionnez les portefeuilles à ouvrir",
4444
"cancel": "Annuler",
45-
"openWallets": "Ouvrir"
45+
"openWallets": "Ouvrir",
46+
"header": "Open from Ledger device"
4647
},
4748
"bitpie": {
4849
"warning": "❗ Utilisateurs du portefeuille BitPie : vous ne pouvez pas importer la phrase mnémonique secrète directement depuis votre portefeuille BitPie. <0>Consultez la documentation pour plus de détails.</0>"
@@ -66,7 +67,8 @@
6667
"debonding": "Debonding",
6768
"delegations": "Délégué (stake)"
6869
},
69-
"noTransactionFound": "Aucune transaction trouvée"
70+
"noTransactionFound": "Aucune transaction trouvée",
71+
"noWalletIsOpen": "To send, receive, stake and swap ROSE tokens, <0>open your wallet!</0>"
7072
},
7173
"transaction": {
7274
"transfer": {
@@ -89,7 +91,11 @@
8991
"recipient": "Destinataire",
9092
"enterAddress": "Entrez une adresse",
9193
"success": "Transaction effectuée. La transaction peut mettre une minute avant d'apparaître sur votre compte.",
92-
"send": "Envoyer"
94+
"send": "Envoyer",
95+
"confirmSendingToValidator": {
96+
"title": "",
97+
"description": ""
98+
}
9399
},
94100
"loading": "Chargement du compte",
95101
"addEscrow": {
@@ -122,7 +128,9 @@
122128
"delegator": "Délégateur",
123129
"validator": "Validateur",
124130
"cancel": "Cancel",
125-
"validators": "Validateurs"
131+
"validators": "Validateurs",
132+
"confirm": "",
133+
"unavailable": "Unavailable"
126134
},
127135
"errors": {
128136
"unknown": "Erreur inconnue : {{message}}",
@@ -138,7 +146,9 @@
138146
"ledgerTransactionRejected": "Transaction rejetée sur le Ledger.",
139147
"ledgerNoDeviceSelected": "Pas de Ledger sélectionné. Si vous voulez réessayer, fermez cette fenêtre et tentez à nouveau.",
140148
"ledgerCannotOpenOasisApp": "Impossible d'accéder à l'application Oasis sur le Ledger. Assurez vous qu'il est dévérouillé et que l'application Oasis est ouverte.",
141-
"unknownLedgerError": "Erreur Ledger inconnue : {{message}}"
149+
"unknownLedgerError": "Erreur Ledger inconnue : {{message}}",
150+
"usbTransportNotSupported": "Your browser does not support WebUSB (e.g. Firefox). Try using Chrome.",
151+
"LedgerOasisAppIsNotOpen": "Oasis App on Ledger is closed."
142152
},
143153
"toolbar": {
144154
"search": {
@@ -165,6 +175,17 @@
165175
"loadingAccounts": "Chargement des adresses",
166176
"loadingBalances": "Chargement du solde des adresses",
167177
"done": "Fin"
178+
},
179+
"instructionSteps": {
180+
"header": "Steps:",
181+
"connectLedger": "Connect your Ledger device to the computer",
182+
"closeLedgerLive": "Close Ledger Live app on the computer",
183+
"openOasisApp": "Open the Oasis App on your Ledger device",
184+
"confirmPendingReview": "Press both buttons on Ledger device to confirm `Pending Ledger review`"
185+
},
186+
"derivationPathType": {
187+
"adr8": "ADR 8 derivation path",
188+
"legacy": "Legacy derivation path"
168189
}
169190
},
170191
"transaction": {

src/types/errors.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export enum WalletErrors {
2121
LedgerNoDeviceSelected = 'no_device_selected',
2222
LedgerTransactionRejected = 'transaction_rejected',
2323
LedgerAppVersionNotSupported = 'ledger_version_not_supported',
24+
LedgerNoDerivationPathTypeProvided = 'no_derivation_path_type_provided'
2425
}
2526

2627
export interface ErrorPayload {

0 commit comments

Comments
 (0)