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

Prepare thorchain-ledger integration #1643

Closed
wants to merge 5 commits into from
Closed
Changes from 1 commit
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
Prev Previous commit
Clean up
- Make `useLedger` more generic `chain` + `index`)
- Add `GetLedgerAddressArgs`
- Remove `getTransport` from `ApiHDWallet`
- Support `index` for path
- Extract `toClientNetwork` to `shared/...`
veado committed Jul 21, 2021
commit 43c0397d5ed42e8a40179613da23aa7204ff0921
8 changes: 3 additions & 5 deletions src/main/api/hdwallet.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import { Chain } from '@xchainjs/xchain-util'
import { ipcRenderer } from 'electron'

import { LedgerTxInfo, Network } from '../../shared/api/types'
import { GetLedgerAddressParams, LedgerTxInfo, Network } from '../../shared/api/types'
import { ApiHDWallet } from '../../shared/api/types'
import IPCMessages from '../ipc/messages'

export const apiHDWallet: ApiHDWallet = {
getLedgerAddress: (chain: Chain, network: Network) =>
ipcRenderer.invoke(IPCMessages.GET_LEDGER_ADDRESS, chain, network),
getLedgerAddress: (args: GetLedgerAddressParams) => ipcRenderer.invoke(IPCMessages.GET_LEDGER_ADDRESS, args),
sendTxInLedger: (chain: Chain, network: Network, txInfo: LedgerTxInfo) =>
ipcRenderer.invoke(IPCMessages.SEND_LEDGER_TX, chain, network, txInfo),
getTransport: () => ipcRenderer.invoke(IPCMessages.GET_TRANSPORT)
ipcRenderer.invoke(IPCMessages.SEND_LEDGER_TX, chain, network, txInfo)
}
8 changes: 4 additions & 4 deletions src/main/api/ledger/address.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import TransportNodeHidSingleton from '@ledgerhq/hw-transport-node-hid-singleton'
import { Chain, THORChain } from '@xchainjs/xchain-util'
import { THORChain } from '@xchainjs/xchain-util'
import * as E from 'fp-ts/Either'

import { LedgerErrorId, Network } from '../../../shared/api/types'
import { GetLedgerAddressParams, LedgerErrorId } from '../../../shared/api/types'
import { getAddress as getTHORAddress } from './thorchain'
import { getErrorId } from './utils'

