From 7d3a8e4d9717b12f0e6de76eb3dec2ff4c2ca7be Mon Sep 17 00:00:00 2001 From: lescuer97 Date: Sun, 18 Jan 2026 17:00:34 +0100 Subject: [PATCH] add linting job. remove paid field from db and struct. fixes from linting --- .github/workflows/golangci-lint.yml | 33 ++++ .github/workflows/workflow.yml | 37 +---- .golangci.yml | 117 ++++++++++++++ AGENTS.md | 1 - api/cashu/auth.go | 6 +- api/cashu/errors.go | 9 +- api/cashu/keys_test.go | 4 +- api/cashu/melt.go | 37 ++--- api/cashu/proofs.go | 21 ++- api/cashu/spend_condition.go | 22 ++- api/cashu/spend_condition_test.go | 3 +- api/cashu/swap.go | 2 +- api/cashu/types.go | 104 ++++++------- api/cashu/websocket.go | 4 +- cmd/nutmix/htlc_route_test.go | 8 - cmd/nutmix/main.go | 6 +- cmd/nutmix/main_test.go | 32 +--- cmd/nutmix/p2pk_route_test.go | 8 - cmd/nutmix/payment_error_handling_test.go | 12 +- internal/database/backend.go | 6 +- .../migrations/37_remove_request_paid.sql | 9 ++ internal/database/mock_db/admin.go | 4 +- internal/database/mock_db/main.go | 9 +- internal/database/postgresql/admin.go | 12 +- internal/database/postgresql/main.go | 38 +++-- .../database/postgresql/operations_test.go | 143 ++++++++---------- internal/lightning/backend.go | 6 +- internal/lightning/cln.go | 6 +- internal/lightning/fake_wallet.go | 2 +- internal/lightning/lnbits.go | 14 +- internal/lightning/lnd.go | 4 +- internal/lightning/strike.go | 12 +- internal/mint/bolt11.go | 4 +- internal/mint/melting.go | 34 ++--- internal/mint/mint.go | 4 +- internal/mint/mint_test.go | 21 ++- internal/mint/utils_test.go | 14 +- internal/mint/websocket.go | 3 +- internal/routes/admin/crons.go | 2 +- internal/routes/admin/keysets.go | 2 +- internal/routes/admin/liquidity-manager.go | 2 +- internal/routes/admin/main.go | 8 +- internal/routes/admin/mint-activity.go | 15 +- internal/routes/admin/pages.go | 6 +- internal/routes/admin/tabs.go | 9 +- internal/routes/admin/tabs_test.go | 2 +- internal/routes/auth.go | 2 +- internal/routes/bolt11.go | 22 ++- internal/routes/mint.go | 8 +- internal/routes/websocket.go | 46 +++--- .../signer/remote_signer/remote_signer.go | 8 +- internal/signer/remote_signer/transformer.go | 1 - internal/signer/remote_signer/util.go | 1 + internal/signer/types.go | 4 +- internal/signer/utils.go | 2 +- internal/utils/common.go | 72 ++++----- internal/utils/files.go | 6 +- internal/utils/liquidityManager.go | 6 +- internal/utils/testing.go | 28 +++- test/configTest/setup.go | 2 +- 60 files changed, 564 insertions(+), 501 deletions(-) create mode 100644 .github/workflows/golangci-lint.yml create mode 100644 .golangci.yml create mode 100644 internal/database/goose/migrations/37_remove_request_paid.sql diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml new file mode 100644 index 00000000..26caf0cf --- /dev/null +++ b/.github/workflows/golangci-lint.yml @@ -0,0 +1,33 @@ +name: golangci-lint +on: + pull_request: + branches: + - master +permissions: + contents: read + +jobs: + golangci: + name: lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - uses: actions/setup-go@v6 + with: + go-version: '1.25.4' + cache: true + - uses: extractions/setup-just@v3 + - name: Set up Bun + uses: oven-sh/setup-bun@v1 + with: + bun-version: latest + - name: Install dependencies + run: just install-deps + - name: Generate code (proto, templ) + run: | + just gen-proto + just gen-templ + just web-install + just web-build-prod + - name: golangci-lint + uses: golangci/golangci-lint-action@v9 diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index fb38ff20..10489da6 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -12,16 +12,7 @@ jobs: with: go-version: '1.25.4' cache: true - - - name: Go Toolchain info - run: | - go version - - - name: Install Just - run: | - sudo apt-get update - sudo apt-get install -y just - + - uses: extractions/setup-just@v3 - name: Set up Bun uses: oven-sh/setup-bun@v1 with: @@ -47,16 +38,7 @@ jobs: with: go-version: '1.25.4' cache: true - - - name: Go Toolchain info - run: | - go version - - - name: Install Just - run: | - sudo apt-get update - sudo apt-get install -y just - + - uses: extractions/setup-just@v3 - name: Set up Bun uses: oven-sh/setup-bun@v1 with: @@ -99,21 +81,16 @@ jobs: with: go-version: '1.25.4' cache: true - - - name: Go Toolchain info - run: | - go version - - - name: Install Just - run: | - sudo apt-get update - sudo apt-get install -y just - + - uses: extractions/setup-just@v3 - name: Set up Bun uses: oven-sh/setup-bun@v1 with: bun-version: latest + - name: Go Toolchain info + run: | + go version + - name: Install dependencies run: just install-deps diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 00000000..21835a28 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,117 @@ +version: "2" + +run: + timeout: 5m + tests: true + modules-download-mode: readonly + +linters: + enable: + # Security-focused linters + - gosec # Security vulnerability scanner + - bidichk # Checks for dangerous unicode character sequences + - bodyclose # Checks HTTP response body is closed + # - contextcheck # Check for non-inherited context + + # Bug detection + - staticcheck # Comprehensive static analysis + - govet # Reports suspicious constructs + - errcheck # Unchecked errors + - ineffassign # Detects unused assignments + + # Code quality + # - revive # Fast, extensible linter + # - gocyclo # Cyclomatic complexity + - unconvert # Unnecessary type conversions + - unparam # Unused function parameters + - misspell # Commonly misspelled words + + settings: + gosec: + # Enable all security rules - these check for common vulnerabilities + includes: + - G101 # Look for hardcoded credentials + - G102 # Bind to all interfaces + - G103 # Audit the use of unsafe block + - G104 # Audit errors not checked + - G106 # Audit the use of ssh.InsecureIgnoreHostKey function + - G107 # URL provided to HTTP request as taint input + - G108 # Profiling endpoint is automatically exposed + - G109 # Converting strconv.Atoi result to int32/int16 + - G110 # Detect io.Copy instead of io.CopyN when decompression + - G111 # Detect http.Dir('/') as a potential risk + - G112 # Detect ReadHeaderTimeout not configured + - G114 # Use of net/http serve function without timeouts + - G116 # Detect Trojan Source attacks using bidirectional Unicode + - G201 # SQL query construction using format string + - G202 # SQL query construction using string concatenation + - G203 # Use of unescaped data in HTML templates + - G204 # Audit use of command execution + - G301 # Poor file permissions used when creating a directory + - G302 # Poor file permissions used with chmod + - G303 # Creating tempfile using a predictable path + - G304 # File path provided as taint input + - G305 # File traversal when extracting zip/tar archive + - G306 # Poor file permissions used when writing to a new file + - G307 # Poor file permissions used with os.Create + - G401 # Detect the usage of MD5 or SHA1 + - G402 # Look for bad TLS connection settings + - G403 # Ensure minimum RSA key length of 2048 bits + - G404 # Insecure random number source (rand instead of crypto/rand) + - G501 # Import blocklist: crypto/md5 + - G502 # Import blocklist: crypto/des + - G503 # Import blocklist: crypto/rc4 + - G504 # Import blocklist: net/http/cgi + - G505 # Import blocklist: crypto/sha1 + - G601 # Implicit memory aliasing in for loop (Go < 1.22) + - G602 # Slice access out of bounds + + # Configure specific rules + config: + G101: + pattern: "(?i)passwd|pass|password|pwd|secret|private_key|token|api_key|apikey|access_key|auth" + ignore_entropy: false + entropy_threshold: "80.0" + per_char_threshold: "3.0" + truncate: "32" + G306: + "0600" + + errcheck: + check-type-assertions: true + # check-blank: true + + govet: + enable-all: true + disable: + - shadow + + gocyclo: + min-complexity: 15 + + bidichk: + # Check for all dangerous bidirectional unicode characters + left-to-right-embedding: true + right-to-left-embedding: true + pop-directional-formatting: true + left-to-right-override: true + right-to-left-override: true + left-to-right-isolate: true + right-to-left-isolate: true + first-strong-isolate: true + pop-directional-isolate: true + + exclusions: + presets: + - common-false-positives + rules: + # Relax some checks in test files, but keep security checks active + - path: '(.+)_test\.go' + linters: + - gocyclo + - dupl + - funlen + +issues: + max-issues-per-linter: 0 + max-same-issues: 0 diff --git a/AGENTS.md b/AGENTS.md index 40f19f5d..652d5704 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -7,5 +7,4 @@ - if you don't know how to do something don't guess. It's okey if you don't know. - Before you change anything review this proposal critically. -When scanning source files, use repomix to save space and tokens. Use the Context7 MCP server to know the latest way to use libraries like `gin` and `templ`. diff --git a/api/cashu/auth.go b/api/cashu/auth.go index 378aa588..3fc90529 100644 --- a/api/cashu/auth.go +++ b/api/cashu/auth.go @@ -31,9 +31,9 @@ type PostAuthBlindMintRequest struct { } type AuthProof struct { + C WrappedPublicKey `json:"C" db:"c"` Id string `json:"id"` Secret string `json:"secret"` - C WrappedPublicKey `json:"C" db:"c"` Amount uint64 `json:"amount" db:"amount"` } @@ -66,17 +66,17 @@ func (a AuthProof) Proof(y WrappedPublicKey, state ProofState) Proof { } type AuthClams struct { + Aud *[]string `json:"aud"` Sub string `json:"sub"` ClientId string `json:"client_id"` - Aud *[]string `json:"aud"` } type PostAuthBlindMintResponse struct { Signatures []BlindSignature `json:"signatures"` } type Nut22Info struct { - BatMaxMint uint64 `json:"bat_max_mint"` ProtectedRoutes []ProtectedRoute `json:"protected_endpoints"` + BatMaxMint uint64 `json:"bat_max_mint"` } func ConvertRouteListToProtectedRouteList(list []string) []ProtectedRoute { diff --git a/api/cashu/errors.go b/api/cashu/errors.go index f2b47f4d..5b654202 100644 --- a/api/cashu/errors.go +++ b/api/cashu/errors.go @@ -127,12 +127,9 @@ func (e ErrorCode) String() string { } type ErrorResponse struct { - // integer code - Code ErrorCode `json:"code"` - // Human readable error - Error string `json:"error,omitempty"` - // Extended explanation of error - Detail *string `json:"detail,omitempty"` + Detail *string `json:"detail,omitempty"` + Error string `json:"error,omitempty"` + Code ErrorCode `json:"code"` } func ErrorCodeToResponse(code ErrorCode, detail *string) ErrorResponse { diff --git a/api/cashu/keys_test.go b/api/cashu/keys_test.go index 19f371fe..c04cc209 100644 --- a/api/cashu/keys_test.go +++ b/api/cashu/keys_test.go @@ -120,8 +120,8 @@ func TestChangeProofsStateToPendingAndQuoteSet(t *testing.T) { func convertJsonMapIntoOrderedArray(raw map[string]string) []*secp256k1.PublicKey { arrays := []struct { - Amount uint64 Pubkey *secp256k1.PublicKey + Amount uint64 }{} // Build the final map[uint64]*btcec.PublicKey // pubkeys := make(map[uint64]*btcec.PublicKey) @@ -149,8 +149,8 @@ func convertJsonMapIntoOrderedArray(raw map[string]string) []*secp256k1.PublicKe } arrays = append(arrays, struct { - Amount uint64 Pubkey *secp256k1.PublicKey + Amount uint64 }{ Amount: uKey, Pubkey: pk, diff --git a/api/cashu/melt.go b/api/cashu/melt.go index ca76eb06..a4680985 100644 --- a/api/cashu/melt.go +++ b/api/cashu/melt.go @@ -15,21 +15,19 @@ const ( ) type MeltRequestDB struct { - Quote string `json:"quote"` - Unit string `json:"unit"` - Expiry int64 `json:"expiry"` - Amount uint64 `json:"amount"` - FeeReserve uint64 `json:"fee_reserve" db:"fee_reserve"` - FeePaid uint64 `json:"paid_fee" db:"fee_paid"` - // Deprecated: Should be removed after all main wallets change to the new State format - RequestPaid bool `json:"paid" db:"request_paid"` + PaymentPreimage string `json:"payment_preimage"` + Unit string `json:"unit"` Request string `json:"request"` - Melted bool `json:"melted"` State ACTION_STATE `json:"state"` - PaymentPreimage string `json:"payment_preimage"` + Quote string `json:"quote"` + CheckingId string `json:"checking_id"` + Expiry int64 `json:"expiry"` + Amount uint64 `json:"amount"` + FeeReserve uint64 `json:"fee_reserve" db:"fee_reserve"` + FeePaid uint64 `json:"paid_fee" db:"fee_paid"` SeenAt int64 `json:"seen_at"` + Melted bool `json:"melted"` Mpp bool `json:"mpp"` - CheckingId string `json:"checking_id"` } func (meltRequest *MeltRequestDB) GetPostMeltQuoteResponse() PostMeltQuoteBolt11Response { @@ -37,7 +35,6 @@ func (meltRequest *MeltRequestDB) GetPostMeltQuoteResponse() PostMeltQuoteBolt11 Quote: meltRequest.Quote, Amount: meltRequest.Amount, FeeReserve: meltRequest.FeeReserve, - Paid: meltRequest.RequestPaid, Expiry: meltRequest.Expiry, State: meltRequest.State, PaymentPreimage: meltRequest.PaymentPreimage, @@ -52,9 +49,9 @@ type PostMeltQuoteBolt11Options struct { } type PostMeltQuoteBolt11Request struct { + Options PostMeltQuoteBolt11Options `json:"options"` Request string `json:"request"` Unit string `json:"unit"` - Options PostMeltQuoteBolt11Options `json:"options"` } func (p PostMeltQuoteBolt11Request) IsMpp() uint64 { @@ -65,17 +62,15 @@ func (p PostMeltQuoteBolt11Request) IsMpp() uint64 { } type PostMeltQuoteBolt11Response struct { - Quote string `json:"quote"` - Amount uint64 `json:"amount"` - FeeReserve uint64 `json:"fee_reserve"` - // Deprecated: Should be removed after all main wallets change to the new State format - Paid bool `json:"paid"` - Expiry int64 `json:"expiry"` + Quote string `json:"quote"` State ACTION_STATE `json:"state"` - Change []BlindSignature `json:"change"` Unit string `json:"unit"` Request string `json:"request"` PaymentPreimage string `json:"payment_preimage"` + Change []BlindSignature `json:"change"` + Amount uint64 `json:"amount"` + FeeReserve uint64 `json:"fee_reserve"` + Expiry int64 `json:"expiry"` } type PostMeltBolt11Request struct { @@ -157,7 +152,7 @@ func (p *PostMeltBolt11Request) verifyConditions() error { return fmt.Errorf("not same data field %w", ErrInvalidSpendCondition) } - if string(spendCondition.Data.Tags.originalTag) != string(firstSpendCondition.Data.Tags.originalTag) { + if spendCondition.Data.Tags.originalTag != firstSpendCondition.Data.Tags.originalTag { return fmt.Errorf("not same tags %w", ErrInvalidSpendCondition) } diff --git a/api/cashu/proofs.go b/api/cashu/proofs.go index e6d51e98..05444953 100644 --- a/api/cashu/proofs.go +++ b/api/cashu/proofs.go @@ -49,15 +49,15 @@ func (p *Proofs) SetQuoteReference(quote string) { } type Proof struct { - Amount uint64 `json:"amount"` - Id string `json:"id"` - Secret string `json:"secret"` C WrappedPublicKey `json:"C" db:"c"` Y WrappedPublicKey `json:"Y" db:"y"` + Quote *string `json:"quote" db:"quote"` + Id string `json:"id"` + Secret string `json:"secret"` Witness string `json:"witness" db:"witness"` - SeenAt int64 `json:"seen_at"` State ProofState `json:"state"` - Quote *string `json:"quote" db:"quote"` + Amount uint64 `json:"amount"` + SeenAt int64 `json:"seen_at"` } func (p Proof) verifyP2PKSpendCondition(spendCondition *SpendCondition, witness *Witness) (bool, error) { @@ -200,10 +200,7 @@ func (p Proof) timelockPassed(spendCondition *SpendCondition) bool { } func (p Proof) verifyTimelockPassedSpendCondition(spendCondition *SpendCondition, witness *Witness) (bool, error) { - pubkeys, err := p.pubkeysForRefund(spendCondition) - if err != nil { - return false, fmt.Errorf("p.pubkeysForRefund(spendCondition). %w", err) - } + pubkeys := p.pubkeysForRefund(spendCondition) nsigToCheck := uint(0) if len(spendCondition.Data.Tags.Refund) > 0 { @@ -277,14 +274,14 @@ func (p Proof) pubkeysForVerification(spendCondition *SpendCondition) (map[strin return pubkeysMap, nil } -func (p Proof) pubkeysForRefund(spendCondition *SpendCondition) (map[string]struct{}, error) { +func (p Proof) pubkeysForRefund(spendCondition *SpendCondition) map[string]struct{} { pubkeysMap := make(map[string]struct{}, 0) for i := range spendCondition.Data.Tags.Refund { if spendCondition.Data.Tags.Refund[i] != nil { pubkeysMap[string(spendCondition.Data.Tags.Refund[i].SerializeCompressed())] = struct{}{} } } - return pubkeysMap, nil + return pubkeysMap } func (p Proof) parseSpendCondition() (*SpendCondition, error) { @@ -406,8 +403,8 @@ func (p *Proof) UnmarshalJSON(data []byte) error { // Define an alias to avoid infinite recursion type Alias Proof aux := &struct { - C string `json:"C"` // Temporarily hold C as a string *Alias + C string `json:"C"` }{ Alias: (*Alias)(p), } diff --git a/api/cashu/spend_condition.go b/api/cashu/spend_condition.go index 5c5fb35e..84205ff1 100644 --- a/api/cashu/spend_condition.go +++ b/api/cashu/spend_condition.go @@ -32,8 +32,8 @@ var ( ) type SpendCondition struct { - Type SpendConditionType Data SpendConditionData + Type SpendConditionType } func (s *SpendCondition) UnmarshalJSON(b []byte) error { @@ -126,11 +126,11 @@ func (sc SpendConditionType) IsSpendConditioned() bool { type TagsInfo struct { originalTag string - Sigflag SigFlag Pubkeys []*btcec.PublicKey + Refund []*btcec.PublicKey + Sigflag SigFlag NSigs uint Locktime uint - Refund []*btcec.PublicKey NSigRefund uint } @@ -419,7 +419,7 @@ func (wit *Witness) String() (string, error) { b, err := json.Marshal(witness) if err != nil { - return "", fmt.Errorf("json.Marshal(singatures): %w", err) + return "", fmt.Errorf("json.Marshal(signatures): %w", err) } return string(b), nil } @@ -464,11 +464,11 @@ func (wit *Witness) UnmarshalJSON(b []byte) error { } type SigflagValidation struct { + pubkeys map[string]struct{} + refundPubkeys map[string]struct{} sigFlag SigFlag signaturesRequired uint - pubkeys map[string]struct{} signaturesRequiredRefund uint - refundPubkeys map[string]struct{} } func checkForSigAll(proofs Proofs) (SigflagValidation, error) { @@ -488,7 +488,7 @@ func checkForSigAll(proofs Proofs) (SigflagValidation, error) { if spendCondition.Data.Tags.Sigflag == SigAll { sigflagValidation.sigFlag = SigAll if spendCondition.Data.Tags.NSigs > 1 { - sigflagValidation.signaturesRequired = uint(spendCondition.Data.Tags.NSigs) + sigflagValidation.signaturesRequired = spendCondition.Data.Tags.NSigs } pubkeys, err := proof.pubkeysForVerification(spendCondition) if err != nil { @@ -499,13 +499,9 @@ func checkForSigAll(proofs Proofs) (SigflagValidation, error) { if len(spendCondition.Data.Tags.Refund) > 0 { sigflagValidation.signaturesRequiredRefund = 1 if spendCondition.Data.Tags.NSigRefund > 1 { - sigflagValidation.signaturesRequiredRefund = uint(spendCondition.Data.Tags.NSigRefund) - } - refundPubkeys, err := proof.pubkeysForRefund(spendCondition) - if err != nil { - return SigflagValidation{}, fmt.Errorf("proof.pubkeysForRefund(spendCondition). %w", err) + sigflagValidation.signaturesRequiredRefund = spendCondition.Data.Tags.NSigRefund } - sigflagValidation.refundPubkeys = refundPubkeys + sigflagValidation.refundPubkeys = proof.pubkeysForRefund(spendCondition) } return sigflagValidation, nil } diff --git a/api/cashu/spend_condition_test.go b/api/cashu/spend_condition_test.go index bdf53a86..e9c20002 100644 --- a/api/cashu/spend_condition_test.go +++ b/api/cashu/spend_condition_test.go @@ -671,6 +671,7 @@ func TestHasSigAllMethod(t *testing.T) { // TestAnyOneCanSpendDetection tests that non-JSON 64-byte secrets are identified correctly func TestAnyOneCanSpendDetection(t *testing.T) { // Create a proof with a 64-byte hex secret (not JSON structured) + // #nosec G101 plainSecret := "a3d98f6b2c1e4f5d8c7b6a9e0f1d2c3b4a5e6f7d8c9b0a1e2f3d4c5b6a7e8f9d" proofWithPlainSecret := Proof{ Amount: 1, @@ -933,10 +934,10 @@ func TestInvalidNumericValues(t *testing.T) { // TestInvalidSpendConditionJSONStructure tests unmarshalling with invalid JSON structures func TestInvalidSpendConditionJSONStructure(t *testing.T) { testCases := []struct { + validate func(*testing.T, SpendCondition) name string json string expectErr bool - validate func(*testing.T, SpendCondition) // Optional validation function }{ { name: "not an array", diff --git a/api/cashu/swap.go b/api/cashu/swap.go index f123fdb1..391ad453 100644 --- a/api/cashu/swap.go +++ b/api/cashu/swap.go @@ -83,7 +83,7 @@ func (p *PostSwapRequest) verifyConditions() error { return fmt.Errorf("not same data field %w", ErrInvalidSpendCondition) } - if string(spendCondition.Data.Tags.originalTag) != string(firstSpendCondition.Data.Tags.originalTag) { + if spendCondition.Data.Tags.originalTag != firstSpendCondition.Data.Tags.originalTag { return fmt.Errorf("not same tags %w", ErrInvalidSpendCondition) } diff --git a/api/cashu/types.go b/api/cashu/types.go index 076c813e..99132bfd 100644 --- a/api/cashu/types.go +++ b/api/cashu/types.go @@ -98,10 +98,10 @@ func UnitFromString(s string) (Unit, error) { var AvailableSeeds []Unit = []Unit{Sat} type BlindedMessage struct { - Amount uint64 `json:"amount"` - Id string `json:"id"` B_ WrappedPublicKey `json:"B_"` + Id string `json:"id"` Witness string `json:"witness,omitempty" db:"witness"` + Amount uint64 `json:"amount"` } func (b BlindedMessage) GenerateBlindSignature(k *secp256k1.PrivateKey) (BlindSignature, error) { @@ -123,10 +123,10 @@ func (b BlindedMessage) GenerateBlindSignature(k *secp256k1.PrivateKey) (BlindSi } type BlindSignature struct { - Amount uint64 `json:"amount"` - Id string `json:"id"` C_ WrappedPublicKey `json:"C_"` Dleq *BlindSignatureDLEQ `json:"dleq,omitempty"` + Id string `json:"id"` + Amount uint64 `json:"amount"` } type MintError struct { @@ -136,14 +136,14 @@ type MintError struct { type MintKeysMap map[uint64]MintKey type MintKey struct { + PrivKey *secp256k1.PrivateKey `json:"priv_key"` + FinalExpiry *uint64 `json:"final_expiry"` Id string `json:"id"` - Active bool `json:"active" db:"active"` Unit string `json:"unit"` Amount uint64 `json:"amount"` - PrivKey *secp256k1.PrivateKey `json:"priv_key"` CreatedAt int64 `json:"created_at"` InputFeePpk uint `json:"input_fee_ppk"` - FinalExpiry *uint64 `json:"final_expiry"` + Active bool `json:"active" db:"active"` } func (keyset *MintKey) GetPubKey() *secp256k1.PublicKey { @@ -167,22 +167,22 @@ func OrderedListOfPubkeys(listKeys []MintKey) []*secp256k1.PublicKey { } type Seed struct { - Active bool - CreatedAt int64 - Version uint32 + FinalExpiry *uint64 `json:"final_expiry" db:"final_expiry"` Unit string Id string - InputFeePpk uint `json:"input_fee_ppk" db:"input_fee_ppk"` - FinalExpiry *uint64 `json:"final_expiry" db:"final_expiry"` + CreatedAt int64 + InputFeePpk uint `json:"input_fee_ppk" db:"input_fee_ppk"` + Version uint32 + Active bool } type SwapMintMethod struct { + Options *SwapMintMethodOptions `json:"options,omitempty"` Method string `json:"method"` Unit string `json:"unit"` + Commands []SubscriptionKind `json:"commands,omitempty"` MinAmount int `json:"min_amount,omitempty"` MaxAmount int `json:"max_amount,omitempty"` - Commands []SubscriptionKind `json:"commands,omitempty"` - Options *SwapMintMethodOptions `json:"options,omitempty"` } type SwapMintMethodOptions struct { Description *bool `json:"description,omitempty"` @@ -205,57 +205,57 @@ type ContactInfo struct { } type GetInfoResponse struct { + Nuts map[string]any `json:"nuts"` + TosUrl *string `json:"tos_url,omitempty"` + IconUrl *string `json:"icon_url,omitempty"` Name string `json:"name"` Version string `json:"version"` Pubkey string `json:"pubkey"` Description string `json:"description"` DescriptionLong string `json:"description_long"` - Contact []ContactInfo `json:"contact"` Motd string `json:"motd"` - Nuts map[string]any `json:"nuts"` - TosUrl *string `json:"tos_url,omitempty"` - IconUrl *string `json:"icon_url,omitempty"` + Contact []ContactInfo `json:"contact"` Time int64 `json:"time"` } type KeysResponse map[string][]Keyset type Keyset struct { + Keys map[string]string `json:"keys"` + FinalExpiry *uint64 `json:"final_expiry,omitempty" db:"final_expiry"` Id string `json:"id"` Unit string `json:"unit"` - Keys map[string]string `json:"keys"` InputFeePpk uint `json:"input_fee_ppk"` - FinalExpiry *uint64 `json:"final_expiry,omitempty" db:"final_expiry"` } type PostMintQuoteBolt11Request struct { - Amount uint64 `json:"amount"` - Unit string `json:"unit"` Description *string `json:"description,omitempty"` Pubkey WrappedPublicKey `json:"pubkey"` + Unit string `json:"unit"` + Amount uint64 `json:"amount"` } type PostMintQuoteBolt11Response struct { + Amount *uint64 `json:"amount,omitempty"` + Pubkey WrappedPublicKey `json:"pubkey"` Quote string `json:"quote"` Request string `json:"request"` - Expiry int64 `json:"expiry"` Unit string `json:"unit"` - Minted bool `json:"minted"` State ACTION_STATE `json:"state"` - Amount *uint64 `json:"amount,omitempty"` - Pubkey WrappedPublicKey `json:"pubkey"` + Expiry int64 `json:"expiry"` + Minted bool `json:"minted"` } func (r PostMintQuoteBolt11Response) MarshalJSON() ([]byte, error) { type Alias struct { Pubkey *string `json:"pubkey,omitempty"` + Amount *uint64 `json:"amount,omitempty"` Quote string `json:"quote"` Request string `json:"request"` - Expiry int64 `json:"expiry"` Unit string `json:"unit"` - Minted bool `json:"minted"` State ACTION_STATE `json:"state"` - Amount *uint64 `json:"amount,omitempty"` + Expiry int64 `json:"expiry"` + Minted bool `json:"minted"` } var alias Alias @@ -273,19 +273,17 @@ func (r PostMintQuoteBolt11Response) MarshalJSON() ([]byte, error) { } type MintRequestDB struct { - Quote string `json:"quote"` - Request string `json:"request"` - // Deprecated: Should be removed after all main wallets change to the new State format - RequestPaid bool `json:"paid" db:"request_paid"` - Expiry int64 `json:"expiry"` - Unit string `json:"unit"` - Minted bool `json:"minted"` - State ACTION_STATE `json:"state"` - SeenAt int64 `json:"seen_at"` Amount *uint64 `json:"amount"` - CheckingId string `json:"checking_id"` Pubkey WrappedPublicKey `json:"pubkey"` Description *string `json:"description,omitempty"` + Quote string `json:"quote"` + Request string `json:"request"` + Unit string `json:"unit"` + State ACTION_STATE `json:"state"` + CheckingId string `json:"checking_id"` + Expiry int64 `json:"expiry"` + SeenAt int64 `json:"seen_at"` + Minted bool `json:"minted"` } func (m *MintRequestDB) PostMintQuoteBolt11Response() PostMintQuoteBolt11Response { @@ -307,16 +305,16 @@ func (m *MintRequestDB) PostMintQuoteBolt11Response() PostMintQuoteBolt11Respons } type PostMintBolt11Request struct { + Signature *schnorr.Signature `json:"signature,omitempty"` Quote string `json:"quote"` Outputs []BlindedMessage `json:"outputs"` - Signature *schnorr.Signature `json:"signature,omitempty"` } func (p *PostMintBolt11Request) UnmarshalJSON(data []byte) error { var aux struct { + Signature *string `json:"signature,omitempty"` Quote string `json:"quote"` Outputs []BlindedMessage `json:"outputs"` - Signature *string `json:"signature,omitempty"` } if err := json.Unmarshal(data, &aux); err != nil { return fmt.Errorf("could not marshall into PostMintBolt11Request: %w", err) @@ -389,12 +387,12 @@ type PostMintBolt11Response struct { } type BasicKeysetResponse struct { - Id string `json:"id"` - Unit string `json:"unit"` - Active bool `json:"active"` - InputFeePpk uint `json:"input_fee_ppk"` - Version uint32 FinalExpiry *uint64 `json:"final_expiry,omitempty"` + Id string `json:"id"` + Unit string `json:"unit"` + InputFeePpk uint `json:"input_fee_ppk"` + Version uint32 + Active bool `json:"active"` } type PostCheckStateRequest struct { @@ -403,8 +401,8 @@ type PostCheckStateRequest struct { type CheckState struct { Y WrappedPublicKey `json:"Y"` - State ProofState `json:"state"` Witness *string `json:"witness,omitempty"` + State ProofState `json:"state"` } type PostCheckStateResponse struct { @@ -412,15 +410,13 @@ type PostCheckStateResponse struct { } type RecoverSigDB struct { - Amount uint64 `json:"amount"` - Id string `json:"id"` B_ WrappedPublicKey `json:"B_" db:"B_"` C_ WrappedPublicKey `json:"C_" db:"C_"` - CreatedAt int64 `json:"created_at" db:"created_at"` Dleq *BlindSignatureDLEQ `json:"dleq,omitempty"` - - // This fields are use for melt_requests pending queries - MeltQuote string `json:"melt_quote" db:"melt_quote"` + Id string `json:"id"` + MeltQuote string `json:"melt_quote" db:"melt_quote"` + Amount uint64 `json:"amount"` + CreatedAt int64 `json:"created_at" db:"created_at"` } func (r RecoverSigDB) GetSigAndMessage() (BlindSignature, BlindedMessage) { @@ -679,7 +675,7 @@ func (p WrappedPublicKey) Value() (driver.Value, error) { if p.PublicKey == nil { return nil, nil } - return p.PublicKey.SerializeCompressed(), nil + return p.SerializeCompressed(), nil } func (p *WrappedPublicKey) Scan(value any) error { diff --git a/api/cashu/websocket.go b/api/cashu/websocket.go index 32affc11..c77817d6 100644 --- a/api/cashu/websocket.go +++ b/api/cashu/websocket.go @@ -12,10 +12,10 @@ const Bolt11MintQuote SubscriptionKind = "bolt11_mint_quote" const ProofStateWs SubscriptionKind = "proof_state" type WebRequestParams struct { + Payload any `json:"payload,omitempty"` Kind SubscriptionKind `json:"kind,omitempty"` SubId string `json:"subId"` Filters []string `json:"filters,omitempty"` - Payload any `json:"payload,omitempty"` } type WsRequest struct { @@ -44,8 +44,8 @@ type WsNotification struct { } type ErrorMsg struct { - Code uint64 `json:"code"` Message string `json:"message"` + Code uint64 `json:"code"` } type WsError struct { JsonRpc string `json:"jsonrpc"` diff --git a/cmd/nutmix/htlc_route_test.go b/cmd/nutmix/htlc_route_test.go index 6461cc51..2c9e2731 100644 --- a/cmd/nutmix/htlc_route_test.go +++ b/cmd/nutmix/htlc_route_test.go @@ -69,10 +69,6 @@ func TestRoutesHTLCSwapMelt(t *testing.T) { wrongPrivKey := secp256k1.PrivKeyFromBytes([]byte{0x01, 0x02, 0x03, 0x05}) - if err != nil { - t.Fatalf("could not parse locking pubkey: %v", err) - } - // MINTING TESTING STARTS // request mint quote of 1000 sats w := httptest.NewRecorder() @@ -426,10 +422,6 @@ func TestHTLCMultisigSigning(t *testing.T) { wrongPrivKey := secp256k1.PrivKeyFromBytes([]byte{0x01, 0x02, 0x03, 0x08}) - if err != nil { - t.Fatalf("could not parse locking pubkey: %v", err) - } - // MINTING TESTING STARTS // request mint quote of 1000 sats w := httptest.NewRecorder() diff --git a/cmd/nutmix/main.go b/cmd/nutmix/main.go index 4dae177b..a8409ea0 100644 --- a/cmd/nutmix/main.go +++ b/cmd/nutmix/main.go @@ -49,7 +49,7 @@ func main() { pathToConfigFile := logsdir + "/" + mint.LogFileName // Manipulate Config file - logFile, err := os.OpenFile(pathToConfigFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0764) + logFile, err := os.OpenFile(pathToConfigFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600) if err != nil { log.Panicf("os.OpenFile(pathToProjectLogFile, os.O_RDWR|os.O_CREATE, 0764) %+v", err) } @@ -67,7 +67,7 @@ func main() { err = godotenv.Load(".env") if err != nil { - log.Printf("Did not find any .env file using enviroment variables!") + log.Printf("Did not find any .env file using environment variables!") } gin.SetMode(gin.ReleaseMode) @@ -111,8 +111,6 @@ func main() { r := gin.Default() r.Use(gin.LoggerWithWriter(w)) - corsConfig := cors.DefaultConfig() - corsConfig.AllowOrigins = []string{"https://" + os.Getenv("MINT_HOSTNAME"), "http://" + os.Getenv("MINT_HOSTNAME")} r.Use(cors.Default()) // // gzip compression diff --git a/cmd/nutmix/main_test.go b/cmd/nutmix/main_test.go index 3b74e227..84d8d1df 100644 --- a/cmd/nutmix/main_test.go +++ b/cmd/nutmix/main_test.go @@ -6,7 +6,6 @@ import ( "encoding/hex" "encoding/json" "fmt" - "io" "log" "log/slog" "net/http/httptest" @@ -552,10 +551,6 @@ func TestMintBolt11FakeWallet(t *testing.T) { t.Fatalf("Error unmarshalling response: %v", err) } - if postMeltQuoteResponse.Paid { - t.Errorf("Expected paid to be true because it's a fake wallet, got %v", postMeltQuoteResponse.Paid) - } - if postMeltQuoteResponse.State != cashu.UNPAID { t.Errorf("Expected state to be UNPAID, got %v", postMeltQuoteResponse.State) } @@ -578,10 +573,6 @@ func TestMintBolt11FakeWallet(t *testing.T) { } - if postMeltQuoteResponse.Paid { - t.Errorf("Expected paid to be true because it's a fake wallet, got %v", postMeltQuoteResponse.Paid) - } - if postMeltQuoteResponse.State != cashu.UNPAID { t.Errorf("Expected state to be UNPAID, got %v", postMeltQuoteResponse.State) } @@ -652,9 +643,6 @@ func TestMintBolt11FakeWallet(t *testing.T) { t.Fatalf("Error unmarshalling response: %v", err) } - if !postMeltResponse.Paid { - t.Errorf("Expected paid to be true because it's a fake wallet, got %v", postMeltResponse.Paid) - } if postMeltResponse.State != cashu.PAID { t.Errorf("Expected state to be Paid, got %v", postMintQuoteResponseTwo.State) } @@ -896,7 +884,7 @@ func TestMintBolt11LndLigthning(t *testing.T) { ctx = context.WithValue(ctx, ctxKeyLndMacaroon, os.Getenv(utils.LND_MACAROON)) if err != nil { - t.Fatalf("Error setting up lightning network enviroment: %+v", err) + t.Fatalf("Error setting up lightning network environment: %+v", err) } LightningBolt11Test(t, ctx, bobLnd) @@ -968,7 +956,7 @@ func TestMintBolt11LNBITSLigthning(t *testing.T) { } if err != nil { - t.Fatalf("Error setting up lightning network enviroment: %+v", err) + t.Fatalf("Error setting up lightning network environment: %+v", err) } LightningBolt11Test(t, ctx, bobLnd) @@ -1179,7 +1167,7 @@ func LightningBolt11Test(t *testing.T, ctx context.Context, bobLnd testcontainer t.Errorf("Expected Amounts in outputs are not the same, got %s", w.Body.String()) } - // MINT SUCCESSFULY + // MINT SUCCESSFULLY blindedMessages, mintingSecrets, mintingSecretKeys, err := CreateBlindedMessages(1000, activeKeys) if err != nil { t.Fatalf("could not createBlind message: %v", err) @@ -1472,7 +1460,6 @@ func LightningBolt11Test(t *testing.T, ctx context.Context, bobLnd testcontainer } // I have to grab the Payment request from the cli reader - reader := io.Reader(invoiceReader) buf := make([]byte, 3024) type LncliInvoice struct { PaymentRequest string `json:"payment_request"` @@ -1480,7 +1467,7 @@ func LightningBolt11Test(t *testing.T, ctx context.Context, bobLnd testcontainer var invoice LncliInvoice for { - n, err := reader.Read(buf) + n, err := invoiceReader.Read(buf) if n > 0 { index := strings.Index(string(buf[:n]), "{") err := json.Unmarshal(buf[index:n], &invoice) @@ -1513,10 +1500,6 @@ func LightningBolt11Test(t *testing.T, ctx context.Context, bobLnd testcontainer t.Fatalf("Error unmarshalling response: %v", err) } - if postMeltQuoteResponse.Paid { - t.Errorf("Expected paid to be false because it's a LND Node, got %v", postMeltQuoteResponse.Paid) - } - if postMeltQuoteResponse.State != cashu.UNPAID { t.Errorf("Expected to not be paid have: %s ", postMeltQuoteResponse.State) } @@ -1538,9 +1521,6 @@ func LightningBolt11Test(t *testing.T, ctx context.Context, bobLnd testcontainer t.Fatalf("Error unmarshalling response: %v", err) } - if postMeltQuoteResponse.Paid { - t.Errorf("Expected paid to be false because it's a Lnd Node, got %v", postMeltQuoteResponse.Paid) - } if postMeltQuoteResponse.State != cashu.UNPAID { t.Errorf("Expected to not be paid have: %s ", postMintQuoteResponseTwo.State) @@ -1616,10 +1596,6 @@ func LightningBolt11Test(t *testing.T, ctx context.Context, bobLnd testcontainer t.Errorf("Expected state to be PAID, got %v", postMintQuoteResponseTwo.State) } - if !postMeltResponse.Paid { - t.Errorf("Expected paid to be true because it's a fake wallet, got %v", postMeltResponse.Paid) - } - // Test melt that has already been melted req = httptest.NewRequest("POST", "/v1/melt/bolt11", strings.NewReader(string(jsonRequestBody))) diff --git a/cmd/nutmix/p2pk_route_test.go b/cmd/nutmix/p2pk_route_test.go index 9a51081c..2fac644f 100644 --- a/cmd/nutmix/p2pk_route_test.go +++ b/cmd/nutmix/p2pk_route_test.go @@ -62,10 +62,6 @@ func TestRoutesP2PKSwapMelt(t *testing.T) { wrongPrivKey := secp256k1.PrivKeyFromBytes([]byte{0x01, 0x02, 0x03, 0x05}) - if err != nil { - t.Fatalf("could not parse locking pubkey: %v", err) - } - // MINTING TESTING STARTS // request mint quote of 1000 sats w := httptest.NewRecorder() @@ -355,10 +351,6 @@ func TestP2PKMultisigSigning(t *testing.T) { wrongPrivKey := secp256k1.PrivKeyFromBytes([]byte{0x01, 0x02, 0x03, 0x08}) - if err != nil { - t.Fatalf("could not parse locking pubkey: %v", err) - } - // MINTING TESTING STARTS // request mint quote of 1000 sats w := httptest.NewRecorder() diff --git a/cmd/nutmix/payment_error_handling_test.go b/cmd/nutmix/payment_error_handling_test.go index db1d90c1..5193b8d1 100644 --- a/cmd/nutmix/payment_error_handling_test.go +++ b/cmd/nutmix/payment_error_handling_test.go @@ -141,8 +141,8 @@ func TestPaymentFailureButPendingCheckPaymentMockDbFakeWallet(t *testing.T) { t.Fatalf("Error unmarshalling response: %v", err) } - if postMeltResponse.Paid { - t.Errorf("Expected paid to be false because it's a fake wallet, got %v", postMeltResponse.Paid) + if postMeltResponse.State == cashu.PAID { + t.Errorf("Expected state to not be PAID because it's a fake wallet, got %v", postMeltResponse.State) } tx, err := mint.MintDB.GetTx(ctx) if err != nil { @@ -345,8 +345,8 @@ func TestPaymentFailureButPendingCheckPaymentPostgresFakeWallet(t *testing.T) { t.Fatalf("Error unmarshalling response: %v", err) } - if postMeltResponse.Paid { - t.Errorf("Expected paid to be true because it's a fake wallet, got %v", postMeltResponse.Paid) + if postMeltResponse.State == cashu.PAID { + t.Errorf("Expected state to not be PAID because it's a fake wallet, got %v", postMeltResponse.State) } tx, err := mint.MintDB.GetTx(ctx) if err != nil { @@ -536,8 +536,8 @@ func TestPaymentPendingButPendingCheckPaymentMockDbFakeWallet(t *testing.T) { t.Fatalf("Error unmarshalling response: %v", err) } - if postMeltResponse.Paid { - t.Errorf("Expected paid to be false because it's a fake wallet, got %v", postMeltResponse.Paid) + if postMeltResponse.State == cashu.PAID { + t.Errorf("Expected state to not be PAID because it's a fake wallet, got %v", postMeltResponse.State) } secreList := []string{} diff --git a/internal/database/backend.go b/internal/database/backend.go index 590e7f46..d053779e 100644 --- a/internal/database/backend.go +++ b/internal/database/backend.go @@ -21,8 +21,8 @@ type NostrLoginAuth struct { } type AuthUser struct { - Sub string `db:"sub"` Aud *string `db:"aud"` + Sub string `db:"sub"` LastLoggedIn uint64 `db:"last_logged_in"` } @@ -71,13 +71,13 @@ type MintDB interface { UpdateSeedsActiveStatus(tx pgx.Tx, seeds []cashu.Seed) error SaveMintRequest(tx pgx.Tx, request cashu.MintRequestDB) error - ChangeMintRequestState(tx pgx.Tx, quote string, paid bool, state cashu.ACTION_STATE, minted bool) error + ChangeMintRequestState(tx pgx.Tx, quote string, state cashu.ACTION_STATE, minted bool) error GetMintRequestById(tx pgx.Tx, quote string) (cashu.MintRequestDB, error) GetMintRequestByRequest(tx pgx.Tx, request string) (cashu.MintRequestDB, error) GetMeltRequestById(tx pgx.Tx, quote string) (cashu.MeltRequestDB, error) SaveMeltRequest(tx pgx.Tx, request cashu.MeltRequestDB) error - ChangeMeltRequestState(tx pgx.Tx, quote string, paid bool, state cashu.ACTION_STATE, melted bool, fee_paid uint64) error + ChangeMeltRequestState(tx pgx.Tx, quote string, state cashu.ACTION_STATE, melted bool, fee_paid uint64) error AddPreimageMeltRequest(tx pgx.Tx, quote string, preimage string) error ChangeCheckingId(tx pgx.Tx, quote string, checking_id string) error diff --git a/internal/database/goose/migrations/37_remove_request_paid.sql b/internal/database/goose/migrations/37_remove_request_paid.sql new file mode 100644 index 00000000..10ce4a3e --- /dev/null +++ b/internal/database/goose/migrations/37_remove_request_paid.sql @@ -0,0 +1,9 @@ +-- +goose Up +ALTER TABLE mint_request DROP COLUMN request_paid; +ALTER TABLE melt_request DROP COLUMN request_paid; + + +-- +goose Down +ALTER TABLE mint_request ADD COLUMN request_paid BOOLEAN NOT NULL DEFAULT FALSE; +ALTER TABLE mint_request ALTER COLUMN request_paid DROP DEFAULT; +ALTER TABLE melt_request ADD COLUMN request_paid BOOLEAN; diff --git a/internal/database/mock_db/admin.go b/internal/database/mock_db/admin.go index 7cf26ee4..967cf935 100644 --- a/internal/database/mock_db/admin.go +++ b/internal/database/mock_db/admin.go @@ -60,10 +60,9 @@ func (m *MockDB) AddLiquiditySwap(tx pgx.Tx, swap utils.LiquiditySwap) error { } func (m *MockDB) ChangeLiquiditySwapState(tx pgx.Tx, id string, state utils.SwapState) error { - var liquiditySwaps []utils.LiquiditySwap for i := 0; i < len(m.LiquiditySwap); i++ { if m.LiquiditySwap[i].Id == id { - liquiditySwaps[i].State = state + m.LiquiditySwap[i].State = state } } @@ -109,7 +108,6 @@ func (m *MockDB) GetMintRequestsByTimeAndId(ctx context.Context, since time.Time if m.MintRequest[i].Quote == *id { return []cashu.MintRequestDB{m.MintRequest[i]}, nil } - return []cashu.MintRequestDB{}, nil } } mintRequests := make([]cashu.MintRequestDB, 0) diff --git a/internal/database/mock_db/main.go b/internal/database/mock_db/main.go index b240f5ad..baa3111b 100644 --- a/internal/database/mock_db/main.go +++ b/internal/database/mock_db/main.go @@ -20,6 +20,7 @@ var ErrDB = errors.New("ERROR DATABASE") var DATABASE_URL_ENV = "DATABASE_URL" type MockDB struct { + ErrorToReturn error Proofs []cashu.Proof MeltRequest []cashu.MeltRequestDB MintRequest []cashu.MintRequestDB @@ -30,7 +31,6 @@ type MockDB struct { Seeds []cashu.Seed AuthUser []database.AuthUser Config utils.Config - ErrorToReturn error } func databaseError(err error) error { @@ -54,7 +54,7 @@ func (m *MockDB) Rollback(ctx context.Context, tx pgx.Tx) error { } func (m *MockDB) GetSeedsByUnit(tx pgx.Tx, unit cashu.Unit) ([]cashu.Seed, error) { - var seeds []cashu.Seed + seeds := []cashu.Seed{} for i := 0; i < len(m.Seeds); i++ { if m.Seeds[i].Unit == unit.String() { @@ -95,7 +95,7 @@ func (m *MockDB) SaveMintRequest(tx pgx.Tx, request cashu.MintRequestDB) error { return nil } -func (m *MockDB) ChangeMintRequestState(tx pgx.Tx, quote string, paid bool, state cashu.ACTION_STATE, minted bool) error { +func (m *MockDB) ChangeMintRequestState(tx pgx.Tx, quote string, state cashu.ACTION_STATE, minted bool) error { for i := 0; i < len(m.MintRequest); i++ { if m.MintRequest[i].Quote == quote { m.MintRequest[i].State = state @@ -185,10 +185,9 @@ func (m *MockDB) AddPreimageMeltRequest(tx pgx.Tx, preimage string, quote string return nil } -func (m *MockDB) ChangeMeltRequestState(tx pgx.Tx, quote string, paid bool, state cashu.ACTION_STATE, melted bool, paid_fee uint64) error { +func (m *MockDB) ChangeMeltRequestState(tx pgx.Tx, quote string, state cashu.ACTION_STATE, melted bool, paid_fee uint64) error { for i := 0; i < len(m.MeltRequest); i++ { if m.MeltRequest[i].Quote == quote { - m.MeltRequest[i].RequestPaid = paid m.MeltRequest[i].State = state m.MeltRequest[i].Melted = melted m.MeltRequest[i].FeePaid = paid_fee diff --git a/internal/database/postgresql/admin.go b/internal/database/postgresql/admin.go index 715ef15e..6dd7a80c 100644 --- a/internal/database/postgresql/admin.go +++ b/internal/database/postgresql/admin.go @@ -54,8 +54,8 @@ func (pql Postgresql) GetMintMeltBalanceByTime(time int64) (database.MintMeltBal var mintMeltBalance database.MintMeltBalance // change the paid status of the quote batch := pgx.Batch{} - batch.Queue("SELECT quote, request, request_paid, expiry, unit, minted, state, seen_at, amount, checking_id, pubkey, description FROM mint_request WHERE seen_at >= $1 AND (state = 'ISSUED' OR state = 'PAID') ", time) - batch.Queue("SELECT quote, request, amount, request_paid, expiry, unit, melted, fee_reserve, state, payment_preimage, seen_at, mpp, fee_paid, checking_id FROM melt_request WHERE seen_at >= $1 AND (state = 'ISSUED' OR state = 'PAID')", time) + batch.Queue("SELECT quote, request, expiry, unit, minted, state, seen_at, amount, checking_id, pubkey, description FROM mint_request WHERE seen_at >= $1 AND (state = 'ISSUED' OR state = 'PAID') ", time) + batch.Queue("SELECT quote, request, amount, expiry, unit, melted, fee_reserve, state, payment_preimage, seen_at, mpp, fee_paid, checking_id FROM melt_request WHERE seen_at >= $1 AND (state = 'ISSUED' OR state = 'PAID')", time) results := pql.pool.SendBatch(context.Background(), &batch) @@ -207,7 +207,7 @@ func (pql Postgresql) GetLiquiditySwapsByStates(tx pgx.Tx, states []utils.SwapSt func (pql Postgresql) GetMintRequestsByTimeAndId(ctx context.Context, since time.Time, id *string) ([]cashu.MintRequestDB, error) { if id != nil { searchQuery := "%" + *id + "%" - rows, err := pql.pool.Query(ctx, "SELECT quote, request, request_paid, expiry, unit, minted, state, seen_at, amount, checking_id, pubkey, description FROM mint_request WHERE quote LIKE $1", searchQuery) + rows, err := pql.pool.Query(ctx, "SELECT quote, request, expiry, unit, minted, state, seen_at, amount, checking_id, pubkey, description FROM mint_request WHERE quote LIKE $1", searchQuery) if err != nil { return nil, fmt.Errorf("error checking for mint request by id: %w", err) } @@ -216,7 +216,7 @@ func (pql Postgresql) GetMintRequestsByTimeAndId(ctx context.Context, since time } sinceUnix := since.Unix() - rows, err := pql.pool.Query(ctx, "SELECT quote, request, request_paid, expiry, unit, minted, state, seen_at, amount, checking_id, pubkey, description FROM mint_request WHERE seen_at >= $1", sinceUnix) + rows, err := pql.pool.Query(ctx, "SELECT quote, request, expiry, unit, minted, state, seen_at, amount, checking_id, pubkey, description FROM mint_request WHERE seen_at >= $1", sinceUnix) if err != nil { return nil, fmt.Errorf("error checking for mint requests: %w", err) } @@ -227,7 +227,7 @@ func (pql Postgresql) GetMintRequestsByTimeAndId(ctx context.Context, since time func (pql Postgresql) GetMeltRequestsByTimeAndId(ctx context.Context, since time.Time, id *string) ([]cashu.MeltRequestDB, error) { if id != nil { searchQuery := "%" + *id + "%" - rows, err := pql.pool.Query(ctx, "SELECT quote, request, amount, request_paid, expiry, unit, melted, fee_reserve, state, payment_preimage, seen_at, mpp, fee_paid, checking_id FROM melt_request WHERE quote LIKE $1", searchQuery) + rows, err := pql.pool.Query(ctx, "SELECT quote, request, amount, expiry, unit, melted, fee_reserve, state, payment_preimage, seen_at, mpp, fee_paid, checking_id FROM melt_request WHERE quote LIKE $1", searchQuery) if err != nil { return nil, fmt.Errorf("error checking for melt request by id: %w", err) } @@ -235,7 +235,7 @@ func (pql Postgresql) GetMeltRequestsByTimeAndId(ctx context.Context, since time return pgx.CollectRows(rows, pgx.RowToStructByName[cashu.MeltRequestDB]) } sinceUnix := since.Unix() - rows, err := pql.pool.Query(ctx, "SELECT quote, request, amount, request_paid, expiry, unit, melted, fee_reserve, state, payment_preimage, seen_at, mpp, fee_paid, checking_id FROM melt_request WHERE seen_at >= $1", sinceUnix) + rows, err := pql.pool.Query(ctx, "SELECT quote, request, amount, expiry, unit, melted, fee_reserve, state, payment_preimage, seen_at, mpp, fee_paid, checking_id FROM melt_request WHERE seen_at >= $1", sinceUnix) if err != nil { return nil, fmt.Errorf("error checking for melt requests: %w", err) } diff --git a/internal/database/postgresql/main.go b/internal/database/postgresql/main.go index e9472cf8..803879df 100644 --- a/internal/database/postgresql/main.go +++ b/internal/database/postgresql/main.go @@ -35,7 +35,7 @@ func DatabaseSetup(ctx context.Context, migrationDir string) (Postgresql, error) dbUrl := os.Getenv(DATABASE_URL_ENV) if dbUrl == "" { - return postgresql, fmt.Errorf("%v enviroment variable empty", DATABASE_URL_ENV) + return postgresql, fmt.Errorf("%v environment variable empty", DATABASE_URL_ENV) } @@ -189,7 +189,7 @@ func (pql Postgresql) UpdateSeedsActiveStatus(tx pgx.Tx, seeds []cashu.Seed) err func (pql Postgresql) SaveMintRequest(tx pgx.Tx, request cashu.MintRequestDB) error { ctx := context.Background() - _, err := tx.Exec(ctx, "INSERT INTO mint_request (quote, request, request_paid, expiry, unit, minted, state, seen_at, amount, checking_id, pubkey, description) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)", request.Quote, request.Request, request.RequestPaid, request.Expiry, request.Unit, request.Minted, request.State, request.SeenAt, request.Amount, request.CheckingId, request.Pubkey, request.Description) + _, err := tx.Exec(ctx, "INSERT INTO mint_request (quote, request, expiry, unit, minted, state, seen_at, amount, checking_id, pubkey, description) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", request.Quote, request.Request, request.Expiry, request.Unit, request.Minted, request.State, request.SeenAt, request.Amount, request.CheckingId, request.Pubkey, request.Description) if err != nil { return databaseError(fmt.Errorf("inserting to mint_request: %w", err)) @@ -197,9 +197,9 @@ func (pql Postgresql) SaveMintRequest(tx pgx.Tx, request cashu.MintRequestDB) er return nil } -func (pql Postgresql) ChangeMintRequestState(tx pgx.Tx, quote string, paid bool, state cashu.ACTION_STATE, minted bool) error { +func (pql Postgresql) ChangeMintRequestState(tx pgx.Tx, quote string, state cashu.ACTION_STATE, minted bool) error { // change the paid status of the quote - _, err := tx.Exec(context.Background(), "UPDATE mint_request SET request_paid = $1, state = $3, minted = $4 WHERE quote = $2", paid, quote, state, minted) + _, err := tx.Exec(context.Background(), "UPDATE mint_request SET state = $2, minted = $3 WHERE quote = $1", quote, state, minted) if err != nil { return databaseError(fmt.Errorf("inserting to mint_request: %w", err)) @@ -213,8 +213,8 @@ func (pql Postgresql) GetMintRequestById(tx pgx.Tx, id string) (cashu.MintReques var mintRequest cashu.MintRequestDB // Use QueryRow instead of Query - err := tx.QueryRow(context.Background(), "SELECT quote, request, request_paid, expiry, unit, minted, state, seen_at, amount, checking_id, pubkey, description FROM mint_request WHERE quote = $1 FOR UPDATE", id). - Scan(&mintRequest.Quote, &mintRequest.Request, &mintRequest.RequestPaid, &mintRequest.Expiry, &mintRequest.Unit, &mintRequest.Minted, &mintRequest.State, &mintRequest.SeenAt, &amount, &mintRequest.CheckingId, &mintRequest.Pubkey, &mintRequest.Description) + err := tx.QueryRow(context.Background(), "SELECT quote, request, expiry, unit, minted, state, seen_at, amount, checking_id, pubkey, description FROM mint_request WHERE quote = $1 FOR UPDATE", id). + Scan(&mintRequest.Quote, &mintRequest.Request, &mintRequest.Expiry, &mintRequest.Unit, &mintRequest.Minted, &mintRequest.State, &mintRequest.SeenAt, &amount, &mintRequest.CheckingId, &mintRequest.Pubkey, &mintRequest.Description) if err != nil { return cashu.MintRequestDB{}, fmt.Errorf("database error: %w", err) @@ -229,8 +229,8 @@ func (pql Postgresql) GetMintRequestByRequest(tx pgx.Tx, request string) (cashu. var mintRequest cashu.MintRequestDB // Use QueryRow instead of Query - err := tx.QueryRow(context.Background(), "SELECT quote, request, request_paid, expiry, unit, minted, state, seen_at, amount, checking_id, pubkey, description FROM mint_request WHERE request = $1 FOR UPDATE", request). - Scan(&mintRequest.Quote, &mintRequest.Request, &mintRequest.RequestPaid, &mintRequest.Expiry, &mintRequest.Unit, &mintRequest.Minted, &mintRequest.State, &mintRequest.SeenAt, &amount, &mintRequest.CheckingId, &mintRequest.Pubkey, &mintRequest.Description) + err := tx.QueryRow(context.Background(), "SELECT quote, request, expiry, unit, minted, state, seen_at, amount, checking_id, pubkey, description FROM mint_request WHERE request = $1 FOR UPDATE", request). + Scan(&mintRequest.Quote, &mintRequest.Request, &mintRequest.Expiry, &mintRequest.Unit, &mintRequest.Minted, &mintRequest.State, &mintRequest.SeenAt, &amount, &mintRequest.CheckingId, &mintRequest.Pubkey, &mintRequest.Description) if err != nil { return cashu.MintRequestDB{}, fmt.Errorf("database error: %w", err) @@ -241,7 +241,7 @@ func (pql Postgresql) GetMintRequestByRequest(tx pgx.Tx, request string) (cashu. } func (pql Postgresql) GetMeltRequestById(tx pgx.Tx, id string) (cashu.MeltRequestDB, error) { - rows, err := tx.Query(context.Background(), "SELECT quote, request, amount, request_paid, expiry, unit, melted, fee_reserve, state, payment_preimage, seen_at, mpp, fee_paid, checking_id FROM melt_request WHERE quote = $1 FOR UPDATE NOWAIT", id) + rows, err := tx.Query(context.Background(), "SELECT quote, request, amount, expiry, unit, melted, fee_reserve, state, payment_preimage, seen_at, mpp, fee_paid, checking_id FROM melt_request WHERE quote = $1 FOR UPDATE NOWAIT", id) if err != nil { return cashu.MeltRequestDB{}, fmt.Errorf("could not find melt request from id %w", err) } @@ -258,7 +258,7 @@ func (pql Postgresql) GetMeltRequestById(tx pgx.Tx, id string) (cashu.MeltReques func (pql Postgresql) GetMeltQuotesByState(state cashu.ACTION_STATE) ([]cashu.MeltRequestDB, error) { - rows, err := pql.pool.Query(context.Background(), "SELECT quote, request, amount, request_paid, expiry, unit, melted, fee_reserve, state, payment_preimage, seen_at, mpp, fee_paid, checking_id FROM melt_request WHERE state = $1", state) + rows, err := pql.pool.Query(context.Background(), "SELECT quote, request, amount, expiry, unit, melted, fee_reserve, state, payment_preimage, seen_at, mpp, fee_paid, checking_id FROM melt_request WHERE state = $1", state) if err != nil { return nil, fmt.Errorf("could not find melt requests from state %w", err) } @@ -276,8 +276,8 @@ func (pql Postgresql) GetMeltQuotesByState(state cashu.ACTION_STATE) ([]cashu.Me func (pql Postgresql) SaveMeltRequest(tx pgx.Tx, request cashu.MeltRequestDB) error { _, err := tx.Exec(context.Background(), - "INSERT INTO melt_request (quote, request, fee_reserve, expiry, unit, amount, request_paid, melted, state, payment_preimage, seen_at, mpp, fee_paid, checking_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)", - request.Quote, request.Request, request.FeeReserve, request.Expiry, request.Unit, request.Amount, request.RequestPaid, request.Melted, request.State, request.PaymentPreimage, request.SeenAt, request.Mpp, request.FeePaid, request.CheckingId) + "INSERT INTO melt_request (quote, request, fee_reserve, expiry, unit, amount, melted, state, payment_preimage, seen_at, mpp, fee_paid, checking_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)", + request.Quote, request.Request, request.FeeReserve, request.Expiry, request.Unit, request.Amount, request.Melted, request.State, request.PaymentPreimage, request.SeenAt, request.Mpp, request.FeePaid, request.CheckingId) if err != nil { return databaseError(fmt.Errorf("inserting to mint_request: %w", err)) } @@ -293,9 +293,9 @@ func (pql Postgresql) AddPreimageMeltRequest(tx pgx.Tx, quote string, preimage s } return nil } -func (pql Postgresql) ChangeMeltRequestState(tx pgx.Tx, quote string, paid bool, state cashu.ACTION_STATE, melted bool, fee_paid uint64) error { +func (pql Postgresql) ChangeMeltRequestState(tx pgx.Tx, quote string, state cashu.ACTION_STATE, melted bool, fee_paid uint64) error { // change the paid status of the quote - _, err := tx.Exec(context.Background(), "UPDATE melt_request SET request_paid = $1, state = $3, melted = $4, fee_paid = $5 WHERE quote = $2", paid, quote, state, melted, fee_paid) + _, err := tx.Exec(context.Background(), "UPDATE melt_request SET state = $2, melted = $3, fee_paid = $4 WHERE quote = $1", quote, state, melted, fee_paid) if err != nil { return databaseError(fmt.Errorf("updating mint_request: %w", err)) @@ -459,9 +459,9 @@ func (pql Postgresql) DeleteProofs(tx pgx.Tx, proofs cashu.Proofs) error { } -func privateKeysToDleq(s_key []byte, e_key []byte, sig *cashu.RecoverSigDB) error { +func privateKeysToDleq(s_key []byte, e_key []byte, sig *cashu.RecoverSigDB) { if s_key == nil || e_key == nil { - return nil + return } dleqTmp := &cashu.BlindSignatureDLEQ{ @@ -473,7 +473,6 @@ func privateKeysToDleq(s_key []byte, e_key []byte, sig *cashu.RecoverSigDB) erro dleqTmp.E = secp256k1.PrivKeyFromBytes(e_key) sig.Dleq = dleqTmp - return nil } func (pql Postgresql) GetRestoreSigsFromBlindedMessages(tx pgx.Tx, B_ []cashu.WrappedPublicKey) ([]cashu.RecoverSigDB, error) { @@ -501,10 +500,7 @@ func (pql Postgresql) GetRestoreSigsFromBlindedMessages(tx pgx.Tx, B_ []cashu.Wr return nil, databaseError(fmt.Errorf("row.Scan(&sig.Amount, &sig.Id, &sig.B_, &sig.C_, &sig.CreatedAt, &sig.Dleq.E, &sig.Dleq.S): %w", err)) } - err = privateKeysToDleq(dleq_s_bytes, dleq_e_bytes, &sig) - if err != nil { - return nil, databaseError(fmt.Errorf("privateKeysToDleq(dleq_s_str, dleq_e_str, sig.Dleq). %w", err)) - } + privateKeysToDleq(dleq_s_bytes, dleq_e_bytes, &sig) signatures = append(signatures, sig) } diff --git a/internal/database/postgresql/operations_test.go b/internal/database/postgresql/operations_test.go index d23d80b8..2813414c 100644 --- a/internal/database/postgresql/operations_test.go +++ b/internal/database/postgresql/operations_test.go @@ -71,14 +71,13 @@ func TestAddAndRequestMintRequestValidPubkey(t *testing.T) { now := time.Now().Unix() mintRequestDB := cashu.MintRequestDB{ - Quote: quoteId, - RequestPaid: false, - Expiry: now, - Unit: cashu.Sat.String(), - State: cashu.UNPAID, - SeenAt: now, - Amount: &amount, - Pubkey: cashu.WrappedPublicKey{PublicKey: pubkey}, + Quote: quoteId, + Expiry: now, + Unit: cashu.Sat.String(), + State: cashu.UNPAID, + SeenAt: now, + Amount: &amount, + Pubkey: cashu.WrappedPublicKey{PublicKey: pubkey}, } log.Println("adding mint request to database") @@ -164,14 +163,13 @@ func TestAddAndRequestMintRequestNilPubkey(t *testing.T) { now := time.Now().Unix() mintRequestDB := cashu.MintRequestDB{ - Quote: quoteId, - RequestPaid: false, - Expiry: now, - Unit: cashu.Sat.String(), - State: cashu.UNPAID, - SeenAt: now, - Amount: &amount, - Pubkey: cashu.WrappedPublicKey{PublicKey: nil}, + Quote: quoteId, + Expiry: now, + Unit: cashu.Sat.String(), + State: cashu.UNPAID, + SeenAt: now, + Amount: &amount, + Pubkey: cashu.WrappedPublicKey{PublicKey: nil}, } log.Println("adding mint request to database") @@ -231,28 +229,26 @@ func TestGetMintMeltBalanceByTime_OnlyPubkey(t *testing.T) { // Mint Request 1: Old, Issued (Excluded by time) mint1 := cashu.MintRequestDB{ - Quote: "mint1", - State: cashu.ISSUED, - SeenAt: entryOldTime, - Amount: ptr(100), - Pubkey: wrappedPubkey, - Request: "req1", - Unit: cashu.Sat.String(), - Expiry: now + 10000, - RequestPaid: true, + Quote: "mint1", + State: cashu.ISSUED, + SeenAt: entryOldTime, + Amount: ptr(100), + Pubkey: wrappedPubkey, + Request: "req1", + Unit: cashu.Sat.String(), + Expiry: now + 10000, } // Mint Request 2: New, Issued (Included) mint2 := cashu.MintRequestDB{ - Quote: "mint2", - State: cashu.ISSUED, - SeenAt: entryNewTime, - Amount: ptr(200), - Pubkey: wrappedPubkey, - Request: "req2", - Unit: cashu.Sat.String(), - Expiry: now + 10000, - RequestPaid: true, + Quote: "mint2", + State: cashu.ISSUED, + SeenAt: entryNewTime, + Amount: ptr(200), + Pubkey: wrappedPubkey, + Request: "req2", + Unit: cashu.Sat.String(), + Expiry: now + 10000, } tx, err := db.GetTx(ctx) @@ -272,26 +268,24 @@ func TestGetMintMeltBalanceByTime_OnlyPubkey(t *testing.T) { // Melt Requests // Melt Request 1: Old, Issued (Excluded by time) melt1 := cashu.MeltRequestDB{ - Quote: "melt1", - State: cashu.ISSUED, - SeenAt: entryOldTime, - Amount: 100, - Request: "reqMelt1", - Unit: cashu.Sat.String(), - Expiry: now + 10000, - RequestPaid: true, + Quote: "melt1", + State: cashu.ISSUED, + SeenAt: entryOldTime, + Amount: 100, + Request: "reqMelt1", + Unit: cashu.Sat.String(), + Expiry: now + 10000, } // Melt Request 2: New, Paid (Included) melt2 := cashu.MeltRequestDB{ - Quote: "melt2", - State: cashu.PAID, - SeenAt: entryNewTime, - Amount: 200, - Request: "reqMelt2", - Unit: cashu.Sat.String(), - Expiry: now + 10000, - RequestPaid: true, + Quote: "melt2", + State: cashu.PAID, + SeenAt: entryNewTime, + Amount: 200, + Request: "reqMelt2", + Unit: cashu.Sat.String(), + Expiry: now + 10000, } tx, err = db.GetTx(ctx) @@ -356,28 +350,26 @@ func TestGetMintMeltBalanceByTime_MixedPubkeys(t *testing.T) { // Mint Request with Pubkey mint1 := cashu.MintRequestDB{ - Quote: "mintWithKey", - State: cashu.ISSUED, - SeenAt: entryNewTime, - Amount: ptr(200), - Pubkey: wrappedPubkey, - Request: "reqWithKey", - Unit: cashu.Sat.String(), - Expiry: now + 10000, - RequestPaid: true, + Quote: "mintWithKey", + State: cashu.ISSUED, + SeenAt: entryNewTime, + Amount: ptr(200), + Pubkey: wrappedPubkey, + Request: "reqWithKey", + Unit: cashu.Sat.String(), + Expiry: now + 10000, } // Mint Request without Pubkey mint2 := cashu.MintRequestDB{ - Quote: "mintNoKey", - State: cashu.ISSUED, - SeenAt: entryNewTime, - Amount: ptr(400), - Pubkey: cashu.WrappedPublicKey{PublicKey: nil}, - Request: "reqNokey", - Unit: cashu.Sat.String(), - Expiry: now + 10000, - RequestPaid: true, + Quote: "mintNoKey", + State: cashu.ISSUED, + SeenAt: entryNewTime, + Amount: ptr(400), + Pubkey: cashu.WrappedPublicKey{PublicKey: nil}, + Request: "reqNokey", + Unit: cashu.Sat.String(), + Expiry: now + 10000, } tx, err := db.GetTx(ctx) @@ -396,14 +388,13 @@ func TestGetMintMeltBalanceByTime_MixedPubkeys(t *testing.T) { // Melt Requests melt1 := cashu.MeltRequestDB{ - Quote: "melt1", - State: cashu.ISSUED, - SeenAt: entryNewTime, - Amount: 100, - Request: "reqMelt1", - Unit: cashu.Sat.String(), - Expiry: now + 10000, - RequestPaid: true, + Quote: "melt1", + State: cashu.ISSUED, + SeenAt: entryNewTime, + Amount: 100, + Request: "reqMelt1", + Unit: cashu.Sat.String(), + Expiry: now + 10000, } tx, err = db.GetTx(ctx) diff --git a/internal/lightning/backend.go b/internal/lightning/backend.go index 50da9c8e..4f8ed22d 100644 --- a/internal/lightning/backend.go +++ b/internal/lightning/backend.go @@ -46,15 +46,15 @@ const UNKNOWN PaymentStatus = iota + 999 type PaymentResponse struct { Preimage string PaymentRequest string - PaymentState PaymentStatus Rhash string - PaidFeeSat int64 CheckingId string + PaymentState PaymentStatus + PaidFeeSat int64 } type FeesResponse struct { + CheckingId string Fees cashu.Amount AmountToSend cashu.Amount - CheckingId string } type InvoiceResponse struct { diff --git a/internal/lightning/cln.go b/internal/lightning/cln.go index f8a332b3..4fefdcf9 100644 --- a/internal/lightning/cln.go +++ b/internal/lightning/cln.go @@ -18,13 +18,15 @@ import ( ) type CLNGRPCWallet struct { - Network chaincfg.Params grpcClient *grpc.ClientConn macaroon string + Network chaincfg.Params } func getTlsConfig(clientCert string, clientKey string, caCert string) (*tls.Config, error) { - tlsConfig := &tls.Config{} + tlsConfig := &tls.Config{ + MinVersion: tls.VersionTLS12, + } if clientCert != "" && clientKey != "" { cert, err := tls.X509KeyPair([]byte(clientCert), []byte(clientKey)) if err != nil { diff --git a/internal/lightning/fake_wallet.go b/internal/lightning/fake_wallet.go index eb6678c1..880af63b 100644 --- a/internal/lightning/fake_wallet.go +++ b/internal/lightning/fake_wallet.go @@ -26,8 +26,8 @@ const ( ) type FakeWallet struct { - Network chaincfg.Params UnpurposeErrors []FakeWalletError + Network chaincfg.Params InvoiceFee uint64 } diff --git a/internal/lightning/lnbits.go b/internal/lightning/lnbits.go index 83307971..4ae2b3f0 100644 --- a/internal/lightning/lnbits.go +++ b/internal/lightning/lnbits.go @@ -17,9 +17,9 @@ import ( ) type LnbitsWallet struct { - Network chaincfg.Params Endpoint string Key string + Network chaincfg.Params } type LNBitsDetailErrorData struct { @@ -27,26 +27,26 @@ type LNBitsDetailErrorData struct { Status string } type lnbitsInvoiceRequest struct { - Amount uint64 `json:"amount"` Unit string `json:"unit,omitempty"` CheckingId string `json:"checking_id,omitempty"` Memo string `json:"memo"` - Out bool `json:"out"` - Expiry int64 `json:"expiry"` Bolt11 string `json:"bolt11"` + Amount uint64 `json:"amount"` + Expiry int64 `json:"expiry"` + Out bool `json:"out"` } type LNBitsPaymentStatusDetail struct { Memo string + Status string Fee int64 Pending bool - Status string } type LNBitsPaymentStatus struct { - Paid bool `json:"paid"` - Pending bool `json:"pending"` Preimage string `json:"preimage"` Details LNBitsPaymentStatusDetail + Paid bool `json:"paid"` + Pending bool `json:"pending"` } type lnbitsFeeResponse struct { FeeReserve uint64 `json:"fee_reserve"` diff --git a/internal/lightning/lnd.go b/internal/lightning/lnd.go index 7a13f45f..8068d9b4 100644 --- a/internal/lightning/lnd.go +++ b/internal/lightning/lnd.go @@ -20,9 +20,9 @@ import ( ) type LndGrpcWallet struct { - Network chaincfg.Params grpcClient *grpc.ClientConn macaroon string + Network chaincfg.Params } func (l *LndGrpcWallet) SetupGrpc(host string, macaroon string, tlsCrt string) error { @@ -217,9 +217,9 @@ func (l LndGrpcWallet) PayInvoice(melt_quote cashu.MeltRequestDB, zpayInvoice *z } type LndPayStatus struct { + Preimage string Fee uint64 Status PaymentStatus - Preimage string } func (l LndGrpcWallet) getPaymentStatus(invoice *zpay32.Invoice) (LndPayStatus, error) { diff --git a/internal/lightning/strike.go b/internal/lightning/strike.go index 1e45279a..76904e8c 100644 --- a/internal/lightning/strike.go +++ b/internal/lightning/strike.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "io" + "log/slog" "net/http" "strconv" "strings" @@ -16,9 +17,9 @@ import ( ) type Strike struct { - Network chaincfg.Params endpoint string key string + Network chaincfg.Params } type strikeAccountBalanceResponse struct { @@ -100,12 +101,12 @@ type strikeInvoiceResponse struct { State strikeInvoiceState `json:"state"` } type strikeInvoiceQuoteResponse struct { + TargetAmount strikeAmount `json:"targetAmount"` QuoteId string `json:"quoteId"` Description string `json:"description"` LnInvoice string `json:"lnInvoice"` Expiration string `json:"expiration"` ExpirationInSec int64 `json:"expirationInSec"` - TargetAmount strikeAmount `json:"targetAmount"` } type strikePaymentRequest struct { @@ -181,6 +182,13 @@ func (l *Strike) StrikeRequest(method string, endpoint string, reqBody any, resp if err != nil { return fmt.Errorf("client.Do(req): %w", err) } + defer func() { + err := resp.Body.Close() + if err != nil { + slog.Error("could not close body from call.", slog.Any("error", err)) + + } + }() body, err := io.ReadAll(resp.Body) if err != nil { diff --git a/internal/mint/bolt11.go b/internal/mint/bolt11.go index 6c658eaa..6e6ba449 100644 --- a/internal/mint/bolt11.go +++ b/internal/mint/bolt11.go @@ -17,12 +17,11 @@ func CheckMintRequest(mint *Mint, quote cashu.MintRequestDB, invoice *zpay32.Inv status, _, err := mint.LightningBackend.CheckReceived(quote, invoice) if err != nil { - return quote, fmt.Errorf("mint.VerifyLightingPaymentHappened(pool, quote.RequestPaid. %w", err) + return quote, fmt.Errorf("mint.VerifyLightingPaymentHappened(pool). %w", err) } switch status { case lightning.SETTLED: quote.State = cashu.PAID - quote.RequestPaid = true // case lightning.PENDING: // quote.State = cashu.PENDING case lightning.FAILED: @@ -75,7 +74,6 @@ func CheckMeltRequest(mint *Mint, quoteId string) (cashu.PostMeltQuoteBolt11Resp quote.PaymentPreimage = preimage quote.State = cashu.PAID quote.FeePaid = fees - quote.RequestPaid = true case lightning.PENDING: quote.State = cashu.PENDING diff --git a/internal/mint/melting.go b/internal/mint/melting.go index 8ec58d4a..a4015807 100644 --- a/internal/mint/melting.go +++ b/internal/mint/melting.go @@ -45,12 +45,11 @@ func (m *Mint) settleIfInternalMelt(tx pgx.Tx, meltQuote cashu.MeltRequestDB) (c meltQuote.Melted = true mintRequest.State = cashu.PAID - mintRequest.RequestPaid = true slog.Info(fmt.Sprintf("Settling bolt11 payment internally: %v. mintRequest: %v, %v, %v", meltQuote.Quote, mintRequest.Quote, meltQuote.Amount, meltQuote.Unit)) - err = m.MintDB.ChangeMeltRequestState(tx, meltQuote.Quote, meltQuote.RequestPaid, meltQuote.State, meltQuote.Melted, meltQuote.FeePaid) + err = m.MintDB.ChangeMeltRequestState(tx, meltQuote.Quote, meltQuote.State, meltQuote.Melted, meltQuote.FeePaid) if err != nil { - return meltQuote, fmt.Errorf("m.MintDB.ChangeMeltRequestState(tx, meltQuote.Quote, meltQuote.RequestPaid, meltQuote.State, meltQuote.Melted, meltQuote.FeePaid) %w", err) + return meltQuote, fmt.Errorf("m.MintDB.ChangeMeltRequestState(tx, meltQuote.Quote, meltQuote.State, meltQuote.Melted, meltQuote.FeePaid) %w", err) } return meltQuote, nil @@ -171,9 +170,9 @@ func (m *Mint) CheckMeltQuoteState(quoteId string) (cashu.MeltRequestDB, error) return quote, fmt.Errorf("m.MintDB.SetProofsState(pending_proofs, cashu.PROOF_SPENT) %w", err) } - err = m.MintDB.ChangeMeltRequestState(settleTx, quote.Quote, quote.RequestPaid, quote.State, quote.Melted, quote.FeePaid) + err = m.MintDB.ChangeMeltRequestState(settleTx, quote.Quote, quote.State, quote.Melted, quote.FeePaid) if err != nil { - return quote, fmt.Errorf("m.MintDB.ChangeMeltRequestState(quote.Quote, quote.RequestPaid, quote.State, quote.Melted, quote.PaidFee) %w", err) + return quote, fmt.Errorf("m.MintDB.ChangeMeltRequestState(quote.Quote, quote.State, quote.Melted, quote.PaidFee) %w", err) } err = m.MintDB.AddPreimageMeltRequest(settleTx, quote.Quote, quote.PaymentPreimage) @@ -200,9 +199,9 @@ func (m *Mint) CheckMeltQuoteState(quoteId string) (cashu.MeltRequestDB, error) } }() - err = m.MintDB.ChangeMeltRequestState(failedLnTx, quote.Quote, quote.RequestPaid, quote.State, quote.Melted, quote.FeePaid) + err = m.MintDB.ChangeMeltRequestState(failedLnTx, quote.Quote, quote.State, quote.Melted, quote.FeePaid) if err != nil { - return quote, fmt.Errorf("m.MintDB.ChangeMeltRequestState(failedLnTx, quote.Quote, quote.RequestPaid, quote.State, quote.Melted, quote.FeePaid) %w", err) + return quote, fmt.Errorf("m.MintDB.ChangeMeltRequestState(failedLnTx, quote.Quote, quote.State, quote.Melted, quote.FeePaid) %w", err) } err = m.MintDB.DeleteChangeByQuote(failedLnTx, quote.Quote) @@ -378,9 +377,9 @@ func (m *Mint) Melt(meltRequest cashu.PostMeltBolt11Request) (cashu.PostMeltQuot if err != nil { return quote.GetPostMeltQuoteResponse(), fmt.Errorf("m.MintDB.SaveProof(preparationTx, meltRequest.Inputs) %w", err) } - err = m.MintDB.ChangeMeltRequestState(preparationTx, quote.Quote, quote.RequestPaid, quote.State, quote.Melted, quote.FeePaid) + err = m.MintDB.ChangeMeltRequestState(preparationTx, quote.Quote, quote.State, quote.Melted, quote.FeePaid) if err != nil { - return quote.GetPostMeltQuoteResponse(), fmt.Errorf("m.MintDB.ChangeMeltRequestState(preparationTx, quote.Quote, quote.RequestPaid, quote.State, quote.Melted, quote.FeePaid) %w", err) + return quote.GetPostMeltQuoteResponse(), fmt.Errorf("m.MintDB.ChangeMeltRequestState(preparationTx, quote.Quote, quote.State, quote.Melted, quote.FeePaid) %w", err) } err = m.MintDB.SaveMeltChange(preparationTx, meltRequest.Outputs, quote.Quote) @@ -411,7 +410,7 @@ func (m *Mint) Melt(meltRequest cashu.PostMeltBolt11Request) (cashu.PostMeltQuot Amount: quote.Amount, } - if !quote.RequestPaid { + if quote.State != cashu.PAID { payment, err := m.LightningBackend.PayInvoice(quote, invoice, quote.FeeReserve, quote.Mpp, amount) // Hardened error handling @@ -450,7 +449,7 @@ func (m *Mint) Melt(meltRequest cashu.PostMeltBolt11Request) (cashu.PostMeltQuot return quote.GetPostMeltQuoteResponse(), fmt.Errorf("m.LightningBackend.CheckPayed(quote.Quote) %w", err) } - slog.Info("after check payed verification") + slog.Info("after check paid verification") quote.FeePaid = fee_paid lnStatusTx, err := m.MintDB.GetTx(ctx) @@ -470,17 +469,17 @@ func (m *Mint) Melt(meltRequest cashu.PostMeltBolt11Request) (cashu.PostMeltQuot case lightning.PENDING, lightning.SETTLED: quote.State = cashu.PENDING // change melt request state - err = m.MintDB.ChangeMeltRequestState(lnStatusTx, quote.Quote, quote.RequestPaid, quote.State, quote.Melted, quote.FeePaid) + err = m.MintDB.ChangeMeltRequestState(lnStatusTx, quote.Quote, quote.State, quote.Melted, quote.FeePaid) if err != nil { - slog.Error(fmt.Errorf("m.MintDB.ChangeMeltRequestState(lnStatusTx, quote.Quote, quote.RequestPaid, quote.State, quote.Melted, quote.FeePaid): %w", err).Error()) + slog.Error(fmt.Errorf("m.MintDB.ChangeMeltRequestState(lnStatusTx, quote.Quote, quote.State, quote.Melted, quote.FeePaid): %w", err).Error()) } // finish failure and release the proofs case lightning.FAILED, lightning.UNKNOWN: quote.State = cashu.UNPAID - errDb := m.MintDB.ChangeMeltRequestState(lnStatusTx, quote.Quote, quote.RequestPaid, quote.State, quote.Melted, quote.FeePaid) + errDb := m.MintDB.ChangeMeltRequestState(lnStatusTx, quote.Quote, quote.State, quote.Melted, quote.FeePaid) if errDb != nil { - return quote.GetPostMeltQuoteResponse(), fmt.Errorf("m.MintDB.ChangeMeltRequestState(lnStatusTx, quote.Quote, quote.RequestPaid, quote.State, quote.Melted, quote.FeePaid) %w", err) + return quote.GetPostMeltQuoteResponse(), fmt.Errorf("m.MintDB.ChangeMeltRequestState(lnStatusTx, quote.Quote, quote.State, quote.Melted, quote.FeePaid) %w", err) } errDb = m.MintDB.DeleteProofs(lnStatusTx, meltRequest.Inputs) if errDb != nil { @@ -501,7 +500,6 @@ func (m *Mint) Melt(meltRequest cashu.PostMeltBolt11Request) (cashu.PostMeltQuot quote.PaymentPreimage = payment.Preimage paidLightningFeeSat = uint64(payment.PaidFeeSat) quote.FeePaid = paidLightningFeeSat - quote.RequestPaid = true quote.State = cashu.PAID quote.Melted = true } @@ -549,9 +547,9 @@ func (m *Mint) Melt(meltRequest cashu.PostMeltBolt11Request) (cashu.PostMeltQuot response.Change = blindSignatures } - err = m.MintDB.ChangeMeltRequestState(paidLnxTx, quote.Quote, quote.RequestPaid, quote.State, quote.Melted, quote.FeePaid) + err = m.MintDB.ChangeMeltRequestState(paidLnxTx, quote.Quote, quote.State, quote.Melted, quote.FeePaid) if err != nil { - return quote.GetPostMeltQuoteResponse(), fmt.Errorf("m.MintDB.ChangeMeltRequestState(paidLnxTx, quote.Quote, quote.RequestPaid, quote.State, quote.Melted, quote.FeePaid) %w", err) + return quote.GetPostMeltQuoteResponse(), fmt.Errorf("m.MintDB.ChangeMeltRequestState(paidLnxTx, quote.Quote, quote.State, quote.Melted, quote.FeePaid) %w", err) } err = m.MintDB.AddPreimageMeltRequest(paidLnxTx, quote.Quote, quote.PaymentPreimage) diff --git a/internal/mint/mint.go b/internal/mint/mint.go index 49f64afa..7c28c765 100644 --- a/internal/mint/mint.go +++ b/internal/mint/mint.go @@ -17,12 +17,12 @@ import ( type Mint struct { LightningBackend lightning.LightningBackend - Config utils.Config - MintPubkey string MintDB database.MintDB Signer signer.Signer OICDClient *oidc.Provider Observer *Observer + MintPubkey string + Config utils.Config } var ( diff --git a/internal/mint/mint_test.go b/internal/mint/mint_test.go index 7c1e05d0..19e970c2 100644 --- a/internal/mint/mint_test.go +++ b/internal/mint/mint_test.go @@ -87,17 +87,16 @@ func SetupDataOnDB(mint *Mint) error { now := time.Now().Unix() melt_quote := cashu.MeltRequestDB{ - Quote: quoteId, - Unit: cashu.Sat.String(), - Expiry: now, - Amount: 2, - FeeReserve: 2, - RequestPaid: false, - Request: "lnbcrt2u1pna2hrlpp5gv4edjsvjzflaxex5y4jcm87yhhm7s6clt6hjar50yhswan83fesdqqcqzzsxqzuysp5u3kq8etcat22w2hraktrgppltaegt3prrf5qz9z4cplreje2kzrq9qxpqysgq2ujupalzlwz9nhn55pl6nuwtv4qqkdlkn02rf835l3janjwy7w3n0tl0whh6v3frpvfcsyzud3g6dsx6gqgmw04xj2c0alz4px5hjecq0pnclr", - State: cashu.PENDING, - Melted: false, - SeenAt: time.Now().Unix(), - Mpp: false, + Quote: quoteId, + Unit: cashu.Sat.String(), + Expiry: now, + Amount: 2, + FeeReserve: 2, + Request: "lnbcrt2u1pna2hrlpp5gv4edjsvjzflaxex5y4jcm87yhhm7s6clt6hjar50yhswan83fesdqqcqzzsxqzuysp5u3kq8etcat22w2hraktrgppltaegt3prrf5qz9z4cplreje2kzrq9qxpqysgq2ujupalzlwz9nhn55pl6nuwtv4qqkdlkn02rf835l3janjwy7w3n0tl0whh6v3frpvfcsyzud3g6dsx6gqgmw04xj2c0alz4px5hjecq0pnclr", + State: cashu.PENDING, + Melted: false, + SeenAt: time.Now().Unix(), + Mpp: false, } c1Priv, err := secp256k1.GeneratePrivateKey() diff --git a/internal/mint/utils_test.go b/internal/mint/utils_test.go index 3a854079..54a25418 100644 --- a/internal/mint/utils_test.go +++ b/internal/mint/utils_test.go @@ -25,10 +25,9 @@ func TestIsInternalTransactionSuccess(t *testing.T) { } mintRequest := cashu.MintRequestDB{ - Quote: "quote1", - Request: RegtestRequest, - RequestPaid: false, - State: cashu.UNPAID, + Quote: "quote1", + Request: RegtestRequest, + State: cashu.UNPAID, } err = mint.MintDB.SaveMintRequest(tx, mintRequest) if err != nil { @@ -61,10 +60,9 @@ func TestIsInternalTransactionFail(t *testing.T) { } mintRequest := cashu.MintRequestDB{ - Quote: "quote1", - Request: "wrong request", - RequestPaid: false, - State: cashu.UNPAID, + Quote: "quote1", + Request: "wrong request", + State: cashu.UNPAID, } err = mint.MintDB.SaveMintRequest(tx, mintRequest) if err != nil { diff --git a/internal/mint/websocket.go b/internal/mint/websocket.go index eb6b18bf..e96d94dc 100644 --- a/internal/mint/websocket.go +++ b/internal/mint/websocket.go @@ -25,11 +25,10 @@ type MeltQuoteChannel struct { } type Observer struct { - sync.Mutex - // the string is the filters from the websockets Proofs map[string][]ProofWatchChannel MintQuote map[string][]MintQuoteChannel MeltQuote map[string][]MeltQuoteChannel + sync.Mutex } func (o *Observer) AddProofWatch(y string, proofChan ProofWatchChannel) { diff --git a/internal/routes/admin/crons.go b/internal/routes/admin/crons.go index 2c34aa3f..bc13a603 100644 --- a/internal/routes/admin/crons.go +++ b/internal/routes/admin/crons.go @@ -188,7 +188,7 @@ func CheckStatusOfLiquiditySwaps(mint *m.Mint, newLiquidity chan string) { return } - slog.Debug("Commiting swap", slog.String("swap_id", swap.Id)) + slog.Debug("Committing swap", slog.String("swap_id", swap.Id)) err = afterCheckTx.Commit(ctx) if err != nil { slog.Error("Could not commit sub transaction", slog.Any("error", err)) diff --git a/internal/routes/admin/keysets.go b/internal/routes/admin/keysets.go index 9652e66c..1bcd6d38 100644 --- a/internal/routes/admin/keysets.go +++ b/internal/routes/admin/keysets.go @@ -137,7 +137,7 @@ func RotateSatsSeed(adminHandler *adminHandler) gin.HandlerFunc { } else { c.Header("HX-Trigger", "recharge-keyset") - err := RenderSuccess(c, "Key succesfully rotated") + err := RenderSuccess(c, "Key successfully rotated") if err != nil { slog.Error("RenderSuccess", slog.Any("error", err)) } diff --git a/internal/routes/admin/liquidity-manager.go b/internal/routes/admin/liquidity-manager.go index 5f84cc9a..8fc1450a 100644 --- a/internal/routes/admin/liquidity-manager.go +++ b/internal/routes/admin/liquidity-manager.go @@ -483,7 +483,7 @@ func ConfirmSwapOutTransaction(mint *m.Mint, newLiquidity chan string) gin.Handl return } - slog.Info("after check payed verification") + slog.Info("after check paid verification") lnStatusTx, err := mint.MintDB.GetTx(ctx) if err != nil { return diff --git a/internal/routes/admin/main.go b/internal/routes/admin/main.go index 2976dafb..81d7d7a3 100644 --- a/internal/routes/admin/main.go +++ b/internal/routes/admin/main.go @@ -116,7 +116,13 @@ func AdminRoutes(ctx context.Context, r *gin.Engine, mint *m.Mint) { panic("invalid ADMIN_NOSTR_NPUB ") } - decodedKey, err := hex.DecodeString(value.(string)) + keyStr, ok := value.(string) + if !ok { + slog.Info("nip19.Decode(adminNpubStr) returned non-string", slog.Any("value", value)) + panic("invalid ADMIN_NOSTR_NPUB type") + } + + decodedKey, err := hex.DecodeString(keyStr) if err != nil { slog.Info("hex.DecodeString(value.(string))", slog.Any("error", err)) panic("decoded ADMIN_NOSTR_NPUB is not correct") diff --git a/internal/routes/admin/mint-activity.go b/internal/routes/admin/mint-activity.go index 7ff2fbf0..7a597a3f 100644 --- a/internal/routes/admin/mint-activity.go +++ b/internal/routes/admin/mint-activity.go @@ -58,12 +58,6 @@ func SummaryComponent(mint *m.Mint, adminHandler *adminHandler) gin.HandlerFunc return } - fees, err := fees(proofsCount, keysets.Keysets) - if err != nil { - _ = c.Error(err) - return - } - lnBalance, err := mint.LightningBackend.WalletBalance() if err != nil { _ = c.Error(err) @@ -79,7 +73,7 @@ func SummaryComponent(mint *m.Mint, adminHandler *adminHandler) gin.HandlerFunc summary := templates.Summary{ LnBalance: lnBalance / 1000, FakeWallet: mint.Config.MINT_LIGHTNING_BACKEND == utils.FAKE_WALLET, - Fees: fees, + Fees: fees(proofsCount, keysets.Keysets), SinceDate: sinceDate, } @@ -91,14 +85,14 @@ func SummaryComponent(mint *m.Mint, adminHandler *adminHandler) gin.HandlerFunc } } -func fees(proofs map[string]database.ProofsCountByKeyset, keysets []cashu.BasicKeysetResponse) (uint64, error) { +func fees(proofs map[string]database.ProofsCountByKeyset, keysets []cashu.BasicKeysetResponse) uint64 { totalFees := uint64(0) for _, keyset := range keysets { if keyset.Unit != cashu.AUTH.String() { for keysetId, proof := range proofs { if keyset.Id == keysetId { - totalFees += uint64(proof.Count) * uint64(keyset.InputFeePpk) + totalFees += proof.Count * uint64(keyset.InputFeePpk) } } } @@ -107,6 +101,5 @@ func fees(proofs map[string]database.ProofsCountByKeyset, keysets []cashu.BasicK totalFees = (totalFees + 999) / 1000 - return totalFees, nil - + return totalFees } diff --git a/internal/routes/admin/pages.go b/internal/routes/admin/pages.go index a521f13d..7563a1a3 100644 --- a/internal/routes/admin/pages.go +++ b/internal/routes/admin/pages.go @@ -426,7 +426,7 @@ func calculateLnChartSummary(data []templates.MintMeltTimeSeriesPoint) templates // buildMintMeltTimeSeries processes raw mint/melt data and aggregates into time buckets // using zpay32 to decode invoice amounts -func buildMintMeltTimeSeries(mintMeltBalance database.MintMeltBalance, network *chaincfg.Params, startTime time.Time, bucketMinutes int) []templates.MintMeltTimeSeriesPoint { +func buildMintMeltTimeSeries(mintMeltBalance database.MintMeltBalance, network *chaincfg.Params, bucketMinutes int) []templates.MintMeltTimeSeriesPoint { bucketSeconds := int64(bucketMinutes * 60) // Maps to aggregate data by bucket @@ -536,7 +536,7 @@ func LnChartCard(mint *mint.Mint) gin.HandlerFunc { } // Process and aggregate into time series using zpay32 for invoice decoding - data := buildMintMeltTimeSeries(mintMeltBalance, mint.LightningBackend.GetNetwork(), startTime, bucketMinutes) + data := buildMintMeltTimeSeries(mintMeltBalance, mint.LightningBackend.GetNetwork(), bucketMinutes) summary := calculateLnChartSummary(data) @@ -567,7 +567,7 @@ func LnChartDataAPI(mint *mint.Mint) gin.HandlerFunc { } // Process and aggregate into time series using zpay32 for invoice decoding - data := buildMintMeltTimeSeries(mintMeltBalance, mint.LightningBackend.GetNetwork(), startTime, bucketMinutes) + data := buildMintMeltTimeSeries(mintMeltBalance, mint.LightningBackend.GetNetwork(), bucketMinutes) // Return HTML fragment for HTMX err = templates.LnChartContent(data).Render(ctx, c.Writer) diff --git a/internal/routes/admin/tabs.go b/internal/routes/admin/tabs.go index f2abc65b..d58917bb 100644 --- a/internal/routes/admin/tabs.go +++ b/internal/routes/admin/tabs.go @@ -70,7 +70,12 @@ func isNostrKeyValid(nostrKey string) (bool, error) { } - return nostr.IsValid32ByteHex(key.(string)), nil + keyStr, ok := key.(string) + if !ok { + return false, fmt.Errorf("nip19.Decode(nostrKey) returned %T", key) + } + + return nostr.IsValid32ByteHex(keyStr), nil } @@ -243,7 +248,6 @@ func MintSettingsGeneral(mint *m.Mint) gin.HandlerFunc { slog.Error("failed to render success", slog.Any("error", err)) return } - return } } @@ -338,7 +342,6 @@ func MintSettingsAuth(mint *m.Mint) gin.HandlerFunc { slog.Error("failed to render success", slog.Any("error", err)) return } - return } } diff --git a/internal/routes/admin/tabs_test.go b/internal/routes/admin/tabs_test.go index 5b4598e5..b0c8f22b 100644 --- a/internal/routes/admin/tabs_test.go +++ b/internal/routes/admin/tabs_test.go @@ -14,7 +14,7 @@ func TestCheckIntegerFromStringSuccess(t *testing.T) { success := 2 if *int != success { - t.Error("Convertion should have occured") + t.Error("Conversion should have occurred") } } diff --git a/internal/routes/auth.go b/internal/routes/auth.go index d988ddac..9e1c30e6 100644 --- a/internal/routes/auth.go +++ b/internal/routes/auth.go @@ -116,7 +116,7 @@ func v1AuthRoutes(r *gin.Engine, mint *m.Mint) { // check all blind messages have the same unit } - if amountBlindMessages > uint64(mint.Config.MINT_AUTH_MAX_BLIND_TOKENS) { + if amountBlindMessages > mint.Config.MINT_AUTH_MAX_BLIND_TOKENS { slog.Warn("Trying to mint auth tokens over the limit") c.JSON(400, cashu.ErrorCodeToResponse(cashu.MAXIMUM_BAT_MINT_LIMIT_EXCEEDED, nil)) return diff --git a/internal/routes/bolt11.go b/internal/routes/bolt11.go index 4035cec1..f09af5d6 100644 --- a/internal/routes/bolt11.go +++ b/internal/routes/bolt11.go @@ -87,7 +87,6 @@ func v1bolt11Routes(r *gin.Engine, mint *m.Mint) { mintRequestDB := cashu.MintRequestDB{ Quote: quoteId, - RequestPaid: false, Expiry: expireTime, Unit: unit.String(), State: cashu.UNPAID, @@ -97,7 +96,7 @@ func v1bolt11Routes(r *gin.Engine, mint *m.Mint) { Description: mintRequest.Description, } - resInvoice, err := mint.LightningBackend.RequestInvoice(mintRequestDB, cashu.Amount{Unit: unit, Amount: uint64(mintRequest.Amount)}) + resInvoice, err := mint.LightningBackend.RequestInvoice(mintRequestDB, cashu.Amount{Unit: unit, Amount: mintRequest.Amount}) if err != nil { slog.Info("Payment request", slog.Any("error", err)) c.JSON(500, "Opps!, something went wrong") @@ -204,9 +203,9 @@ func v1bolt11Routes(r *gin.Engine, mint *m.Mint) { } }() - err = mint.MintDB.ChangeMintRequestState(stateChangeTX, quote.Quote, quote.RequestPaid, quote.State, quote.Minted) + err = mint.MintDB.ChangeMintRequestState(stateChangeTX, quote.Quote, quote.State, quote.Minted) if err != nil { - slog.Error("mint.MintDB.ChangeMintRequestState(tx, quote.Quote, quote.RequestPaid, quote.State, quote.Minted)", slog.Any("error", err)) + slog.Error("mint.MintDB.ChangeMintRequestState(tx, quote.Quote, quote.State, quote.Minted)", slog.Any("error", err)) } err = mint.MintDB.Commit(ctx, stateChangeTX) @@ -332,7 +331,7 @@ func v1bolt11Routes(r *gin.Engine, mint *m.Mint) { c.JSON(403, "Amounts in outputs are not the same") return } - if !mintRequestDB.RequestPaid && mintRequestDB.State == cashu.UNPAID { + if mintRequestDB.State == cashu.UNPAID { slog.Debug(fmt.Sprintf("Checking payment state quote id: %v. ", mintRequestDB.Quote)) mintRequestDB, err = m.CheckMintRequest(mint, mintRequestDB, invoice) @@ -361,9 +360,9 @@ func v1bolt11Routes(r *gin.Engine, mint *m.Mint) { }() slog.Debug(fmt.Sprintf("Changing state of mint request id %v. To: %v", mintRequestDB.Quote, mintRequestDB.State)) - err = mint.MintDB.ChangeMintRequestState(afterCheckTx, mintRequestDB.Quote, mintRequestDB.RequestPaid, mintRequestDB.State, mintRequestDB.Minted) + err = mint.MintDB.ChangeMintRequestState(afterCheckTx, mintRequestDB.Quote, mintRequestDB.State, mintRequestDB.Minted) if err != nil { - slog.Error(fmt.Errorf("mint.MintDB.ChangeMintRequestState(afterCheckTx, quote.Quote, quote.RequestPaid, quote.State, quote.Minted): %w", err).Error()) + slog.Error(fmt.Errorf("mint.MintDB.ChangeMintRequestState(afterCheckTx, quote.Quote, quote.State, quote.Minted): %w", err).Error()) return } err = mint.MintDB.Commit(ctx, afterCheckTx) @@ -402,9 +401,9 @@ func v1bolt11Routes(r *gin.Engine, mint *m.Mint) { } }() - err = mint.MintDB.ChangeMintRequestState(afterBlindSignTx, mintRequestDB.Quote, mintRequestDB.RequestPaid, mintRequestDB.State, mintRequestDB.Minted) + err = mint.MintDB.ChangeMintRequestState(afterBlindSignTx, mintRequestDB.Quote, mintRequestDB.State, mintRequestDB.Minted) if err != nil { - slog.Error(fmt.Errorf("mint.MintDB.ChangeMintRequestState(afterBlindSignTx, quote.Quote, quote.RequestPaid, quote.State, quote.Minted): %w", err).Error()) + slog.Error(fmt.Errorf("mint.MintDB.ChangeMintRequestState(afterBlindSignTx, quote.Quote, quote.State, quote.Minted): %w", err).Error()) return } @@ -417,7 +416,7 @@ func v1bolt11Routes(r *gin.Engine, mint *m.Mint) { return } - slog.Debug(fmt.Sprintf("Commiting transaction for: id %v", mintRequestDB.Quote)) + slog.Debug(fmt.Sprintf("Committing transaction for: id %v", mintRequestDB.Quote)) err = mint.MintDB.Commit(ctx, afterBlindSignTx) if err != nil { _ = c.Error(fmt.Errorf("mint.MintDB.Commit(ctx, afterBlindSignTx). %w", err)) @@ -495,7 +494,7 @@ func v1bolt11Routes(r *gin.Engine, mint *m.Mint) { cashuAmount := cashu.Amount{Unit: unit, Amount: uint64(amount)} isMpp := false - mppAmount := cashu.Amount{Unit: cashu.Msat, Amount: uint64(meltRequest.IsMpp())} + mppAmount := cashu.Amount{Unit: cashu.Msat, Amount: meltRequest.IsMpp()} // if mpp is valid than change amount to mpp amount if mppAmount.Amount != 0 { @@ -542,7 +541,6 @@ func v1bolt11Routes(r *gin.Engine, mint *m.Mint) { Unit: unit.String(), Expiry: expireTime, FeeReserve: (queryFee + 1), - RequestPaid: false, State: cashu.UNPAID, PaymentPreimage: "", SeenAt: now, diff --git a/internal/routes/mint.go b/internal/routes/mint.go index ffbdebbd..f9618832 100644 --- a/internal/routes/mint.go +++ b/internal/routes/mint.go @@ -117,8 +117,12 @@ func v1MintRoutes(r *gin.Engine, mint *m.Mint) { Disabled: &b, } if entry, ok := nuts[nut]; ok { - - mintInfo := entry.(cashu.SwapMintInfo) + mintInfo, ok := entry.(cashu.SwapMintInfo) + if !ok { + slog.Error("nuts entry type mismatch", slog.String("nut", nut), slog.Any("value", entry)) + c.JSON(500, "Server side error") + return + } // Then we modify the copy mintInfo.Disabled = &mint.Config.PEG_OUT_ONLY diff --git a/internal/routes/websocket.go b/internal/routes/websocket.go index e4966ccd..334f90ec 100644 --- a/internal/routes/websocket.go +++ b/internal/routes/websocket.go @@ -54,23 +54,7 @@ func v1WebSocketRoute(r *gin.Engine, mint *m.Mint) { meltChan := make(chan cashu.MeltRequestDB, 1) closeChan := make(chan string, 1) // parse request check if subscription or unsubscribe - err = handleWSRequest(request, mint.Observer, proofChan, mintChan, meltChan, closeChan) - - if err != nil { - if errors.Is(err, ErrAlreadySubscribed) { - errMsg := cashu.WsError{ - JsonRpc: "2.0", - Id: request.Id, - Error: cashu.ErrorMsg{ - Code: uint64(cashu.UNKNOWN), - Message: "Already subscribed to filter", - }, - } - err = m.SendJson(conn, errMsg) - } - slog.Error("Error on creating websocket", slog.Any("error", err)) - return - } + handleWSRequest(request, mint.Observer, proofChan, mintChan, meltChan, closeChan) slog.Debug("New request", slog.Any("request", request)) // confirm subscription or unsubscribe @@ -167,7 +151,7 @@ func v1WebSocketRoute(r *gin.Engine, mint *m.Mint) { func handleWSRequest(request cashu.WsRequest, observer *m.Observer, proofChan chan cashu.Proof, mintChan chan cashu.MintRequestDB, meltChan chan cashu.MeltRequestDB, closeChan chan string, -) error { +) { switch request.Method { case cashu.Subcribe: @@ -191,7 +175,6 @@ func handleWSRequest(request cashu.WsRequest, observer *m.Observer, proofChan ch go observer.RemoveWatch(request.Params.SubId) closeChan <- "asked for unsubscribe" } - return nil } func ListenToIncommingMessage(subs *m.Observer, conn *websocket.Conn, listenChannel chan error, proofChan chan cashu.Proof, mintChan chan cashu.MintRequestDB, meltChan chan cashu.MeltRequestDB, closeChan chan string) { @@ -203,11 +186,7 @@ func ListenToIncommingMessage(subs *m.Observer, conn *websocket.Conn, listenChan return } - err = handleWSRequest(request, subs, proofChan, mintChan, meltChan, closeChan) - if err != nil { - listenChannel <- fmt.Errorf("handleWSRequest(request, subs) %w", err) - return - } + handleWSRequest(request, subs, proofChan, mintChan, meltChan, closeChan) response := cashu.WsResponse{ JsonRpc: "2.0", Id: request.Id, @@ -274,7 +253,11 @@ func CheckStatusOfSub(request cashu.WsRequest, mint *m.Mint, conn *websocket.Con } statusNotif.Params.Payload = mintState if exists { - if value.(cashu.MintRequestDB).State != mintState.State { + mintRequest, ok := value.(cashu.MintRequestDB) + if !ok { + return fmt.Errorf("unexpected mint request type: %T", value) + } + if mintRequest.State != mintState.State { alreadyCheckedFilter[filter] = mintState err := m.SendJson(conn, statusNotif) if err != nil { @@ -296,8 +279,11 @@ func CheckStatusOfSub(request cashu.WsRequest, mint *m.Mint, conn *websocket.Con statusNotif.Params.Payload = meltState if exists { - - if value.(cashu.MeltRequestDB).State != meltState.State { + meltRequest, ok := value.(cashu.MeltRequestDB) + if !ok { + return fmt.Errorf("unexpected melt request type: %T", value) + } + if meltRequest.State != meltState.State { alreadyCheckedFilter[filter] = meltState err := m.SendJson(conn, statusNotif) if err != nil { @@ -331,7 +317,11 @@ func CheckStatusOfSub(request cashu.WsRequest, mint *m.Mint, conn *websocket.Con } // check for subscription and if the state changed if exists && len(proofsState) > 0 { - if value.(cashu.CheckState).State != proofsState[0].State { + checkState, ok := value.(cashu.CheckState) + if !ok { + return fmt.Errorf("unexpected check state type: %T", value) + } + if checkState.State != proofsState[0].State { statusNotif.Params.Payload = proofsState[0] alreadyCheckedFilter[filter] = proofsState[0] diff --git a/internal/signer/remote_signer/remote_signer.go b/internal/signer/remote_signer/remote_signer.go index c6e10b67..539eff09 100644 --- a/internal/signer/remote_signer/remote_signer.go +++ b/internal/signer/remote_signer/remote_signer.go @@ -15,13 +15,13 @@ import ( ) type MintPublicKeyset struct { - Id []byte - Unit string - Active bool Keys map[uint64]string + FinalExpiry *uint64 + Unit string + Id []byte InputFeePpk uint Version uint32 - FinalExpiry *uint64 + Active bool } type RemoteSigner struct { diff --git a/internal/signer/remote_signer/transformer.go b/internal/signer/remote_signer/transformer.go index 8cee8691..f60c4e54 100644 --- a/internal/signer/remote_signer/transformer.go +++ b/internal/signer/remote_signer/transformer.go @@ -150,4 +150,3 @@ func CheckIfSignerErrorExists(err *sig.Error) error { return errResult } - diff --git a/internal/signer/remote_signer/util.go b/internal/signer/remote_signer/util.go index 6d100949..46575622 100644 --- a/internal/signer/remote_signer/util.go +++ b/internal/signer/remote_signer/util.go @@ -48,6 +48,7 @@ func GetTlsSecurityCredential() (credentials.TransportCredentials, error) { Certificates: []tls.Certificate{serverCert}, ClientAuth: tls.RequireAndVerifyClientCert, // Require client certificate ClientCAs: certPool, // Verify client certificate against this CA + MinVersion: tls.VersionTLS12, } // Create the TLS credentials diff --git a/internal/signer/types.go b/internal/signer/types.go index ac82740d..d142d34e 100644 --- a/internal/signer/types.go +++ b/internal/signer/types.go @@ -16,11 +16,11 @@ type GetKeysetsResponse struct { } type KeysetResponse struct { + Keys map[uint64]string `json:"keys"` Id string `json:"id"` Unit string `json:"unit"` - Active bool `json:"active"` - Keys map[uint64]string `json:"keys"` InputFeePpk uint `json:"input_fee_ppk"` + Active bool `json:"active"` } type BasicKeysetResponse struct { diff --git a/internal/signer/utils.go b/internal/signer/utils.go index 13b2ccec..eed5a6d6 100644 --- a/internal/signer/utils.go +++ b/internal/signer/utils.go @@ -55,7 +55,7 @@ func DeriveKeyset(mintKey *bip32.Key, seed cashu.Seed) ([]cashu.MintKey, error) return nil, fmt.Errorf("mintKey.NewChildKey(uint32(unit.EnumIndex())). %w", err) } - versionKey, err := unitKey.NewChildKey(uint32(seed.Version)) + versionKey, err := unitKey.NewChildKey(seed.Version) if err != nil { return nil, fmt.Errorf("mintKey.NewChildKey(uint32(seed.Version)) %w", err) } diff --git a/internal/utils/common.go b/internal/utils/common.go index ee6958dd..7a5cb853 100644 --- a/internal/utils/common.go +++ b/internal/utils/common.go @@ -37,46 +37,38 @@ func StringToLightningBackend(text string) LightningBackend { } type Config struct { - NAME string `db:"name"` - IconUrl *string `db:"icon_url,omitempty"` - TosUrl *string `db:"tos_url,omitempty"` - DESCRIPTION string `db:"description"` - DESCRIPTION_LONG string `db:"description_long"` - MOTD string `db:"motd"` - EMAIL string `db:"email"` - NOSTR string `db:"nostr"` - - NETWORK string `db:"network"` - - MINT_LIGHTNING_BACKEND LightningBackend `db:"mint_lightning_backend"` - LND_GRPC_HOST string `db:"lnd_grpc_host"` - LND_TLS_CERT string `db:"lnd_tls_cert"` - LND_MACAROON string `db:"lnd_macaroon"` - - MINT_LNBITS_ENDPOINT string `db:"mint_lnbits_endpoint"` - MINT_LNBITS_KEY string `db:"mint_lnbits_key"` - - CLN_GRPC_HOST string `db:"cln_grpc_host"` - CLN_CA_CERT string `db:"cln_ca_cert"` - CLN_CLIENT_CERT string `db:"cln_client_cert"` - CLN_CLIENT_KEY string `db:"cln_client_key"` - CLN_MACAROON string `db:"cln_macaroon"` - - STRIKE_KEY string `db:"strike_key"` - STRIKE_ENDPOINT string `db:"strike_endpoint"` - - PEG_OUT_ONLY bool `db:"peg_out_only"` - PEG_OUT_LIMIT_SATS *int `db:"peg_out_limit_sats,omitempty"` - PEG_IN_LIMIT_SATS *int `db:"peg_in_limit_sats,omitempty"` - - MINT_REQUIRE_AUTH bool `db:"mint_require_auth,omitempty"` - MINT_AUTH_OICD_URL string `db:"mint_auth_oicd_url,omitempty"` - MINT_AUTH_OICD_CLIENT_ID string `db:"mint_auth_oicd_client_id,omitempty"` - MINT_AUTH_RATE_LIMIT_PER_MINUTE int `db:"mint_auth_rate_limit_per_minute,omitempty"` - MINT_AUTH_MAX_BLIND_TOKENS uint64 `db:"mint_auth_max_blind_tokens,omitempty"` - - MINT_AUTH_CLEAR_AUTH_URLS []string `db:"mint_auth_clear_auth_urls,omitempty"` - MINT_AUTH_BLIND_AUTH_URLS []string `db:"mint_auth_blind_auth_urls,omitempty"` + PEG_OUT_LIMIT_SATS *int `db:"peg_out_limit_sats,omitempty"` + IconUrl *string `db:"icon_url,omitempty"` + TosUrl *string `db:"tos_url,omitempty"` + PEG_IN_LIMIT_SATS *int `db:"peg_in_limit_sats,omitempty"` + NETWORK string `db:"network"` + CLN_CLIENT_CERT string `db:"cln_client_cert"` + EMAIL string `db:"email"` + NOSTR string `db:"nostr"` + NAME string `db:"name"` + MINT_LIGHTNING_BACKEND LightningBackend `db:"mint_lightning_backend"` + LND_GRPC_HOST string `db:"lnd_grpc_host"` + LND_TLS_CERT string `db:"lnd_tls_cert"` + LND_MACAROON string `db:"lnd_macaroon"` + MINT_LNBITS_ENDPOINT string `db:"mint_lnbits_endpoint"` + MINT_LNBITS_KEY string `db:"mint_lnbits_key"` + CLN_GRPC_HOST string `db:"cln_grpc_host"` + CLN_CA_CERT string `db:"cln_ca_cert"` + MOTD string `db:"motd"` + CLN_CLIENT_KEY string `db:"cln_client_key"` + CLN_MACAROON string `db:"cln_macaroon"` + STRIKE_KEY string `db:"strike_key"` + STRIKE_ENDPOINT string `db:"strike_endpoint"` + MINT_AUTH_OICD_CLIENT_ID string `db:"mint_auth_oicd_client_id,omitempty"` + DESCRIPTION_LONG string `db:"description_long"` + DESCRIPTION string `db:"description"` + MINT_AUTH_OICD_URL string `db:"mint_auth_oicd_url,omitempty"` + MINT_AUTH_CLEAR_AUTH_URLS []string `db:"mint_auth_clear_auth_urls,omitempty"` + MINT_AUTH_BLIND_AUTH_URLS []string `db:"mint_auth_blind_auth_urls,omitempty"` + MINT_AUTH_RATE_LIMIT_PER_MINUTE int `db:"mint_auth_rate_limit_per_minute,omitempty"` + MINT_AUTH_MAX_BLIND_TOKENS uint64 `db:"mint_auth_max_blind_tokens,omitempty"` + MINT_REQUIRE_AUTH bool `db:"mint_require_auth,omitempty"` + PEG_OUT_ONLY bool `db:"peg_out_only"` } func (c *Config) Default() { diff --git a/internal/utils/files.go b/internal/utils/files.go index 34534d61..ac98468c 100644 --- a/internal/utils/files.go +++ b/internal/utils/files.go @@ -20,10 +20,10 @@ var ( type SlogRecordJSON struct { Time time.Time + Extras map[string]any `json:"-"` Msg string + ExtraInfo string `json:"extra-info"` Level slog.Level - ExtraInfo string `json:"extra-info"` - Extras map[string]any `json:"-"` } // ParseLogFileByLevelAndTime parses the provided log file line-by-line assuming the file is in ascending time order @@ -161,7 +161,7 @@ func CreateDirectoryAndPath(dirPath string, filename string) error { _, err := os.Stat(dirPath) if os.IsNotExist(err) { - err = os.MkdirAll(dirPath, 0764) + err = os.MkdirAll(dirPath, 0750) if err != nil { return fmt.Errorf("os.MkdirAll(pathToProjectDir, 0764) %w", err) } diff --git a/internal/utils/liquidityManager.go b/internal/utils/liquidityManager.go index 41e3ff04..a39b0b90 100644 --- a/internal/utils/liquidityManager.go +++ b/internal/utils/liquidityManager.go @@ -67,11 +67,11 @@ func CanUseLiquidityManager(backend LightningBackend) bool { } type LiquiditySwap struct { - Amount uint64 `json:"amount"` Id string `json:"id"` + LightningInvoice string `db:"lightning_invoice"` + CheckingId string `db:"checking_id"` State SwapState `json:"state"` Type SwapType `json:"type"` + Amount uint64 `json:"amount"` Expiration uint64 `json:"expiration"` - LightningInvoice string `db:"lightning_invoice"` - CheckingId string `db:"checking_id"` } diff --git a/internal/utils/testing.go b/internal/utils/testing.go index d7d9f2cb..98801d71 100644 --- a/internal/utils/testing.go +++ b/internal/utils/testing.go @@ -8,6 +8,7 @@ import ( "fmt" "io" "log" + "log/slog" "net/http" "os" "strings" @@ -109,7 +110,6 @@ func SetUpLightingNetworkTestEnviroment(ctx context.Context, names string) (test return nil, nil, nil, nil, fmt.Errorf("could not execute newaddress command: %w", err) } - reader := io.Reader(addressReader) buf := make([]byte, 1024) type LndAddress struct { @@ -118,7 +118,7 @@ func SetUpLightingNetworkTestEnviroment(ctx context.Context, names string) (test var address LndAddress for { - n, err := reader.Read(buf) + n, err := addressReader.Read(buf) if n > 0 { index := strings.Index(string(buf[:n]), "{") err := json.Unmarshal(buf[index:n], &address) @@ -183,7 +183,6 @@ func SetUpLightingNetworkTestEnviroment(ctx context.Context, names string) (test return nil, nil, nil, nil, fmt.Errorf("could not get nodeInfo %w ", err) } - reader = io.Reader(getInfoBobReader) buf = make([]byte, 3024) type NodeInfo struct { @@ -196,7 +195,7 @@ func SetUpLightingNetworkTestEnviroment(ctx context.Context, names string) (test var bobInfo NodeInfo for { - n, err := reader.Read(buf) + n, err := getInfoBobReader.Read(buf) if n > 0 { index := strings.Index(string(buf[:n]), "{") err := json.Unmarshal(buf[index:n], &bobInfo) @@ -236,11 +235,10 @@ func SetUpLightingNetworkTestEnviroment(ctx context.Context, names string) (test return nil, nil, nil, nil, fmt.Errorf("could not get nodeInfo %w ", err) } - reader = io.Reader(getInfoBobReaderTwo) buf = make([]byte, 3024) var bobInfoTwo NodeInfo for { - n, err := reader.Read(buf) + n, err := getInfoBobReaderTwo.Read(buf) if n > 0 { index := strings.Index(string(buf[:n]), "{") err := json.Unmarshal(buf[index:n], &bobInfoTwo) @@ -383,6 +381,12 @@ func SetUpLightingNetworkTestEnviroment(ctx context.Context, names string) (test if err != nil { return nil, nil, nil, nil, fmt.Errorf("could not make request %w", err) } + defer func() { + err := resp.Body.Close() + if err != nil { + slog.Error("could not close body from call.", slog.Any("error", err)) + } + }() body, err := io.ReadAll(resp.Body) @@ -417,6 +421,12 @@ func SetUpLightingNetworkTestEnviroment(ctx context.Context, names string) (test if err != nil { return nil, nil, nil, nil, fmt.Errorf("could not make request %w", err) } + defer func() { + // err := walletsRequest.Body.Close() + // if err != nil { + // slog.Error("could not close body from call.", slog.Any("error", err)) + // } + }() walletsRequest.Header.Add("Authorization", "Bearer "+response.AccessToken) walletsRequest.Header.Add("cookie_access_token", response.AccessToken) @@ -425,6 +435,12 @@ func SetUpLightingNetworkTestEnviroment(ctx context.Context, names string) (test if err != nil { return nil, nil, nil, nil, fmt.Errorf("could not make response %w", err) } + defer func() { + err := respWallet.Body.Close() + if err != nil { + slog.Error("could not close body from call.", slog.Any("error", err)) + } + }() body, err = io.ReadAll(respWallet.Body) diff --git a/test/configTest/setup.go b/test/configTest/setup.go index 90e02d26..ebeb4fd3 100644 --- a/test/configTest/setup.go +++ b/test/configTest/setup.go @@ -47,7 +47,7 @@ func WriteConfigFile(file []byte) error { var pathToProjectDir = dir + "/" + mint.ConfigDirName var pathToProjectConfigFile = pathToProjectDir + "/" + mint.ConfigFileName - err = os.WriteFile(pathToProjectConfigFile, file, 0764) + err = os.WriteFile(pathToProjectConfigFile, file, 0600) if err != nil { return fmt.Errorf("os.WriteFile(pathToProjectConfigFile, file, 0764), %w", err) }