diff --git a/src/app/components/ChannelInfo/index.tsx b/src/app/components/ChannelInfo/index.tsx index 548b26f6..d578543f 100644 --- a/src/app/components/ChannelInfo/index.tsx +++ b/src/app/components/ChannelInfo/index.tsx @@ -7,7 +7,7 @@ import Unit from 'components/Unit'; import DetailsTable, { DetailsRow } from 'components/DetailsTable'; import TransferIcons from 'components/TransferIcons'; import Copy from 'components/Copy'; -import { CHANNEL_STATUS } from 'lnd/message'; +import { CHANNEL_STATUS } from 'lib/lnd-http'; import { AppState } from 'store/reducers'; import { getAccountInfo } from 'modules/account/actions'; import { closeChannel } from 'modules/channels/actions'; diff --git a/src/app/components/ChannelList/ChannelRow.tsx b/src/app/components/ChannelList/ChannelRow.tsx index e3efb83c..e7080663 100644 --- a/src/app/components/ChannelList/ChannelRow.tsx +++ b/src/app/components/ChannelList/ChannelRow.tsx @@ -7,7 +7,7 @@ import Unit from 'components/Unit'; import { enumToClassName } from 'utils/formatters'; import { channelStatusText } from 'utils/constants'; import { ChannelWithNode } from 'modules/channels/types'; -import { CHANNEL_STATUS } from 'lnd/message'; +import { CHANNEL_STATUS } from 'lib/lnd-http'; import './ChannelRow.less'; interface Props { diff --git a/src/app/components/SelectNode/ConfirmNode.tsx b/src/app/components/SelectNode/ConfirmNode.tsx index 9419f60d..19df6a93 100644 --- a/src/app/components/SelectNode/ConfirmNode.tsx +++ b/src/app/components/SelectNode/ConfirmNode.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { Button } from 'antd'; -import { GetInfoResponse } from 'lnd/message'; +import { GetInfoResponse } from 'lib/lnd-http'; import { blockchainDisplayName, CHAIN_TYPE } from 'utils/constants'; import './ConfirmNode.less'; diff --git a/src/lnd/errors.ts b/src/app/lib/lnd-http/errors.ts similarity index 100% rename from src/lnd/errors.ts rename to src/app/lib/lnd-http/errors.ts diff --git a/src/lnd/http/index.ts b/src/app/lib/lnd-http/index.ts similarity index 88% rename from src/lnd/http/index.ts rename to src/app/lib/lnd-http/index.ts index 2111c5ba..580d5ad3 100644 --- a/src/lnd/http/index.ts +++ b/src/app/lib/lnd-http/index.ts @@ -1,12 +1,13 @@ import { stringify } from 'query-string'; -import { txIdBytesToHex } from '../utils'; -import * as T from '../types'; -export * from '../errors'; -export * from '../types'; +import { parseNodeErrorResponse, txIdBytesToHex } from './utils'; +import { NetworkError, SendTransactionError } from './errors'; +import * as T from './types'; +export * from './errors'; +export * from './types'; export type ApiMethod = 'GET' | 'POST' | 'PUT' | 'DELETE'; -export class LndHttpClient implements T.LndAPI { +export class LndHttpClient { url: string; macaroon: undefined | T.Macaroon; @@ -279,8 +280,7 @@ export class LndHttpClient implements T.LndAPI { args, ).then(res => { if (res.payment_error) { - // Make it easy to convert on the other side - throw new Error(`SendTransactionError: ${res.payment_error}`); + throw new SendTransactionError(res.payment_error); } return { ...res, @@ -393,12 +393,12 @@ export class LndHttpClient implements T.LndAPI { }; // Internal fetch function - protected async request( + protected request( method: ApiMethod, path: string, args?: A, defaultValues?: Partial, - ): Promise { + ): T.Response { let body = null; let query = ''; const headers = new Headers(); @@ -416,42 +416,36 @@ export class LndHttpClient implements T.LndAPI { headers.append('Grpc-Metadata-macaroon', this.macaroon); } - try { - const res = await fetch(this.url + path + query, { - method, - headers, - body, - }); - if (!res.ok) { - let errBody: any; - try { - errBody = await res.json(); - if (!errBody.error) { - throw new Error(); + return fetch(this.url + path + query, { + method, + headers, + body, + }) + .then(async res => { + if (!res.ok) { + let errBody: any; + try { + errBody = await res.json(); + if (!errBody.error) throw new Error(); + } catch (err) { + throw new NetworkError(res.statusText, res.status); } - } catch (err) { - throw { - statusText: res.statusText, - status: res.status, - } as T.LndAPIResponseError; + const error = parseNodeErrorResponse(errBody); + throw error; } - console.log('errBody', errBody); - throw errBody as T.LndAPIResponseError; - } - const json = await res.json(); - if (defaultValues) { - // TS can't handle generic spreadables - return { ...(defaultValues as any), ...(json as any) } as R; - } - return json as R; - } catch (err) { - console.error(`API error calling ${method} ${path}`, err); - // Thrown errors must be JSON serializable, so include metadata if possible - if (err.code || err.status || !err.message) { + return res.json(); + }) + .then((res: Partial) => { + if (defaultValues) { + // TS can't handle generic spreadables + return { ...(defaultValues as any), ...(res as any) } as R; + } + return res as R; + }) + .catch(err => { + console.error(`API error calling ${method} ${path}`, err); throw err; - } - throw err.message; - } + }); } } diff --git a/src/lnd/types.ts b/src/app/lib/lnd-http/types.ts similarity index 77% rename from src/lnd/types.ts rename to src/app/lib/lnd-http/types.ts index a3bd272f..9dd70c15 100644 --- a/src/lnd/types.ts +++ b/src/app/lib/lnd-http/types.ts @@ -1,6 +1,8 @@ // Shared Types export type Macaroon = string; +export type Response = Promise; + export type AddressType = '0' | '2'; export type UtxoAddressType = 'NESTED_PUBKEY_HASH' | 'WITNESS_PUBKEY_HASH'; @@ -405,72 +407,3 @@ export interface GetUtxosParams { export interface GetUtxosResponse { utxos: Utxo[]; } - -// Shared API interface -export interface LndAPI { - getInfo(): Promise; - getNodeInfo(pubKey: string): Promise; - getChannels(): Promise; - getPendingChannels(): Promise; - getBlockchainBalance(): Promise; - getChannelsBalance(): Promise; - getTransactions(): Promise; - getPayments(): Promise; - getInvoices(args?: GetInvoicesArguments): Promise; - getInvoice(paymentHash: string): Promise; - createInvoice(args: CreateInvoiceArguments): Promise; - decodePaymentRequest(paymentRequest: string): Promise; - queryRoutes( - pubKey: string, - amount: string, - args: QueryRoutesArguments, - ): Promise; - sendPayment(args: SendPaymentArguments): Promise; - sendOnChain(args: SendOnChainArguments): Promise; - getAddress(args: NewAddressArguments): Promise; - getPeers(): Promise; - connectPeer(address: string, perm?: boolean): Promise<{}>; - openChannel(params: OpenChannelParams): Promise; - closeChannel(fundingTxid: string, outputIndex: string): Promise; - signMessage(message: string): Promise; - verifyMessage(params: VerifyMessageParams): Promise; - getUtxos(params?: GetUtxosParams): Promise; -} - -export type LndAPIMethod = keyof LndAPI; - -// Browser message interface -export interface LndAPIRequestMessage { - type: 'lnd-api-request'; - url: string; - macaroon: undefined | Macaroon; - method: M; - args: Parameters; -} - -export interface LndAPIResponseNetworkError { - statusText: string; - status: number; -} - -export type LndAPIResponseError = - // Fetch error - | LndAPIResponseNetworkError - // LND error - | ErrorResponse - // Generic error - | string; - -export type LndAPIResponseMessage = - | { - type: 'lnd-api-response'; - method: M; - data: ReturnType; - error: undefined; - } - | { - type: 'lnd-api-response'; - method: M; - error: LndAPIResponseError; - data: undefined; - }; diff --git a/src/app/lib/lnd-http/utils.ts b/src/app/lib/lnd-http/utils.ts new file mode 100644 index 00000000..dfbc66f7 --- /dev/null +++ b/src/app/lib/lnd-http/utils.ts @@ -0,0 +1,32 @@ +import * as Errors from './errors'; +import { ErrorResponse } from './types'; + +export function parseNodeErrorResponse(res: ErrorResponse): Error { + if (res.error.includes('expected 1 macaroon')) { + return new Errors.MacaroonAuthError('Macaroon is required'); + } + + if (res.error.includes('permission denied')) { + return new Errors.PermissionDeniedError('You lack permission to do that'); + } + + if (res.error.includes('unable to find a path to destination')) { + return new Errors.NoRouteError('No route available for payment'); + } + + if (res.error.includes('already connected to peer')) { + return new Errors.AlreadyConnectedError('You are already peers with that node'); + } + + return new Errors.UnknownServerError(res.error); +} + +export function txIdBytesToHex(txbytes: string) { + const txbinary = Buffer.from(txbytes, 'base64').toString('binary'); + const txarray = new Uint8Array(txbinary.length); + for (let i = 0; i < txbinary.length; i++) { + txarray[i] = txbinary.charCodeAt(i); + } + txarray.reverse(); + return new Buffer(txarray).toString('hex'); +} diff --git a/src/app/modules/account/actions.ts b/src/app/modules/account/actions.ts index 9e0fcbe5..2375c3b4 100644 --- a/src/app/modules/account/actions.ts +++ b/src/app/modules/account/actions.ts @@ -1,4 +1,4 @@ -import { NewAddressArguments } from 'lnd/message'; +import { NewAddressArguments } from 'lib/lnd-http'; import types from './types'; export function getAccountInfo() { diff --git a/src/app/modules/account/reducers.ts b/src/app/modules/account/reducers.ts index 5388775e..f83bc8ae 100644 --- a/src/app/modules/account/reducers.ts +++ b/src/app/modules/account/reducers.ts @@ -1,5 +1,5 @@ import types, { Account, LightningPaymentWithToNode } from './types'; -import { LightningInvoice, ChainTransaction } from 'lnd/message'; +import { LightningInvoice, ChainTransaction } from 'lib/lnd-http'; export interface AccountState { account: Account | null; diff --git a/src/app/modules/account/types.ts b/src/app/modules/account/types.ts index 9125a401..222d7a91 100644 --- a/src/app/modules/account/types.ts +++ b/src/app/modules/account/types.ts @@ -3,7 +3,7 @@ import { LightningInvoice, LightningPayment, ChainTransaction, -} from 'lnd/message'; +} from 'lib/lnd-http'; enum AccountTypes { GET_ACCOUNT_INFO = 'GET_ACCOUNT_INFO', diff --git a/src/app/modules/channels/types.ts b/src/app/modules/channels/types.ts index 9c3f874f..e8b0131d 100644 --- a/src/app/modules/channels/types.ts +++ b/src/app/modules/channels/types.ts @@ -5,7 +5,7 @@ import { ForceClosingChannel, WaitingChannel, LightningNode, -} from 'lnd/message'; +} from 'lib/lnd-http'; enum ChannelsTypes { GET_CHANNELS = 'GET_CHANNELS', diff --git a/src/app/modules/node/actions.ts b/src/app/modules/node/actions.ts index 23699d43..585c4b97 100644 --- a/src/app/modules/node/actions.ts +++ b/src/app/modules/node/actions.ts @@ -1,4 +1,4 @@ -import LndMessageClient, { Macaroon } from 'lnd/message'; +import LndHttpClient, { Macaroon } from 'lib/lnd-http'; import { selectSyncedUnencryptedNodeState, selectSyncedEncryptedNodeState, @@ -63,7 +63,7 @@ export function setNode( url, adminMacaroon, readonlyMacaroon, - lib: new LndMessageClient(url, adminMacaroon), + lib: new LndHttpClient(url, adminMacaroon), }, }; } @@ -81,7 +81,7 @@ export function setSyncedUnencryptedNodeState( payload: { url, readonlyMacaroon, - lib: url ? new LndMessageClient(url as string, readonlyMacaroon as string) : null, + lib: url ? new LndHttpClient(url as string, readonlyMacaroon as string) : null, }, }; } @@ -95,7 +95,7 @@ export function setSyncedEncryptedNodeState( payload: { url, adminMacaroon, - lib: url ? new LndMessageClient(url as string, adminMacaroon as string) : null, + lib: url ? new LndHttpClient(url as string, adminMacaroon as string) : null, }, }; } diff --git a/src/app/modules/node/reducers.ts b/src/app/modules/node/reducers.ts index f5601d4b..7cce6aad 100644 --- a/src/app/modules/node/reducers.ts +++ b/src/app/modules/node/reducers.ts @@ -1,9 +1,9 @@ -import { Macaroon, GetInfoResponse, LndAPI } from 'lnd/message'; +import LndHttpClient, { Macaroon, GetInfoResponse } from 'lib/lnd-http'; import types from './types'; import settingsTypes from 'modules/settings/types'; export interface NodeState { - lib: LndAPI | null; + lib: LndHttpClient | null; url: string | null; isNodeChecked: boolean; adminMacaroon: Macaroon | null; diff --git a/src/app/modules/node/sagas.ts b/src/app/modules/node/sagas.ts index 542a503a..6bf46914 100644 --- a/src/app/modules/node/sagas.ts +++ b/src/app/modules/node/sagas.ts @@ -11,12 +11,12 @@ import { import { requirePassword } from 'modules/crypto/sagas'; import { accountTypes } from 'modules/account'; import { channelsTypes } from 'modules/channels'; -import LndMessageClient, { MacaroonAuthError, PermissionDeniedError } from 'lnd/message'; +import LndHttpClient, { MacaroonAuthError, PermissionDeniedError } from 'lib/lnd-http'; import types from './types'; export function* handleCheckNode(action: ReturnType) { const url = action.payload; - const client = new LndMessageClient(url); + const client = new LndHttpClient(url); try { yield call(client.getInfo); } catch (err) { @@ -36,7 +36,7 @@ export function* handleCheckNodes(action: ReturnType) const requests = urls.map(url => { return new Promise(async resolve => { try { - const client = new LndMessageClient(url); + const client = new LndHttpClient(url); await client.getInfo(); resolve(url); } catch (err) { @@ -62,7 +62,7 @@ export function* handleCheckAuth(action: ReturnType) { const { url, admin, readonly } = action.payload; // Check read-only by making sure request doesn't error - let client = new LndMessageClient(url, readonly); + let client = new LndHttpClient(url, readonly); let nodeInfo; try { nodeInfo = yield call(client.getInfo); @@ -78,7 +78,7 @@ export function* handleCheckAuth(action: ReturnType) { // Test admin by intentionally send an invalid payment, // but make sure we didn't error out with a macaroon auth error // TODO: Replace with sign message once REST supports it - client = new LndMessageClient(url, admin); + client = new LndHttpClient(url, admin); try { yield call(client.sendPayment, { payment_request: 'testing admin' }); } catch (err) { diff --git a/src/app/modules/onchain/reducers.ts b/src/app/modules/onchain/reducers.ts index 326f1d64..bb101676 100644 --- a/src/app/modules/onchain/reducers.ts +++ b/src/app/modules/onchain/reducers.ts @@ -1,5 +1,5 @@ import types from './types'; -import { Utxo } from 'lnd/message'; +import { Utxo } from 'lib/lnd-http'; export interface OnChainState { utxos: Utxo[] | null; diff --git a/src/app/modules/onchain/sagas.ts b/src/app/modules/onchain/sagas.ts index 1b34459e..eea6c36e 100644 --- a/src/app/modules/onchain/sagas.ts +++ b/src/app/modules/onchain/sagas.ts @@ -1,7 +1,7 @@ import { SagaIterator } from 'redux-saga'; import { takeLatest, select, call, put } from 'redux-saga/effects'; import { selectNodeLibOrThrow } from 'modules/node/selectors'; -import { GetUtxosResponse } from 'lnd/types'; +import { GetUtxosResponse } from 'lib/lnd-http/types'; import types from './types'; export function* handleGetUtxos() { diff --git a/src/app/modules/payment/actions.ts b/src/app/modules/payment/actions.ts index fb8098fc..72f3af5c 100644 --- a/src/app/modules/payment/actions.ts +++ b/src/app/modules/payment/actions.ts @@ -2,7 +2,7 @@ import { SendPaymentArguments, CreateInvoiceArguments, SendOnChainArguments, -} from 'lnd/message'; +} from 'lib/lnd-http'; import types from './types'; export function checkPaymentRequest(paymentRequest: string, amount?: string) { diff --git a/src/app/modules/payment/reducers.ts b/src/app/modules/payment/reducers.ts index ac569f21..2f88bb5b 100644 --- a/src/app/modules/payment/reducers.ts +++ b/src/app/modules/payment/reducers.ts @@ -2,7 +2,7 @@ import { SendPaymentResponse, CreateInvoiceResponse, SendOnChainResponse, -} from 'lnd/message'; +} from 'lib/lnd-http'; import types, { PaymentRequestState, OnChainFeeEstimates } from './types'; export interface PaymentState { diff --git a/src/app/modules/payment/sagas.ts b/src/app/modules/payment/sagas.ts index f6b9c509..1275cf3b 100644 --- a/src/app/modules/payment/sagas.ts +++ b/src/app/modules/payment/sagas.ts @@ -11,7 +11,7 @@ import { checkPaymentRequest, sendPayment, createInvoice, sendOnChain } from './ import { apiFetchOnChainFees } from 'lib/earn'; import types from './types'; import { CHAIN_TYPE } from 'utils/constants'; -import { NoRouteError } from 'lnd/errors'; +import { NoRouteError } from 'lib/lnd-http/errors'; export function* handleSendPayment(action: ReturnType) { try { diff --git a/src/app/modules/payment/types.ts b/src/app/modules/payment/types.ts index cdf5827b..5a927cdc 100644 --- a/src/app/modules/payment/types.ts +++ b/src/app/modules/payment/types.ts @@ -1,4 +1,4 @@ -import { DecodePaymentRequestResponse, LightningNode, Route } from 'lnd/message'; +import { DecodePaymentRequestResponse, LightningNode, Route } from 'lib/lnd-http'; enum PaymentTypes { CHECK_PAYMENT_REQUEST = 'CHECK_PAYMENT_REQUEST', diff --git a/src/app/modules/peers/types.ts b/src/app/modules/peers/types.ts index bf7da630..b75bd001 100644 --- a/src/app/modules/peers/types.ts +++ b/src/app/modules/peers/types.ts @@ -1,4 +1,4 @@ -import { Peer, LightningNode } from 'lnd/message'; +import { Peer, LightningNode } from 'lib/lnd-http'; enum PeersTypes { GET_PEERS = 'GET_PEERS_INFO', diff --git a/src/app/modules/sign/sagas.ts b/src/app/modules/sign/sagas.ts index b5017c35..c7d85404 100644 --- a/src/app/modules/sign/sagas.ts +++ b/src/app/modules/sign/sagas.ts @@ -8,7 +8,7 @@ import types from './types'; import { SignMessageResponse as LndSignMessageResponse, VerifyMessageResponse as LndVerifyMessageResponse, -} from 'lnd/types'; +} from 'lib/lnd-http/types'; import { safeGetNodeInfo } from 'utils/misc'; export function* handleSignMessage(action: ReturnType) { diff --git a/src/app/utils/balances.ts b/src/app/utils/balances.ts index f96d3a54..045774e4 100644 --- a/src/app/utils/balances.ts +++ b/src/app/utils/balances.ts @@ -2,7 +2,7 @@ import BN from 'bn.js'; import moment from 'moment'; import { ChannelWithNode } from 'modules/channels/types'; -import { Utxo, CHANNEL_STATUS } from 'lnd/message'; +import { Utxo, CHANNEL_STATUS } from 'lib/lnd-http'; export interface BalanceStats { total: string; diff --git a/src/app/utils/constants.ts b/src/app/utils/constants.ts index f11928cb..298fe15d 100644 --- a/src/app/utils/constants.ts +++ b/src/app/utils/constants.ts @@ -4,8 +4,8 @@ import DecredLogo from 'static/images/decred.svg'; import GroestlcoinLogo from 'static/images/groestlcoin.svg'; import * as React from 'react'; import { CustomIconComponentProps } from 'antd/lib/icon'; -import { CHANNEL_STATUS } from 'lnd/message'; -import { AddressType } from 'lnd/types'; +import { CHANNEL_STATUS } from 'lib/lnd-http'; +import { AddressType } from 'lib/lnd-http/types'; export enum NODE_TYPE { LOCAL = 'LOCAL', diff --git a/src/app/utils/misc.ts b/src/app/utils/misc.ts index 6074e45a..d0db44b5 100644 --- a/src/app/utils/misc.ts +++ b/src/app/utils/misc.ts @@ -1,9 +1,9 @@ import { + LndHttpClient, GetNodeInfoResponse, AlreadyConnectedError, LightningNode, - LndAPI, -} from 'lnd/message'; +} from 'lib/lnd-http'; export function sleep(time: number) { return new Promise(resolve => { @@ -29,7 +29,7 @@ export const UNKNOWN_NODE: LightningNode = { // Run getNodeInfo, but if it fails, return a spoofed node object export async function safeGetNodeInfo( - lib: LndAPI, + lib: LndHttpClient, pubkey: string, ): Promise { if (!pubkey) { @@ -56,7 +56,7 @@ export async function safeGetNodeInfo( } // Run connectPeer, but if it fails due to duplicate, just ignore -export async function safeConnectPeer(lib: LndAPI, address: string): Promise { +export async function safeConnectPeer(lib: LndHttpClient, address: string): Promise { try { lib.connectPeer(address); } catch (err) { diff --git a/src/app/utils/typeguards.ts b/src/app/utils/typeguards.ts index 07c98706..6d6b30f0 100644 --- a/src/app/utils/typeguards.ts +++ b/src/app/utils/typeguards.ts @@ -1,5 +1,5 @@ import { AnyTransaction, LightningPaymentWithToNode } from 'modules/account/types'; -import { LightningInvoice, ChainTransaction } from 'lnd/message'; +import { LightningInvoice, ChainTransaction } from 'lib/lnd-http'; export function isInvoice(source: AnyTransaction): source is LightningInvoice { return !!(source as LightningInvoice).expiry; diff --git a/src/background_script/getNodeInfo.ts b/src/background_script/getNodeInfo.ts index b1c4cc1b..a386fd63 100644 --- a/src/background_script/getNodeInfo.ts +++ b/src/background_script/getNodeInfo.ts @@ -1,6 +1,6 @@ import { GetInfoResponse } from 'webln'; import runSelector from '../content_script/runSelector'; -import { LndHttpClient } from 'lnd/http'; +import { LndHttpClient } from 'lib/lnd-http'; import { selectSyncedUnencryptedNodeState } from 'modules/node/selectors'; export default async function getNodeInfo(): Promise { diff --git a/src/background_script/handleLndHttp.ts b/src/background_script/handleLndHttp.ts deleted file mode 100644 index 1e7306b3..00000000 --- a/src/background_script/handleLndHttp.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { browser } from 'webextension-polyfill-ts'; -import { - LndHttpClient, - LndAPIRequestMessage, - LndAPIResponseMessage, - LndAPIMethod, - LndAPIResponseError, -} from '../lnd/http'; - -function isLndRequestMessage(req: any): req is LndAPIRequestMessage { - if (req && req.type === 'lnd-api-request') { - return true; - } - return false; -} - -export default function handleLndHttp() { - // Background manages communication between page and its windows - browser.runtime.onMessage.addListener(async (request: unknown) => { - if (!isLndRequestMessage(request)) { - return; - } - - const client = new LndHttpClient(request.url, request.macaroon); - const fn = client[request.method] as LndHttpClient[typeof request.method]; - const args = request.args as Parameters; - - return (fn as any)(...args) - .then((data: ReturnType) => { - return { - type: 'lnd-api-response', - method: request.method, - data, - } as LndAPIResponseMessage; - }) - .catch((err: LndAPIResponseError) => { - return { - type: 'lnd-api-response', - method: request.method, - error: err, - } as LndAPIResponseMessage; - }); - }); -} diff --git a/src/background_script/index.ts b/src/background_script/index.ts index ffb5f8a5..9354fdcb 100755 --- a/src/background_script/index.ts +++ b/src/background_script/index.ts @@ -1,10 +1,8 @@ -import handleLndHttp from './handleLndHttp'; import handlePrompts from './handlePrompts'; import handlePassword from './handlePassword'; import handleContextMenu from './handleContextMenu'; function initBackground() { - handleLndHttp(); handlePrompts(); handlePassword(); handleContextMenu(); diff --git a/src/lnd/message/index.ts b/src/lnd/message/index.ts deleted file mode 100644 index 6ab732c4..00000000 --- a/src/lnd/message/index.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { browser } from 'webextension-polyfill-ts'; -import { parseResponseError } from '../utils'; -import * as T from '../types'; -export * from '../types'; -export * from '../errors'; - -// TS doesn't like dynamically constructed class methods -class LndMessageClient implements T.LndAPI { - url: string; - macaroon: undefined | T.Macaroon; - - constructor(url: string, macaroon?: T.Macaroon) { - // Remove trailing slash for consistency - this.url = url.replace(/\/$/, ''); - this.macaroon = macaroon; - } - - // Manually re-implement the methods, tedious but that's TS life for ya - getInfo = (...args: any[]) => this.request('getInfo', args) as any; - getNodeInfo = (...args: any[]) => this.request('getNodeInfo', args) as any; - getChannels = (...args: any[]) => this.request('getChannels', args) as any; - getPendingChannels = (...args: any[]) => - this.request('getPendingChannels', args) as any; - getBlockchainBalance = (...args: any[]) => - this.request('getBlockchainBalance', args) as any; - getChannelsBalance = (...args: any[]) => - this.request('getChannelsBalance', args) as any; - getTransactions = (...args: any[]) => this.request('getTransactions', args) as any; - getPayments = (...args: any[]) => this.request('getPayments', args) as any; - getInvoices = (...args: any[]) => this.request('getInvoices', args) as any; - getInvoice = (...args: any[]) => this.request('getInvoice', args) as any; - createInvoice = (...args: any[]) => this.request('createInvoice', args) as any; - decodePaymentRequest = (...args: any[]) => - this.request('decodePaymentRequest', args) as any; - queryRoutes = (...args: any[]) => this.request('queryRoutes', args) as any; - sendPayment = (...args: any[]) => this.request('sendPayment', args) as any; - sendOnChain = (...args: any[]) => this.request('sendOnChain', args) as any; - getAddress = (...args: any[]) => this.request('getAddress', args) as any; - getPeers = (...args: any[]) => this.request('getPeers', args) as any; - connectPeer = (...args: any[]) => this.request('connectPeer', args) as any; - openChannel = (...args: any[]) => this.request('openChannel', args) as any; - closeChannel = (...args: any[]) => this.request('closeChannel', args) as any; - signMessage = (...args: any[]) => this.request('signMessage', args) as any; - verifyMessage = (...args: any[]) => this.request('verifyMessage', args) as any; - getUtxos = (...args: any[]) => this.request('getUtxos', args) as any; - - // Internal request function, sends a message to the background context and - // returns its response. - protected async request( - method: M, - args: any, - ): Promise> { - const message: T.LndAPIRequestMessage = { - type: 'lnd-api-request', - url: this.url, - macaroon: this.macaroon, - method, - args, - }; - const res: T.LndAPIResponseMessage = await browser.runtime.sendMessage(message); - console.log(res); - if (res.data) { - return res.data; - } - throw parseResponseError(res.error || 'Unknown response from extension'); - } -} - -export default LndMessageClient; diff --git a/src/lnd/utils.ts b/src/lnd/utils.ts deleted file mode 100644 index 066c4340..00000000 --- a/src/lnd/utils.ts +++ /dev/null @@ -1,50 +0,0 @@ -import * as Errors from './errors'; -import { LndAPIResponseNetworkError, LndAPIResponseError } from './types'; - -const isNetworkError = ( - error: LndAPIResponseError, -): error is LndAPIResponseNetworkError => - (error as LndAPIResponseNetworkError).statusText !== undefined; - -export function parseResponseError(err: LndAPIResponseError): Error { - console.log(err); - if (typeof err === 'string') { - return new Error(err); - } - - if (isNetworkError(err)) { - return new Errors.NetworkError(err.statusText, err.status); - } - - if (err.error.includes('SendTransactionError')) { - return new Errors.SendTransactionError(err.error.split('SendTransactionError: ')[1]); - } - - if (err.error.includes('expected 1 macaroon')) { - return new Errors.MacaroonAuthError('Macaroon is required'); - } - - if (err.error.includes('permission denied')) { - return new Errors.PermissionDeniedError('You lack permission to do that'); - } - - if (err.error.includes('unable to find a path to destination')) { - return new Errors.NoRouteError('No route available for payment'); - } - - if (err.error.includes('already connected to peer')) { - return new Errors.AlreadyConnectedError('You are already peers with that node'); - } - - return new Errors.UnknownServerError(err.error); -} - -export function txIdBytesToHex(txbytes: string) { - const txbinary = Buffer.from(txbytes, 'base64').toString('binary'); - const txarray = new Uint8Array(txbinary.length); - for (let i = 0; i < txbinary.length; i++) { - txarray[i] = txbinary.charCodeAt(i); - } - txarray.reverse(); - return new Buffer(txarray).toString('hex'); -} diff --git a/tsconfig.json b/tsconfig.json index 0ebfe7ea..a33b4eb9 100755 --- a/tsconfig.json +++ b/tsconfig.json @@ -27,8 +27,7 @@ "store/*": ["./src/app/store/*"], "style/*": ["./src/app/style/*"], "typings/*": ["./src/app/typings/*"], - "utils/*": ["./src/app/utils/*"], - "lnd/*": ["./src/lnd/*"] + "utils/*": ["./src/app/utils/*"] } }, "include": ["src", "webpack.config.ts"] diff --git a/webpack.config.js b/webpack.config.js index c00b5214..622390ec 100755 --- a/webpack.config.js +++ b/webpack.config.js @@ -160,7 +160,6 @@ module.exports = { style: `${srcApp}/style`, typings: `${srcApp}/typings`, utils: `${srcApp}/utils`, - lnd: `${src}/lnd`, }, }, plugins: [