commit
831ca1c77d
5 changed files with 403 additions and 184 deletions
33
.vscode/snippets.code-snippets
vendored
Normal file
33
.vscode/snippets.code-snippets
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
// Place your api workspace snippets here. Each snippet is defined under a
|
||||
// snippet name and has a scope, prefix, body and description. Add comma
|
||||
// separated ids of the languages where the snippet is applicable in the scope
|
||||
// field. If scope is left empty or omitted, the snippet gets applied to all
|
||||
// languages. The prefix is what is used to trigger the snippet and the body
|
||||
// will be expanded and inserted. Possible variables are: $1, $2 for tab
|
||||
// stops, $0 for the final cursor position, and ${1:label}, ${2:another} for
|
||||
// placeholders. Placeholders with the same ids are connected. Example: "Print
|
||||
// to console": {"scope": "javascript,typescript", "prefix": "log", "body":
|
||||
// ["console.log('$1');", "$2"
|
||||
// ],
|
||||
// "description": "Log output to console"
|
||||
// }
|
||||
|
||||
"Route Body": {
|
||||
"body": [
|
||||
"try {",
|
||||
" return res.json({",
|
||||
"",
|
||||
" })",
|
||||
"} catch (e) {",
|
||||
" console.log(e)",
|
||||
" return res.status(500).json({",
|
||||
" errorMessage: e.message",
|
||||
" })",
|
||||
"}"
|
||||
],
|
||||
"description": "Route Body",
|
||||
"prefix": "rbody",
|
||||
"scope": "javascript"
|
||||
}
|
||||
}
|
||||
281
src/routes.js
281
src/routes.js
|
|
@ -30,11 +30,7 @@ const {
|
|||
const GunActions = require('../services/gunDB/contact-api/actions')
|
||||
const GunGetters = require('../services/gunDB/contact-api/getters')
|
||||
const GunKey = require('../services/gunDB/contact-api/key')
|
||||
const {
|
||||
sendPaymentV2Keysend,
|
||||
sendPaymentV2Invoice,
|
||||
listPayments
|
||||
} = require('../utils/lightningServices/v2')
|
||||
const LV2 = require('../utils/lightningServices/v2')
|
||||
const GunWriteRPC = require('../services/gunDB/rpc')
|
||||
|
||||
const DEFAULT_MAX_NUM_ROUTES_TO_QUERY = 10
|
||||
|
|
@ -1024,30 +1020,15 @@ module.exports = async (
|
|||
)
|
||||
})
|
||||
// get lnd chan info
|
||||
app.post('/api/lnd/getchaninfo', (req, res) => {
|
||||
const { lightning } = LightningServices.services
|
||||
|
||||
lightning.getChanInfo(
|
||||
{ chan_id: req.body.chan_id },
|
||||
async (err, response) => {
|
||||
if (err) {
|
||||
logger.debug('GetChanInfo Error:', err)
|
||||
const health = await checkHealth()
|
||||
if (health.LNDStatus.success) {
|
||||
res.status(400)
|
||||
res.json({
|
||||
field: 'getChanInfo',
|
||||
errorMessage: sanitizeLNDError(err.message)
|
||||
})
|
||||
} else {
|
||||
res.status(500)
|
||||
res.json({ errorMessage: 'LND is down' })
|
||||
}
|
||||
}
|
||||
logger.debug('GetChanInfo:', response)
|
||||
res.json(response)
|
||||
}
|
||||
)
|
||||
app.post('/api/lnd/getchaninfo', async (req, res) => {
|
||||
try {
|
||||
return res.json(await LV2.getChanInfo(req.body.chan_id))
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
return res.status(500).json({
|
||||
errorMessage: e.message
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
app.get('/api/lnd/getnetworkinfo', (req, res) => {
|
||||
|
|
@ -1072,47 +1053,30 @@ module.exports = async (
|
|||
})
|
||||
|
||||
// get lnd node active channels list
|
||||
app.get('/api/lnd/listpeers', (req, res) => {
|
||||
const { lightning } = LightningServices.services
|
||||
lightning.listPeers({}, async (err, response) => {
|
||||
if (err) {
|
||||
logger.debug('ListPeers Error:', err)
|
||||
const health = await checkHealth()
|
||||
if (health.LNDStatus.success) {
|
||||
res.status(400).json({
|
||||
field: 'listPeers',
|
||||
errorMessage: sanitizeLNDError(err.message)
|
||||
})
|
||||
} else {
|
||||
res.status(500)
|
||||
res.json({ errorMessage: 'LND is down' })
|
||||
}
|
||||
}
|
||||
logger.debug('ListPeers:', response)
|
||||
res.json(response)
|
||||
})
|
||||
app.get('/api/lnd/listpeers', async (req, res) => {
|
||||
try {
|
||||
return res.json({
|
||||
peers: await LV2.listPeers(req.body.latestError)
|
||||
})
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
return res.status(500).json({
|
||||
errorMessage: e.message
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// newaddress
|
||||
app.post('/api/lnd/newaddress', (req, res) => {
|
||||
const { lightning } = LightningServices.services
|
||||
lightning.newAddress({ type: req.body.type }, async (err, response) => {
|
||||
if (err) {
|
||||
logger.debug('NewAddress Error:', err)
|
||||
const health = await checkHealth()
|
||||
if (health.LNDStatus.success) {
|
||||
res.status(400).json({
|
||||
field: 'newAddress',
|
||||
errorMessage: sanitizeLNDError(err.message)
|
||||
})
|
||||
} else {
|
||||
res.status(500)
|
||||
res.json({ errorMessage: 'LND is down' })
|
||||
}
|
||||
}
|
||||
logger.debug('NewAddress:', response)
|
||||
res.json(response)
|
||||
})
|
||||
app.post('/api/lnd/newaddress', async (req, res) => {
|
||||
try {
|
||||
return res.json({
|
||||
address: await LV2.newAddress(req.body.type)
|
||||
})
|
||||
} catch (e) {
|
||||
return res.status(500).json({
|
||||
errorMessage: e.message
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// connect peer to lnd node
|
||||
|
|
@ -1157,47 +1121,28 @@ module.exports = async (
|
|||
})
|
||||
|
||||
// get lnd node opened channels list
|
||||
app.get('/api/lnd/listchannels', (req, res) => {
|
||||
const { lightning } = LightningServices.services
|
||||
lightning.listChannels({}, async (err, response) => {
|
||||
if (err) {
|
||||
logger.debug('ListChannels Error:', err)
|
||||
const health = await checkHealth()
|
||||
if (health.LNDStatus.success) {
|
||||
res.status(400).json({
|
||||
field: 'listChannels',
|
||||
errorMessage: sanitizeLNDError(err.message)
|
||||
})
|
||||
} else {
|
||||
res.status(500)
|
||||
res.json({ errorMessage: 'LND is down' })
|
||||
}
|
||||
}
|
||||
logger.debug('ListChannels:', response)
|
||||
res.json(response)
|
||||
})
|
||||
app.get('/api/lnd/listchannels', async (_, res) => {
|
||||
try {
|
||||
return res.json({
|
||||
channels: await LV2.listChannels()
|
||||
})
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
return res.status(500).json({
|
||||
errorMessage: e.message
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// get lnd node pending channels list
|
||||
app.get('/api/lnd/pendingchannels', (req, res) => {
|
||||
const { lightning } = LightningServices.services
|
||||
lightning.pendingChannels({}, async (err, response) => {
|
||||
if (err) {
|
||||
logger.debug('PendingChannels Error:', err)
|
||||
const health = await checkHealth()
|
||||
if (health.LNDStatus.success) {
|
||||
res.status(400).json({
|
||||
field: 'pendingChannels',
|
||||
errorMessage: sanitizeLNDError(err.message)
|
||||
})
|
||||
} else {
|
||||
res.status(500)
|
||||
res.json({ errorMessage: 'LND is down' })
|
||||
}
|
||||
}
|
||||
logger.debug('PendingChannels:', response)
|
||||
res.json(response)
|
||||
})
|
||||
app.get('/api/lnd/pendingchannels', async (req, res) => {
|
||||
try {
|
||||
return res.json(await LV2.pendingChannels())
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
return res.status(500).json({
|
||||
errorMessage: e.message
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
app.get('/api/lnd/unifiedTrx', (req, res) => {
|
||||
|
|
@ -1375,7 +1320,7 @@ module.exports = async (
|
|||
}
|
||||
|
||||
return res.status(200).json(
|
||||
await listPayments({
|
||||
await LV2.listPayments({
|
||||
include_incomplete,
|
||||
index_offset,
|
||||
max_payments,
|
||||
|
|
@ -1662,7 +1607,7 @@ module.exports = async (
|
|||
})
|
||||
}
|
||||
|
||||
const payment = await sendPaymentV2Keysend({
|
||||
const payment = await LV2.sendPaymentV2Keysend({
|
||||
amt,
|
||||
dest,
|
||||
feeLimit,
|
||||
|
|
@ -1675,7 +1620,7 @@ module.exports = async (
|
|||
}
|
||||
const { payreq } = req.body
|
||||
|
||||
const payment = await sendPaymentV2Invoice({
|
||||
const payment = await LV2.sendPaymentV2Invoice({
|
||||
feeLimit,
|
||||
payment_request: payreq,
|
||||
amt: req.body.amt,
|
||||
|
|
@ -1764,64 +1709,32 @@ module.exports = async (
|
|||
})
|
||||
|
||||
// addinvoice
|
||||
app.post('/api/lnd/addinvoice', (req, res) => {
|
||||
const { lightning } = LightningServices.services
|
||||
const invoiceRequest = { memo: req.body.memo, private: true }
|
||||
if (req.body.value) {
|
||||
invoiceRequest.value = req.body.value
|
||||
}
|
||||
if (req.body.expiry) {
|
||||
invoiceRequest.expiry = req.body.expiry
|
||||
}
|
||||
lightning.addInvoice(invoiceRequest, async (err, newInvoice) => {
|
||||
if (err) {
|
||||
logger.debug('AddInvoice Error:', err)
|
||||
const health = await checkHealth()
|
||||
if (health.LNDStatus.success) {
|
||||
res.status(400).json({
|
||||
field: 'addInvoice',
|
||||
errorMessage: sanitizeLNDError(err.message)
|
||||
})
|
||||
} else {
|
||||
res.status(500)
|
||||
res.json({ errorMessage: 'LND is down' })
|
||||
app.post('/api/lnd/addinvoice', async (req, res) => {
|
||||
const { expiry, value, memo } = req.body
|
||||
const addInvoiceRes = await LV2.addInvoice(value, memo, true, expiry)
|
||||
|
||||
if (value) {
|
||||
const channelsList = await LV2.listChannels({ active_only: true })
|
||||
let remoteBalance = Big(0)
|
||||
channelsList.forEach(element => {
|
||||
const remB = Big(element.remote_balance)
|
||||
if (remB.gt(remoteBalance)) {
|
||||
remoteBalance = remB
|
||||
}
|
||||
return err
|
||||
}
|
||||
logger.debug('AddInvoice:', newInvoice)
|
||||
if (req.body.value) {
|
||||
logger.debug('AddInvoice liquidity check:')
|
||||
lightning.listChannels({ active_only: true }, async (err, response) => {
|
||||
if (err) {
|
||||
logger.debug('ListChannels Error:', err)
|
||||
const health = await checkHealth()
|
||||
if (health.LNDStatus.success) {
|
||||
res.status(400).json({
|
||||
field: 'listChannels',
|
||||
errorMessage: sanitizeLNDError(err.message)
|
||||
})
|
||||
} else {
|
||||
res.status(500)
|
||||
res.json({ errorMessage: 'LND is down' })
|
||||
}
|
||||
}
|
||||
logger.debug('ListChannels:', response)
|
||||
const channelsList = response.channels
|
||||
let remoteBalance = Big(0)
|
||||
channelsList.forEach(element => {
|
||||
const remB = Big(element.remote_balance)
|
||||
if (remB.gt(remoteBalance)) {
|
||||
remoteBalance = remB
|
||||
}
|
||||
})
|
||||
newInvoice.liquidityCheck = remoteBalance > req.body.value
|
||||
//newInvoice.remoteBalance = remoteBalance
|
||||
res.json(newInvoice)
|
||||
})
|
||||
} else {
|
||||
res.json(newInvoice)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
addInvoiceRes.liquidityCheck = remoteBalance > value
|
||||
//newInvoice.remoteBalance = remoteBalance
|
||||
}
|
||||
|
||||
try {
|
||||
return res.json(addInvoiceRes)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
return res.status(500).json({
|
||||
errorMessage: e.message
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// signmessage
|
||||
|
|
@ -1959,23 +1872,25 @@ module.exports = async (
|
|||
)
|
||||
})
|
||||
|
||||
app.post('/api/lnd/listunspent', (req, res) => {
|
||||
const { lightning } = LightningServices.services
|
||||
const { minConfirmations = 3, maxConfirmations = 6 } = req.body
|
||||
lightning.listUnspent(
|
||||
{
|
||||
min_confs: minConfirmations,
|
||||
max_confs: maxConfirmations
|
||||
},
|
||||
(err, unspent) => {
|
||||
if (err) {
|
||||
return handleError(res, err)
|
||||
}
|
||||
logger.debug('ListUnspent:', unspent)
|
||||
res.json(unspent)
|
||||
}
|
||||
)
|
||||
})
|
||||
const listunspent = async (req, res) => {
|
||||
try {
|
||||
return res.status(200).json({
|
||||
utxos: await LV2.listUnspent(
|
||||
req.body.minConfirmations,
|
||||
req.body.maxConfirmations
|
||||
)
|
||||
})
|
||||
} catch (e) {
|
||||
return res.status(500).json({
|
||||
errorMessage: e.message
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
app.get('/api/lnd/listunspent', listunspent)
|
||||
|
||||
// TODO: should be GET
|
||||
app.post('/api/lnd/listunspent', listunspent)
|
||||
|
||||
app.get('/api/lnd/transactions', (req, res) => {
|
||||
const { lightning } = LightningServices.services
|
||||
|
|
|
|||
|
|
@ -74,6 +74,13 @@ class LightningServices {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {import('./types').Services}
|
||||
*/
|
||||
getServices() {
|
||||
return this.services
|
||||
}
|
||||
|
||||
get servicesData() {
|
||||
return this.lnServicesData
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/**
|
||||
* @format
|
||||
*/
|
||||
import * as Common from 'shock-common'
|
||||
|
||||
export interface PaymentV2 {
|
||||
payment_hash: string
|
||||
|
|
@ -106,3 +107,90 @@ export interface SendPaymentInvoiceParams {
|
|||
payment_request: string
|
||||
timeoutSeconds?: number
|
||||
}
|
||||
|
||||
type StreamListener = (data: any) => void
|
||||
|
||||
/**
|
||||
* Caution: Not all methods return an stream.
|
||||
*/
|
||||
interface LightningStream {
|
||||
on(ev: 'data' | 'end' | 'error' | 'status', listener: StreamListener): void
|
||||
}
|
||||
|
||||
type LightningCB = (err: Error, data: Record<string, any>) => void
|
||||
|
||||
type LightningMethod = (
|
||||
args: Record<string, any>,
|
||||
cb?: LightningCB
|
||||
) => LightningStream
|
||||
|
||||
/**
|
||||
* Makes it easier for code calling services.
|
||||
*/
|
||||
export interface Services {
|
||||
lightning: Record<string, LightningMethod>
|
||||
walletUnlocker: Record<string, LightningMethod>
|
||||
router: Record<string, LightningMethod>
|
||||
}
|
||||
|
||||
export interface ListChannelsReq {
|
||||
active_only: boolean
|
||||
inactive_only: boolean
|
||||
public_only: boolean
|
||||
private_only: boolean
|
||||
/**
|
||||
* Filters the response for channels with a target peer's pubkey. If peer is
|
||||
* empty, all channels will be returned.
|
||||
*/
|
||||
peer: Common.Bytes
|
||||
}
|
||||
|
||||
/**
|
||||
* https://api.lightning.community/#pendingchannels
|
||||
*/
|
||||
export interface PendingChannelsRes {
|
||||
/**
|
||||
* The balance in satoshis encumbered in pending channels.
|
||||
*/
|
||||
total_limbo_balance: string
|
||||
/**
|
||||
* Channels pending opening.
|
||||
*/
|
||||
pending_open_channels: Common.PendingOpenChannel[]
|
||||
/**
|
||||
* Channels pending force closing.
|
||||
*/
|
||||
pending_force_closing_channels: Common.ForceClosedChannel[]
|
||||
/**
|
||||
* Channels waiting for closing tx to confirm.
|
||||
*/
|
||||
waiting_close_channels: Common.WaitingCloseChannel[]
|
||||
}
|
||||
|
||||
/**
|
||||
* https://github.com/lightningnetwork/lnd/blob/daf7c8a85420fc67fffa18fa5f7d08c2040946e4/lnrpc/rpc.proto#L2948
|
||||
*/
|
||||
export interface AddInvoiceRes {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
r_hash: Common.Bytes
|
||||
/**
|
||||
* A bare-bones invoice for a payment within the Lightning Network. With the
|
||||
* details of the invoice, the sender has all the data necessary to send a
|
||||
* payment to the recipient.
|
||||
*/
|
||||
payment_request: string
|
||||
/**
|
||||
* The "add" index of this invoice. Each newly created invoice will increment
|
||||
* this index making it monotonically increasing. Callers to the
|
||||
* SubscribeInvoices call can use this to instantly get notified of all added
|
||||
* invoices with an add_index greater than this one.
|
||||
*/
|
||||
add_index: string
|
||||
/**
|
||||
* The payment address of the generated invoice. This value should be used in
|
||||
* all payments for this invoice as we require it for end to end security.
|
||||
*/
|
||||
payment_addr: Common.Bytes
|
||||
}
|
||||
|
|
|
|||
|
|
@ -402,9 +402,185 @@ const decodePayReq = payReq =>
|
|||
)
|
||||
})
|
||||
|
||||
/**
|
||||
* @param {0|1} type
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
const newAddress = (type = 0) => {
|
||||
const { lightning } = lightningServices.getServices()
|
||||
|
||||
return Common.Utils.makePromise((res, rej) => {
|
||||
lightning.newAddress({ type }, (err, response) => {
|
||||
if (err) {
|
||||
rej(new Error(err.message))
|
||||
} else {
|
||||
res(response.address)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} minConfs
|
||||
* @param {number} maxConfs
|
||||
* @returns {Promise<Common.Utxo[]>}
|
||||
*/
|
||||
const listUnspent = (minConfs = 3, maxConfs = 6) =>
|
||||
Common.makePromise((res, rej) => {
|
||||
const { lightning } = lightningServices.getServices()
|
||||
|
||||
lightning.listUnspent(
|
||||
{
|
||||
min_confs: minConfs,
|
||||
max_confs: maxConfs
|
||||
},
|
||||
(err, unspent) => {
|
||||
if (err) {
|
||||
rej(new Error(err.message))
|
||||
} else {
|
||||
res(unspent.utxos)
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
/**
|
||||
* @typedef {import('./types').ListChannelsReq} ListChannelsReq
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {ListChannelsReq} req
|
||||
* @returns {Promise<Common.Channel[]>}
|
||||
*/
|
||||
const listChannels = req =>
|
||||
Common.makePromise((res, rej) => {
|
||||
const { lightning } = lightningServices.getServices()
|
||||
|
||||
lightning.listChannels(req, (err, resp) => {
|
||||
if (err) {
|
||||
rej(new Error(err.message))
|
||||
} else {
|
||||
res(resp.channels)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* https://api.lightning.community/#getchaninfo
|
||||
* @param {string} chanID
|
||||
* @returns {Promise<Common.ChannelEdge>}
|
||||
*/
|
||||
const getChanInfo = chanID =>
|
||||
Common.makePromise((res, rej) => {
|
||||
const { lightning } = lightningServices.getServices()
|
||||
|
||||
lightning.getChanInfo(
|
||||
{
|
||||
chan_id: chanID
|
||||
},
|
||||
(err, resp) => {
|
||||
if (err) {
|
||||
rej(new Error(err.message))
|
||||
} else {
|
||||
// Needs cast because typescript refuses to assign Record<string, any>
|
||||
// to an actual object :shrugs
|
||||
res(/** @type {Common.ChannelEdge} */ (resp))
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
/**
|
||||
* https://api.lightning.community/#listpeers
|
||||
* @param {boolean=} latestError If true, only the last error that our peer sent
|
||||
* us will be returned with the peer's information, rather than the full set of
|
||||
* historic errors we have stored.
|
||||
* @returns {Promise<Common.Peer[]>}
|
||||
*/
|
||||
const listPeers = latestError =>
|
||||
Common.makePromise((res, rej) => {
|
||||
const { lightning } = lightningServices.getServices()
|
||||
|
||||
lightning.listPeers(
|
||||
{
|
||||
latest_error: latestError
|
||||
},
|
||||
(err, resp) => {
|
||||
if (err) {
|
||||
rej(new Error(err.message))
|
||||
} else {
|
||||
res(resp.peers)
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
/**
|
||||
* @typedef {import('./types').PendingChannelsRes} PendingChannelsRes
|
||||
*/
|
||||
|
||||
/**
|
||||
* @returns {Promise<PendingChannelsRes>}
|
||||
*/
|
||||
const pendingChannels = () =>
|
||||
Common.makePromise((res, rej) => {
|
||||
const { lightning } = lightningServices.getServices()
|
||||
|
||||
lightning.pendingChannels({}, (err, resp) => {
|
||||
if (err) {
|
||||
rej(new Error(err.message))
|
||||
} else {
|
||||
// Needs cast because typescript refuses to assign Record<string, any>
|
||||
// to an actual object :shrugs
|
||||
res(/** @type {PendingChannelsRes} */ (resp))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* @typedef {import('./types').AddInvoiceRes} AddInvoiceRes
|
||||
*/
|
||||
/**
|
||||
* https://api.lightning.community/#addinvoice
|
||||
* @param {number} value
|
||||
* @param {string=} memo
|
||||
* @param {boolean=} confidential Alias for `private`.
|
||||
* @param {number=} expiry
|
||||
* @returns {Promise<AddInvoiceRes>}
|
||||
*/
|
||||
const addInvoice = (value, memo = '', confidential = true, expiry = 180) =>
|
||||
Common.makePromise((res, rej) => {
|
||||
const { lightning } = lightningServices.getServices()
|
||||
|
||||
lightning.addInvoice(
|
||||
{
|
||||
value,
|
||||
memo,
|
||||
private: confidential,
|
||||
expiry
|
||||
},
|
||||
(err, resp) => {
|
||||
if (err) {
|
||||
rej(new Error(err.message))
|
||||
} else {
|
||||
// Needs cast because typescript refuses to assign Record<string, any>
|
||||
// to an actual object :shrugs
|
||||
res(/** @type {AddInvoiceRes} */ (resp))
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
module.exports = {
|
||||
sendPaymentV2Keysend,
|
||||
sendPaymentV2Invoice,
|
||||
listPayments,
|
||||
decodePayReq
|
||||
decodePayReq,
|
||||
newAddress,
|
||||
listUnspent,
|
||||
listChannels,
|
||||
getChanInfo,
|
||||
listPeers,
|
||||
pendingChannels,
|
||||
addInvoice
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue