Skip to content
This repository has been archived by the owner on Oct 10, 2023. It is now read-only.

Resolve: [Ledger] Add wallet index input for RUNE #1889

Merged
merged 3 commits into from
Oct 27, 2021
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
4 changes: 2 additions & 2 deletions src/main/api/ledger/address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const getAddress = async ({
const transport = await TransportNodeHidSingleton.open()
switch (chain) {
case THORChain:
res = await getTHORAddress(transport, network)
res = await getTHORAddress(transport, network, walletIndex)
break
case BNBChain:
res = await getBNBAddress(transport, network, walletIndex)
Expand All @@ -43,7 +43,7 @@ export const verifyLedgerAddress = async ({ chain, network, walletIndex = 0 }: I
const transport = await TransportNodeHidSingleton.open()
switch (chain) {
case THORChain:
verifyTHORAddress(transport, network)
verifyTHORAddress(transport, network, walletIndex)
break
case BNBChain:
verifyBNBAddress(transport, network, walletIndex)
Expand Down
13 changes: 8 additions & 5 deletions src/main/api/ledger/thorchain/address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,19 @@ import { LedgerError, LedgerErrorId, Network } from '../../../../shared/api/type
import { toClientNetwork } from '../../../../shared/utils/client'
import { isError } from '../../../../shared/utils/guard'
import { WalletAddress } from '../../../../shared/wallet/types'
import { fromLedgerErrorType, PATH } from './common'
import { fromLedgerErrorType, getDerivationPath } from './common'

export const getAddress = async (
transport: Transport,
network: Network
network: Network,
walletIndex: number
): Promise<E.Either<LedgerError, WalletAddress>> => {
try {
const app = new THORChainApp(transport)
const clientNetwork = toClientNetwork(network)
const prefix = getPrefix(clientNetwork)
const { bech32Address, returnCode } = await app.getAddressAndPubKey(PATH, prefix)
const path = getDerivationPath(walletIndex)
const { bech32Address, returnCode } = await app.getAddressAndPubKey(path, prefix)
if (!bech32Address || returnCode !== LedgerErrorType.NoErrors) {
return E.left({
errorId: fromLedgerErrorType(returnCode),
Expand All @@ -34,9 +36,10 @@ export const getAddress = async (
}
}

export const verifyAddress = async (transport: Transport, network: Network) => {
export const verifyAddress = async (transport: Transport, network: Network, walletIndex: number) => {
const app = new THORChainApp(transport)
const clientNetwork = toClientNetwork(network)
const prefix = getPrefix(clientNetwork)
app.showAddressAndPubKey(PATH, prefix)
const path = getDerivationPath(walletIndex)
app.showAddressAndPubKey(path, prefix)
}
2 changes: 1 addition & 1 deletion src/main/api/ledger/thorchain/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { LedgerErrorType } from '@thorchain/ledger-thorchain'
import { LedgerErrorId } from '../../../../shared/api/types'

// TODO(@veado) Get path by using `xchain-thorchain`
export const PATH = [44, 931, 0, 0, 0]
export const getDerivationPath = (walletIndex = 0) => [44, 931, 0, 0, walletIndex]

export const fromLedgerErrorType = (error: number): LedgerErrorId => {
switch (error) {
Expand Down
20 changes: 13 additions & 7 deletions src/main/api/ledger/thorchain/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { LedgerError, LedgerErrorId, Network } from '../../../../shared/api/type
import { getClientUrl } from '../../../../shared/thorchain/client'
import { toClientNetwork } from '../../../../shared/utils/client'
import { isError } from '../../../../shared/utils/guard'
import { fromLedgerErrorType, PATH } from './common'
import { fromLedgerErrorType, getDerivationPath } from './common'

/**
* Sends `MsgSend` message using Ledger
Expand All @@ -33,21 +33,24 @@ export const send = async ({
network,
amount,
memo,
recipient
recipient,
walletIndex
}: {
transport: Transport
amount: BaseAmount
network: Network
recipient: Address
memo?: string
walletIndex: number
}): Promise<E.Either<LedgerError, TxHash>> => {
try {
const clientNetwork = toClientNetwork(network)
const prefix = getPrefix(clientNetwork)

const app = new THORChainApp(transport)
const path = getDerivationPath(walletIndex)
// get address + public key
const { bech32Address, returnCode, compressedPk } = await app.getAddressAndPubKey(PATH, prefix)
const { bech32Address, returnCode, compressedPk } = await app.getAddressAndPubKey(path, prefix)
if (!bech32Address || !compressedPk || returnCode !== LedgerErrorType.NoErrors) {
return E.left({
errorId: fromLedgerErrorType(returnCode),
Expand Down Expand Up @@ -107,7 +110,7 @@ export const send = async ({
const signedStdTx = unsignedStdTx.getSignBytes(chainId, account_number.toString(), sequence.toString())

// Sign StdTx
const { signature } = await app.sign(PATH, signedStdTx.toString())
const { signature } = await app.sign(path, signedStdTx.toString())

if (!signature) {
return E.left({
Expand Down Expand Up @@ -160,20 +163,23 @@ export const deposit = async ({
transport,
network,
amount,
memo
memo,
walletIndex
}: {
transport: Transport
amount: BaseAmount
network: Network
memo: string
walletIndex: number
}): Promise<E.Either<LedgerError, TxHash>> => {
try {
const clientNetwork = toClientNetwork(network)
const prefix = getPrefix(clientNetwork)

const app = new THORChainApp(transport)
const path = getDerivationPath(walletIndex)
// get address + public key
const { bech32Address, returnCode, compressedPk } = await app.getAddressAndPubKey(PATH, prefix)
const { bech32Address, returnCode, compressedPk } = await app.getAddressAndPubKey(path, prefix)
if (!bech32Address || !compressedPk || returnCode !== LedgerErrorType.NoErrors) {
return E.left({
errorId: fromLedgerErrorType(returnCode),
Expand Down Expand Up @@ -219,7 +225,7 @@ export const deposit = async ({
// Get bytes from StdTx to sign
const signedStdTx = unsignedStdTx.getSignBytes(chainId, account_number.toString(), sequence.toString())
// Sign StdTx
const { signature } = await app.sign(PATH, signedStdTx.toString())
const { signature } = await app.sign(path, signedStdTx.toString())

if (!signature) {
return E.left({
Expand Down
18 changes: 13 additions & 5 deletions src/main/api/ledger/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,21 @@ export const sendTx = async ({
amount,
asset,
memo,
walletIndex
walletIndex = 0
}: IPCLedgerSendTxParams): Promise<E.Either<LedgerError, TxHash>> => {
try {
const transport = await TransportNodeHidSingleton.open()
let res: E.Either<LedgerError, string>
switch (chain) {
case THORChain:
res = await THOR.send({ transport, network, recipient, amount, memo })
res = await THOR.send({
transport,
network,
recipient,
amount,
memo,
walletIndex
})
break
case BNBChain:
res = await BNB.send({
Expand All @@ -35,7 +42,7 @@ export const sendTx = async ({
amount,
asset,
memo,
walletIndex: walletIndex ? walletIndex : 0
walletIndex
})
break
default:
Expand All @@ -58,14 +65,15 @@ export const deposit = async ({
chain,
network,
amount,
memo
memo,
walletIndex
gromxyz marked this conversation as resolved.
Show resolved Hide resolved
}: IPCLedgerDepositTxParams): Promise<E.Either<LedgerError, TxHash>> => {
try {
const transport = await TransportNodeHidSingleton.open()
let res: E.Either<LedgerError, string>
switch (chain) {
case THORChain:
res = await THOR.deposit({ transport, network, amount, memo })
res = await THOR.deposit({ transport, network, amount, memo, walletIndex: walletIndex ? walletIndex : 0 })
break
default:
res = E.left({
Expand Down
40 changes: 31 additions & 9 deletions src/renderer/components/wallet/settings/WalletSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,18 @@ import React, { useCallback, useMemo, useState } from 'react'

import * as RD from '@devexperts/remote-data-ts'
import { Address } from '@xchainjs/xchain-client'
import { Asset, Chain } from '@xchainjs/xchain-util'
import {
Asset,
BCHChain,
BNBChain,
BTCChain,
Chain,
CosmosChain,
ETHChain,
LTCChain,
PolkadotChain,
THORChain
} from '@xchainjs/xchain-util'
import { Col, List, Row } from 'antd'
import * as FP from 'fp-ts/function'
import * as O from 'fp-ts/lib/Option'
Expand All @@ -16,7 +27,7 @@ import { PasswordModal } from '../../../components/modal/password'
import { AssetIcon } from '../../../components/uielements/assets/assetIcon/AssetIcon'
import { QRCodeModal } from '../../../components/uielements/qrCodeModal/QRCodeModal'
import { PhraseCopyModal } from '../../../components/wallet/phrase/PhraseCopyModal'
import { getChainAsset, isBnbChain } from '../../../helpers/chainHelper'
import { getChainAsset, isBnbChain, isThorChain } from '../../../helpers/chainHelper'
import { ValidatePasswordHandler, WalletAccounts, WalletAddressAsync } from '../../../services/wallet/types'
import { walletTypeToI18n } from '../../../services/wallet/util'
import { InfoIcon } from '../../uielements/info'
Expand Down Expand Up @@ -72,7 +83,16 @@ export const WalletSettings: React.FC<Props> = (props): JSX.Element => {
const [showRemoveWalletModal, setShowRemoveWalletModal] = useState(false)
const [showQRModal, setShowQRModal] = useState<O.Option<{ asset: Asset; address: Address }>>(O.none)
const closeQrModal = useCallback(() => setShowQRModal(O.none), [setShowQRModal])
const [walletIndex, setWalletIndex] = useState<number>(0)
const [walletIndex, setWalletIndex] = useState<Record<Chain, number>>({
[BNBChain]: 0,
[BTCChain]: 0,
[BCHChain]: 0,
[LTCChain]: 0,
[THORChain]: 0,
[ETHChain]: 0,
[CosmosChain]: 0,
[PolkadotChain]: 0
})

const removeWallet = useCallback(() => {
removeKeystore()
Expand Down Expand Up @@ -105,18 +125,20 @@ export const WalletSettings: React.FC<Props> = (props): JSX.Element => {
(chain: Chain, { type: walletType, address: addressRD }: WalletAddressAsync) => {
const renderAddLedger = (chain: Chain, loading: boolean) => (
veado marked this conversation as resolved.
Show resolved Hide resolved
<Styled.AddLedgerContainer>
<Styled.AddLedgerButton loading={loading} onClick={() => addLedgerAddress(chain, walletIndex)}>
<Styled.AddLedgerButton loading={loading} onClick={() => addLedgerAddress(chain, walletIndex[chain])}>
<Styled.AddLedgerIcon /> {intl.formatMessage({ id: 'ledger.add.device' })}
</Styled.AddLedgerButton>
{isBnbChain(chain) && (
{(isBnbChain(chain) || isThorChain(chain)) && (
<>
<Styled.IndexLabel>{intl.formatMessage({ id: 'setting.wallet.index' })}</Styled.IndexLabel>
<Styled.WalletIndexInput
value={walletIndex.toString()}
value={walletIndex[chain].toString()}
pattern="[0-9]+"
onChange={(value) => value !== null && +value >= 0 && setWalletIndex(+value)}
onChange={(value) =>
value !== null && +value >= 0 && setWalletIndex({ ...walletIndex, [chain]: +value })
}
style={{ width: 60 }}
onPressEnter={() => addLedgerAddress(chain, walletIndex)}
onPressEnter={() => addLedgerAddress(chain, walletIndex[chain])}
/>
<InfoIcon tooltip={intl.formatMessage({ id: 'setting.wallet.index.info' })} />
</>
Expand Down Expand Up @@ -152,7 +174,7 @@ export const WalletSettings: React.FC<Props> = (props): JSX.Element => {
chain
})
)
verifyLedgerAddress(chain, walletIndex)
verifyLedgerAddress(chain, walletIndex[chain])
}}
/>
)}
Expand Down
3 changes: 2 additions & 1 deletion src/renderer/services/thorchain/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ export const createTransactionService = (client$: Client$, network$: Network$):
network,
asset: params.asset,
amount: params.amount,
memo: params.memo
memo: params.memo,
walletIndex: params.walletIndex
}
const encoded = ipcLedgerDepositTxParamsIO.encode(depositLedgerTxParams)

Expand Down
2 changes: 1 addition & 1 deletion src/renderer/views/wallet/WalletSettingsView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export const WalletSettingsView: React.FC = (): JSX.Element => {
}

const verifyLedgerAddressHandler = (chain: Chain, walletIndex = 0) => {
if (isThorChain(chain)) return verifyLedgerThorAddress()
if (isThorChain(chain)) return verifyLedgerThorAddress(walletIndex)
if (isBnbChain(chain)) return verifyLedgerBnbAddress(walletIndex)

return FP.constVoid
Expand Down
3 changes: 2 additions & 1 deletion src/shared/api/io.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ export const ipcLedgerDepositTxParamsIO = t.type({
network: networkIO,
asset: t.union([assetIO, t.undefined]),
amount: baseAmountIO,
memo: t.string
memo: t.string,
walletIndex: t.union([t.number, t.undefined])
})

export type IPCLedgerDepositTxParams = t.TypeOf<typeof ipcLedgerDepositTxParamsIO>