committed by
GitHub
43 changed files with 1375 additions and 376 deletions
@ -0,0 +1,9 @@ |
|||
// Cert will be located depending on your machine
|
|||
// Mac OS X: /Users/user/Library/Application Support/Lnd/tls.cert
|
|||
// Linux: ~/.lnd/tls.cert
|
|||
// Windows: TODO find out where cert is located for windows machine
|
|||
export default { |
|||
lightningRpc: `${__dirname}/rpc.proto`, |
|||
lightningHost: 'localhost:10009', |
|||
cert: '/Users/jmow/Library/Application Support/Lnd/tls.cert' |
|||
} |
@ -0,0 +1,690 @@ |
|||
syntax = "proto3"; |
|||
|
|||
//import "google/api/annotations.proto"; |
|||
|
|||
package lnrpc; |
|||
|
|||
service Lightning { |
|||
rpc WalletBalance (WalletBalanceRequest) returns (WalletBalanceResponse) { |
|||
option (google.api.http) = { |
|||
get: "/v1/balance/blockchain" |
|||
}; |
|||
} |
|||
rpc ChannelBalance (ChannelBalanceRequest) returns (ChannelBalanceResponse) { |
|||
option (google.api.http) = { |
|||
get: "/v1/balance/channels" |
|||
}; |
|||
} |
|||
|
|||
rpc GetTransactions (GetTransactionsRequest) returns (TransactionDetails) { |
|||
option (google.api.http) = { |
|||
get: "/v1/transactions" |
|||
}; |
|||
} |
|||
rpc SendCoins (SendCoinsRequest) returns (SendCoinsResponse) { |
|||
option (google.api.http) = { |
|||
post: "/v1/transactions" |
|||
body: "*" |
|||
}; |
|||
} |
|||
rpc SubscribeTransactions (GetTransactionsRequest) returns (stream Transaction); |
|||
|
|||
rpc SendMany (SendManyRequest) returns (SendManyResponse); |
|||
|
|||
rpc NewAddress (NewAddressRequest) returns (NewAddressResponse); |
|||
rpc NewWitnessAddress (NewWitnessAddressRequest) returns (NewAddressResponse) { |
|||
option (google.api.http) = { |
|||
get: "/v1/newaddress" |
|||
}; |
|||
} |
|||
|
|||
rpc SignMessage (SignMessageRequest) returns (SignMessageResponse); |
|||
rpc VerifyMessage (VerifyMessageRequest) returns (VerifyMessageResponse); |
|||
|
|||
rpc ConnectPeer (ConnectPeerRequest) returns (ConnectPeerResponse) { |
|||
option (google.api.http) = { |
|||
post: "/v1/peers" |
|||
body: "*" |
|||
}; |
|||
} |
|||
|
|||
rpc DisconnectPeer (DisconnectPeerRequest) returns (DisconnectPeerResponse) { |
|||
option (google.api.http) = { |
|||
delete: "/v1/peers/{pub_key}" |
|||
}; |
|||
} |
|||
|
|||
rpc ListPeers (ListPeersRequest) returns (ListPeersResponse) { |
|||
option (google.api.http) = { |
|||
get: "/v1/peers" |
|||
}; |
|||
} |
|||
rpc GetInfo (GetInfoRequest) returns (GetInfoResponse) { |
|||
option (google.api.http) = { |
|||
get: "/v1/getinfo" |
|||
}; |
|||
} |
|||
|
|||
// TODO(roasbeef): merge with below with bool? |
|||
rpc PendingChannels (PendingChannelRequest) returns (PendingChannelResponse) { |
|||
option (google.api.http) = { |
|||
get: "/v1/channels/pending" |
|||
}; |
|||
} |
|||
rpc ListChannels (ListChannelsRequest) returns (ListChannelsResponse) { |
|||
option (google.api.http) = { |
|||
get: "/v1/channels" |
|||
}; |
|||
} |
|||
rpc OpenChannelSync (OpenChannelRequest) returns (ChannelPoint) { |
|||
option (google.api.http) = { |
|||
post: "/v1/channels" |
|||
body: "*" |
|||
}; |
|||
} |
|||
|
|||
rpc OpenChannel (OpenChannelRequest) returns (stream OpenStatusUpdate); |
|||
|
|||
rpc CloseChannel (CloseChannelRequest) returns (stream CloseStatusUpdate) { |
|||
option (google.api.http) = { |
|||
delete: "/v1/channels/{channel_point.funding_txid}/{channel_point.output_index}/{force}" |
|||
}; |
|||
} |
|||
|
|||
rpc SendPayment (stream SendRequest) returns (stream SendResponse); |
|||
|
|||
rpc SendPaymentSync (SendRequest) returns (SendResponse) { |
|||
option (google.api.http) = { |
|||
post: "/v1/channels/transactions" |
|||
body: "*" |
|||
}; |
|||
} |
|||
|
|||
rpc AddInvoice (Invoice) returns (AddInvoiceResponse) { |
|||
option (google.api.http) = { |
|||
post: "/v1/invoices" |
|||
body: "*" |
|||
}; |
|||
} |
|||
rpc ListInvoices (ListInvoiceRequest) returns (ListInvoiceResponse) { |
|||
option (google.api.http) = { |
|||
get: "/v1/invoices/{pending_only}" |
|||
}; |
|||
} |
|||
rpc LookupInvoice (PaymentHash) returns (Invoice) { |
|||
option (google.api.http) = { |
|||
get: "/v1/invoices/{r_hash_str}" |
|||
}; |
|||
} |
|||
rpc SubscribeInvoices (InvoiceSubscription) returns (stream Invoice) { |
|||
option (google.api.http) = { |
|||
get: "/v1/invoices/subscribe" |
|||
}; |
|||
} |
|||
rpc DecodePayReq (PayReqString) returns (PayReq) { |
|||
option (google.api.http) = { |
|||
get: "/v1/payreq/{pay_req}" |
|||
}; |
|||
} |
|||
|
|||
rpc ListPayments (ListPaymentsRequest) returns (ListPaymentsResponse) { |
|||
option (google.api.http) = { |
|||
get: "/v1/payments" |
|||
}; |
|||
}; |
|||
|
|||
rpc DeleteAllPayments (DeleteAllPaymentsRequest) returns (DeleteAllPaymentsResponse) { |
|||
option (google.api.http) = { |
|||
delete: "/v1/payments" |
|||
}; |
|||
}; |
|||
|
|||
rpc DescribeGraph (ChannelGraphRequest) returns (ChannelGraph) { |
|||
option (google.api.http) = { |
|||
get: "/v1/graph" |
|||
}; |
|||
} |
|||
|
|||
rpc GetChanInfo (ChanInfoRequest) returns (ChannelEdge) { |
|||
option (google.api.http) = { |
|||
get: "/v1/graph/edge/{chan_id}" |
|||
}; |
|||
} |
|||
|
|||
rpc GetNodeInfo (NodeInfoRequest) returns (NodeInfo) { |
|||
option (google.api.http) = { |
|||
get: "/v1/graph/node/{pub_key}" |
|||
}; |
|||
} |
|||
|
|||
rpc QueryRoutes(QueryRoutesRequest) returns (QueryRoutesResponse) { |
|||
option (google.api.http) = { |
|||
get: "/v1/graph/routes/{pub_key}/{amt}" |
|||
}; |
|||
} |
|||
|
|||
rpc GetNetworkInfo (NetworkInfoRequest) returns (NetworkInfo) { |
|||
option (google.api.http) = { |
|||
get: "/v1/graph/info" |
|||
}; |
|||
} |
|||
|
|||
rpc StopDaemon(StopRequest) returns (StopResponse); |
|||
|
|||
rpc SubscribeChannelGraph(GraphTopologySubscription) returns (stream GraphTopologyUpdate); |
|||
|
|||
rpc SetAlias(SetAliasRequest) returns (SetAliasResponse); |
|||
|
|||
rpc DebugLevel (DebugLevelRequest) returns (DebugLevelResponse); |
|||
} |
|||
|
|||
message Transaction { |
|||
string tx_hash = 1 [ json_name = "tx_hash" ]; |
|||
int64 amount = 2 [ json_name = "amount" ]; |
|||
int32 num_confirmations = 3 [ json_name = "num_confirmations" ]; |
|||
string block_hash = 4 [ json_name = "block_hash" ]; |
|||
int32 block_height = 5 [ json_name = "block_height" ]; |
|||
int64 time_stamp = 6 [ json_name = "time_stamp" ]; |
|||
int64 total_fees = 7 [ json_name = "total_fees" ]; |
|||
} |
|||
message GetTransactionsRequest { |
|||
} |
|||
message TransactionDetails { |
|||
repeated Transaction transactions = 1 [json_name = "transactions"]; |
|||
} |
|||
|
|||
message SendRequest { |
|||
bytes dest = 1; |
|||
string dest_string = 2; |
|||
|
|||
int64 amt = 3; |
|||
|
|||
bytes payment_hash = 4; |
|||
string payment_hash_string = 5; |
|||
|
|||
string payment_request = 6; |
|||
} |
|||
message SendResponse { |
|||
string payment_error = 1 [json_name = "payment_error"]; |
|||
bytes payment_preimage = 2 [json_name = "payment_preimage"]; |
|||
Route payment_route = 3 [json_name = "payment_route"]; |
|||
} |
|||
|
|||
message ChannelPoint { |
|||
// TODO(roasbeef): make str vs bytes into a oneof |
|||
bytes funding_txid = 1 [ json_name = "funding_txid" ]; |
|||
string funding_txid_str = 2 [ json_name = "funding_txid_str" ]; |
|||
uint32 output_index = 3 [ json_name = "output_index" ]; |
|||
} |
|||
|
|||
message LightningAddress { |
|||
string pubkey = 1 [json_name = "pubkey"]; |
|||
string host = 2 [json_name = "host"]; |
|||
} |
|||
|
|||
message SendManyRequest { |
|||
map<string, int64> AddrToAmount = 1; |
|||
} |
|||
message SendManyResponse { |
|||
string txid = 1 [json_name = "txid"]; |
|||
} |
|||
|
|||
message SendCoinsRequest { |
|||
string addr = 1; |
|||
int64 amount = 2; |
|||
} |
|||
message SendCoinsResponse { |
|||
string txid = 1 [json_name = "txid"]; |
|||
} |
|||
|
|||
message NewAddressRequest { |
|||
enum AddressType { |
|||
WITNESS_PUBKEY_HASH = 0; |
|||
NESTED_PUBKEY_HASH = 1; |
|||
PUBKEY_HASH = 2; |
|||
} |
|||
AddressType type = 1; |
|||
} |
|||
message NewWitnessAddressRequest { |
|||
} |
|||
message NewAddressResponse { |
|||
string address = 1 [json_name = "address"]; |
|||
} |
|||
|
|||
message SignMessageRequest { |
|||
bytes msg = 1 [ json_name = "msg" ]; |
|||
} |
|||
message SignMessageResponse { |
|||
string signature = 1 [ json_name = "signature" ]; |
|||
} |
|||
|
|||
message VerifyMessageRequest { |
|||
bytes msg = 1 [ json_name = "msg" ]; |
|||
string signature = 2 [ json_name = "signature" ]; |
|||
} |
|||
message VerifyMessageResponse { |
|||
bool valid = 1 [ json_name = "valid" ]; |
|||
string pubkey = 2 [ json_name = "pubkey" ]; |
|||
} |
|||
|
|||
message ConnectPeerRequest { |
|||
LightningAddress addr = 1; |
|||
bool perm = 2; |
|||
} |
|||
message ConnectPeerResponse { |
|||
int32 peer_id = 1 [json_name = "peer_id"]; |
|||
} |
|||
|
|||
message DisconnectPeerRequest { |
|||
string pub_key = 1 [json_name = "pub_key"]; |
|||
} |
|||
message DisconnectPeerResponse { |
|||
} |
|||
|
|||
message HTLC { |
|||
bool incoming = 1 [json_name = "incoming"]; |
|||
int64 amount = 2 [json_name = "amount"]; |
|||
bytes hash_lock = 3 [json_name = "hash_lock"]; |
|||
uint32 expiration_height = 4 [json_name = "expiration_height"]; |
|||
uint32 revocation_delay = 5 [json_name = "revocation_delay"]; |
|||
} |
|||
|
|||
message ActiveChannel { |
|||
bool active = 1 [json_name = "active"]; |
|||
string remote_pubkey = 2 [json_name = "remote_pubkey"]; |
|||
string channel_point = 3 [json_name = "channel_point"]; |
|||
uint64 chan_id = 4 [json_name = "chan_id"]; |
|||
|
|||
int64 capacity = 5 [json_name = "capacity"]; |
|||
int64 local_balance = 6 [json_name = "local_balance"]; |
|||
int64 remote_balance = 7 [json_name = "remote_balance"]; |
|||
|
|||
int64 commit_fee = 8 [json_name = "commit_fee"]; |
|||
int64 commit_weight = 9 [ json_name = "commit_weight" ]; |
|||
int64 fee_per_kw = 10 [json_name = "fee_per_kw"]; |
|||
|
|||
int64 unsettled_balance = 11 [json_name = "unsettled_balance"]; |
|||
int64 total_satoshis_sent = 12 [json_name = "total_satoshis_sent"]; |
|||
int64 total_satoshis_received = 13 [json_name = "total_satoshis_received"]; |
|||
uint64 num_updates = 14 [json_name = "num_updates"]; |
|||
|
|||
repeated HTLC pending_htlcs = 15 [json_name = "pending_htlcs"]; |
|||
} |
|||
|
|||
message ListChannelsRequest { |
|||
} |
|||
message ListChannelsResponse { |
|||
repeated ActiveChannel channels = 11 [json_name = "channels"]; |
|||
} |
|||
|
|||
message Peer { |
|||
string pub_key = 1 [json_name = "pub_key"]; |
|||
int32 peer_id = 2 [json_name = "peer_id"]; |
|||
string address = 3 [json_name = "address"]; |
|||
|
|||
uint64 bytes_sent = 4 [json_name = "bytes_sent"]; |
|||
uint64 bytes_recv = 5 [json_name = "bytes_recv"]; |
|||
|
|||
int64 sat_sent = 6 [json_name = "sat_sent"]; |
|||
int64 sat_recv = 7 [json_name = "sat_recv"]; |
|||
|
|||
bool inbound = 8 [json_name = "inbound"]; |
|||
|
|||
int64 ping_time = 9 [json_name = "ping_time"]; |
|||
} |
|||
|
|||
message ListPeersRequest { |
|||
} |
|||
message ListPeersResponse { |
|||
repeated Peer peers = 1 [json_name = "peers"]; |
|||
} |
|||
|
|||
message GetInfoRequest { |
|||
} |
|||
message GetInfoResponse { |
|||
string identity_pubkey = 1 [json_name = "identity_pubkey"]; |
|||
string alias = 2 [json_name = "alias"]; |
|||
|
|||
uint32 num_pending_channels = 3 [json_name = "num_pending_channels"]; |
|||
uint32 num_active_channels = 4 [json_name = "num_active_channels"]; |
|||
|
|||
uint32 num_peers = 5 [json_name = "num_peers"]; |
|||
|
|||
uint32 block_height = 6 [json_name = "block_height"]; |
|||
string block_hash = 8 [json_name = "block_hash"]; |
|||
|
|||
bool synced_to_chain = 9 [ json_name = "synced_to_chain" ]; |
|||
bool testnet = 10 [ json_name = "testnet" ]; |
|||
|
|||
repeated string chains = 11 [ json_name = "chains" ]; |
|||
} |
|||
|
|||
message ConfirmationUpdate { |
|||
bytes block_sha = 1; |
|||
int32 block_height = 2; |
|||
|
|||
uint32 num_confs_left = 3; |
|||
} |
|||
|
|||
message ChannelOpenUpdate { |
|||
ChannelPoint channel_point = 1 [json_name = "channel_point"]; |
|||
} |
|||
|
|||
message ChannelCloseUpdate { |
|||
bytes closing_txid = 1 [json_name = "closing_txid"]; |
|||
|
|||
bool success = 2 [json_name = "success"]; |
|||
} |
|||
|
|||
message CloseChannelRequest { |
|||
ChannelPoint channel_point = 1; |
|||
int64 time_limit = 2; |
|||
bool force = 3; |
|||
} |
|||
message CloseStatusUpdate { |
|||
oneof update { |
|||
PendingUpdate close_pending = 1 [json_name = "close_pending"]; |
|||
ConfirmationUpdate confirmation = 2 [json_name = "confirmation"]; |
|||
ChannelCloseUpdate chan_close = 3 [json_name = "chan_close"]; |
|||
} |
|||
} |
|||
|
|||
message PendingUpdate { |
|||
bytes txid = 1 [json_name = "txid"]; |
|||
uint32 output_index = 2 [json_name = "output_index"]; |
|||
} |
|||
|
|||
message OpenChannelRequest { |
|||
int32 target_peer_id = 1 [json_name = "target_peer_id"]; |
|||
bytes node_pubkey = 2 [json_name = "node_pubkey"]; |
|||
string node_pubkey_string = 3 [json_name = "node_pubkey_string"]; |
|||
|
|||
int64 local_funding_amount = 4 [json_name = "local_funding_amount"]; |
|||
int64 push_sat = 5 [json_name = "push_sat"]; |
|||
|
|||
uint32 num_confs = 6 [json_name = "num_confs"]; |
|||
} |
|||
message OpenStatusUpdate { |
|||
oneof update { |
|||
PendingUpdate chan_pending = 1 [json_name = "chan_pending"]; |
|||
ConfirmationUpdate confirmation = 2 [json_name = "confirmation"]; |
|||
ChannelOpenUpdate chan_open = 3 [json_name = "chan_open"]; |
|||
} |
|||
} |
|||
|
|||
message PendingChannelRequest {} |
|||
message PendingChannelResponse { |
|||
message PendingChannel { |
|||
string remote_node_pub = 1 [ json_name = "remote_node_pub" ]; |
|||
string channel_point = 2 [ json_name = "channel_point" ]; |
|||
|
|||
int64 capacity = 3 [ json_name = "capacity" ]; |
|||
|
|||
int64 local_balance = 4 [ json_name = "local_balance" ]; |
|||
int64 remote_balance = 5 [ json_name = "remote_balance" ]; |
|||
} |
|||
|
|||
message PendingOpenChannel { |
|||
PendingChannel channel = 1 [ json_name = "channel" ]; |
|||
|
|||
uint32 confirmation_height = 2 [ json_name = "confirmation_height" ]; |
|||
uint32 blocks_till_open = 3 [ json_name = "blocks_till_open" ]; |
|||
|
|||
int64 commit_fee = 4 [json_name = "commit_fee" ]; |
|||
int64 commit_weight = 5 [ json_name = "commit_weight" ]; |
|||
int64 fee_per_kw = 6 [ json_name = "fee_per_kw" ]; |
|||
} |
|||
|
|||
message ClosedChannel { |
|||
PendingChannel channel = 1; |
|||
|
|||
string closing_txid = 2 [ json_name = "closing_txid" ]; |
|||
} |
|||
|
|||
message ForceClosedChannel { |
|||
PendingChannel channel = 1 [ json_name = "channel" ]; |
|||
|
|||
// TODO(roasbeef): HTLC's as well? |
|||
|
|||
string closing_txid = 2 [ json_name = "closing_txid" ]; |
|||
|
|||
int64 limbo_balance = 3 [ json_name = "limbo_balance" ]; |
|||
uint32 maturity_height = 4 [ json_name = "maturity_height" ]; |
|||
uint32 blocks_til_maturity = 5 [ json_name = "blocks_til_maturity" ]; |
|||
} |
|||
|
|||
int64 total_limbo_balance = 1 [ json_name = "total_limbo_balance" ]; |
|||
repeated PendingOpenChannel pending_open_channels = 2 [ json_name = "pending_open_channels" ]; |
|||
repeated ClosedChannel pending_closing_channels = 3 [ json_name = "pending_closing_channels" ]; |
|||
repeated ForceClosedChannel pending_force_closing_channels = 4 [ json_name = "pending_force_closing_channels" ]; |
|||
} |
|||
|
|||
message WalletBalanceRequest { |
|||
bool witness_only = 1; |
|||
} |
|||
message WalletBalanceResponse { |
|||
int64 balance = 1 [json_name = "balance"]; |
|||
} |
|||
|
|||
message ChannelBalanceRequest { |
|||
} |
|||
message ChannelBalanceResponse { |
|||
int64 balance = 1 [json_name = "balance"]; |
|||
} |
|||
|
|||
message QueryRoutesRequest { |
|||
string pub_key = 1; |
|||
int64 amt = 2; |
|||
} |
|||
message QueryRoutesResponse { |
|||
repeated Route routes = 1 [ json_name = "routes"]; |
|||
} |
|||
|
|||
message Hop { |
|||
uint64 chan_id = 1 [json_name = "chan_id"]; |
|||
int64 chan_capacity = 2 [json_name = "chan_capacity"]; |
|||
int64 amt_to_forward = 3 [json_name = "amt_to_forward"]; |
|||
int64 fee = 4 [json_name = "fee"]; |
|||
} |
|||
|
|||
message Route { |
|||
uint32 total_time_lock = 1 [json_name = "total_time_lock"]; |
|||
int64 total_fees = 2 [json_name = "total_fees"]; |
|||
int64 total_amt = 3 [json_name = "total_amt"]; |
|||
|
|||
repeated Hop hops = 4 [json_name = "hops"]; |
|||
} |
|||
|
|||
message NodeInfoRequest { |
|||
string pub_key = 1; |
|||
} |
|||
|
|||
message NodeInfo { |
|||
LightningNode node = 1 [json_name = "node"]; |
|||
|
|||
uint32 num_channels = 2 [json_name = "num_channels"]; |
|||
int64 total_capacity = 3 [json_name = "total_capacity"]; |
|||
} |
|||
|
|||
message LightningNode { |
|||
uint32 last_update = 1 [ json_name = "last_update" ]; |
|||
string pub_key = 2 [ json_name = "pub_key" ]; |
|||
string alias = 3 [ json_name = "alias" ]; |
|||
repeated NodeAddress addresses = 4 [ json_name = "addresses" ]; |
|||
} |
|||
|
|||
message NodeAddress { |
|||
string network = 1 [ json_name = "network" ]; |
|||
string addr = 2 [ json_name = "addr" ]; |
|||
} |
|||
|
|||
message RoutingPolicy { |
|||
uint32 time_lock_delta = 1 [json_name = "time_lock_delta"]; |
|||
int64 min_htlc = 2 [json_name = "min_htlc"]; |
|||
int64 fee_base_msat = 3 [json_name = "fee_base_msat"]; |
|||
int64 fee_rate_milli_msat = 4 [json_name = "fee_rate_milli_msat"]; |
|||
} |
|||
|
|||
message ChannelEdge { |
|||
uint64 channel_id = 1 [json_name = "channel_id"]; |
|||
string chan_point = 2 [json_name = "chan_point"]; |
|||
|
|||
uint32 last_update = 3 [json_name = "last_update"]; |
|||
|
|||
string node1_pub = 4 [json_name = "node1_pub"]; |
|||
string node2_pub = 5 [json_name = "node2_pub"]; |
|||
|
|||
int64 capacity = 6 [json_name = "capacity"]; |
|||
|
|||
RoutingPolicy node1_policy = 7 [json_name = "node1_policy"]; |
|||
RoutingPolicy node2_policy = 8 [json_name = "node2_policy"]; |
|||
} |
|||
|
|||
message ChannelGraphRequest { |
|||
} |
|||
|
|||
message ChannelGraph { |
|||
repeated LightningNode nodes = 1 [json_name = "nodes"]; |
|||
repeated ChannelEdge edges = 2 [json_name = "edges"]; |
|||
} |
|||
|
|||
message ChanInfoRequest { |
|||
uint64 chan_id = 1; |
|||
} |
|||
|
|||
message NetworkInfoRequest { |
|||
} |
|||
message NetworkInfo { |
|||
uint32 graph_diameter = 1 [json_name = "graph_diameter"]; |
|||
double avg_out_degree = 2 [json_name = "avg_out_degree"]; |
|||
uint32 max_out_degree = 3 [json_name = "max_out_degree"]; |
|||
|
|||
uint32 num_nodes = 4 [json_name = "num_nodes"]; |
|||
uint32 num_channels = 5 [json_name = "num_channels"]; |
|||
|
|||
int64 total_network_capacity = 6 [json_name = "total_network_capacity"]; |
|||
|
|||
double avg_channel_size = 7 [json_name = "avg_channel_size"]; |
|||
int64 min_channel_size = 8 [json_name = "min_channel_size"]; |
|||
int64 max_channel_size = 9 [json_name = "max_channel_size"]; |
|||
|
|||
// TODO(roasbeef): fee rate info, expiry |
|||
// * also additional RPC for tracking fee info once in |
|||
} |
|||
|
|||
message StopRequest{} |
|||
message StopResponse{} |
|||
|
|||
message GraphTopologySubscription {} |
|||
message GraphTopologyUpdate { |
|||
repeated NodeUpdate node_updates = 1; |
|||
repeated ChannelEdgeUpdate channel_updates = 2; |
|||
repeated ClosedChannelUpdate closed_chans = 3; |
|||
} |
|||
message NodeUpdate { |
|||
repeated string addresses = 1; |
|||
string identity_key = 2; |
|||
bytes global_features = 3; |
|||
string alias = 4; |
|||
} |
|||
message ChannelEdgeUpdate { |
|||
uint64 chan_id = 1; |
|||
|
|||
ChannelPoint chan_point = 2; |
|||
|
|||
int64 capacity = 3; |
|||
|
|||
RoutingPolicy routing_policy = 4; |
|||
|
|||
string advertising_node = 5; |
|||
string connecting_node = 6; |
|||
} |
|||
message ClosedChannelUpdate { |
|||
uint64 chan_id = 1; |
|||
int64 capacity = 2; |
|||
uint32 closed_height = 3; |
|||
ChannelPoint chan_point = 4; |
|||
} |
|||
|
|||
message SetAliasRequest { |
|||
string new_alias = 1; |
|||
} |
|||
message SetAliasResponse { |
|||
} |
|||
|
|||
message Invoice { |
|||
string memo = 1 [json_name = "memo"]; |
|||
bytes receipt = 2 [json_name = "receipt"]; |
|||
|
|||
bytes r_preimage = 3 [json_name = "r_preimage"]; |
|||
bytes r_hash = 4 [json_name = "r_hash"]; |
|||
|
|||
int64 value = 5 [json_name = "value"]; |
|||
|
|||
bool settled = 6 [json_name = "settled"]; |
|||
|
|||
int64 creation_date = 7 [json_name = "creation_date"]; |
|||
int64 settle_date = 8 [json_name = "settle_date"]; |
|||
|
|||
string payment_request = 9 [json_name = "payment_request"]; |
|||
} |
|||
message AddInvoiceResponse { |
|||
bytes r_hash = 1 [json_name = "r_hash"]; |
|||
|
|||
string payment_request = 2 [json_name = "payment_request"]; |
|||
} |
|||
message PaymentHash { |
|||
string r_hash_str = 1 [json_name = "r_hash_str"]; |
|||
bytes r_hash = 2 [json_name = "r_hash"]; |
|||
} |
|||
message ListInvoiceRequest { |
|||
bool pending_only = 1; |
|||
} |
|||
message ListInvoiceResponse { |
|||
repeated Invoice invoices = 1 [json_name = "invoices"]; |
|||
} |
|||
|
|||
message InvoiceSubscription { |
|||
} |
|||
|
|||
|
|||
message Payment { |
|||
string payment_hash = 1 [json_name = "payment_hash"]; |
|||
int64 value = 2 [json_name = "value"]; |
|||
|
|||
int64 creation_date = 3 [json_name = "creation_date"]; |
|||
|
|||
repeated string path = 4 [ json_name = "path" ]; |
|||
|
|||
int64 fee = 5 [json_name = "fee"]; |
|||
} |
|||
|
|||
message ListPaymentsRequest { |
|||
} |
|||
|
|||
message ListPaymentsResponse { |
|||
repeated Payment payments = 1 [json_name = "payments"]; |
|||
} |
|||
|
|||
message DeleteAllPaymentsRequest { |
|||
} |
|||
|
|||
message DeleteAllPaymentsResponse { |
|||
} |
|||
|
|||
message DebugLevelRequest { |
|||
bool show = 1; |
|||
string level_spec = 2; |
|||
} |
|||
message DebugLevelResponse { |
|||
string sub_systems = 1 [json_name = "sub_systems"]; |
|||
} |
|||
|
|||
message PayReqString { |
|||
string pay_req = 1; |
|||
} |
|||
message PayReq { |
|||
string destination = 1 [json_name = "destination"]; |
|||
string payment_hash = 2 [json_name = "payment_hash"]; |
|||
int64 num_satoshis = 3 [json_name = "num_satoshis"]; |
|||
} |
@ -0,0 +1,7 @@ |
|||
import config from './config' |
|||
import lightning from './lib/lightning' |
|||
import methods from './methods' |
|||
|
|||
const lnd = lightning(config.lightningRpc, config.lightningHost) |
|||
|
|||
export default (event, msg, data) => methods(lnd, event, msg, data) |
@ -0,0 +1,14 @@ |
|||
import fs from 'fs' |
|||
import grpc from 'grpc' |
|||
import config from '../config' |
|||
|
|||
module.exports = (path, host) => { |
|||
process.env.GRPC_SSL_CIPHER_SUITES = 'HIGH+ECDSA' |
|||
|
|||
const rpc = grpc.load(path) |
|||
|
|||
const lndCert = fs.readFileSync(config.cert) |
|||
const credentials = grpc.credentials.createSsl(lndCert) |
|||
|
|||
return new rpc.lnrpc.Lightning(host, credentials) |
|||
} |
@ -0,0 +1,10 @@ |
|||
// LND Get Channel Balance
|
|||
export default function channelbalance(lnd) { |
|||
return new Promise((resolve, reject) => { |
|||
lnd.channelBalance({}, (err, data) => { |
|||
if (err) { reject(err) } |
|||
|
|||
resolve(data) |
|||
}) |
|||
}) |
|||
} |
@ -0,0 +1,10 @@ |
|||
// LND List Channels
|
|||
export default function channels(lnd) { |
|||
return new Promise((resolve, reject) => { |
|||
lnd.listChannels({}, (err, data) => { |
|||
if (err) { reject(err) } |
|||
|
|||
resolve(data) |
|||
}) |
|||
}) |
|||
} |
@ -0,0 +1,10 @@ |
|||
// LND Connect to a peer
|
|||
export default function connectpeer(lnd, { pubkey, host }) { |
|||
return new Promise((resolve, reject) => { |
|||
lnd.connectPeer({ addr: { pubkey, host }, perm: true }, (err, data) => { |
|||
if (err) { reject(err) } |
|||
|
|||
resolve(data) |
|||
}) |
|||
}) |
|||
} |
@ -0,0 +1,10 @@ |
|||
// LND Create an invoice
|
|||
export default function createInvoice(lnd, { memo, value }) { |
|||
return new Promise((resolve, reject) => { |
|||
lnd.addInvoice({ memo, value }, (err, data) => { |
|||
if (err) { reject(err) } |
|||
|
|||
resolve(data) |
|||
}) |
|||
}) |
|||
} |
@ -0,0 +1,10 @@ |
|||
// LND Disconnect from a peer
|
|||
export default function disconnectpeer(lnd, { pubkey }) { |
|||
return new Promise((resolve, reject) => { |
|||
lnd.disconnectPeer({ pub_key: pubkey }, (err, data) => { |
|||
if (err) { reject(err) } |
|||
|
|||
resolve(data) |
|||
}) |
|||
}) |
|||
} |
@ -0,0 +1,115 @@ |
|||
/* eslint no-console: 0 */ // --> OFF
|
|||
|
|||
import channelbalance from './channelbalance' |
|||
import channels from './channels' |
|||
import connectpeer from './connectpeer' |
|||
import createinvoice from './createinvoice' |
|||
import disconnectpeer from './disconnectpeer' |
|||
import info from './info' |
|||
import invoice from './invoice' |
|||
import invoices from './invoices' |
|||
import openchannel from './openchannel' |
|||
import payinvoice from './payinvoice' |
|||
import payments from './payments' |
|||
import peers from './peers' |
|||
import pendingchannels from './pendingchannels' |
|||
import walletbalance from './walletbalance' |
|||
|
|||
export default function (lnd, event, msg, data) { |
|||
switch (msg) { |
|||
case 'info': |
|||
info(lnd) |
|||
.then(infoData => event.sender.send('receiveInfo', infoData)) |
|||
.catch(error => console.log('info error: ', error)) |
|||
break |
|||
case 'peers': |
|||
// Data looks like { peers: [] }
|
|||
peers(lnd) |
|||
.then(peersData => event.sender.send('receivePeers', peersData)) |
|||
.catch(error => console.log('peers error: ', error)) |
|||
break |
|||
case 'channels': |
|||
// Data looks like
|
|||
// [ { channels: [] }, { total_limbo_balance: 0, pending_open_channels: [], pending_closing_channels: [], pending_force_closing_channels: [] } ]
|
|||
Promise.all([channels, pendingchannels].map(func => func(lnd))) |
|||
.then(channelsData => |
|||
event.sender.send('receiveChannels', { channels: channelsData[0].channels, pendingChannels: channelsData[1] }) |
|||
) |
|||
.catch(error => console.log('channels error: ', error)) |
|||
break |
|||
case 'payments': |
|||
// Data looks like { payments: [] }
|
|||
payments(lnd) |
|||
.then(paymentsData => event.sender.send('receivePayments', paymentsData)) |
|||
.catch(error => console.log('payments error: ', error)) |
|||
break |
|||
case 'invoices': |
|||
// Data looks like { invoices: [] }
|
|||
invoices(lnd) |
|||
.then(invoicesData => event.sender.send('receiveInvoices', invoicesData)) |
|||
.catch(error => console.log('invoices error: ', error)) |
|||
break |
|||
case 'invoice': |
|||
// Data looks like { invoices: [] }
|
|||
invoice(data.payreq) |
|||
.then(invoiceData => event.sender.send('receiveInvoice', invoiceData)) |
|||
.catch(error => console.log('invoice error: ', error)) |
|||
break |
|||
case 'balance': |
|||
// Balance looks like [ { balance: '129477456' }, { balance: '243914' } ]
|
|||
Promise.all([walletbalance, channelbalance].map(func => func(lnd))) |
|||
.then(balance => event.sender.send('receiveBalance', { walletBalance: balance[0].balance, channelBalance: balance[1].balance })) |
|||
.catch(error => console.log('balance error: ', error)) |
|||
break |
|||
case 'createInvoice': |
|||
// Invoice looks like { r_hash: Buffer, payment_request: '' }
|
|||
// { memo, value } = data
|
|||
createinvoice(lnd, data) |
|||
.then(newinvoice => |
|||
event.sender.send( |
|||
'createdInvoice', |
|||
Object.assign(newinvoice, { memo: data.memo, value: data.value, r_hash: new Buffer(newinvoice.r_hash, 'hex').toString('hex') }) |
|||
) |
|||
) |
|||
.catch(error => console.log('createInvoice error: ', error)) |
|||
break |
|||
case 'sendPayment': |
|||
// Payment looks like { payment_preimage: Buffer, payment_route: Object }
|
|||
// { paymentRequest } = data
|
|||
payinvoice(lnd, data) |
|||
.then(({ payment_route }) => event.sender.send('paymentSuccessful', Object.assign(data, { payment_route }))) |
|||
.catch(error => console.log('payinvoice error: ', error)) |
|||
break |
|||
case 'openChannel': |
|||
// Response is empty. Streaming updates on channel status and updates
|
|||
// { pubkey, localamt, pushamt } = data
|
|||
openchannel(lnd, event, data) |
|||
.then((channel) => { |
|||
console.log('CHANNEL: ', channel) |
|||
event.sender.send('channelSuccessful', { channel }) |
|||
}) |
|||
.catch(error => console.log('openChannel error: ', error)) |
|||
break |
|||
case 'connectPeer': |
|||
// Returns a peer_id. Pass the pubkey, host and peer_id so we can add a new peer to the list
|
|||
// { pubkey, host } = data
|
|||
connectpeer(lnd, data) |
|||
.then(({ peer_id }) => { |
|||
console.log('peer_id: ', peer_id) |
|||
event.sender.send('connectSuccess', { pub_key: data.pubkey, address: data.host, peer_id }) |
|||
}) |
|||
.catch(error => console.log('connectPeer error: ', error)) |
|||
break |
|||
case 'disconnectPeer': |
|||
// Empty response. Pass back pubkey on success to remove it from the peers list
|
|||
// { pubkey } = data
|
|||
disconnectpeer(lnd, data) |
|||
.then(() => { |
|||
console.log('pubkey: ', data.pubkey) |
|||
event.sender.send('disconnectSuccess', { pubkey: data.pubkey }) |
|||
}) |
|||
.catch(error => console.log('disconnectPeer error: ', error)) |
|||
break |
|||
default: |
|||
} |
|||
} |
@ -0,0 +1,10 @@ |
|||
// LND Get Info
|
|||
export default function info(lnd) { |
|||
return new Promise((resolve, reject) => { |
|||
lnd.getInfo({}, (err, data) => { |
|||
if (err) { reject(err) } |
|||
|
|||
resolve(data) |
|||
}) |
|||
}) |
|||
} |
@ -0,0 +1,12 @@ |
|||
import { decodeInvoice } from '../utils' |
|||
|
|||
// LND Get Invoice
|
|||
export default function invoice(payreq) { |
|||
return new Promise((resolve, reject) => { |
|||
try { |
|||
resolve(decodeInvoice(payreq)) |
|||
} catch (error) { |
|||
reject(error) |
|||
} |
|||
}) |
|||
} |
@ -0,0 +1,10 @@ |
|||
// LND Get Invoices
|
|||
export default function invoices(lnd) { |
|||
return new Promise((resolve, reject) => { |
|||
lnd.listInvoices({}, (err, data) => { |
|||
if (err) { reject(err) } |
|||
|
|||
resolve(data) |
|||
}) |
|||
}) |
|||
} |
@ -0,0 +1,19 @@ |
|||
import bitcore from 'bitcore-lib' |
|||
import pushchannel from '../push/channel' |
|||
|
|||
const BufferUtil = bitcore.util.buffer |
|||
|
|||
export default function openchannel(lnd, event, payload) { |
|||
const { pubkey, localamt, pushamt } = payload |
|||
const res = { |
|||
node_pubkey: BufferUtil.hexToBuffer(pubkey), |
|||
local_funding_amount: Number(localamt), |
|||
push_sat: Number(pushamt) |
|||
} |
|||
|
|||
return new Promise((resolve, reject) => |
|||
pushchannel(lnd, event, res) |
|||
.then(data => resolve(data)) |
|||
.catch(error => reject(error)) |
|||
) |
|||
} |
@ -0,0 +1,10 @@ |
|||
// LND Pay an invoice
|
|||
export default function payinvoice(lnd, { paymentRequest }) { |
|||
return new Promise((resolve, reject) => { |
|||
lnd.sendPaymentSync({ payment_request: paymentRequest }, (err, data) => { |
|||
if (err) { reject(err) } |
|||
|
|||
resolve(data) |
|||
}) |
|||
}) |
|||
} |
@ -0,0 +1,10 @@ |
|||
// LND Get Payments
|
|||
export default function payments(lnd) { |
|||
return new Promise((resolve, reject) => { |
|||
lnd.listPayments({}, (err, data) => { |
|||
if (err) { reject(err) } |
|||
|
|||
resolve(data) |
|||
}) |
|||
}) |
|||
} |
@ -0,0 +1,10 @@ |
|||
// LND List Peers
|
|||
export default function peers(lnd) { |
|||
return new Promise((resolve, reject) => { |
|||
lnd.listPeers({}, (err, data) => { |
|||
if (err) { reject(err) } |
|||
|
|||
resolve(data) |
|||
}) |
|||
}) |
|||
} |
@ -0,0 +1,10 @@ |
|||
// LND Get Pending Channels
|
|||
export default function channels(lnd) { |
|||
return new Promise((resolve, reject) => { |
|||
lnd.pendingChannels({}, (err, data) => { |
|||
if (err) { reject(err) } |
|||
|
|||
resolve(data) |
|||
}) |
|||
}) |
|||
} |
@ -0,0 +1,10 @@ |
|||
// LND Get Wallet Balance
|
|||
export default function walletbalance(lnd) { |
|||
return new Promise((resolve, reject) => { |
|||
lnd.walletBalance({}, (err, data) => { |
|||
if (err) { reject(err) } |
|||
|
|||
resolve(data) |
|||
}) |
|||
}) |
|||
} |
@ -0,0 +1,16 @@ |
|||
export default function pushchannel(lnd, event, payload) { |
|||
return new Promise((resolve, reject) => { |
|||
try { |
|||
const call = lnd.openChannel(payload) |
|||
|
|||
call.on('data', data => event.sender.send('pushchannelupdated', { data })) |
|||
call.on('end', () => event.sender.send('pushchannelend')) |
|||
call.on('error', error => event.sender.send('pushchannelerror', { error })) |
|||
call.on('status', status => event.sender.send('pushchannelstatus', { status })) |
|||
|
|||
resolve(null, payload) |
|||
} catch (error) { |
|||
reject(error, null) |
|||
} |
|||
}) |
|||
} |
@ -0,0 +1,38 @@ |
|||
import zbase32 from 'zbase32' |
|||
|
|||
function convertBigEndianBufferToLong(longBuffer) { |
|||
let longValue = 0 |
|||
const byteArray = Buffer.from(longBuffer).swap64() |
|||
|
|||
for (let i = byteArray.length - 1; i >= 0; i -= 1) { |
|||
longValue = (longValue * 256) + byteArray[i] |
|||
} |
|||
|
|||
return longValue |
|||
} |
|||
|
|||
export function decodeInvoice(payreq) { |
|||
const payreqBase32 = zbase32.decode(payreq) |
|||
|
|||
const bufferHexRotated = Buffer.from(payreqBase32).toString('hex') |
|||
const bufferHex = bufferHexRotated.substr(bufferHexRotated.length - 1, bufferHexRotated.length) |
|||
+ bufferHexRotated.substr(0, bufferHexRotated.length - 1) |
|||
const buffer = Buffer.from(bufferHex, 'hex') |
|||
|
|||
const paymentHashBuffer = buffer.slice(33, 65) |
|||
const paymentHashHex = paymentHashBuffer.toString('hex') |
|||
|
|||
const valueBuffer = buffer.slice(65, 73) |
|||
|
|||
const amount = convertBigEndianBufferToLong(valueBuffer) |
|||
|
|||
return { |
|||
payreq, |
|||
amount, |
|||
r_hash: paymentHashHex |
|||
} |
|||
} |
|||
|
|||
export default { |
|||
decodeInvoice |
|||
} |
@ -1,54 +0,0 @@ |
|||
import { callApis } from '../api' |
|||
// ------------------------------------
|
|||
// Constants
|
|||
// ------------------------------------
|
|||
export const GET_ACTIVITY = 'GET_ACTIVITY' |
|||
export const RECEIVE_ACTIVITY = 'RECEIVE_ACTIVITY' |
|||
|
|||
// ------------------------------------
|
|||
// Actions
|
|||
// ------------------------------------
|
|||
export function getActivity() { |
|||
return { |
|||
type: GET_ACTIVITY |
|||
} |
|||
} |
|||
|
|||
export function receiveActvity(data) { |
|||
return { |
|||
type: RECEIVE_ACTIVITY, |
|||
payments: data[0].data.payments.reverse(), |
|||
invoices: data[1].data.invoices.reverse() |
|||
} |
|||
} |
|||
|
|||
export const fetchActivity = () => async (dispatch) => { |
|||
dispatch(getActivity()) |
|||
const activity = await callApis(['payments', 'invoices']) |
|||
dispatch(receiveActvity(activity)) |
|||
} |
|||
|
|||
// ------------------------------------
|
|||
// Action Handlers
|
|||
// ------------------------------------
|
|||
const ACTION_HANDLERS = { |
|||
[GET_ACTIVITY]: state => ({ ...state, activityLoading: true }), |
|||
[RECEIVE_ACTIVITY]: (state, { payments, invoices }) => ( |
|||
{ ...state, activityLoading: false, payments, invoices } |
|||
) |
|||
} |
|||
|
|||
// ------------------------------------
|
|||
// Reducer
|
|||
// ------------------------------------
|
|||
const initialState = { |
|||
activityLoading: false, |
|||
payments: [], |
|||
invoices: [] |
|||
} |
|||
|
|||
export default function activityReducer(state = initialState, action) { |
|||
const handler = ACTION_HANDLERS[action.type] |
|||
|
|||
return handler ? handler(state, action) : state |
|||
} |
@ -0,0 +1,36 @@ |
|||
import createIpc from 'redux-electron-ipc' |
|||
import { receiveInfo } from './info' |
|||
import { receivePeers, connectSuccess, disconnectSuccess } from './peers' |
|||
import { |
|||
receiveChannels, |
|||
channelSuccessful, |
|||
pushchannelupdated, |
|||
pushchannelend, |
|||
pushchannelerror, |
|||
pushchannelstatus |
|||
} from './channels' |
|||
import { receivePayments, paymentSuccessful } from './payment' |
|||
import { receiveInvoices, createdInvoice, receiveFormInvoice } from './invoice' |
|||
import { receiveBalance } from './balance' |
|||
|
|||
// Import all receiving IPC event handlers and pass them into createIpc
|
|||
const ipc = createIpc({ |
|||
receiveInfo, |
|||
receivePeers, |
|||
receiveChannels, |
|||
receivePayments, |
|||
receiveInvoices, |
|||
receiveInvoice: receiveFormInvoice, |
|||
receiveBalance, |
|||
createdInvoice, |
|||
paymentSuccessful, |
|||
channelSuccessful, |
|||
pushchannelupdated, |
|||
pushchannelend, |
|||
pushchannelerror, |
|||
pushchannelstatus, |
|||
connectSuccess, |
|||
disconnectSuccess |
|||
}) |
|||
|
|||
export default ipc |
@ -1,20 +0,0 @@ |
|||
import React from 'react' |
|||
import PropTypes from 'prop-types' |
|||
import Websocket from 'react-websocket' |
|||
|
|||
const Socket = ({ fetchChannels }) => { |
|||
const onMessage = () => { |
|||
// TODO: Assumes only socket relationship is with channels. Actually flesh out socket logic
|
|||
fetchChannels() |
|||
} |
|||
|
|||
return ( |
|||
<Websocket debug url='ws://localhost:3000/' onMessage={onMessage} /> |
|||
) |
|||
} |
|||
|
|||
Socket.propTypes = { |
|||
fetchChannels: PropTypes.func.isRequired |
|||
} |
|||
|
|||
export default Socket |
@ -1,55 +0,0 @@ |
|||
import { callApi } from '../../app/api' |
|||
|
|||
describe('API', () => { |
|||
describe('getinfo', () => { |
|||
it('is synced to the chain', async () => { |
|||
const info = await callApi('info') |
|||
expect(info.data.synced_to_chain).toEqual(true) |
|||
}) |
|||
|
|||
it('only supports 1 chain at a time', async () => { |
|||
const info = await callApi('info') |
|||
expect(info.data.chains.length).toEqual(1) |
|||
}) |
|||
}) |
|||
|
|||
describe('balance', () => { |
|||
it('returns wallet balance', async () => { |
|||
const wallet_balances = await callApi('wallet_balance') |
|||
expect(typeof (wallet_balances.data.balance)).toEqual('string') |
|||
}) |
|||
|
|||
it('returns channel balance', async () => { |
|||
const channel_balances = await callApi('channel_balance') |
|||
expect(typeof (channel_balances.data.balance)).toEqual('string') |
|||
}) |
|||
}) |
|||
|
|||
describe('peers', () => { |
|||
it('peers is an array', async () => { |
|||
const peers = await callApi('peers') |
|||
expect(Array.isArray(peers.data.peers)).toEqual(true) |
|||
}) |
|||
}) |
|||
|
|||
describe('channels', () => { |
|||
it('channels is an array', async () => { |
|||
const channels = await callApi('channels') |
|||
expect(Array.isArray(channels.data.channels)).toEqual(true) |
|||
}) |
|||
}) |
|||
|
|||
describe('invoices', () => { |
|||
it('invoices is an array', async () => { |
|||
const invoices = await callApi('invoices') |
|||
expect(Array.isArray(invoices.data.invoices)).toEqual(true) |
|||
}) |
|||
}) |
|||
|
|||
describe('payments', () => { |
|||
it('payments is an array', async () => { |
|||
const payments = await callApi('payments') |
|||
expect(Array.isArray(payments.data.payments)).toEqual(true) |
|||
}) |
|||
}) |
|||
}) |
Loading…
Reference in new issue