Skip to content
This repository has been archived by the owner on Sep 2, 2024. It is now read-only.

Add SignMessage method #124

Merged
merged 16 commits into from
Mar 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion breez.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import (
"time"

"github.com/breez/breez-sdk-go/breez_sdk"
"github.com/getAlby/nostr-wallet-connect/models/lnclient"
decodepay "github.com/nbd-wtf/ln-decodepay"
"github.com/sirupsen/logrus"

"github.com/getAlby/nostr-wallet-connect/models/lnclient"
)

type BreezService struct {
Expand Down Expand Up @@ -398,6 +399,17 @@ func (bs *BreezService) ResetRouter(ctx context.Context) error {
return nil
}

func (bs *BreezService) SignMessage(ctx context.Context, message string) (string, error) {
resp, err := bs.svc.SignMessage(breez_sdk.SignMessageRequest{
Message: message,
})
if err != nil {
return "", err
}

return resp.Signature, nil
}

func (bs *BreezService) GetBalances(ctx context.Context) (*lnclient.BalancesResponse, error) {
info, err := bs.svc.NodeInfo()
if err != nil {
Expand Down
7 changes: 6 additions & 1 deletion frontend/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
PopiconsBookmarkLine,
PopiconsClipboardTextLine,
PopiconsDatabaseLine,
PopiconsPenToolLine,
PopiconsSearchCircleLine,
PopiconsWalletLine,
} from "@popicons/react";
Expand All @@ -13,6 +14,7 @@ export const NIP_47_GET_INFO_METHOD = "get_info";
export const NIP_47_MAKE_INVOICE_METHOD = "make_invoice";
export const NIP_47_LOOKUP_INVOICE_METHOD = "lookup_invoice";
export const NIP_47_LIST_TRANSACTIONS_METHOD = "list_transactions";
export const NIP_47_SIGN_MESSAGE_METHOD = "sign_message";

export type BackendType = "LND" | "BREEZ" | "GREENLIGHT" | "LDK";

Expand All @@ -22,7 +24,8 @@ export type RequestMethodType =
| "get_info"
| "make_invoice"
| "lookup_invoice"
| "list_transactions";
| "list_transactions"
| "sign_message";

export type BudgetRenewalType =
| "daily"
Expand All @@ -45,6 +48,7 @@ export const iconMap: IconMap = {
[NIP_47_LOOKUP_INVOICE_METHOD]: PopiconsSearchCircleLine,
[NIP_47_MAKE_INVOICE_METHOD]: PopiconsClipboardTextLine,
[NIP_47_PAY_INVOICE_METHOD]: PopiconsBoltLine,
[NIP_47_SIGN_MESSAGE_METHOD]: PopiconsPenToolLine,
};

export const validBudgetRenewals: BudgetRenewalType[] = [
Expand All @@ -62,6 +66,7 @@ export const nip47MethodDescriptions: Record<RequestMethodType, string> = {
[NIP_47_LOOKUP_INVOICE_METHOD]: "Lookup status of invoices",
[NIP_47_MAKE_INVOICE_METHOD]: "Create invoices",
[NIP_47_PAY_INVOICE_METHOD]: "Send payments",
[NIP_47_SIGN_MESSAGE_METHOD]: "Sign messages",
};

export const expiryOptions: Record<string, number> = {
Expand Down
13 changes: 13 additions & 0 deletions greenlight.go
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,19 @@ func (gs *GreenlightService) RedeemOnchainFunds(ctx context.Context, toAddress s
return txId.Txid, nil
}

func (gs *GreenlightService) SignMessage(ctx context.Context, message string) (string, error) {
response, err := gs.client.SignMessage(glalby.SignMessageRequest{
Message: message,
})

if err != nil {
gs.svc.Logger.Errorf("SignMessage failed: %v", err)
return "", err
}

return response.Zbase, nil
}

func (gs *GreenlightService) greenlightInvoiceToTransaction(invoice *glalby.ListInvoicesInvoice) (*Nip47Transaction, error) {
description := ""
descriptionHash := ""
Expand Down
54 changes: 54 additions & 0 deletions handle_sign_message_request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package main

import (
"context"

"github.com/nbd-wtf/go-nostr"
"github.com/sirupsen/logrus"
)

func (svc *Service) HandleSignMessageEvent(ctx context.Context, nip47Request *Nip47Request, requestEvent *RequestEvent, app *App, publishResponse func(*Nip47Response, nostr.Tags)) {
signParams := &Nip47SignMessageParams{}
resp := svc.decodeNip47Request(nip47Request, requestEvent, app, signParams)
if resp != nil {
publishResponse(resp, nostr.Tags{})
return
}

resp = svc.checkPermission(nip47Request, requestEvent.NostrId, app, 0)
if resp != nil {
publishResponse(resp, nostr.Tags{})
return
}

svc.Logger.WithFields(logrus.Fields{
"requestEventNostrId": requestEvent.NostrId,
"appId": app.ID,
}).Info("Signing message")

signature, err := svc.lnClient.SignMessage(ctx, signParams.Message)
if err != nil {
svc.Logger.WithFields(logrus.Fields{
"requestEventNostrId": requestEvent.NostrId,
"appId": app.ID,
}).Infof("Failed to sign message: %v", err)
publishResponse(&Nip47Response{
ResultType: nip47Request.Method,
Error: &Nip47Error{
Code: NIP_47_ERROR_INTERNAL,
Message: err.Error(),
},
}, nostr.Tags{})
return
}

responsePayload := Nip47SignMessageResponse{
Message: signParams.Message,
Signature: signature,
}

publishResponse(&Nip47Response{
ResultType: nip47Request.Method,
Result: responsePayload,
}, nostr.Tags{})
}
10 changes: 10 additions & 0 deletions ldk.go
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,16 @@ func (ls *LDKService) ResetRouter(ctx context.Context) error {
return err
}

func (gs *LDKService) SignMessage(ctx context.Context, message string) (string, error) {
sign, err := gs.node.SignMessage([]byte(message))
if err != nil {
gs.svc.Logger.Errorf("SignMessage failed: %v", err)
return "", err
}

return sign, nil
}

func (gs *LDKService) ldkPaymentToTransaction(payment *ldk_node.PaymentDetails) (*Nip47Transaction, error) {
transactionType := "incoming"
if payment.Direction == ldk_node.PaymentDirectionOutbound {
Expand Down
9 changes: 9 additions & 0 deletions lnd.go
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,15 @@ func (svc *LNDService) RedeemOnchainFunds(ctx context.Context, toAddress string)
return "", nil
}

func (svc *LNDService) SignMessage(ctx context.Context, message string) (string, error) {
resp, err := svc.client.SignMessage(ctx, &lnrpc.SignMessageRequest{Msg: []byte(message)})
if err != nil {
return "", err
}

return resp.Signature, nil
}

func (svc *LNDService) GetBalances(ctx context.Context) (*lnclient.BalancesResponse, error) {
balance, err := svc.GetBalance(ctx)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions lnd/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type LightningClientWrapper interface {
DecodeBolt11(ctx context.Context, bolt11 string, options ...grpc.CallOption) (*lnrpc.PayReq, error)
IsIdentityPubkey(pubkey string) (isOurPubkey bool)
GetMainPubkey() (pubkey string)
SignMessage(ctx context.Context, req *lnrpc.SignMessageRequest, options ...grpc.CallOption) (*lnrpc.SignMessageResponse, error)
}

type SubscribeInvoicesWrapper interface {
Expand Down
4 changes: 4 additions & 0 deletions lnd/lnd.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,3 +140,7 @@ func (wrapper *LNDWrapper) IsIdentityPubkey(pubkey string) (isOurPubkey bool) {
func (wrapper *LNDWrapper) GetMainPubkey() (pubkey string) {
return wrapper.IdentityPubkey
}

func (wrapper *LNDWrapper) SignMessage(ctx context.Context, req *lnrpc.SignMessageRequest, options ...grpc.CallOption) (*lnrpc.SignMessageResponse, error) {
return wrapper.client.SignMessage(ctx, req, options...)
}
12 changes: 11 additions & 1 deletion models.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const (
NIP_47_PAY_KEYSEND_METHOD = "pay_keysend"
NIP_47_MULTI_PAY_INVOICE_METHOD = "multi_pay_invoice"
NIP_47_MULTI_PAY_KEYSEND_METHOD = "multi_pay_keysend"
NIP_47_SIGN_MESSAGE_METHOD = "sign_message"
NIP_47_ERROR_INTERNAL = "INTERNAL"
NIP_47_ERROR_NOT_IMPLEMENTED = "NOT_IMPLEMENTED"
NIP_47_ERROR_QUOTA_EXCEEDED = "QUOTA_EXCEEDED"
Expand All @@ -29,7 +30,7 @@ const (
NIP_47_ERROR_RESTRICTED = "RESTRICTED"
NIP_47_ERROR_BAD_REQUEST = "BAD_REQUEST"
NIP_47_OTHER = "OTHER"
NIP_47_CAPABILITIES = "pay_invoice pay_keysend get_balance get_info make_invoice lookup_invoice list_transactions multi_pay_invoice multi_pay_keysend"
NIP_47_CAPABILITIES = "pay_invoice pay_keysend get_balance get_info make_invoice lookup_invoice list_transactions multi_pay_invoice multi_pay_keysend sign_message"
)

const (
Expand Down Expand Up @@ -208,3 +209,12 @@ type Nip47ListTransactionsParams struct {
type Nip47ListTransactionsResponse struct {
Transactions []Nip47Transaction `json:"transactions"`
}

type Nip47SignMessageParams struct {
Message string `json:"message"`
}

type Nip47SignMessageResponse struct {
Message string `json:"message"`
Signature string `json:"signature"`
}
1 change: 1 addition & 0 deletions models/lnclient/lnclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ type LNClient interface {
GetOnchainBalance(ctx context.Context) (*OnchainBalanceResponse, error)
GetBalances(ctx context.Context) (*BalancesResponse, error)
RedeemOnchainFunds(ctx context.Context, toAddress string) (txId string, err error)
SignMessage(ctx context.Context, message string) (string, error)
}

type Channel struct {
Expand Down
2 changes: 2 additions & 0 deletions service.go
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,8 @@ func (svc *Service) HandleEvent(ctx context.Context, sub *nostr.Subscription, ev
svc.HandleListTransactionsEvent(ctx, nip47Request, &requestEvent, &app, publishResponse)
case NIP_47_GET_INFO_METHOD:
svc.HandleGetInfoEvent(ctx, nip47Request, &requestEvent, &app, publishResponse)
case NIP_47_SIGN_MESSAGE_METHOD:
svc.HandleSignMessageEvent(ctx, nip47Request, &requestEvent, &app, publishResponse)
default:
svc.handleUnknownMethod(ctx, nip47Request, publishResponse)
}
Expand Down
3 changes: 3 additions & 0 deletions service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1315,3 +1315,6 @@ func (mln *MockLn) RedeemOnchainFunds(ctx context.Context, toAddress string) (tx
func (mln *MockLn) ResetRouter(ctx context.Context) error {
return nil
}
func (mln *MockLn) SignMessage(ctx context.Context, message string) (string, error) {
return "", nil
}
Loading