Merge branch 'master' into feature/ln-ux
This commit is contained in:
commit
b54598a941
8 changed files with 2671 additions and 1495 deletions
|
|
@ -36,6 +36,8 @@ module.exports = (mainnet = false) => {
|
|||
lndAddress: "127.0.0.1:9735",
|
||||
maxNumRoutesToQuery: 20,
|
||||
lndProto: parsePath(`${__dirname}/rpc.proto`),
|
||||
routerProto: parsePath(`${__dirname}/router.proto`),
|
||||
walletUnlockerProto: parsePath(`${__dirname}/walletunlocker.proto`),
|
||||
lndHost: "localhost:10009",
|
||||
lndCertPath: parsePath(`${lndDirectory}/tls.cert`),
|
||||
macaroonPath: parsePath(
|
||||
|
|
@ -47,6 +49,7 @@ module.exports = (mainnet = false) => {
|
|||
lndLogFile: parsePath(`${lndDirectory}/logs/bitcoin/${network}/lnd.log`),
|
||||
lndDirPath: lndDirectory,
|
||||
peers: ["http://gun.shock.network:8765/gun"],
|
||||
useTLS: false,
|
||||
tokenExpirationMS: 4500000
|
||||
};
|
||||
};
|
||||
|
|
|
|||
581
config/router.proto
Normal file
581
config/router.proto
Normal file
|
|
@ -0,0 +1,581 @@
|
|||
syntax = "proto3";
|
||||
|
||||
import "rpc.proto";
|
||||
|
||||
package routerrpc;
|
||||
|
||||
option go_package = "github.com/lightningnetwork/lnd/lnrpc/routerrpc";
|
||||
|
||||
// Router is a service that offers advanced interaction with the router
|
||||
// subsystem of the daemon.
|
||||
service Router {
|
||||
/*
|
||||
SendPaymentV2 attempts to route a payment described by the passed
|
||||
PaymentRequest to the final destination. The call returns a stream of
|
||||
payment updates.
|
||||
*/
|
||||
rpc SendPaymentV2 (SendPaymentRequest) returns (stream lnrpc.Payment);
|
||||
|
||||
/*
|
||||
TrackPaymentV2 returns an update stream for the payment identified by the
|
||||
payment hash.
|
||||
*/
|
||||
rpc TrackPaymentV2 (TrackPaymentRequest) returns (stream lnrpc.Payment);
|
||||
|
||||
/*
|
||||
EstimateRouteFee allows callers to obtain a lower bound w.r.t how much it
|
||||
may cost to send an HTLC to the target end destination.
|
||||
*/
|
||||
rpc EstimateRouteFee (RouteFeeRequest) returns (RouteFeeResponse);
|
||||
|
||||
/*
|
||||
Deprecated, use SendToRouteV2. SendToRoute attempts to make a payment via
|
||||
the specified route. This method differs from SendPayment in that it
|
||||
allows users to specify a full route manually. This can be used for
|
||||
things like rebalancing, and atomic swaps. It differs from the newer
|
||||
SendToRouteV2 in that it doesn't return the full HTLC information.
|
||||
*/
|
||||
rpc SendToRoute (SendToRouteRequest) returns (SendToRouteResponse) {
|
||||
option deprecated = true;
|
||||
}
|
||||
|
||||
/*
|
||||
SendToRouteV2 attempts to make a payment via the specified route. This method
|
||||
differs from SendPayment in that it allows users to specify a full route
|
||||
manually. This can be used for things like rebalancing, and atomic swaps.
|
||||
*/
|
||||
rpc SendToRouteV2 (SendToRouteRequest) returns (lnrpc.HTLCAttempt);
|
||||
|
||||
/*
|
||||
ResetMissionControl clears all mission control state and starts with a clean
|
||||
slate.
|
||||
*/
|
||||
rpc ResetMissionControl (ResetMissionControlRequest)
|
||||
returns (ResetMissionControlResponse);
|
||||
|
||||
/*
|
||||
QueryMissionControl exposes the internal mission control state to callers.
|
||||
It is a development feature.
|
||||
*/
|
||||
rpc QueryMissionControl (QueryMissionControlRequest)
|
||||
returns (QueryMissionControlResponse);
|
||||
|
||||
/*
|
||||
QueryProbability returns the current success probability estimate for a
|
||||
given node pair and amount.
|
||||
*/
|
||||
rpc QueryProbability (QueryProbabilityRequest)
|
||||
returns (QueryProbabilityResponse);
|
||||
|
||||
/*
|
||||
BuildRoute builds a fully specified route based on a list of hop public
|
||||
keys. It retrieves the relevant channel policies from the graph in order to
|
||||
calculate the correct fees and time locks.
|
||||
*/
|
||||
rpc BuildRoute (BuildRouteRequest) returns (BuildRouteResponse);
|
||||
|
||||
/*
|
||||
SubscribeHtlcEvents creates a uni-directional stream from the server to
|
||||
the client which delivers a stream of htlc events.
|
||||
*/
|
||||
rpc SubscribeHtlcEvents (SubscribeHtlcEventsRequest)
|
||||
returns (stream HtlcEvent);
|
||||
|
||||
/*
|
||||
Deprecated, use SendPaymentV2. SendPayment attempts to route a payment
|
||||
described by the passed PaymentRequest to the final destination. The call
|
||||
returns a stream of payment status updates.
|
||||
*/
|
||||
rpc SendPayment (SendPaymentRequest) returns (stream PaymentStatus) {
|
||||
option deprecated = true;
|
||||
}
|
||||
|
||||
/*
|
||||
Deprecated, use TrackPaymentV2. TrackPayment returns an update stream for
|
||||
the payment identified by the payment hash.
|
||||
*/
|
||||
rpc TrackPayment (TrackPaymentRequest) returns (stream PaymentStatus) {
|
||||
option deprecated = true;
|
||||
}
|
||||
}
|
||||
|
||||
message SendPaymentRequest {
|
||||
// The identity pubkey of the payment recipient
|
||||
bytes dest = 1;
|
||||
|
||||
/*
|
||||
Number of satoshis to send.
|
||||
|
||||
The fields amt and amt_msat are mutually exclusive.
|
||||
*/
|
||||
int64 amt = 2;
|
||||
|
||||
/*
|
||||
Number of millisatoshis to send.
|
||||
|
||||
The fields amt and amt_msat are mutually exclusive.
|
||||
*/
|
||||
int64 amt_msat = 12;
|
||||
|
||||
// The hash to use within the payment's HTLC
|
||||
bytes payment_hash = 3;
|
||||
|
||||
/*
|
||||
The CLTV delta from the current height that should be used to set the
|
||||
timelock for the final hop.
|
||||
*/
|
||||
int32 final_cltv_delta = 4;
|
||||
|
||||
/*
|
||||
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. The amount in the payment request may be zero. In
|
||||
that case it is required to set the amt field as well. If no payment request
|
||||
is specified, the following fields are required: dest, amt and payment_hash.
|
||||
*/
|
||||
string payment_request = 5;
|
||||
|
||||
/*
|
||||
An upper limit on the amount of time we should spend when attempting to
|
||||
fulfill the payment. This is expressed in seconds. If we cannot make a
|
||||
successful payment within this time frame, an error will be returned.
|
||||
This field must be non-zero.
|
||||
*/
|
||||
int32 timeout_seconds = 6;
|
||||
|
||||
/*
|
||||
The maximum number of satoshis that will be paid as a fee of the payment.
|
||||
If this field is left to the default value of 0, only zero-fee routes will
|
||||
be considered. This usually means single hop routes connecting directly to
|
||||
the destination. To send the payment without a fee limit, use max int here.
|
||||
|
||||
The fields fee_limit_sat and fee_limit_msat are mutually exclusive.
|
||||
*/
|
||||
int64 fee_limit_sat = 7;
|
||||
|
||||
/*
|
||||
The maximum number of millisatoshis that will be paid as a fee of the
|
||||
payment. If this field is left to the default value of 0, only zero-fee
|
||||
routes will be considered. This usually means single hop routes connecting
|
||||
directly to the destination. To send the payment without a fee limit, use
|
||||
max int here.
|
||||
|
||||
The fields fee_limit_sat and fee_limit_msat are mutually exclusive.
|
||||
*/
|
||||
int64 fee_limit_msat = 13;
|
||||
|
||||
/*
|
||||
Deprecated, use outgoing_chan_ids. The channel id of the channel that must
|
||||
be taken to the first hop. If zero, any channel may be used (unless
|
||||
outgoing_chan_ids are set).
|
||||
*/
|
||||
uint64 outgoing_chan_id = 8 [jstype = JS_STRING, deprecated = true];
|
||||
|
||||
/*
|
||||
The channel ids of the channels are allowed for the first hop. If empty,
|
||||
any channel may be used.
|
||||
*/
|
||||
repeated uint64 outgoing_chan_ids = 19;
|
||||
|
||||
/*
|
||||
The pubkey of the last hop of the route. If empty, any hop may be used.
|
||||
*/
|
||||
bytes last_hop_pubkey = 14;
|
||||
|
||||
/*
|
||||
An optional maximum total time lock for the route. This should not exceed
|
||||
lnd's `--max-cltv-expiry` setting. If zero, then the value of
|
||||
`--max-cltv-expiry` is enforced.
|
||||
*/
|
||||
int32 cltv_limit = 9;
|
||||
|
||||
/*
|
||||
Optional route hints to reach the destination through private channels.
|
||||
*/
|
||||
repeated lnrpc.RouteHint route_hints = 10;
|
||||
|
||||
/*
|
||||
An optional field that can be used to pass an arbitrary set of TLV records
|
||||
to a peer which understands the new records. This can be used to pass
|
||||
application specific data during the payment attempt. Record types are
|
||||
required to be in the custom range >= 65536. When using REST, the values
|
||||
must be encoded as base64.
|
||||
*/
|
||||
map<uint64, bytes> dest_custom_records = 11;
|
||||
|
||||
// If set, circular payments to self are permitted.
|
||||
bool allow_self_payment = 15;
|
||||
|
||||
/*
|
||||
Features assumed to be supported by the final node. All transitive feature
|
||||
dependencies must also be set properly. For a given feature bit pair, either
|
||||
optional or remote may be set, but not both. If this field is nil or empty,
|
||||
the router will try to load destination features from the graph as a
|
||||
fallback.
|
||||
*/
|
||||
repeated lnrpc.FeatureBit dest_features = 16;
|
||||
|
||||
/*
|
||||
The maximum number of partial payments that may be use to complete the full
|
||||
amount.
|
||||
*/
|
||||
uint32 max_parts = 17;
|
||||
|
||||
/*
|
||||
If set, only the final payment update is streamed back. Intermediate updates
|
||||
that show which htlcs are still in flight are suppressed.
|
||||
*/
|
||||
bool no_inflight_updates = 18;
|
||||
}
|
||||
|
||||
message TrackPaymentRequest {
|
||||
// The hash of the payment to look up.
|
||||
bytes payment_hash = 1;
|
||||
|
||||
/*
|
||||
If set, only the final payment update is streamed back. Intermediate updates
|
||||
that show which htlcs are still in flight are suppressed.
|
||||
*/
|
||||
bool no_inflight_updates = 2;
|
||||
}
|
||||
|
||||
message RouteFeeRequest {
|
||||
/*
|
||||
The destination once wishes to obtain a routing fee quote to.
|
||||
*/
|
||||
bytes dest = 1;
|
||||
|
||||
/*
|
||||
The amount one wishes to send to the target destination.
|
||||
*/
|
||||
int64 amt_sat = 2;
|
||||
}
|
||||
|
||||
message RouteFeeResponse {
|
||||
/*
|
||||
A lower bound of the estimated fee to the target destination within the
|
||||
network, expressed in milli-satoshis.
|
||||
*/
|
||||
int64 routing_fee_msat = 1;
|
||||
|
||||
/*
|
||||
An estimate of the worst case time delay that can occur. Note that callers
|
||||
will still need to factor in the final CLTV delta of the last hop into this
|
||||
value.
|
||||
*/
|
||||
int64 time_lock_delay = 2;
|
||||
}
|
||||
|
||||
message SendToRouteRequest {
|
||||
// The payment hash to use for the HTLC.
|
||||
bytes payment_hash = 1;
|
||||
|
||||
// Route that should be used to attempt to complete the payment.
|
||||
lnrpc.Route route = 2;
|
||||
}
|
||||
|
||||
message SendToRouteResponse {
|
||||
// The preimage obtained by making the payment.
|
||||
bytes preimage = 1;
|
||||
|
||||
// The failure message in case the payment failed.
|
||||
lnrpc.Failure failure = 2;
|
||||
}
|
||||
|
||||
message ResetMissionControlRequest {
|
||||
}
|
||||
|
||||
message ResetMissionControlResponse {
|
||||
}
|
||||
|
||||
message QueryMissionControlRequest {
|
||||
}
|
||||
|
||||
// QueryMissionControlResponse contains mission control state.
|
||||
message QueryMissionControlResponse {
|
||||
reserved 1;
|
||||
|
||||
// Node pair-level mission control state.
|
||||
repeated PairHistory pairs = 2;
|
||||
}
|
||||
|
||||
// PairHistory contains the mission control state for a particular node pair.
|
||||
message PairHistory {
|
||||
// The source node pubkey of the pair.
|
||||
bytes node_from = 1;
|
||||
|
||||
// The destination node pubkey of the pair.
|
||||
bytes node_to = 2;
|
||||
|
||||
reserved 3, 4, 5, 6;
|
||||
|
||||
PairData history = 7;
|
||||
}
|
||||
|
||||
message PairData {
|
||||
// Time of last failure.
|
||||
int64 fail_time = 1;
|
||||
|
||||
/*
|
||||
Lowest amount that failed to forward rounded to whole sats. This may be
|
||||
set to zero if the failure is independent of amount.
|
||||
*/
|
||||
int64 fail_amt_sat = 2;
|
||||
|
||||
/*
|
||||
Lowest amount that failed to forward in millisats. This may be
|
||||
set to zero if the failure is independent of amount.
|
||||
*/
|
||||
int64 fail_amt_msat = 4;
|
||||
|
||||
reserved 3;
|
||||
|
||||
// Time of last success.
|
||||
int64 success_time = 5;
|
||||
|
||||
// Highest amount that we could successfully forward rounded to whole sats.
|
||||
int64 success_amt_sat = 6;
|
||||
|
||||
// Highest amount that we could successfully forward in millisats.
|
||||
int64 success_amt_msat = 7;
|
||||
}
|
||||
|
||||
message QueryProbabilityRequest {
|
||||
// The source node pubkey of the pair.
|
||||
bytes from_node = 1;
|
||||
|
||||
// The destination node pubkey of the pair.
|
||||
bytes to_node = 2;
|
||||
|
||||
// The amount for which to calculate a probability.
|
||||
int64 amt_msat = 3;
|
||||
}
|
||||
|
||||
message QueryProbabilityResponse {
|
||||
// The success probability for the requested pair.
|
||||
double probability = 1;
|
||||
|
||||
// The historical data for the requested pair.
|
||||
PairData history = 2;
|
||||
}
|
||||
|
||||
message BuildRouteRequest {
|
||||
/*
|
||||
The amount to send expressed in msat. If set to zero, the minimum routable
|
||||
amount is used.
|
||||
*/
|
||||
int64 amt_msat = 1;
|
||||
|
||||
/*
|
||||
CLTV delta from the current height that should be used for the timelock
|
||||
of the final hop
|
||||
*/
|
||||
int32 final_cltv_delta = 2;
|
||||
|
||||
/*
|
||||
The channel id of the channel that must be taken to the first hop. If zero,
|
||||
any channel may be used.
|
||||
*/
|
||||
uint64 outgoing_chan_id = 3 [jstype = JS_STRING];
|
||||
|
||||
/*
|
||||
A list of hops that defines the route. This does not include the source hop
|
||||
pubkey.
|
||||
*/
|
||||
repeated bytes hop_pubkeys = 4;
|
||||
}
|
||||
|
||||
message BuildRouteResponse {
|
||||
/*
|
||||
Fully specified route that can be used to execute the payment.
|
||||
*/
|
||||
lnrpc.Route route = 1;
|
||||
}
|
||||
|
||||
message SubscribeHtlcEventsRequest {
|
||||
}
|
||||
|
||||
/*
|
||||
HtlcEvent contains the htlc event that was processed. These are served on a
|
||||
best-effort basis; events are not persisted, delivery is not guaranteed
|
||||
(in the event of a crash in the switch, forward events may be lost) and
|
||||
some events may be replayed upon restart. Events consumed from this package
|
||||
should be de-duplicated by the htlc's unique combination of incoming and
|
||||
outgoing channel id and htlc id. [EXPERIMENTAL]
|
||||
*/
|
||||
message HtlcEvent {
|
||||
/*
|
||||
The short channel id that the incoming htlc arrived at our node on. This
|
||||
value is zero for sends.
|
||||
*/
|
||||
uint64 incoming_channel_id = 1;
|
||||
|
||||
/*
|
||||
The short channel id that the outgoing htlc left our node on. This value
|
||||
is zero for receives.
|
||||
*/
|
||||
uint64 outgoing_channel_id = 2;
|
||||
|
||||
/*
|
||||
Incoming id is the index of the incoming htlc in the incoming channel.
|
||||
This value is zero for sends.
|
||||
*/
|
||||
uint64 incoming_htlc_id = 3;
|
||||
|
||||
/*
|
||||
Outgoing id is the index of the outgoing htlc in the outgoing channel.
|
||||
This value is zero for receives.
|
||||
*/
|
||||
uint64 outgoing_htlc_id = 4;
|
||||
|
||||
/*
|
||||
The time in unix nanoseconds that the event occurred.
|
||||
*/
|
||||
uint64 timestamp_ns = 5;
|
||||
|
||||
enum EventType {
|
||||
UNKNOWN = 0;
|
||||
SEND = 1;
|
||||
RECEIVE = 2;
|
||||
FORWARD = 3;
|
||||
}
|
||||
|
||||
/*
|
||||
The event type indicates whether the htlc was part of a send, receive or
|
||||
forward.
|
||||
*/
|
||||
EventType event_type = 6;
|
||||
|
||||
oneof event {
|
||||
ForwardEvent forward_event = 7;
|
||||
ForwardFailEvent forward_fail_event = 8;
|
||||
SettleEvent settle_event = 9;
|
||||
LinkFailEvent link_fail_event = 10;
|
||||
}
|
||||
}
|
||||
|
||||
message HtlcInfo {
|
||||
// The timelock on the incoming htlc.
|
||||
uint32 incoming_timelock = 1;
|
||||
|
||||
// The timelock on the outgoing htlc.
|
||||
uint32 outgoing_timelock = 2;
|
||||
|
||||
// The amount of the incoming htlc.
|
||||
uint64 incoming_amt_msat = 3;
|
||||
|
||||
// The amount of the outgoing htlc.
|
||||
uint64 outgoing_amt_msat = 4;
|
||||
}
|
||||
|
||||
message ForwardEvent {
|
||||
// Info contains details about the htlc that was forwarded.
|
||||
HtlcInfo info = 1;
|
||||
}
|
||||
|
||||
message ForwardFailEvent {
|
||||
}
|
||||
|
||||
message SettleEvent {
|
||||
}
|
||||
|
||||
message LinkFailEvent {
|
||||
// Info contains details about the htlc that we failed.
|
||||
HtlcInfo info = 1;
|
||||
|
||||
// FailureCode is the BOLT error code for the failure.
|
||||
lnrpc.Failure.FailureCode wire_failure = 2;
|
||||
|
||||
/*
|
||||
FailureDetail provides additional information about the reason for the
|
||||
failure. This detail enriches the information provided by the wire message
|
||||
and may be 'no detail' if the wire message requires no additional metadata.
|
||||
*/
|
||||
FailureDetail failure_detail = 3;
|
||||
|
||||
// A string representation of the link failure.
|
||||
string failure_string = 4;
|
||||
}
|
||||
|
||||
enum FailureDetail {
|
||||
UNKNOWN = 0;
|
||||
NO_DETAIL = 1;
|
||||
ONION_DECODE = 2;
|
||||
LINK_NOT_ELIGIBLE = 3;
|
||||
ON_CHAIN_TIMEOUT = 4;
|
||||
HTLC_EXCEEDS_MAX = 5;
|
||||
INSUFFICIENT_BALANCE = 6;
|
||||
INCOMPLETE_FORWARD = 7;
|
||||
HTLC_ADD_FAILED = 8;
|
||||
FORWARDS_DISABLED = 9;
|
||||
INVOICE_CANCELED = 10;
|
||||
INVOICE_UNDERPAID = 11;
|
||||
INVOICE_EXPIRY_TOO_SOON = 12;
|
||||
INVOICE_NOT_OPEN = 13;
|
||||
MPP_INVOICE_TIMEOUT = 14;
|
||||
ADDRESS_MISMATCH = 15;
|
||||
SET_TOTAL_MISMATCH = 16;
|
||||
SET_TOTAL_TOO_LOW = 17;
|
||||
SET_OVERPAID = 18;
|
||||
UNKNOWN_INVOICE = 19;
|
||||
INVALID_KEYSEND = 20;
|
||||
MPP_IN_PROGRESS = 21;
|
||||
CIRCULAR_ROUTE = 22;
|
||||
}
|
||||
|
||||
enum PaymentState {
|
||||
/*
|
||||
Payment is still in flight.
|
||||
*/
|
||||
IN_FLIGHT = 0;
|
||||
|
||||
/*
|
||||
Payment completed successfully.
|
||||
*/
|
||||
SUCCEEDED = 1;
|
||||
|
||||
/*
|
||||
There are more routes to try, but the payment timeout was exceeded.
|
||||
*/
|
||||
FAILED_TIMEOUT = 2;
|
||||
|
||||
/*
|
||||
All possible routes were tried and failed permanently. Or were no
|
||||
routes to the destination at all.
|
||||
*/
|
||||
FAILED_NO_ROUTE = 3;
|
||||
|
||||
/*
|
||||
A non-recoverable error has occured.
|
||||
*/
|
||||
FAILED_ERROR = 4;
|
||||
|
||||
/*
|
||||
Payment details incorrect (unknown hash, invalid amt or
|
||||
invalid final cltv delta)
|
||||
*/
|
||||
FAILED_INCORRECT_PAYMENT_DETAILS = 5;
|
||||
|
||||
/*
|
||||
Insufficient local balance.
|
||||
*/
|
||||
FAILED_INSUFFICIENT_BALANCE = 6;
|
||||
}
|
||||
|
||||
message PaymentStatus {
|
||||
// Current state the payment is in.
|
||||
PaymentState state = 1;
|
||||
|
||||
/*
|
||||
The pre-image of the payment when state is SUCCEEDED.
|
||||
*/
|
||||
bytes preimage = 2;
|
||||
|
||||
reserved 3;
|
||||
|
||||
/*
|
||||
The HTLCs made in attempt to settle the payment [EXPERIMENTAL].
|
||||
*/
|
||||
repeated lnrpc.HTLCAttempt htlcs = 4;
|
||||
}
|
||||
|
||||
2938
config/rpc.proto
2938
config/rpc.proto
File diff suppressed because it is too large
Load diff
192
config/walletunlocker.proto
Normal file
192
config/walletunlocker.proto
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
syntax = "proto3";
|
||||
|
||||
import "rpc.proto";
|
||||
|
||||
package lnrpc;
|
||||
|
||||
option go_package = "github.com/lightningnetwork/lnd/lnrpc";
|
||||
|
||||
/*
|
||||
* Comments in this file will be directly parsed into the API
|
||||
* Documentation as descriptions of the associated method, message, or field.
|
||||
* These descriptions should go right above the definition of the object, and
|
||||
* can be in either block or // comment format.
|
||||
*
|
||||
* An RPC method can be matched to an lncli command by placing a line in the
|
||||
* beginning of the description in exactly the following format:
|
||||
* lncli: `methodname`
|
||||
*
|
||||
* Failure to specify the exact name of the command will cause documentation
|
||||
* generation to fail.
|
||||
*
|
||||
* More information on how exactly the gRPC documentation is generated from
|
||||
* this proto file can be found here:
|
||||
* https://github.com/lightninglabs/lightning-api
|
||||
*/
|
||||
|
||||
// WalletUnlocker is a service that is used to set up a wallet password for
|
||||
// lnd at first startup, and unlock a previously set up wallet.
|
||||
service WalletUnlocker {
|
||||
/*
|
||||
GenSeed is the first method that should be used to instantiate a new lnd
|
||||
instance. This method allows a caller to generate a new aezeed cipher seed
|
||||
given an optional passphrase. If provided, the passphrase will be necessary
|
||||
to decrypt the cipherseed to expose the internal wallet seed.
|
||||
|
||||
Once the cipherseed is obtained and verified by the user, the InitWallet
|
||||
method should be used to commit the newly generated seed, and create the
|
||||
wallet.
|
||||
*/
|
||||
rpc GenSeed (GenSeedRequest) returns (GenSeedResponse);
|
||||
|
||||
/*
|
||||
InitWallet is used when lnd is starting up for the first time to fully
|
||||
initialize the daemon and its internal wallet. At the very least a wallet
|
||||
password must be provided. This will be used to encrypt sensitive material
|
||||
on disk.
|
||||
|
||||
In the case of a recovery scenario, the user can also specify their aezeed
|
||||
mnemonic and passphrase. If set, then the daemon will use this prior state
|
||||
to initialize its internal wallet.
|
||||
|
||||
Alternatively, this can be used along with the GenSeed RPC to obtain a
|
||||
seed, then present it to the user. Once it has been verified by the user,
|
||||
the seed can be fed into this RPC in order to commit the new wallet.
|
||||
*/
|
||||
rpc InitWallet (InitWalletRequest) returns (InitWalletResponse);
|
||||
|
||||
/* lncli: `unlock`
|
||||
UnlockWallet is used at startup of lnd to provide a password to unlock
|
||||
the wallet database.
|
||||
*/
|
||||
rpc UnlockWallet (UnlockWalletRequest) returns (UnlockWalletResponse);
|
||||
|
||||
/* lncli: `changepassword`
|
||||
ChangePassword changes the password of the encrypted wallet. This will
|
||||
automatically unlock the wallet database if successful.
|
||||
*/
|
||||
rpc ChangePassword (ChangePasswordRequest) returns (ChangePasswordResponse);
|
||||
}
|
||||
|
||||
message GenSeedRequest {
|
||||
/*
|
||||
aezeed_passphrase is an optional user provided passphrase that will be used
|
||||
to encrypt the generated aezeed cipher seed. When using REST, this field
|
||||
must be encoded as base64.
|
||||
*/
|
||||
bytes aezeed_passphrase = 1;
|
||||
|
||||
/*
|
||||
seed_entropy is an optional 16-bytes generated via CSPRNG. If not
|
||||
specified, then a fresh set of randomness will be used to create the seed.
|
||||
When using REST, this field must be encoded as base64.
|
||||
*/
|
||||
bytes seed_entropy = 2;
|
||||
}
|
||||
message GenSeedResponse {
|
||||
/*
|
||||
cipher_seed_mnemonic is a 24-word mnemonic that encodes a prior aezeed
|
||||
cipher seed obtained by the user. This field is optional, as if not
|
||||
provided, then the daemon will generate a new cipher seed for the user.
|
||||
Otherwise, then the daemon will attempt to recover the wallet state linked
|
||||
to this cipher seed.
|
||||
*/
|
||||
repeated string cipher_seed_mnemonic = 1;
|
||||
|
||||
/*
|
||||
enciphered_seed are the raw aezeed cipher seed bytes. This is the raw
|
||||
cipher text before run through our mnemonic encoding scheme.
|
||||
*/
|
||||
bytes enciphered_seed = 2;
|
||||
}
|
||||
|
||||
message InitWalletRequest {
|
||||
/*
|
||||
wallet_password is the passphrase that should be used to encrypt the
|
||||
wallet. This MUST be at least 8 chars in length. After creation, this
|
||||
password is required to unlock the daemon. When using REST, this field
|
||||
must be encoded as base64.
|
||||
*/
|
||||
bytes wallet_password = 1;
|
||||
|
||||
/*
|
||||
cipher_seed_mnemonic is a 24-word mnemonic that encodes a prior aezeed
|
||||
cipher seed obtained by the user. This may have been generated by the
|
||||
GenSeed method, or be an existing seed.
|
||||
*/
|
||||
repeated string cipher_seed_mnemonic = 2;
|
||||
|
||||
/*
|
||||
aezeed_passphrase is an optional user provided passphrase that will be used
|
||||
to encrypt the generated aezeed cipher seed. When using REST, this field
|
||||
must be encoded as base64.
|
||||
*/
|
||||
bytes aezeed_passphrase = 3;
|
||||
|
||||
/*
|
||||
recovery_window is an optional argument specifying the address lookahead
|
||||
when restoring a wallet seed. The recovery window applies to each
|
||||
individual branch of the BIP44 derivation paths. Supplying a recovery
|
||||
window of zero indicates that no addresses should be recovered, such after
|
||||
the first initialization of the wallet.
|
||||
*/
|
||||
int32 recovery_window = 4;
|
||||
|
||||
/*
|
||||
channel_backups is an optional argument that allows clients to recover the
|
||||
settled funds within a set of channels. This should be populated if the
|
||||
user was unable to close out all channels and sweep funds before partial or
|
||||
total data loss occurred. If specified, then after on-chain recovery of
|
||||
funds, lnd begin to carry out the data loss recovery protocol in order to
|
||||
recover the funds in each channel from a remote force closed transaction.
|
||||
*/
|
||||
ChanBackupSnapshot channel_backups = 5;
|
||||
}
|
||||
message InitWalletResponse {
|
||||
}
|
||||
|
||||
message UnlockWalletRequest {
|
||||
/*
|
||||
wallet_password should be the current valid passphrase for the daemon. This
|
||||
will be required to decrypt on-disk material that the daemon requires to
|
||||
function properly. When using REST, this field must be encoded as base64.
|
||||
*/
|
||||
bytes wallet_password = 1;
|
||||
|
||||
/*
|
||||
recovery_window is an optional argument specifying the address lookahead
|
||||
when restoring a wallet seed. The recovery window applies to each
|
||||
individual branch of the BIP44 derivation paths. Supplying a recovery
|
||||
window of zero indicates that no addresses should be recovered, such after
|
||||
the first initialization of the wallet.
|
||||
*/
|
||||
int32 recovery_window = 2;
|
||||
|
||||
/*
|
||||
channel_backups is an optional argument that allows clients to recover the
|
||||
settled funds within a set of channels. This should be populated if the
|
||||
user was unable to close out all channels and sweep funds before partial or
|
||||
total data loss occurred. If specified, then after on-chain recovery of
|
||||
funds, lnd begin to carry out the data loss recovery protocol in order to
|
||||
recover the funds in each channel from a remote force closed transaction.
|
||||
*/
|
||||
ChanBackupSnapshot channel_backups = 3;
|
||||
}
|
||||
message UnlockWalletResponse {
|
||||
}
|
||||
|
||||
message ChangePasswordRequest {
|
||||
/*
|
||||
current_password should be the current valid passphrase used to unlock the
|
||||
daemon. When using REST, this field must be encoded as base64.
|
||||
*/
|
||||
bytes current_password = 1;
|
||||
|
||||
/*
|
||||
new_password should be the new passphrase that will be needed to unlock the
|
||||
daemon. When using REST, this field must be encoded as base64.
|
||||
*/
|
||||
bytes new_password = 2;
|
||||
}
|
||||
message ChangePasswordResponse {
|
||||
}
|
||||
|
|
@ -6,25 +6,49 @@ const errorConstants = require("../../constants/errors");
|
|||
|
||||
// expose the routes to our app with module.exports
|
||||
/**
|
||||
* @param {string} protoPath
|
||||
* @param {string} lndHost
|
||||
* @param {string} lndCertPath
|
||||
* @param {string|null} macaroonPath
|
||||
* @returns {Promise<any>}
|
||||
* @typedef LightningConfig
|
||||
* @prop {string} lnrpcProtoPath
|
||||
* @prop {string} routerProtoPath
|
||||
* @prop {string} walletUnlockerProtoPath
|
||||
* @prop {string} lndHost
|
||||
* @prop {string} lndCertPath
|
||||
* @prop {string?} macaroonPath
|
||||
*/
|
||||
module.exports = async (protoPath, lndHost, lndCertPath, macaroonPath) => {
|
||||
|
||||
/**
|
||||
* @typedef LightningServices
|
||||
* @prop {any} lightning
|
||||
* @prop {any} walletUnlocker
|
||||
* @prop {any} router
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {LightningConfig} args0
|
||||
* @returns {Promise<LightningServices>}
|
||||
*/
|
||||
module.exports = async ({
|
||||
lnrpcProtoPath,
|
||||
routerProtoPath,
|
||||
walletUnlockerProtoPath,
|
||||
lndHost,
|
||||
lndCertPath,
|
||||
macaroonPath
|
||||
}) => {
|
||||
try {
|
||||
process.env.GRPC_SSL_CIPHER_SUITES = "HIGH+ECDSA";
|
||||
|
||||
const packageDefinition = await protoLoader.load(protoPath, {
|
||||
const protoLoaderConfig = {
|
||||
keepCase: true,
|
||||
longs: String,
|
||||
enums: String,
|
||||
defaults: true,
|
||||
oneofs: true,
|
||||
includeDirs: ["node_modules/google-proto-files", "proto"]
|
||||
});
|
||||
const { lnrpc } = grpc.loadPackageDefinition(packageDefinition);
|
||||
}
|
||||
|
||||
const [lnrpcProto, routerProto, walletUnlockerProto] = await Promise.all([protoLoader.load(lnrpcProtoPath, protoLoaderConfig), protoLoader.load(routerProtoPath, protoLoaderConfig), protoLoader.load(walletUnlockerProtoPath, protoLoaderConfig)]);
|
||||
const { lnrpc } = grpc.loadPackageDefinition(lnrpcProto);
|
||||
const { routerrpc } = grpc.loadPackageDefinition(routerProto);
|
||||
const { lnrpc: walletunlockerrpc } = grpc.loadPackageDefinition(walletUnlockerProto);
|
||||
|
||||
const getCredentials = async () => {
|
||||
const lndCert = await fs.readFile(lndCertPath);
|
||||
|
|
@ -65,11 +89,14 @@ module.exports = async (protoPath, lndHost, lndCertPath, macaroonPath) => {
|
|||
// @ts-ignore
|
||||
const lightning = new lnrpc.Lightning(lndHost, credentials);
|
||||
// @ts-ignore
|
||||
const walletUnlocker = new lnrpc.WalletUnlocker(lndHost, credentials);
|
||||
const walletUnlocker = new walletunlockerrpc.WalletUnlocker(lndHost, credentials);
|
||||
// @ts-ignore
|
||||
const router = new routerrpc.Router(lndHost, credentials);
|
||||
|
||||
return {
|
||||
lightning,
|
||||
walletUnlocker
|
||||
walletUnlocker,
|
||||
router
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -90,5 +117,6 @@ module.exports = async (protoPath, lndHost, lndCertPath, macaroonPath) => {
|
|||
"Failed to connect to LND server, make sure it's up and running."
|
||||
};
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
172
src/routes.js
172
src/routes.js
|
|
@ -373,7 +373,7 @@ module.exports = async (
|
|||
|
||||
const authorizedDevice = await Encryption.authorizeDevice({ deviceId, publicKey })
|
||||
logger.info(authorizedDevice)
|
||||
return res.status(200).json(authorizedDevice)
|
||||
return res.json(authorizedDevice)
|
||||
} catch (err) {
|
||||
logger.error(err)
|
||||
return res.status(401).json({
|
||||
|
|
@ -943,20 +943,8 @@ module.exports = async (
|
|||
});
|
||||
|
||||
// connect peer to lnd node
|
||||
app.post("/api/lnd/connectpeer", async (req, res) => {
|
||||
app.post("/api/lnd/connectpeer", (req, res) => {
|
||||
const { lightning } = LightningServices.services;
|
||||
if (req.limituser) {
|
||||
const health = await checkHealth();
|
||||
if (health.LNDStatus.success) {
|
||||
res.status(403);
|
||||
return res.json({
|
||||
field: "limituser",
|
||||
errorMessage: "User limited"
|
||||
});
|
||||
}
|
||||
res.status(500);
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
const connectRequest = {
|
||||
addr: { pubkey: req.body.pubkey, host: req.body.host },
|
||||
perm: true
|
||||
|
|
@ -974,20 +962,8 @@ module.exports = async (
|
|||
});
|
||||
|
||||
// disconnect peer from lnd node
|
||||
app.post("/api/lnd/disconnectpeer", async (req, res) => {
|
||||
app.post("/api/lnd/disconnectpeer", (req, res) => {
|
||||
const { lightning } = LightningServices.services;
|
||||
if (req.limituser) {
|
||||
const health = await checkHealth();
|
||||
if (health.LNDStatus.success) {
|
||||
res.status(403);
|
||||
return res.json({
|
||||
field: "limituser",
|
||||
errorMessage: "User limited"
|
||||
});
|
||||
}
|
||||
res.status(500);
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
const disconnectRequest = { pub_key: req.body.pubkey };
|
||||
logger.debug("DisconnectPeer Request:", disconnectRequest);
|
||||
lightning.disconnectPeer(disconnectRequest, (err, response) => {
|
||||
|
|
@ -1275,18 +1251,8 @@ module.exports = async (
|
|||
});
|
||||
|
||||
// openchannel
|
||||
app.post("/api/lnd/openchannel", async (req, res) => {
|
||||
app.post("/api/lnd/openchannel", (req, res) => {
|
||||
const { lightning } = LightningServices.services;
|
||||
if (req.limituser) {
|
||||
const health = await checkHealth();
|
||||
if (health.LNDStatus.success) {
|
||||
res.sendStatus(403);
|
||||
} else {
|
||||
res.status(500);
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const { pubkey, channelCapacity, channelPushAmount,satPerByte } = req.body;
|
||||
|
||||
|
|
@ -1298,6 +1264,7 @@ module.exports = async (
|
|||
};
|
||||
logger.info("OpenChannelRequest", openChannelRequest);
|
||||
const openedChannel = lightning.openChannel(openChannelRequest);
|
||||
// only emits one event
|
||||
openedChannel.on("data", response => {
|
||||
logger.debug("OpenChannelRequest:", response);
|
||||
if (!res.headersSent) {
|
||||
|
|
@ -1318,18 +1285,8 @@ module.exports = async (
|
|||
});
|
||||
|
||||
// closechannel
|
||||
app.post("/api/lnd/closechannel", async (req, res) => {
|
||||
app.post("/api/lnd/closechannel", (req, res) => {
|
||||
const { lightning } = LightningServices.services;
|
||||
if (req.limituser) {
|
||||
const health = await checkHealth();
|
||||
if (health.LNDStatus.success) {
|
||||
// return res.sendStatus(403);
|
||||
res.sendStatus(403);
|
||||
} else {
|
||||
res.status(500);
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
}
|
||||
const { channelPoint, outputIndex, force,satPerByte } = req.body;
|
||||
const closeChannelRequest = {
|
||||
channel_point: {
|
||||
|
|
@ -1369,26 +1326,21 @@ module.exports = async (
|
|||
});
|
||||
|
||||
// sendpayment
|
||||
app.post("/api/lnd/sendpayment", async (req, res) => {
|
||||
const { lightning } = LightningServices.services;
|
||||
if (req.limituser) {
|
||||
const health = await checkHealth();
|
||||
if (health.LNDStatus.success) {
|
||||
res.sendStatus(403);
|
||||
} else {
|
||||
res.status(500);
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
}
|
||||
const paymentRequest = { payment_request: req.body.payreq };
|
||||
app.post("/api/lnd/sendpayment", (req, res) => {
|
||||
const { router } = LightningServices.services;
|
||||
// this is the recommended value from lightning labs
|
||||
const { maxParts = 3, payreq } = req.body;
|
||||
|
||||
const paymentRequest = { payment_request: payreq, max_parts: maxParts };
|
||||
|
||||
if (req.body.amt) {
|
||||
paymentRequest.amt = req.body.amt;
|
||||
}
|
||||
|
||||
logger.info("Sending payment", paymentRequest);
|
||||
const sentPayment = lightning.sendPayment(paymentRequest);
|
||||
const sentPayment = router.sendPaymentV2(paymentRequest);
|
||||
|
||||
// only emits one event
|
||||
sentPayment.on("data", response => {
|
||||
if (response.payment_error) {
|
||||
logger.error("SendPayment Info:", response)
|
||||
|
|
@ -1421,19 +1373,78 @@ module.exports = async (
|
|||
sentPayment.write(paymentRequest);
|
||||
});
|
||||
|
||||
// addinvoice
|
||||
app.post("/api/lnd/addinvoice", async (req, res) => {
|
||||
const { lightning } = LightningServices.services;
|
||||
if (req.limituser) {
|
||||
app.post("/api/lnd/trackpayment", (req, res) => {
|
||||
const { router } = LightningServices.services;
|
||||
const { paymentHash, inflightUpdates = true } = req.body;
|
||||
|
||||
logger.info("Tracking payment payment", { paymentHash, inflightUpdates });
|
||||
const trackedPayment = router.trackPaymentV2({
|
||||
payment_hash: paymentHash,
|
||||
no_inflight_updates: !inflightUpdates
|
||||
});
|
||||
|
||||
// only emits one event
|
||||
trackedPayment.on("data", response => {
|
||||
if (response.payment_error) {
|
||||
logger.error("TrackPayment Info:", response)
|
||||
return res.status(500).json({
|
||||
errorMessage: response.payment_error
|
||||
});
|
||||
}
|
||||
|
||||
logger.info("TrackPayment Data:", response);
|
||||
return res.json(response);
|
||||
});
|
||||
|
||||
trackedPayment.on("status", status => {
|
||||
logger.info("TrackPayment Status:", status);
|
||||
});
|
||||
|
||||
trackedPayment.on("error", async err => {
|
||||
logger.error("TrackPayment Error:", err);
|
||||
const health = await checkHealth();
|
||||
if (health.LNDStatus.success) {
|
||||
res.sendStatus(403);
|
||||
res.status(500).json({
|
||||
errorMessage: sanitizeLNDError(err.message)
|
||||
});
|
||||
} else {
|
||||
res.status(500);
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/api/lnd/sendtoroute", (req, res) => {
|
||||
const { router } = LightningServices.services;
|
||||
const { paymentHash, route } = req.body;
|
||||
|
||||
router.sendToRoute({ payment_hash: paymentHash, route }, (err, data) => {
|
||||
if (err) {
|
||||
logger.error("SendToRoute Error:", err);
|
||||
return res.status(400).json(err);
|
||||
}
|
||||
|
||||
return res.json(data);
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/api/lnd/estimateroutefee", (req, res) => {
|
||||
const { router } = LightningServices.services;
|
||||
const { dest, amount } = req.body;
|
||||
|
||||
router.estimateRouteFee({ dest, amt_sat: amount }, (err, data) => {
|
||||
if (err) {
|
||||
logger.error("EstimateRouteFee Error:", err);
|
||||
return res.status(400).json(err);
|
||||
}
|
||||
|
||||
return res.json(data);
|
||||
});
|
||||
});
|
||||
|
||||
// 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;
|
||||
|
|
@ -1491,17 +1502,8 @@ module.exports = async (
|
|||
});
|
||||
|
||||
// signmessage
|
||||
app.post("/api/lnd/signmessage", async (req, res) => {
|
||||
app.post("/api/lnd/signmessage", (req, res) => {
|
||||
const { lightning } = LightningServices.services;
|
||||
if (req.limituser) {
|
||||
const health = await checkHealth();
|
||||
if (health.LNDStatus.success) {
|
||||
res.sendStatus(403);
|
||||
} else {
|
||||
res.status(500);
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
}
|
||||
lightning.signMessage(
|
||||
{ msg: Buffer.from(req.body.msg, "utf8") },
|
||||
async (err, response) => {
|
||||
|
|
@ -1544,17 +1546,8 @@ module.exports = async (
|
|||
});
|
||||
|
||||
// sendcoins
|
||||
app.post("/api/lnd/sendcoins", async (req, res) => {
|
||||
app.post("/api/lnd/sendcoins", (req, res) => {
|
||||
const { lightning } = LightningServices.services;
|
||||
if (req.limituser) {
|
||||
const health = await checkHealth();
|
||||
if (health.LNDStatus.success) {
|
||||
res.sendStatus(403);
|
||||
} else {
|
||||
res.status(500);
|
||||
res.json({ errorMessage: "LND is down" });
|
||||
}
|
||||
}
|
||||
const sendCoinsRequest = {
|
||||
addr: req.body.addr,
|
||||
amount: req.body.amount,
|
||||
|
|
@ -1723,7 +1716,6 @@ module.exports = async (
|
|||
|
||||
const GunEvent = Common.Constants.Event
|
||||
const Key = require('../services/gunDB/contact-api/key')
|
||||
|
||||
app.get("/api/gun/lndchanbackups", async (req,res) => {
|
||||
try{
|
||||
const user = require('../services/gunDB/Mediator').getUser()
|
||||
|
|
|
|||
201
src/sockets.js
201
src/sockets.js
|
|
@ -1,70 +1,175 @@
|
|||
/** @prettier */
|
||||
// app/sockets.js
|
||||
|
||||
const logger = require("winston");
|
||||
const LightningServices = require("../utils/lightningServices");
|
||||
const logger = require('winston')
|
||||
const Encryption = require('../utils/encryptionStore')
|
||||
const LightningServices = require('../utils/lightningServices')
|
||||
|
||||
module.exports = (
|
||||
/** @type {import('socket.io').Server} */
|
||||
io
|
||||
) => {
|
||||
const Mediator = require("../services/gunDB/Mediator/index.js");
|
||||
|
||||
const Mediator = require('../services/gunDB/Mediator/index.js')
|
||||
|
||||
// This should be used for encrypting and emitting your data
|
||||
const emitEncryptedEvent = ({ eventName, data, socket }) => {
|
||||
try {
|
||||
if (Encryption.isNonEncrypted(eventName)) {
|
||||
return socket.emit(eventName, data)
|
||||
}
|
||||
|
||||
const deviceId = socket.handshake.query['x-shockwallet-device-id']
|
||||
const authorized = Encryption.isAuthorizedDevice({ deviceId })
|
||||
|
||||
if (!deviceId) {
|
||||
throw {
|
||||
field: 'deviceId',
|
||||
message: 'Please specify a device ID'
|
||||
}
|
||||
}
|
||||
|
||||
if (!authorized) {
|
||||
throw {
|
||||
field: 'deviceId',
|
||||
message: 'Please exchange keys with the API before using the socket'
|
||||
}
|
||||
}
|
||||
|
||||
const encryptedMessage = Encryption.encryptMessage({
|
||||
message: data,
|
||||
deviceId
|
||||
})
|
||||
|
||||
return socket.emit(eventName, encryptedMessage)
|
||||
} catch (err) {
|
||||
logger.error(
|
||||
`[SOCKET] An error has occurred while encrypting an event (${eventName}):`,
|
||||
err
|
||||
)
|
||||
|
||||
return socket.emit('encryption:error', err)
|
||||
}
|
||||
}
|
||||
|
||||
const parseJSON = data => {
|
||||
try {
|
||||
if (typeof data === 'string') {
|
||||
return JSON.parse(data)
|
||||
}
|
||||
|
||||
return data
|
||||
} catch (err) {
|
||||
return data
|
||||
}
|
||||
}
|
||||
|
||||
const decryptEvent = ({ eventName, data, socket }) => {
|
||||
try {
|
||||
const deviceId = socket.handshake.query['x-shockwallet-device-id']
|
||||
if (Encryption.isNonEncrypted(eventName)) {
|
||||
return data
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return data
|
||||
}
|
||||
|
||||
const parsedData = parseJSON(data)
|
||||
|
||||
if (!deviceId) {
|
||||
throw {
|
||||
field: 'deviceId',
|
||||
message: 'Please specify a device ID'
|
||||
}
|
||||
}
|
||||
|
||||
if (!Encryption.isAuthorizedDevice({ deviceId })) {
|
||||
throw {
|
||||
field: 'deviceId',
|
||||
message: 'Please exchange keys with the API before using the socket'
|
||||
}
|
||||
}
|
||||
|
||||
const decryptedKey = Encryption.decryptKey({
|
||||
deviceId,
|
||||
message: parsedData.encryptedKey
|
||||
})
|
||||
const decryptedMessage = Encryption.decryptMessage({
|
||||
message: parsedData.encryptedData,
|
||||
key: decryptedKey,
|
||||
iv: parsedData.iv
|
||||
})
|
||||
const decryptedData = JSON.parse(decryptedMessage)
|
||||
return decryptedData
|
||||
} catch (err) {
|
||||
logger.error(
|
||||
`[SOCKET] An error has occurred while decrypting an event (${eventName}):`,
|
||||
err
|
||||
)
|
||||
|
||||
return socket.emit('encryption:error', err)
|
||||
}
|
||||
}
|
||||
|
||||
const onNewInvoice = socket => {
|
||||
const { lightning } = LightningServices.services;
|
||||
logger.warn("Subscribing to invoices socket...")
|
||||
const stream = lightning.subscribeInvoices({});
|
||||
stream.on("data", data => {
|
||||
logger.info("[SOCKET] New invoice data:", data);
|
||||
socket.emit("invoice:new", data)
|
||||
const { lightning } = LightningServices.services
|
||||
logger.warn('Subscribing to invoices socket...')
|
||||
const stream = lightning.subscribeInvoices({})
|
||||
stream.on('data', data => {
|
||||
logger.info('[SOCKET] New invoice data:', data)
|
||||
emitEncryptedEvent({ eventName: 'invoice:new', data, socket })
|
||||
})
|
||||
stream.on("end", () => {
|
||||
logger.info("New invoice stream ended, starting a new one...")
|
||||
onNewInvoice(socket);
|
||||
stream.on('end', () => {
|
||||
logger.info('New invoice stream ended, starting a new one...')
|
||||
// Prevents call stack overflow exceptions
|
||||
process.nextTick(() => onNewInvoice(socket))
|
||||
})
|
||||
stream.on("error", err => {
|
||||
logger.error("New invoice stream error:", err);
|
||||
stream.on('error', err => {
|
||||
logger.error('New invoice stream error:', err)
|
||||
})
|
||||
stream.on("status", status => {
|
||||
logger.error("New invoice stream status:", status);
|
||||
stream.on('status', status => {
|
||||
logger.warn('New invoice stream status:', status)
|
||||
if (status.code === 14) {
|
||||
onNewInvoice(socket);
|
||||
// Prevents call stack overflow exceptions
|
||||
process.nextTick(() => onNewInvoice(socket))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const onNewTransaction = socket => {
|
||||
const { lightning } = LightningServices.services;
|
||||
const stream = lightning.subscribeTransactions({});
|
||||
logger.warn("Subscribing to transactions socket...")
|
||||
stream.on("data", data => {
|
||||
logger.info("[SOCKET] New transaction data:", data);
|
||||
socket.emit("transaction:new", data)
|
||||
const { lightning } = LightningServices.services
|
||||
const stream = lightning.subscribeTransactions({})
|
||||
logger.warn('Subscribing to transactions socket...')
|
||||
stream.on('data', data => {
|
||||
logger.info('[SOCKET] New transaction data:', data)
|
||||
emitEncryptedEvent({ eventName: 'transaction:new', data, socket })
|
||||
})
|
||||
stream.on("end", () => {
|
||||
logger.info("New invoice stream ended, starting a new one...")
|
||||
onNewTransaction(socket);
|
||||
stream.on('end', () => {
|
||||
logger.info('New invoice stream ended, starting a new one...')
|
||||
process.nextTick(() => onNewTransaction(socket))
|
||||
})
|
||||
stream.on("error", err => {
|
||||
logger.error("New invoice stream error:", err);
|
||||
stream.on('error', err => {
|
||||
logger.error('New invoice stream error:', err)
|
||||
})
|
||||
stream.on("status", status => {
|
||||
logger.error("New invoice stream status:", status);
|
||||
stream.on('status', status => {
|
||||
logger.error('New invoice stream status:', status)
|
||||
if (status.code === 14) {
|
||||
onNewTransaction(socket);
|
||||
process.nextTick(() => onNewTransaction(socket))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
io.on("connection", socket => {
|
||||
io.on('connection', socket => {
|
||||
logger.info(`io.onconnection`)
|
||||
|
||||
logger.info("socket.handshake", socket.handshake);
|
||||
|
||||
/** printing out the client who joined */
|
||||
logger.info("New socket client connected (id=" + socket.id + ").");
|
||||
logger.info('socket.handshake', socket.handshake)
|
||||
|
||||
const isOneTimeUseSocket = !!socket.handshake.query.IS_GUN_AUTH
|
||||
const isLNDSocket = !!socket.handshake.query.IS_LND_SOCKET
|
||||
if (!isLNDSocket) {
|
||||
/** printing out the client who joined */
|
||||
logger.info('New socket client connected (id=' + socket.id + ').')
|
||||
}
|
||||
|
||||
if (isOneTimeUseSocket) {
|
||||
logger.info('New socket is one time use')
|
||||
|
|
@ -89,21 +194,23 @@ module.exports = (
|
|||
}
|
||||
})
|
||||
} else {
|
||||
if (isLNDSocket) {
|
||||
logger.info('[LND] New LND Socket created')
|
||||
onNewInvoice(socket)
|
||||
onNewTransaction(socket)
|
||||
return
|
||||
}
|
||||
logger.info('New socket is NOT one time use')
|
||||
// this is where we create the websocket connection
|
||||
// with the GunDB service.
|
||||
Mediator.createMediator(socket);
|
||||
if (isLNDSocket) {
|
||||
onNewInvoice(socket);
|
||||
onNewTransaction(socket);
|
||||
}
|
||||
Mediator.createMediator(socket)
|
||||
|
||||
/** listening if client has disconnected */
|
||||
socket.on("disconnect", () => {
|
||||
logger.info("client disconnected (id=" + socket.id + ").");
|
||||
});
|
||||
socket.on('disconnect', () => {
|
||||
logger.info('client disconnected (id=' + socket.id + ').')
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return io;
|
||||
};
|
||||
return io
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ const lnrpc = require("../services/lnd/lightning");
|
|||
* @prop {string} lndCertPath
|
||||
* @prop {string} macaroonPath
|
||||
* @prop {string} lndProto
|
||||
* @prop {string} routerProto
|
||||
* @prop {string} walletUnlockerProto
|
||||
*/
|
||||
|
||||
class LightningServices {
|
||||
|
|
@ -41,21 +43,18 @@ class LightningServices {
|
|||
/**
|
||||
* @type {Config}
|
||||
*/
|
||||
const newDefaults = {
|
||||
...require("../config/defaults")(program.mainnet),
|
||||
useTLS: false,
|
||||
}
|
||||
const newDefaults = require("../config/defaults")(program.mainnet)
|
||||
|
||||
this.defaults = newDefaults;
|
||||
|
||||
this._config = {
|
||||
...newDefaults,
|
||||
useTLS: program.usetls,
|
||||
serverPort: program.serverport || newDefaults.serverPort,
|
||||
serverHost: program.serverhost || newDefaults.serverHost,
|
||||
lndHost: program.lndhost || newDefaults.lndHost,
|
||||
lndCertPath: program.lndCertPath || newDefaults.lndCertPath,
|
||||
macaroonPath: program.macaroonPath || newDefaults.macaroonPath,
|
||||
lndProto: newDefaults.lndProto
|
||||
macaroonPath: program.macaroonPath || newDefaults.macaroonPath
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -67,6 +66,7 @@ class LightningServices {
|
|||
return {
|
||||
lightning: this.lightning,
|
||||
walletUnlocker: this.walletUnlocker,
|
||||
router: this.router
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -108,17 +108,22 @@ class LightningServices {
|
|||
const { macaroonPath, lndHost, lndCertPath } = this.config;
|
||||
const macaroonExists = await FS.access(macaroonPath);
|
||||
const lnServices = await lnrpc(
|
||||
this.defaults.lndProto,
|
||||
lndHost,
|
||||
lndCertPath,
|
||||
macaroonExists ? macaroonPath : null
|
||||
{
|
||||
lnrpcProtoPath: this.defaults.lndProto,
|
||||
routerProtoPath: this.defaults.routerProto,
|
||||
walletUnlockerProtoPath: this.defaults.walletUnlockerProto,
|
||||
lndHost,
|
||||
lndCertPath,
|
||||
macaroonPath: macaroonExists ? macaroonPath : null
|
||||
}
|
||||
);
|
||||
if (!lnServices) {
|
||||
throw new Error(`Could not init lnServices`)
|
||||
}
|
||||
const { lightning, walletUnlocker } = lnServices;
|
||||
const { lightning, walletUnlocker, router } = lnServices;
|
||||
this.lightning = lightning;
|
||||
this.walletUnlocker = walletUnlocker
|
||||
this.router = router;
|
||||
this.lnServicesData = {
|
||||
lndProto: this.defaults.lndProto,
|
||||
lndHost,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue