Renamed NWC client methods and added RPCRaw wrappers
* Renamed `NWCClient` to `nwc.NewNWCClient(opts)` in `cmd/nwcclient/main.go`
* Added `RPCRaw` wrappers for NWC client methods in `pkg/protocol/nwc/methods.go`
**Updated walletcli main function**
* Updated the main function in `cmd/walletcli/main.go` to use new NWC client and RPCRaw wrappers
**Added new methods for walletcli**
* Added new methods for handling NWC client RPC calls, such as:
* `handleGetWalletServiceInfo`
* `handleMakeHoldInvoice`
* `handleSettleHoldInvoice`
* `handleCancelHoldInvoice`
**Code formatting and style changes**
* Formatted code according to Go standard
* Used consistent naming conventions and coding styles
**Other updates**
* Updated dependencies and imported packages accordingly
This commit is contained in:
@@ -1,285 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"orly.dev/pkg/protocol/nwc"
|
||||
)
|
||||
|
||||
func printUsage() {
|
||||
fmt.Println("Usage: nwcclient \"<connection URL>\" <method> [parameters...]")
|
||||
fmt.Println("\nSupported methods:")
|
||||
fmt.Println(" get_info - Get wallet information")
|
||||
fmt.Println(" get_balance - Get wallet balance")
|
||||
fmt.Println(" get_budget - Get wallet budget")
|
||||
fmt.Println(" make_invoice - Create an invoice (amount, description, [description_hash], [expiry])")
|
||||
fmt.Println(" pay_invoice - Pay an invoice (invoice, [amount])")
|
||||
fmt.Println(" pay_keysend - Send a keysend payment (amount, pubkey, [preimage])")
|
||||
fmt.Println(" lookup_invoice - Look up an invoice (payment_hash or invoice)")
|
||||
fmt.Println(" list_transactions - List transactions ([from], [until], [limit], [offset], [unpaid], [type])")
|
||||
fmt.Println(" sign_message - Sign a message (message)")
|
||||
fmt.Println("\nUnsupported methods (due to limitations in the nwc package):")
|
||||
fmt.Println(" create_connection - Create a connection")
|
||||
fmt.Println(" make_hold_invoice - Create a hold invoice")
|
||||
fmt.Println(" settle_hold_invoice - Settle a hold invoice")
|
||||
fmt.Println(" cancel_hold_invoice - Cancel a hold invoice")
|
||||
fmt.Println(" multi_pay_invoice - Pay multiple invoices")
|
||||
fmt.Println(" multi_pay_keysend - Send multiple keysend payments")
|
||||
fmt.Println("\nParameters format:")
|
||||
fmt.Println(" - Positional parameters are used for required fields")
|
||||
fmt.Println(" - For list_transactions, named parameters are used: 'from', 'until', 'limit', 'offset', 'unpaid', 'type'")
|
||||
fmt.Println(" Example: nwcclient <url> list_transactions limit 10 type incoming")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Check if we have enough arguments
|
||||
if len(os.Args) < 3 {
|
||||
printUsage()
|
||||
}
|
||||
|
||||
// Parse connection URL and method
|
||||
connectionURL := os.Args[1]
|
||||
methodStr := os.Args[2]
|
||||
method := nwc.Capability(methodStr)
|
||||
|
||||
// Parse the wallet connect URL
|
||||
opts, err := nwc.ParseWalletConnectURL(connectionURL)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error parsing connection URL: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Create a new NWC client
|
||||
client, err := nwc.NewNWCClient(opts)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error creating NWC client: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
// Execute the requested method
|
||||
var result interface{}
|
||||
|
||||
switch method {
|
||||
case nwc.GetInfo:
|
||||
result, err = client.GetInfo()
|
||||
|
||||
case nwc.GetBalance:
|
||||
result, err = client.GetBalance()
|
||||
|
||||
case nwc.GetBudget:
|
||||
result, err = client.GetBudget()
|
||||
|
||||
case nwc.MakeInvoice:
|
||||
if len(os.Args) < 5 {
|
||||
fmt.Fprintf(
|
||||
os.Stderr,
|
||||
"Error: make_invoice requires at least amount and description\n",
|
||||
)
|
||||
printUsage()
|
||||
}
|
||||
amount, err := strconv.ParseInt(os.Args[3], 10, 64)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error parsing amount: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
description := os.Args[4]
|
||||
|
||||
req := &nwc.MakeInvoiceRequest{
|
||||
Amount: amount,
|
||||
Description: description,
|
||||
}
|
||||
|
||||
// Optional parameters
|
||||
if len(os.Args) > 5 {
|
||||
req.DescriptionHash = os.Args[5]
|
||||
}
|
||||
if len(os.Args) > 6 {
|
||||
expiry, err := strconv.ParseInt(os.Args[6], 10, 64)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error parsing expiry: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
req.Expiry = &expiry
|
||||
}
|
||||
|
||||
result, err = client.MakeInvoice(req)
|
||||
|
||||
case nwc.PayInvoice:
|
||||
if len(os.Args) < 4 {
|
||||
fmt.Fprintf(os.Stderr, "Error: pay_invoice requires an invoice\n")
|
||||
printUsage()
|
||||
}
|
||||
|
||||
req := &nwc.PayInvoiceRequest{
|
||||
Invoice: os.Args[3],
|
||||
}
|
||||
|
||||
// Optional amount parameter
|
||||
if len(os.Args) > 4 {
|
||||
amount, err := strconv.ParseInt(os.Args[4], 10, 64)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error parsing amount: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
req.Amount = &amount
|
||||
}
|
||||
|
||||
result, err = client.PayInvoice(req)
|
||||
|
||||
case nwc.PayKeysend:
|
||||
if len(os.Args) < 5 {
|
||||
fmt.Fprintf(
|
||||
os.Stderr, "Error: pay_keysend requires amount and pubkey\n",
|
||||
)
|
||||
printUsage()
|
||||
}
|
||||
|
||||
amount, err := strconv.ParseInt(os.Args[3], 10, 64)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error parsing amount: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
req := &nwc.PayKeysendRequest{
|
||||
Amount: amount,
|
||||
Pubkey: os.Args[4],
|
||||
}
|
||||
|
||||
// Optional preimage
|
||||
if len(os.Args) > 5 {
|
||||
req.Preimage = os.Args[5]
|
||||
}
|
||||
|
||||
result, err = client.PayKeysend(req)
|
||||
|
||||
case nwc.LookupInvoice:
|
||||
if len(os.Args) < 4 {
|
||||
fmt.Fprintf(
|
||||
os.Stderr,
|
||||
"Error: lookup_invoice requires a payment_hash or invoice\n",
|
||||
)
|
||||
printUsage()
|
||||
}
|
||||
|
||||
param := os.Args[3]
|
||||
req := &nwc.LookupInvoiceRequest{}
|
||||
|
||||
// Determine if the parameter is a payment hash or an invoice
|
||||
if strings.HasPrefix(param, "ln") {
|
||||
req.Invoice = param
|
||||
} else {
|
||||
req.PaymentHash = param
|
||||
}
|
||||
|
||||
result, err = client.LookupInvoice(req)
|
||||
|
||||
case nwc.ListTransactions:
|
||||
req := &nwc.ListTransactionsRequest{}
|
||||
|
||||
// Parse optional parameters
|
||||
paramIndex := 3
|
||||
for paramIndex < len(os.Args) {
|
||||
if paramIndex+1 >= len(os.Args) {
|
||||
break
|
||||
}
|
||||
|
||||
paramName := os.Args[paramIndex]
|
||||
paramValue := os.Args[paramIndex+1]
|
||||
|
||||
switch paramName {
|
||||
case "from":
|
||||
val, err := strconv.ParseInt(paramValue, 10, 64)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error parsing from: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
req.From = &val
|
||||
case "until":
|
||||
val, err := strconv.ParseInt(paramValue, 10, 64)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error parsing until: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
req.Until = &val
|
||||
case "limit":
|
||||
val, err := strconv.ParseInt(paramValue, 10, 64)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error parsing limit: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
req.Limit = &val
|
||||
case "offset":
|
||||
val, err := strconv.ParseInt(paramValue, 10, 64)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error parsing offset: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
req.Offset = &val
|
||||
case "unpaid":
|
||||
val := paramValue == "true"
|
||||
req.Unpaid = &val
|
||||
case "type":
|
||||
req.Type = ¶mValue
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "Unknown parameter: %s\n", paramName)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
paramIndex += 2
|
||||
}
|
||||
|
||||
result, err = client.ListTransactions(req)
|
||||
|
||||
case nwc.SignMessage:
|
||||
if len(os.Args) < 4 {
|
||||
fmt.Fprintf(os.Stderr, "Error: sign_message requires a message\n")
|
||||
printUsage()
|
||||
}
|
||||
|
||||
req := &nwc.SignMessageRequest{
|
||||
Message: os.Args[3],
|
||||
}
|
||||
|
||||
result, err = client.SignMessage(req)
|
||||
|
||||
case nwc.CreateConnection, nwc.MakeHoldInvoice, nwc.SettleHoldInvoice, nwc.CancelHoldInvoice, nwc.MultiPayInvoice, nwc.MultiPayKeysend:
|
||||
fmt.Fprintf(
|
||||
os.Stderr,
|
||||
"Error: Method %s is not directly supported by the CLI tool.\n",
|
||||
methodStr,
|
||||
)
|
||||
fmt.Fprintf(
|
||||
os.Stderr,
|
||||
"This is because these methods don't have exported client methods in the nwc package.\n",
|
||||
)
|
||||
fmt.Fprintf(
|
||||
os.Stderr,
|
||||
"Only the following methods are currently supported: get_info, get_balance, get_budget, make_invoice, pay_invoice, pay_keysend, lookup_invoice, list_transactions, sign_message\n",
|
||||
)
|
||||
os.Exit(1)
|
||||
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "Error: Unsupported method: %s\n", methodStr)
|
||||
printUsage()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error executing method: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Print the result as JSON
|
||||
jsonData, err := json.MarshalIndent(result, "", " ")
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error marshaling result to JSON: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Println(string(jsonData))
|
||||
}
|
||||
511
cmd/walletcli/main.go
Normal file
511
cmd/walletcli/main.go
Normal file
@@ -0,0 +1,511 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"orly.dev/pkg/protocol/nwc"
|
||||
"orly.dev/pkg/utils/context"
|
||||
)
|
||||
|
||||
func printUsage() {
|
||||
fmt.Println("Usage: walletcli '<NWC connection URL>' <method> [<args...>]")
|
||||
fmt.Println("\nAvailable methods:")
|
||||
fmt.Println(" get_wallet_service_info - Get wallet service information")
|
||||
fmt.Println(" get_info - Get wallet information")
|
||||
fmt.Println(" get_balance - Get wallet balance")
|
||||
fmt.Println(" get_budget - Get wallet budget")
|
||||
fmt.Println(" make_invoice - Create an invoice")
|
||||
fmt.Println(" Args: <amount> [<description>] [<description_hash>] [<expiry>]")
|
||||
fmt.Println(" pay_invoice - Pay an invoice")
|
||||
fmt.Println(" Args: <invoice> [<amount>] [<comment>]")
|
||||
fmt.Println(" pay_keysend - Pay to a node using keysend")
|
||||
fmt.Println(" Args: <pubkey> <amount> [<preimage>] [<tlv_type> <tlv_value>...]")
|
||||
fmt.Println(" lookup_invoice - Look up an invoice")
|
||||
fmt.Println(" Args: <payment_hash or invoice>")
|
||||
fmt.Println(" list_transactions - List transactions")
|
||||
fmt.Println(" Args: [<limit>] [<offset>] [<from>] [<until>]")
|
||||
fmt.Println(" make_hold_invoice - Create a hold invoice")
|
||||
fmt.Println(" Args: <amount> <payment_hash> [<description>] [<description_hash>] [<expiry>]")
|
||||
fmt.Println(" settle_hold_invoice - Settle a hold invoice")
|
||||
fmt.Println(" Args: <preimage>")
|
||||
fmt.Println(" cancel_hold_invoice - Cancel a hold invoice")
|
||||
fmt.Println(" Args: <payment_hash>")
|
||||
fmt.Println(" sign_message - Sign a message")
|
||||
fmt.Println(" Args: <message>")
|
||||
fmt.Println(" create_connection - Create a connection")
|
||||
fmt.Println(" Args: <pubkey> <name> <methods> [<notification_types>] [<max_amount>] [<budget_renewal>] [<expires_at>]")
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 3 {
|
||||
printUsage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
connectionURL := os.Args[1]
|
||||
method := os.Args[2]
|
||||
args := os.Args[3:]
|
||||
|
||||
// Create context
|
||||
ctx := context.Bg()
|
||||
|
||||
// Create NWC client
|
||||
client, err := nwc.NewClient(ctx, connectionURL)
|
||||
if err != nil {
|
||||
fmt.Printf("Error creating client: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Execute the requested method
|
||||
switch method {
|
||||
case "get_wallet_service_info":
|
||||
handleGetWalletServiceInfo(ctx, client)
|
||||
case "get_info":
|
||||
handleGetInfo(ctx, client)
|
||||
case "get_balance":
|
||||
handleGetBalance(ctx, client)
|
||||
case "get_budget":
|
||||
handleGetBudget(ctx, client)
|
||||
case "make_invoice":
|
||||
handleMakeInvoice(ctx, client, args)
|
||||
case "pay_invoice":
|
||||
handlePayInvoice(ctx, client, args)
|
||||
case "pay_keysend":
|
||||
handlePayKeysend(ctx, client, args)
|
||||
case "lookup_invoice":
|
||||
handleLookupInvoice(ctx, client, args)
|
||||
case "list_transactions":
|
||||
handleListTransactions(ctx, client, args)
|
||||
case "make_hold_invoice":
|
||||
handleMakeHoldInvoice(ctx, client, args)
|
||||
case "settle_hold_invoice":
|
||||
handleSettleHoldInvoice(ctx, client, args)
|
||||
case "cancel_hold_invoice":
|
||||
handleCancelHoldInvoice(ctx, client, args)
|
||||
case "sign_message":
|
||||
handleSignMessage(ctx, client, args)
|
||||
case "create_connection":
|
||||
handleCreateConnection(ctx, client, args)
|
||||
default:
|
||||
fmt.Printf("Unknown method: %s\n", method)
|
||||
printUsage()
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func handleGetWalletServiceInfo(ctx context.T, client *nwc.Client) {
|
||||
raw, err := client.GetWalletServiceInfoRaw(ctx)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(string(raw))
|
||||
}
|
||||
|
||||
func handleGetInfo(ctx context.T, client *nwc.Client) {
|
||||
raw, err := client.GetInfoRaw(ctx)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(string(raw))
|
||||
}
|
||||
|
||||
func handleGetBalance(ctx context.T, client *nwc.Client) {
|
||||
raw, err := client.GetBalanceRaw(ctx)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(string(raw))
|
||||
}
|
||||
|
||||
func handleGetBudget(ctx context.T, client *nwc.Client) {
|
||||
raw, err := client.GetBudgetRaw(ctx)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(string(raw))
|
||||
}
|
||||
|
||||
func handleMakeInvoice(ctx context.T, client *nwc.Client, args []string) {
|
||||
if len(args) < 1 {
|
||||
fmt.Println("Error: Missing required arguments")
|
||||
fmt.Println("Usage: walletcli <NWC connection URL> make_invoice <amount> [<description>] [<description_hash>] [<expiry>]")
|
||||
return
|
||||
}
|
||||
|
||||
amount, err := strconv.ParseUint(args[0], 10, 64)
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing amount: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
params := &nwc.MakeInvoiceParams{
|
||||
Amount: amount,
|
||||
}
|
||||
|
||||
if len(args) > 1 {
|
||||
params.Description = args[1]
|
||||
}
|
||||
|
||||
if len(args) > 2 {
|
||||
params.DescriptionHash = args[2]
|
||||
}
|
||||
|
||||
if len(args) > 3 {
|
||||
expiry, err := strconv.ParseInt(args[3], 10, 64)
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing expiry: %v\n", err)
|
||||
return
|
||||
}
|
||||
params.Expiry = &expiry
|
||||
}
|
||||
|
||||
raw, err := client.MakeInvoiceRaw(ctx, params)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(string(raw))
|
||||
}
|
||||
|
||||
func handlePayInvoice(ctx context.T, client *nwc.Client, args []string) {
|
||||
if len(args) < 1 {
|
||||
fmt.Println("Error: Missing required arguments")
|
||||
fmt.Println("Usage: walletcli <NWC connection URL> pay_invoice <invoice> [<amount>] [<comment>]")
|
||||
return
|
||||
}
|
||||
|
||||
params := &nwc.PayInvoiceParams{
|
||||
Invoice: args[0],
|
||||
}
|
||||
|
||||
if len(args) > 1 {
|
||||
amount, err := strconv.ParseUint(args[1], 10, 64)
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing amount: %v\n", err)
|
||||
return
|
||||
}
|
||||
params.Amount = &amount
|
||||
}
|
||||
|
||||
if len(args) > 2 {
|
||||
comment := args[2]
|
||||
params.Metadata = &nwc.PayInvoiceMetadata{
|
||||
Comment: &comment,
|
||||
}
|
||||
}
|
||||
|
||||
raw, err := client.PayInvoiceRaw(ctx, params)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(string(raw))
|
||||
}
|
||||
|
||||
func handleLookupInvoice(ctx context.T, client *nwc.Client, args []string) {
|
||||
if len(args) < 1 {
|
||||
fmt.Println("Error: Missing required arguments")
|
||||
fmt.Println("Usage: walletcli <NWC connection URL> lookup_invoice <payment_hash or invoice>")
|
||||
return
|
||||
}
|
||||
|
||||
params := &nwc.LookupInvoiceParams{}
|
||||
|
||||
// Determine if the argument is a payment hash or an invoice
|
||||
if strings.HasPrefix(args[0], "ln") {
|
||||
invoice := args[0]
|
||||
params.Invoice = &invoice
|
||||
} else {
|
||||
paymentHash := args[0]
|
||||
params.PaymentHash = &paymentHash
|
||||
}
|
||||
|
||||
raw, err := client.LookupInvoiceRaw(ctx, params)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(string(raw))
|
||||
}
|
||||
|
||||
func handleListTransactions(ctx context.T, client *nwc.Client, args []string) {
|
||||
params := &nwc.ListTransactionsParams{}
|
||||
|
||||
if len(args) > 0 {
|
||||
limit, err := strconv.ParseUint(args[0], 10, 16)
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing limit: %v\n", err)
|
||||
return
|
||||
}
|
||||
limitUint16 := uint16(limit)
|
||||
params.Limit = &limitUint16
|
||||
}
|
||||
|
||||
if len(args) > 1 {
|
||||
offset, err := strconv.ParseUint(args[1], 10, 32)
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing offset: %v\n", err)
|
||||
return
|
||||
}
|
||||
offsetUint32 := uint32(offset)
|
||||
params.Offset = &offsetUint32
|
||||
}
|
||||
|
||||
if len(args) > 2 {
|
||||
from, err := strconv.ParseInt(args[2], 10, 64)
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing from: %v\n", err)
|
||||
return
|
||||
}
|
||||
params.From = &from
|
||||
}
|
||||
|
||||
if len(args) > 3 {
|
||||
until, err := strconv.ParseInt(args[3], 10, 64)
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing until: %v\n", err)
|
||||
return
|
||||
}
|
||||
params.Until = &until
|
||||
}
|
||||
|
||||
raw, err := client.ListTransactionsRaw(ctx, params)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(string(raw))
|
||||
}
|
||||
|
||||
func handleMakeHoldInvoice(ctx context.T, client *nwc.Client, args []string) {
|
||||
if len(args) < 2 {
|
||||
fmt.Println("Error: Missing required arguments")
|
||||
fmt.Println("Usage: walletcli <NWC connection URL> make_hold_invoice <amount> <payment_hash> [<description>] [<description_hash>] [<expiry>]")
|
||||
return
|
||||
}
|
||||
|
||||
amount, err := strconv.ParseUint(args[0], 10, 64)
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing amount: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
params := &nwc.MakeHoldInvoiceParams{
|
||||
Amount: amount,
|
||||
PaymentHash: args[1],
|
||||
}
|
||||
|
||||
if len(args) > 2 {
|
||||
params.Description = args[2]
|
||||
}
|
||||
|
||||
if len(args) > 3 {
|
||||
params.DescriptionHash = args[3]
|
||||
}
|
||||
|
||||
if len(args) > 4 {
|
||||
expiry, err := strconv.ParseInt(args[4], 10, 64)
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing expiry: %v\n", err)
|
||||
return
|
||||
}
|
||||
params.Expiry = &expiry
|
||||
}
|
||||
|
||||
raw, err := client.MakeHoldInvoiceRaw(ctx, params)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(string(raw))
|
||||
}
|
||||
|
||||
func handleSettleHoldInvoice(ctx context.T, client *nwc.Client, args []string) {
|
||||
if len(args) < 1 {
|
||||
fmt.Println("Error: Missing required arguments")
|
||||
fmt.Println("Usage: walletcli <NWC connection URL> settle_hold_invoice <preimage>")
|
||||
return
|
||||
}
|
||||
|
||||
params := &nwc.SettleHoldInvoiceParams{
|
||||
Preimage: args[0],
|
||||
}
|
||||
|
||||
raw, err := client.SettleHoldInvoiceRaw(ctx, params)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(string(raw))
|
||||
}
|
||||
|
||||
func handleCancelHoldInvoice(ctx context.T, client *nwc.Client, args []string) {
|
||||
if len(args) < 1 {
|
||||
fmt.Println("Error: Missing required arguments")
|
||||
fmt.Println("Usage: walletcli <NWC connection URL> cancel_hold_invoice <payment_hash>")
|
||||
return
|
||||
}
|
||||
|
||||
params := &nwc.CancelHoldInvoiceParams{
|
||||
PaymentHash: args[0],
|
||||
}
|
||||
|
||||
raw, err := client.CancelHoldInvoiceRaw(ctx, params)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(string(raw))
|
||||
}
|
||||
|
||||
func handleSignMessage(ctx context.T, client *nwc.Client, args []string) {
|
||||
if len(args) < 1 {
|
||||
fmt.Println("Error: Missing required arguments")
|
||||
fmt.Println("Usage: walletcli <NWC connection URL> sign_message <message>")
|
||||
return
|
||||
}
|
||||
|
||||
params := &nwc.SignMessageParams{
|
||||
Message: args[0],
|
||||
}
|
||||
|
||||
raw, err := client.SignMessageRaw(ctx, params)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(string(raw))
|
||||
}
|
||||
|
||||
func handlePayKeysend(ctx context.T, client *nwc.Client, args []string) {
|
||||
if len(args) < 2 {
|
||||
fmt.Println("Error: Missing required arguments")
|
||||
fmt.Println("Usage: walletcli <NWC connection URL> pay_keysend <pubkey> <amount> [<preimage>] [<tlv_type> <tlv_value>...]")
|
||||
return
|
||||
}
|
||||
|
||||
pubkey := args[0]
|
||||
|
||||
amount, err := strconv.ParseUint(args[1], 10, 64)
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing amount: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
params := &nwc.PayKeysendParams{
|
||||
Pubkey: pubkey,
|
||||
Amount: amount,
|
||||
}
|
||||
|
||||
// Optional preimage
|
||||
if len(args) > 2 {
|
||||
preimage := args[2]
|
||||
params.Preimage = &preimage
|
||||
}
|
||||
|
||||
// Optional TLV records (must come in pairs)
|
||||
if len(args) > 3 {
|
||||
// Start from index 3 and process pairs of arguments
|
||||
for i := 3; i < len(args)-1; i += 2 {
|
||||
tlvType, err := strconv.ParseUint(args[i], 10, 32)
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing TLV type: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
tlvValue := args[i+1]
|
||||
|
||||
params.TLVRecords = append(
|
||||
params.TLVRecords, nwc.PayKeysendTLVRecord{
|
||||
Type: uint32(tlvType),
|
||||
Value: tlvValue,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
raw, err := client.PayKeysendRaw(ctx, params)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(string(raw))
|
||||
}
|
||||
|
||||
func handleCreateConnection(ctx context.T, client *nwc.Client, args []string) {
|
||||
if len(args) < 3 {
|
||||
fmt.Println("Error: Missing required arguments")
|
||||
fmt.Println("Usage: walletcli <NWC connection URL> create_connection <pubkey> <name> <methods> [<notification_types>] [<max_amount>] [<budget_renewal>] [<expires_at>]")
|
||||
return
|
||||
}
|
||||
|
||||
params := &nwc.CreateConnectionParams{
|
||||
Pubkey: args[0],
|
||||
Name: args[1],
|
||||
RequestMethods: strings.Split(args[2], ","),
|
||||
}
|
||||
|
||||
if len(args) > 3 {
|
||||
params.NotificationTypes = strings.Split(args[3], ",")
|
||||
}
|
||||
|
||||
if len(args) > 4 {
|
||||
maxAmount, err := strconv.ParseUint(args[4], 10, 64)
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing max_amount: %v\n", err)
|
||||
return
|
||||
}
|
||||
params.MaxAmount = &maxAmount
|
||||
}
|
||||
|
||||
if len(args) > 5 {
|
||||
params.BudgetRenewal = &args[5]
|
||||
}
|
||||
|
||||
if len(args) > 6 {
|
||||
expiresAt, err := strconv.ParseInt(args[6], 10, 64)
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing expires_at: %v\n", err)
|
||||
return
|
||||
}
|
||||
params.ExpiresAt = &expiresAt
|
||||
}
|
||||
|
||||
raw, err := client.CreateConnectionRaw(ctx, params)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(string(raw))
|
||||
}
|
||||
|
||||
func printJSON(v interface{}) {
|
||||
data, err := json.MarshalIndent(v, "", " ")
|
||||
if err != nil {
|
||||
fmt.Printf("Error marshaling JSON: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(data))
|
||||
}
|
||||
@@ -33,7 +33,7 @@ func NewPubFromHex[V []byte | string](pkh V) (sign signer.I, err error) {
|
||||
}
|
||||
|
||||
func HexToBin(hexStr string) (b []byte, err error) {
|
||||
if _, err = hex.DecBytes(b, []byte(hexStr)); chk.E(err) {
|
||||
if b, err = hex.DecAppend(b, []byte(hexStr)); chk.E(err) {
|
||||
return
|
||||
}
|
||||
return
|
||||
|
||||
@@ -4,6 +4,7 @@ package hex
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/templexxx/xhex"
|
||||
"orly.dev/pkg/utils/chk"
|
||||
"orly.dev/pkg/utils/errorf"
|
||||
|
||||
@@ -5,6 +5,7 @@ package tag
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
text2 "orly.dev/pkg/encoders/text"
|
||||
"orly.dev/pkg/utils/errorf"
|
||||
"orly.dev/pkg/utils/log"
|
||||
@@ -26,7 +27,7 @@ const (
|
||||
)
|
||||
|
||||
// BS is an abstract data type that can process strings and byte slices as byte slices.
|
||||
type BS[Z []byte | string] []byte
|
||||
type BS[Z ~[]byte | ~string] []byte
|
||||
|
||||
// T is a list of strings with a literal ordering.
|
||||
//
|
||||
@@ -36,7 +37,7 @@ type T struct {
|
||||
}
|
||||
|
||||
// New creates a new tag.T from a variadic parameter that can be either string or byte slice.
|
||||
func New[V string | []byte](fields ...V) (t *T) {
|
||||
func New[V ~string | ~[]byte](fields ...V) (t *T) {
|
||||
t = &T{field: make([]BS[[]byte], len(fields))}
|
||||
for i, field := range fields {
|
||||
t.field[i] = []byte(field)
|
||||
|
||||
@@ -84,7 +84,7 @@ func (cl *Client) RPC(
|
||||
c context.T, method Capability, params, result any, opts *rpcOptions,
|
||||
) (err error) {
|
||||
timeout := time.Duration(10)
|
||||
if opts == nil && opts.timeout == nil {
|
||||
if opts != nil && opts.timeout != nil {
|
||||
timeout = *opts.timeout
|
||||
}
|
||||
ctx, cancel := context.Timeout(c, timeout)
|
||||
@@ -172,3 +172,90 @@ func (cl *Client) RPC(
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// RPCRaw performs an RPC call and returns the raw JSON response
|
||||
func (cl *Client) RPCRaw(
|
||||
c context.T, method Capability, params any, opts *rpcOptions,
|
||||
) (rawResponse []byte, err error) {
|
||||
timeout := time.Duration(10)
|
||||
if opts != nil && opts.timeout != nil {
|
||||
timeout = *opts.timeout
|
||||
}
|
||||
ctx, cancel := context.Timeout(c, timeout)
|
||||
defer cancel()
|
||||
var req []byte
|
||||
if req, err = json.Marshal(
|
||||
Request{
|
||||
Method: string(method),
|
||||
Params: params,
|
||||
},
|
||||
); chk.E(err) {
|
||||
return
|
||||
}
|
||||
var content []byte
|
||||
if content, err = encryption.Encrypt(req, cl.conversationKey); chk.E(err) {
|
||||
return
|
||||
}
|
||||
ev := &event.E{
|
||||
Content: content,
|
||||
CreatedAt: timestamp.Now(),
|
||||
Kind: kind.WalletRequest,
|
||||
Tags: tags.New(
|
||||
tag.New([]byte("p"), cl.walletPublicKey),
|
||||
tag.New(EncryptionTag, Nip44V2),
|
||||
),
|
||||
}
|
||||
if err = ev.Sign(cl.clientSecretKey); chk.E(err) {
|
||||
return
|
||||
}
|
||||
hasWorked := make(chan struct{})
|
||||
evs := cl.pool.SubMany(
|
||||
c, cl.relays, &filters.T{
|
||||
F: []*filter.F{
|
||||
{
|
||||
Limit: values.ToUintPointer(1),
|
||||
Kinds: kinds.New(kind.WalletRequest),
|
||||
Authors: tag.New(cl.walletPublicKey),
|
||||
Tags: tags.New(tag.New([]byte("#e"), ev.ID)),
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
for _, u := range cl.relays {
|
||||
go func(u string) {
|
||||
var relay *ws.Client
|
||||
if relay, err = cl.pool.EnsureRelay(u); chk.E(err) {
|
||||
return
|
||||
}
|
||||
if err = relay.Publish(c, ev); chk.E(err) {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case hasWorked <- struct{}{}:
|
||||
case <-ctx.Done():
|
||||
err = fmt.Errorf("context canceled waiting for request send")
|
||||
return
|
||||
default:
|
||||
}
|
||||
}(u)
|
||||
}
|
||||
select {
|
||||
case <-hasWorked:
|
||||
// continue
|
||||
case <-ctx.Done():
|
||||
err = fmt.Errorf("timed out waiting for relays")
|
||||
return
|
||||
}
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
err = fmt.Errorf("context canceled waiting for response")
|
||||
case e := <-evs:
|
||||
if rawResponse, err = encryption.Decrypt(
|
||||
e.Event.Content, cl.conversationKey,
|
||||
); chk.E(err) {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package nwc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"orly.dev/pkg/encoders/filter"
|
||||
@@ -65,6 +66,34 @@ func (cl *Client) GetWalletServiceInfo(c context.T) (
|
||||
return
|
||||
}
|
||||
|
||||
func (cl *Client) GetWalletServiceInfoRaw(c context.T) (
|
||||
raw []byte, err error,
|
||||
) {
|
||||
lim := uint(1)
|
||||
evc := cl.pool.SubMany(
|
||||
c, cl.relays, &filters.T{
|
||||
F: []*filter.F{
|
||||
{
|
||||
Limit: &lim,
|
||||
Kinds: kinds.New(kind.WalletInfo),
|
||||
Authors: tag.New(cl.walletPublicKey),
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
select {
|
||||
case <-c.Done():
|
||||
err = fmt.Errorf("GetWalletServiceInfoRaw canceled")
|
||||
return
|
||||
case ev := <-evc:
|
||||
// Marshal the event to JSON
|
||||
if raw, err = json.Marshal(ev.Event); chk.E(err) {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (cl *Client) CancelHoldInvoice(
|
||||
c context.T, chi *CancelHoldInvoiceParams,
|
||||
) (err error) {
|
||||
@@ -74,6 +103,15 @@ func (cl *Client) CancelHoldInvoice(
|
||||
return
|
||||
}
|
||||
|
||||
func (cl *Client) CancelHoldInvoiceRaw(
|
||||
c context.T, chi *CancelHoldInvoiceParams,
|
||||
) (raw []byte, err error) {
|
||||
if raw, err = cl.RPCRaw(c, CancelHoldInvoice, chi, nil); chk.E(err) {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (cl *Client) CreateConnection(
|
||||
c context.T, cc *CreateConnectionParams,
|
||||
) (err error) {
|
||||
@@ -83,6 +121,15 @@ func (cl *Client) CreateConnection(
|
||||
return
|
||||
}
|
||||
|
||||
func (cl *Client) CreateConnectionRaw(
|
||||
c context.T, cc *CreateConnectionParams,
|
||||
) (raw []byte, err error) {
|
||||
if raw, err = cl.RPCRaw(c, CreateConnection, cc, nil); chk.E(err) {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (cl *Client) GetBalance(c context.T) (gb *GetBalanceResult, err error) {
|
||||
gb = &GetBalanceResult{}
|
||||
if err = cl.RPC(c, GetBalance, nil, gb, nil); chk.E(err) {
|
||||
@@ -91,8 +138,23 @@ func (cl *Client) GetBalance(c context.T) (gb *GetBalanceResult, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (cl *Client) GetBalanceRaw(c context.T) (raw []byte, err error) {
|
||||
if raw, err = cl.RPCRaw(c, GetBalance, nil, nil); chk.E(err) {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (cl *Client) GetBudget(c context.T) (gb *GetBudgetResult, err error) {
|
||||
if err = cl.RPC(c, CreateConnection, nil, gb, nil); chk.E(err) {
|
||||
gb = &GetBudgetResult{}
|
||||
if err = cl.RPC(c, GetBudget, nil, gb, nil); chk.E(err) {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (cl *Client) GetBudgetRaw(c context.T) (raw []byte, err error) {
|
||||
if raw, err = cl.RPCRaw(c, GetBudget, nil, nil); chk.E(err) {
|
||||
return
|
||||
}
|
||||
return
|
||||
@@ -106,6 +168,13 @@ func (cl *Client) GetInfo(c context.T) (gi *GetInfoResult, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (cl *Client) GetInfoRaw(c context.T) (raw []byte, err error) {
|
||||
if raw, err = cl.RPCRaw(c, GetInfo, nil, nil); chk.E(err) {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (cl *Client) ListTransactions(
|
||||
c context.T, params *ListTransactionsParams,
|
||||
) (lt *ListTransactionsResult, err error) {
|
||||
@@ -116,6 +185,15 @@ func (cl *Client) ListTransactions(
|
||||
return
|
||||
}
|
||||
|
||||
func (cl *Client) ListTransactionsRaw(
|
||||
c context.T, params *ListTransactionsParams,
|
||||
) (raw []byte, err error) {
|
||||
if raw, err = cl.RPCRaw(c, ListTransactions, params, nil); chk.E(err) {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (cl *Client) LookupInvoice(
|
||||
c context.T, params *LookupInvoiceParams,
|
||||
) (li *LookupInvoiceResult, err error) {
|
||||
@@ -126,12 +204,31 @@ func (cl *Client) LookupInvoice(
|
||||
return
|
||||
}
|
||||
|
||||
func (cl *Client) LookupInvoiceRaw(
|
||||
c context.T, params *LookupInvoiceParams,
|
||||
) (raw []byte, err error) {
|
||||
if raw, err = cl.RPCRaw(c, LookupInvoice, params, nil); chk.E(err) {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (cl *Client) MakeHoldInvoice(
|
||||
c context.T,
|
||||
mhi *MakeHoldInvoiceParams,
|
||||
) (mi *MakeInvoiceResult, err error) {
|
||||
mi = &MakeInvoiceResult{}
|
||||
if err = cl.RPC(c, GetBalance, mhi, mi, nil); chk.E(err) {
|
||||
if err = cl.RPC(c, MakeHoldInvoice, mhi, mi, nil); chk.E(err) {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (cl *Client) MakeHoldInvoiceRaw(
|
||||
c context.T,
|
||||
mhi *MakeHoldInvoiceParams,
|
||||
) (raw []byte, err error) {
|
||||
if raw, err = cl.RPCRaw(c, MakeHoldInvoice, mhi, nil); chk.E(err) {
|
||||
return
|
||||
}
|
||||
return
|
||||
@@ -147,10 +244,38 @@ func (cl *Client) MakeInvoice(
|
||||
return
|
||||
}
|
||||
|
||||
func (cl *Client) MakeInvoiceRaw(
|
||||
c context.T, params *MakeInvoiceParams,
|
||||
) (raw []byte, err error) {
|
||||
if raw, err = cl.RPCRaw(c, MakeInvoice, params, nil); chk.E(err) {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// MultiPayInvoice
|
||||
|
||||
// MultiPayKeysend
|
||||
|
||||
func (cl *Client) PayKeysend(
|
||||
c context.T, params *PayKeysendParams,
|
||||
) (pk *PayKeysendResult, err error) {
|
||||
pk = &PayKeysendResult{}
|
||||
if err = cl.RPC(c, PayKeysend, params, &pk, nil); chk.E(err) {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (cl *Client) PayKeysendRaw(
|
||||
c context.T, params *PayKeysendParams,
|
||||
) (raw []byte, err error) {
|
||||
if raw, err = cl.RPCRaw(c, PayKeysend, params, nil); chk.E(err) {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (cl *Client) PayInvoice(
|
||||
c context.T, params *PayInvoiceParams,
|
||||
) (pi *PayInvoiceResult, err error) {
|
||||
@@ -161,6 +286,15 @@ func (cl *Client) PayInvoice(
|
||||
return
|
||||
}
|
||||
|
||||
func (cl *Client) PayInvoiceRaw(
|
||||
c context.T, params *PayInvoiceParams,
|
||||
) (raw []byte, err error) {
|
||||
if raw, err = cl.RPCRaw(c, PayInvoice, params, nil); chk.E(err) {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (cl *Client) SettleHoldInvoice(
|
||||
c context.T, shi *SettleHoldInvoiceParams,
|
||||
) (err error) {
|
||||
@@ -170,6 +304,15 @@ func (cl *Client) SettleHoldInvoice(
|
||||
return
|
||||
}
|
||||
|
||||
func (cl *Client) SettleHoldInvoiceRaw(
|
||||
c context.T, shi *SettleHoldInvoiceParams,
|
||||
) (raw []byte, err error) {
|
||||
if raw, err = cl.RPCRaw(c, SettleHoldInvoice, shi, nil); chk.E(err) {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (cl *Client) SignMessage(
|
||||
c context.T, sm *SignMessageParams,
|
||||
) (res *SignMessageResult, err error) {
|
||||
@@ -179,3 +322,12 @@ func (cl *Client) SignMessage(
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (cl *Client) SignMessageRaw(
|
||||
c context.T, sm *SignMessageParams,
|
||||
) (raw []byte, err error) {
|
||||
if raw, err = cl.RPCRaw(c, SignMessage, sm, nil); chk.E(err) {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package nwc
|
||||
import (
|
||||
"errors"
|
||||
"net/url"
|
||||
|
||||
"orly.dev/pkg/crypto/p256k"
|
||||
"orly.dev/pkg/utils/chk"
|
||||
)
|
||||
@@ -13,6 +14,11 @@ type ConnectionParams struct {
|
||||
relays []string
|
||||
}
|
||||
|
||||
// GetWalletPublicKey returns the wallet public key from the ConnectionParams.
|
||||
func (c *ConnectionParams) GetWalletPublicKey() []byte {
|
||||
return c.walletPublicKey
|
||||
}
|
||||
|
||||
func ParseConnectionURI(nwcUri string) (parts *ConnectionParams, err error) {
|
||||
var p *url.URL
|
||||
if p, err = url.Parse(nwcUri); chk.E(err) {
|
||||
|
||||
Reference in New Issue
Block a user