mirror of
https://github.com/nbd-wtf/go-nostr.git
synced 2025-10-10 04:44:02 +02:00
nip60: fixes, actual Cashu stuff and a wallet.Receive() method.
This commit is contained in:
362
nip60/client/client.go
Normal file
362
nip60/client/client.go
Normal file
@@ -0,0 +1,362 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/elnosh/gonuts/cashu"
|
||||
"github.com/elnosh/gonuts/cashu/nuts/nut01"
|
||||
"github.com/elnosh/gonuts/cashu/nuts/nut02"
|
||||
"github.com/elnosh/gonuts/cashu/nuts/nut03"
|
||||
"github.com/elnosh/gonuts/cashu/nuts/nut04"
|
||||
"github.com/elnosh/gonuts/cashu/nuts/nut05"
|
||||
"github.com/elnosh/gonuts/cashu/nuts/nut06"
|
||||
"github.com/elnosh/gonuts/cashu/nuts/nut07"
|
||||
"github.com/elnosh/gonuts/cashu/nuts/nut09"
|
||||
)
|
||||
|
||||
func GetMintInfo(ctx context.Context, mintURL string) (*nut06.MintInfo, error) {
|
||||
resp, err := httpGet(ctx, mintURL+"/v1/info")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var mintInfo nut06.MintInfo
|
||||
if err := json.Unmarshal(body, &mintInfo); err != nil {
|
||||
return nil, fmt.Errorf("error reading response from mint: %v", err)
|
||||
}
|
||||
|
||||
return &mintInfo, nil
|
||||
}
|
||||
|
||||
func GetActiveKeyset(ctx context.Context, mintURL string) (*nut01.Keyset, error) {
|
||||
resp, err := httpGet(ctx, mintURL+"/v1/keys")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var keysetRes nut01.GetKeysResponse
|
||||
if err := json.Unmarshal(body, &keysetRes); err != nil {
|
||||
return nil, fmt.Errorf("error reading response from mint: %w", err)
|
||||
}
|
||||
|
||||
for _, keyset := range keysetRes.Keysets {
|
||||
if keyset.Unit == cashu.Sat.String() {
|
||||
return &keyset, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("mint has no sat-denominated keyset? %v", keysetRes)
|
||||
}
|
||||
|
||||
func GetAllKeysets(ctx context.Context, mintURL string) ([]nut02.Keyset, error) {
|
||||
resp, err := httpGet(ctx, mintURL+"/v1/keysets")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var keysetsRes nut02.GetKeysetsResponse
|
||||
if err := json.Unmarshal(body, &keysetsRes); err != nil {
|
||||
return nil, fmt.Errorf("error reading response from mint: %v", err)
|
||||
}
|
||||
|
||||
return keysetsRes.Keysets, nil
|
||||
}
|
||||
|
||||
func GetKeysetById(ctx context.Context, mintURL, id string) (map[uint64]string, error) {
|
||||
resp, err := httpGet(ctx, mintURL+"/v1/keys/"+id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var keysetRes nut01.GetKeysResponse
|
||||
if err := json.Unmarshal(body, &keysetRes); err != nil || len(keysetRes.Keysets) != 1 {
|
||||
return nil, fmt.Errorf("error reading response from mint: %w", err)
|
||||
}
|
||||
|
||||
return keysetRes.Keysets[0].Keys, nil
|
||||
}
|
||||
|
||||
func PostMintQuoteBolt11(
|
||||
ctx context.Context,
|
||||
mintURL string,
|
||||
mintQuoteRequest nut04.PostMintQuoteBolt11Request,
|
||||
) (*nut04.PostMintQuoteBolt11Response, error) {
|
||||
resp, err := httpPost(ctx, mintURL+"/v1/mint/quote/bolt11", mintQuoteRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var reqMintResponse nut04.PostMintQuoteBolt11Response
|
||||
if err := json.Unmarshal(body, &reqMintResponse); err != nil {
|
||||
return nil, fmt.Errorf("error reading response from mint: %w", err)
|
||||
}
|
||||
|
||||
return &reqMintResponse, nil
|
||||
}
|
||||
|
||||
func GetMintQuoteState(ctx context.Context, mintURL, quoteId string) (*nut04.PostMintQuoteBolt11Response, error) {
|
||||
resp, err := httpGet(ctx, mintURL+"/v1/mint/quote/bolt11/"+quoteId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var mintQuoteResponse nut04.PostMintQuoteBolt11Response
|
||||
if err := json.Unmarshal(body, &mintQuoteResponse); err != nil {
|
||||
return nil, fmt.Errorf("error reading response from mint: %w", err)
|
||||
}
|
||||
|
||||
return &mintQuoteResponse, nil
|
||||
}
|
||||
|
||||
func PostMintBolt11(
|
||||
ctx context.Context,
|
||||
mintURL string,
|
||||
mintRequest nut04.PostMintBolt11Request,
|
||||
) (*nut04.PostMintBolt11Response, error) {
|
||||
resp, err := httpPost(ctx, mintURL+"/v1/mint/bolt11", mintRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var reqMintResponse nut04.PostMintBolt11Response
|
||||
if err := json.Unmarshal(body, &reqMintResponse); err != nil {
|
||||
return nil, fmt.Errorf("error reading response from mint: %w", err)
|
||||
}
|
||||
|
||||
return &reqMintResponse, nil
|
||||
}
|
||||
|
||||
func PostSwap(ctx context.Context, mintURL string, swapRequest nut03.PostSwapRequest) (*nut03.PostSwapResponse, error) {
|
||||
resp, err := httpPost(ctx, mintURL+"/v1/swap", swapRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var swapResponse nut03.PostSwapResponse
|
||||
if err := json.Unmarshal(body, &swapResponse); err != nil {
|
||||
return nil, fmt.Errorf("error reading response from mint: %w", err)
|
||||
}
|
||||
|
||||
return &swapResponse, nil
|
||||
}
|
||||
|
||||
func PostMeltQuoteBolt11(
|
||||
ctx context.Context,
|
||||
mintURL string,
|
||||
meltQuoteRequest nut05.PostMeltQuoteBolt11Request,
|
||||
) (*nut05.PostMeltQuoteBolt11Response, error) {
|
||||
resp, err := httpPost(ctx, mintURL+"/v1/melt/quote/bolt11", meltQuoteRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var meltQuoteResponse nut05.PostMeltQuoteBolt11Response
|
||||
if err := json.Unmarshal(body, &meltQuoteResponse); err != nil {
|
||||
return nil, fmt.Errorf("error reading response from mint: %w", err)
|
||||
}
|
||||
|
||||
return &meltQuoteResponse, nil
|
||||
}
|
||||
|
||||
func GetMeltQuoteState(ctx context.Context, mintURL, quoteId string) (*nut05.PostMeltQuoteBolt11Response, error) {
|
||||
resp, err := httpGet(ctx, mintURL+"/v1/melt/quote/bolt11/"+quoteId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var meltQuoteResponse nut05.PostMeltQuoteBolt11Response
|
||||
if err := json.Unmarshal(body, &meltQuoteResponse); err != nil {
|
||||
return nil, fmt.Errorf("error reading response from mint: %w", err)
|
||||
}
|
||||
|
||||
return &meltQuoteResponse, nil
|
||||
}
|
||||
|
||||
func PostMeltBolt11(
|
||||
ctx context.Context,
|
||||
mintURL string,
|
||||
meltRequest nut05.PostMeltBolt11Request,
|
||||
) (*nut05.PostMeltQuoteBolt11Response, error) {
|
||||
resp, err := httpPost(ctx, mintURL+"/v1/melt/bolt11", meltRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var meltResponse nut05.PostMeltQuoteBolt11Response
|
||||
if err := json.Unmarshal(body, &meltResponse); err != nil {
|
||||
return nil, fmt.Errorf("error reading response from mint: %w", err)
|
||||
}
|
||||
|
||||
return &meltResponse, nil
|
||||
}
|
||||
|
||||
func PostCheckProofState(
|
||||
ctx context.Context,
|
||||
mintURL string,
|
||||
stateRequest nut07.PostCheckStateRequest,
|
||||
) (*nut07.PostCheckStateResponse, error) {
|
||||
resp, err := httpPost(ctx, mintURL+"/v1/checkstate", stateRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var stateResponse nut07.PostCheckStateResponse
|
||||
if err := json.Unmarshal(body, &stateResponse); err != nil {
|
||||
return nil, fmt.Errorf("error reading response from mint: %v", err)
|
||||
}
|
||||
|
||||
return &stateResponse, nil
|
||||
}
|
||||
|
||||
func PostRestore(
|
||||
ctx context.Context,
|
||||
mintURL string,
|
||||
restoreRequest nut09.PostRestoreRequest,
|
||||
) (*nut09.PostRestoreResponse, error) {
|
||||
resp, err := httpPost(ctx, mintURL+"/v1/restore", restoreRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var restoreResponse nut09.PostRestoreResponse
|
||||
if err := json.Unmarshal(body, &restoreResponse); err != nil {
|
||||
return nil, fmt.Errorf("error reading response from mint: %v", err)
|
||||
}
|
||||
|
||||
return &restoreResponse, nil
|
||||
}
|
||||
|
||||
func httpGet(ctx context.Context, url string) (*http.Response, error) {
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return parse(resp)
|
||||
}
|
||||
|
||||
func httpPost(ctx context.Context, url string, data any) (*http.Response, error) {
|
||||
r, w := io.Pipe()
|
||||
json.NewEncoder(w).Encode(data)
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "POST", url, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return parse(resp)
|
||||
}
|
||||
|
||||
func parse(response *http.Response) (*http.Response, error) {
|
||||
if response.StatusCode == 400 {
|
||||
var errResponse cashu.Error
|
||||
err := json.NewDecoder(response.Body).Decode(&errResponse)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not decode error response from mint: %v", err)
|
||||
}
|
||||
return nil, errResponse
|
||||
}
|
||||
|
||||
if response.StatusCode != 200 {
|
||||
body, err := io.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, fmt.Errorf("%s", body)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
Reference in New Issue
Block a user