From 5370b2c4af9b657acbc582fa82ec092d02c98d5c Mon Sep 17 00:00:00 2001 From: gromxyz Date: Wed, 27 Oct 2021 12:11:40 +0200 Subject: [PATCH 1/3] Enable ledger walletIndex for RUNE --- src/main/api/ledger/address.ts | 4 +- src/main/api/ledger/thorchain/address.ts | 13 +++--- src/main/api/ledger/thorchain/common.ts | 2 +- src/main/api/ledger/thorchain/transaction.ts | 20 ++++++---- src/main/api/ledger/transaction.ts | 14 +++++-- .../wallet/settings/WalletSettings.tsx | 40 ++++++++++++++----- .../services/thorchain/transaction.ts | 3 +- src/shared/api/io.ts | 3 +- 8 files changed, 70 insertions(+), 29 deletions(-) diff --git a/src/main/api/ledger/address.ts b/src/main/api/ledger/address.ts index aa16dc2f6..56ead9407 100644 --- a/src/main/api/ledger/address.ts +++ b/src/main/api/ledger/address.ts @@ -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) @@ -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) diff --git a/src/main/api/ledger/thorchain/address.ts b/src/main/api/ledger/thorchain/address.ts index c3123f515..3c3557040 100644 --- a/src/main/api/ledger/thorchain/address.ts +++ b/src/main/api/ledger/thorchain/address.ts @@ -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> => { 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), @@ -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) } diff --git a/src/main/api/ledger/thorchain/common.ts b/src/main/api/ledger/thorchain/common.ts index 34ffb1a48..68d5bc6b6 100644 --- a/src/main/api/ledger/thorchain/common.ts +++ b/src/main/api/ledger/thorchain/common.ts @@ -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) { diff --git a/src/main/api/ledger/thorchain/transaction.ts b/src/main/api/ledger/thorchain/transaction.ts index 61e7b1188..c3a22bb82 100644 --- a/src/main/api/ledger/thorchain/transaction.ts +++ b/src/main/api/ledger/thorchain/transaction.ts @@ -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 @@ -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> => { 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), @@ -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({ @@ -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> => { 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), @@ -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({ diff --git a/src/main/api/ledger/transaction.ts b/src/main/api/ledger/transaction.ts index cf9c7a671..e6c80f59b 100644 --- a/src/main/api/ledger/transaction.ts +++ b/src/main/api/ledger/transaction.ts @@ -24,7 +24,14 @@ export const sendTx = async ({ let res: E.Either switch (chain) { case THORChain: - res = await THOR.send({ transport, network, recipient, amount, memo }) + res = await THOR.send({ + transport, + network, + recipient, + amount, + memo, + walletIndex: walletIndex ? walletIndex : 0 + }) break case BNBChain: res = await BNB.send({ @@ -58,14 +65,15 @@ export const deposit = async ({ chain, network, amount, - memo + memo, + walletIndex }: IPCLedgerDepositTxParams): Promise> => { try { const transport = await TransportNodeHidSingleton.open() let res: E.Either 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({ diff --git a/src/renderer/components/wallet/settings/WalletSettings.tsx b/src/renderer/components/wallet/settings/WalletSettings.tsx index ec6aa0a82..0526401aa 100644 --- a/src/renderer/components/wallet/settings/WalletSettings.tsx +++ b/src/renderer/components/wallet/settings/WalletSettings.tsx @@ -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' @@ -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' @@ -72,7 +83,16 @@ export const WalletSettings: React.FC = (props): JSX.Element => { const [showRemoveWalletModal, setShowRemoveWalletModal] = useState(false) const [showQRModal, setShowQRModal] = useState>(O.none) const closeQrModal = useCallback(() => setShowQRModal(O.none), [setShowQRModal]) - const [walletIndex, setWalletIndex] = useState(0) + const [walletIndex, setWalletIndex] = useState({ + [BNBChain]: 0, + [BTCChain]: 0, + [BCHChain]: 0, + [LTCChain]: 0, + [THORChain]: 0, + [ETHChain]: 0, + [CosmosChain]: 0, + [PolkadotChain]: 0 + }) const removeWallet = useCallback(() => { removeKeystore() @@ -105,18 +125,20 @@ export const WalletSettings: React.FC = (props): JSX.Element => { (chain: Chain, { type: walletType, address: addressRD }: WalletAddressAsync) => { const renderAddLedger = (chain: Chain, loading: boolean) => ( - addLedgerAddress(chain, walletIndex)}> + addLedgerAddress(chain, walletIndex[chain])}> {intl.formatMessage({ id: 'ledger.add.device' })} - {isBnbChain(chain) && ( + {(isBnbChain(chain) || isThorChain(chain)) && ( <> {intl.formatMessage({ id: 'setting.wallet.index' })} 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])} /> @@ -152,7 +174,7 @@ export const WalletSettings: React.FC = (props): JSX.Element => { chain }) ) - verifyLedgerAddress(chain, walletIndex) + verifyLedgerAddress(chain, walletIndex[chain]) }} /> )} diff --git a/src/renderer/services/thorchain/transaction.ts b/src/renderer/services/thorchain/transaction.ts index 546a574c2..a10933047 100644 --- a/src/renderer/services/thorchain/transaction.ts +++ b/src/renderer/services/thorchain/transaction.ts @@ -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) diff --git a/src/shared/api/io.ts b/src/shared/api/io.ts index c40f390e9..ebcb6f08a 100644 --- a/src/shared/api/io.ts +++ b/src/shared/api/io.ts @@ -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 From 70045ff94dea2b457c43e1f24f4c897ef4303f4d Mon Sep 17 00:00:00 2001 From: gromxyz Date: Wed, 27 Oct 2021 12:28:23 +0200 Subject: [PATCH 2/3] Add walletIndex to verify ledger address --- src/renderer/views/wallet/WalletSettingsView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/views/wallet/WalletSettingsView.tsx b/src/renderer/views/wallet/WalletSettingsView.tsx index afcd4a800..4d1b247c5 100644 --- a/src/renderer/views/wallet/WalletSettingsView.tsx +++ b/src/renderer/views/wallet/WalletSettingsView.tsx @@ -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 From 09b2b43bbebc2d2df1b3bc1d46c9a558df4cb41d Mon Sep 17 00:00:00 2001 From: gromxyz Date: Wed, 27 Oct 2021 12:56:10 +0200 Subject: [PATCH 3/3] Code review suggestions --- src/main/api/ledger/transaction.ts | 6 +++--- src/renderer/components/wallet/settings/WalletSettings.tsx | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/api/ledger/transaction.ts b/src/main/api/ledger/transaction.ts index e6c80f59b..c9ccbe36d 100644 --- a/src/main/api/ledger/transaction.ts +++ b/src/main/api/ledger/transaction.ts @@ -17,7 +17,7 @@ export const sendTx = async ({ amount, asset, memo, - walletIndex + walletIndex = 0 }: IPCLedgerSendTxParams): Promise> => { try { const transport = await TransportNodeHidSingleton.open() @@ -30,7 +30,7 @@ export const sendTx = async ({ recipient, amount, memo, - walletIndex: walletIndex ? walletIndex : 0 + walletIndex }) break case BNBChain: @@ -42,7 +42,7 @@ export const sendTx = async ({ amount, asset, memo, - walletIndex: walletIndex ? walletIndex : 0 + walletIndex }) break default: diff --git a/src/renderer/components/wallet/settings/WalletSettings.tsx b/src/renderer/components/wallet/settings/WalletSettings.tsx index 0526401aa..7fb5b0d3b 100644 --- a/src/renderer/components/wallet/settings/WalletSettings.tsx +++ b/src/renderer/components/wallet/settings/WalletSettings.tsx @@ -83,7 +83,7 @@ export const WalletSettings: React.FC = (props): JSX.Element => { const [showRemoveWalletModal, setShowRemoveWalletModal] = useState(false) const [showQRModal, setShowQRModal] = useState>(O.none) const closeQrModal = useCallback(() => setShowQRModal(O.none), [setShowQRModal]) - const [walletIndex, setWalletIndex] = useState({ + const [walletIndex, setWalletIndex] = useState>({ [BNBChain]: 0, [BTCChain]: 0, [BCHChain]: 0,