export const getAddress = async (chain: Chain, network: Network) => {
export const getAddress = async ({ chain, network, index }: GetLedgerAddressParams) => {
try {
let res: E.Either<LedgerErrorId, string>
const transport = await TransportNodeHidSingleton.open()
switch (chain) {
case THORChain:
res = await getTHORAddress(transport, network)
res = await getTHORAddress({ transport, network, index })
break
default:
res = E.left(LedgerErrorId.NO_APP)
7 changes: 4 additions & 3 deletions src/main/api/ledger/common.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import TransportNodeHidSingleton from '@ledgerhq/hw-transport-node-hid-singleton'

export const getTransport = async () => await TransportNodeHidSingleton.open()
/**
* Derivation path by given `index` (similar to "44'/931'/0'/0/{index}")
*/
export const getPath = (index = 0) => [44, 931, 0, 0, index]
2 changes: 1 addition & 1 deletion src/main/api/ledger/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export * from './address'
export * from './transaction'
export * from './common'
export * from './transport'
24 changes: 12 additions & 12 deletions src/main/api/ledger/thorchain.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
import Transport from '@ledgerhq/hw-transport'
import THORChainApp from '@thorchain/ledger-thorchain'
import * as Client from '@xchainjs/xchain-client'
import { getPrefix } from '@xchainjs/xchain-thorchain'
import * as E from 'fp-ts/Either'

import { Network } from '../../../shared/api/types'
import { toClientNetwork } from '../../../shared/utils/utils'
import { getPath } from './common'
import { getErrorId } from './utils'

// TODO(@Veado) Move `toClientNetwork` from `renderer/services/clients` to `main/util` or so
const toClientNetwork = (network: Network): Client.Network =>
network === 'mainnet' ? Client.Network.Mainnet : Client.Network.Testnet
// TODO(@veado) Get path by using `xchain-thorchain`
const PATH = [44, 931, 0, 0, 0]

export const getAddress = async (transport: Transport, network: Network) => {
export const getAddress = async ({
transport,
network,
index
}: {
transport: Transport
network: Network
index: number
}) => {
try {
const app = new THORChainApp(transport)
const clientNetwork = toClientNetwork(network)
const prefix = getPrefix(clientNetwork)
console.log('clientNetwork:', clientNetwork)
console.log('prefix:', prefix)
const res = await app.getAddressAndPubKey(PATH, prefix)
console.log('response:', res)
const res = await app.getAddressAndPubKey(getPath(index), prefix)
if (!res.bech32_address || res.return_code !== 0x9000 /* ERROR_CODE.NoError */) {
return E.left(res.return_code.toString())
}
3 changes: 3 additions & 0 deletions src/main/api/ledger/transport.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import TransportNodeHidSingleton from '@ledgerhq/hw-transport-node-hid-singleton'

export const getTransport = async () => await TransportNodeHidSingleton.open()
6 changes: 2 additions & 4 deletions src/main/electron.ts
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ import isDev from 'electron-is-dev'
import log from 'electron-log'
import { warn } from 'electron-log'

import { LedgerTxInfo, Network, StoreFileName } from '../shared/api/types'
import { GetLedgerAddressParams, LedgerTxInfo, Network, StoreFileName } from '../shared/api/types'
import { DEFAULT_STORAGES } from '../shared/const'
import { Locale } from '../shared/i18n/types'
import { registerAppCheckUpdatedHandler } from './api/appUpdate'
@@ -137,9 +137,7 @@ const initIPC = () => {
)
ipcMain.handle(IPCMessages.LOAD_KEYSTORE, () => loadKeystore())
// Ledger
ipcMain.handle(IPCMessages.GET_LEDGER_ADDRESS, async (_, chain: Chain, network: Network) =>
getLedgerAddress(chain, network)
)
ipcMain.handle(IPCMessages.GET_LEDGER_ADDRESS, async (_, args: GetLedgerAddressParams) => getLedgerAddress(args))
ipcMain.handle(IPCMessages.SEND_LEDGER_TX, (_, chain: Chain, network: Network, txInfo: LedgerTxInfo) =>
sendLedgerTx(chain, network, txInfo)
)
2 changes: 1 addition & 1 deletion src/renderer/helpers/addressHelper.ts
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ import { ethers } from 'ethers'
import * as O from 'fp-ts/lib/Option'

import { Network } from '../../shared/api/types'
import { toClientNetwork } from '../services/clients'
import { toClientNetwork } from '../../shared/utils/utils'

export const truncateAddress = (addr: Address, chain: Chain, network: Network): string => {
const first = addr.substr(0, Math.max(getAddressPrefixLength(chain, network) + 3, 6))
21 changes: 9 additions & 12 deletions src/renderer/hooks/useLedger.ts
Original file line number Diff line number Diff line change
@@ -13,25 +13,22 @@ import { observableState } from '../helpers/stateHelper'
import { DEFAULT_NETWORK } from '../services/const'
import { LedgerAddressRD } from '../services/wallet/types'

export const useLedger = () => {
export const useLedger = (chain: Chain, index: number) => {
const { network$ } = useAppContext()
const network = useObservableState<Network>(network$, DEFAULT_NETWORK)

const { get$: address$, set: setAddress } = useMemo(() => observableState<LedgerAddressRD>(RD.initial), [])

const addressRD = useObservableState(FP.pipe(address$, RxOp.shareReplay(1)), RD.initial)

const getAddress = useCallback(
(chain: Chain) => {
FP.pipe(
Rx.from(window.apiHDWallet.getLedgerAddress(chain, network)),
RxOp.map(RD.fromEither),
RxOp.startWith(RD.pending),
RxOp.catchError((error) => Rx.of(RD.failure(error)))
).subscribe(setAddress)
},
[network, setAddress]
)
const getAddress = useCallback(() => {
FP.pipe(
Rx.from(window.apiHDWallet.getLedgerAddress({ chain, network, index })),
RxOp.map(RD.fromEither),
RxOp.startWith(RD.pending),
RxOp.catchError((error) => Rx.of(RD.failure(error)))
).subscribe(setAddress)
}, [chain, index, network, setAddress])

return {
getAddress,
2 changes: 1 addition & 1 deletion src/renderer/services/app/service.ts
Original file line number Diff line number Diff line change
@@ -4,9 +4,9 @@ import { startWith, mapTo, distinctUntilChanged } from 'rxjs/operators'
import * as RxOp from 'rxjs/operators'

import { Network } from '../../../shared/api/types'
import { toClientNetwork } from '../../../shared/utils/utils'
import { observableState } from '../../helpers/stateHelper'
import { SlipTolerance } from '../../types/asgardex'
import { toClientNetwork } from '../clients'
import { DEFAULT_NETWORK, DEFAULT_SLIP_TOLERANCE } from '../const'
import { Network$, SlipTolerance$, OnlineStatus } from './types'

4 changes: 2 additions & 2 deletions src/renderer/services/binance/ledger.ts
Original file line number Diff line number Diff line change
@@ -12,9 +12,9 @@ import { LedgerService } from './types'

const { get$: ledgerAddress$, set: setLedgerAddressRD } = observableState<LedgerAddressRD>(RD.initial)

const retrieveLedgerAddress = (network: Network) =>
const retrieveLedgerAddress = (network: Network, index: number) =>
FP.pipe(
Rx.from(window.apiHDWallet.getLedgerAddress(BNBChain, network)),
Rx.from(window.apiHDWallet.getLedgerAddress({ chain: BNBChain, network, index })),
map(RD.fromEither),
startWith(RD.pending),
catchError((error) => Rx.of(RD.failure(error)))
2 changes: 1 addition & 1 deletion src/renderer/services/binance/types.ts
Original file line number Diff line number Diff line change
@@ -57,7 +57,7 @@ export type TransactionService = C.TransactionService<SendTxParams>

export type LedgerService = {
ledgerAddress$: LedgerAddressLD
retrieveLedgerAddress: (network: Network) => void
retrieveLedgerAddress: (network: Network, index: number) => void
removeLedgerAddress: () => void
ledgerTxRD$: LedgerTxHashLD
pushLedgerTx: (network: Network, params: LedgerBNCTxInfo) => Rx.Subscription
4 changes: 2 additions & 2 deletions src/renderer/services/bitcoin/ledger.ts
Original file line number Diff line number Diff line change
@@ -12,9 +12,9 @@ import { LedgerService } from './types'

const { get$: ledgerAddress$, set: setLedgerAddressRD } = observableState<LedgerAddressRD>(RD.initial)

const retrieveLedgerAddress = (network: Network) =>
const retrieveLedgerAddress = (network: Network, index: number) =>
FP.pipe(
Rx.from(window.apiHDWallet.getLedgerAddress(BTCChain, network)),
Rx.from(window.apiHDWallet.getLedgerAddress({ chain: BTCChain, network, index })),
map(RD.fromEither),
startWith(RD.pending),
catchError((error) => Rx.of(RD.failure(error)))
2 changes: 1 addition & 1 deletion src/renderer/services/bitcoin/types.ts
Original file line number Diff line number Diff line change
@@ -37,7 +37,7 @@ export type FeesService = C.FeesService & {

export type LedgerService = {
ledgerAddress$: LedgerAddressLD
retrieveLedgerAddress: (network: Network) => void
retrieveLedgerAddress: (network: Network, index: number) => void
removeLedgerAddress: () => void
ledgerTxRD$: LedgerTxHashLD
pushLedgerTx: (network: Network, params: LedgerBTCTxInfo) => Rx.Subscription
8 changes: 4 additions & 4 deletions src/renderer/services/chain/ledger.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { BNBChain, BTCChain, Chain } from '@xchainjs/xchain-util'

import { GetLedgerAddressParams } from '../../../shared/api/types'
import { network$ } from '../app/service'
import * as BNB from '../binance'
import * as BTC from '../bitcoin'
import { LedgerAddressParams } from './types'

const retrieveLedgerAddress = ({ chain, network }: LedgerAddressParams): void => {
const retrieveLedgerAddress = ({ chain, network, index }: GetLedgerAddressParams): void => {
switch (chain) {
case BTCChain:
return BTC.retrieveLedgerAddress(network)
return BTC.retrieveLedgerAddress(network, index)
case BNBChain:
return BNB.retrieveLedgerAddress(network)
return BNB.retrieveLedgerAddress(network, index)
default:
break
}
2 changes: 0 additions & 2 deletions src/renderer/services/chain/types.ts
Original file line number Diff line number Diff line change
@@ -86,8 +86,6 @@ export type SendPoolTxParams = SendTxParams & {
router: O.Option<Address>
}

export type LedgerAddressParams = { chain: Chain; network: Network }

/**
* State to reflect status of a swap by doing different requests
*/
1 change: 0 additions & 1 deletion src/renderer/services/clients/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
export * from './address'
export * from './common'
export * from './types'
export * from './utils'
export * from './balances'
export * from './transaction'
export * from './fees'
2 changes: 1 addition & 1 deletion src/renderer/services/ethereum/common.ts
Original file line number Diff line number Diff line change
@@ -8,11 +8,11 @@ import * as Rx from 'rxjs'
import * as RxOp from 'rxjs/operators'

import { Network } from '../../../shared/api/types'
import { toClientNetwork } from '../../../shared/utils/utils'
import { envOrDefault } from '../../helpers/envHelper'
import { clientNetwork$ } from '../app/service'
import * as C from '../clients'
import { Address$, ExplorerUrl$ } from '../clients/types'
import { toClientNetwork } from '../clients/utils'
import { keystoreService } from '../wallet/keystore'
import { getPhrase } from '../wallet/util'
import { Client$, ClientState, ClientState$ } from './types'
7 changes: 4 additions & 3 deletions src/renderer/views/wallet/SettingsView.tsx
Original file line number Diff line number Diff line change
@@ -262,15 +262,16 @@ export const SettingsView: React.FC = (): JSX.Element => {
}
}

const { getAddress: getLedgerAddress, address: ledgerAddressRD } = useLedger()
// TODO (@Veado) Let the user enter an index
const { getAddress: getTHORLedgerAddress, address: thorLedgerAddressRD } = useLedger(THORChain, 0)

return (
<>
<Row>
<Col>
<Button onClick={() => getLedgerAddress(THORChain)}>Get Ledger THOR address</Button>
<Button onClick={() => getTHORLedgerAddress()}>Get Ledger THOR address</Button>
</Col>
<Col>ledgerAddressRD: {JSON.stringify(ledgerAddressRD)}</Col>
<Col>ledgerAddressRD: {JSON.stringify(thorLedgerAddressRD)}</Col>
</Row>
<Row>
<Col span={24}>
10 changes: 7 additions & 3 deletions src/shared/api/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as RD from '@devexperts/remote-data-ts'
import Transport from '@ledgerhq/hw-transport'
import { Address, FeeRate, TxParams } from '@xchainjs/xchain-client'
import { Keystore } from '@xchainjs/xchain-crypto'
import { Chain } from '@xchainjs/xchain-util'
@@ -89,10 +88,15 @@ export type LedgerBTCTxInfo = Pick<TxParams, 'amount' | 'recipient'> & {

export type LedgerTxInfo = LedgerBTCTxInfo | LedgerBNCTxInfo

export type GetLedgerAddressParams = {
chain: Chain
network: Network
index: number
}

export type ApiHDWallet = {
getLedgerAddress: (chain: Chain, network: Network) => Promise<Either<LedgerErrorId, Address>>
getLedgerAddress: (args: GetLedgerAddressParams) => Promise<Either<LedgerErrorId, Address>>
sendTxInLedger: (chain: Chain, network: Network, txInfo: LedgerTxInfo) => Promise<Either<LedgerErrorId, string>>
getTransport: () => Promise<Transport>
}

declare global {
3 changes: 1 addition & 2 deletions src/shared/mock/api.ts
Original file line number Diff line number Diff line change
@@ -77,6 +77,5 @@ export const apiUrl: ApiUrl = {
// Mock `apiHDWallet`
export const apiHDWallet: ApiHDWallet = {
getLedgerAddress: () => Promise.resolve(E.right('ledger_address')),
sendTxInLedger: () => Promise.resolve(E.right('tx_hash')),
getTransport: () => Promise.reject(Error('`getTransport` is not implemented'))
sendTxInLedger: () => Promise.resolve(E.right('tx_hash'))
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as Client from '@xchainjs/xchain-client'

import { Network } from '../../../shared/api/types'
import { Network } from '../api/types'

/**
* Helper to type cast `Network` (ASGDX) -> `Client.Network` (xchain-client)
7 changes: 0 additions & 7 deletions webpack.main.js
Original file line number Diff line number Diff line change
@@ -25,13 +25,6 @@ const common = (_ /* env */, argv) => ({
__dirname: false,
__filename: false
}
// Add `node-hid` to externals dure build issues - see https://github.com/thorchain/asgardex-electron/pull/881
// https://webpack.js.org/configuration/externals/#root
// Note: ^ Disabled temporary due sign issues on macOS
// externals: {
// 'node-hid': 'commonjs node-hid',
// usb: 'commonjs usb'
// }
})

const main = (env, arg) => {