Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
0ef4bc2
feat(crypto): add bls12-381 primitives for v3 keysets
robwoodgate May 12, 2026
089a701
feat(crypto): widen Point types via CurvePoint tagged union (Phase 2)
robwoodgate May 12, 2026
53ceed1
feat(crypto): wire v3 BLS keysets through NUT-01/13 and keyset-id (Ph…
robwoodgate May 12, 2026
3f41045
feat(crypto): wire v3 OutputData round-trip + tests (Phase 4)
robwoodgate May 13, 2026
de152a2
docs(crypto): cite sources for BLS constants and document v3 wire len…
robwoodgate May 13, 2026
f1d76b9
feat(crypto): close v3 BLS wallet integration gaps (Phase 6)
robwoodgate May 13, 2026
3909a82
chore: update lock and api report
robwoodgate May 13, 2026
1718084
feat(crypto)!: bls phase 7 — v5 type cleanup and review fixes
robwoodgate May 13, 2026
c66f488
build(makefile): add nutshell-bls integration target
robwoodgate May 13, 2026
490a076
chore: stop tracking PLAN.md
robwoodgate May 13, 2026
ccd9d4d
fix(wallet): accept v3 proofs in sendOffline under requireDleq
robwoodgate May 13, 2026
0b6fe2a
test(integration): wire v3 BLS nutshell mint + skip v1/v2 dleq tests
robwoodgate May 13, 2026
9dbe346
refactor(crypto): use isBlsKeyset helper for v3 dispatch
robwoodgate May 13, 2026
71657be
perf(wallet): batch-verify v3 proofs at receive
robwoodgate May 13, 2026
66396df
test(crypto): lock in batch-pairing forgery defence with regression test
robwoodgate May 13, 2026
0cca495
refactor(crypto): derive batch-verify weights via Fiat-Shamir
robwoodgate May 13, 2026
ffdc216
docs(crypto): trim redundant Fiat-Shamir note from batchVerify doc
robwoodgate May 13, 2026
19799d9
feat(auth): wire BLS v3 keysets into BAT verification
robwoodgate May 13, 2026
2e47c4c
feat(examples): add Nutshell BLS auth-mint compose variant
robwoodgate May 13, 2026
598e6d2
docs(crypto): clarify why public Fiat-Shamir weights resist forgery
robwoodgate May 14, 2026
fe5a645
perf(crypto): single-pairing v3 single-proof verify
robwoodgate May 14, 2026
f3370df
feat(crypto): align v3 mint key derivation with Nutshell
robwoodgate May 14, 2026
c9a208f
chore: remove internal link from tsdoc
robwoodgate May 14, 2026
6b35448
test(crypto): lock v3 mint key parity vector against Nutshell
robwoodgate May 15, 2026
5c9875f
fix(crypto): verify v3 BLS pairing inside OutputData.toProof
robwoodgate May 15, 2026
a6f15a7
chore(auth): document redundant v3 pairing check on BAT top-up
robwoodgate May 15, 2026
d078474
fix(crypto): reject base64 keyset ids in isBlsKeyset
robwoodgate May 15, 2026
e585ade
test(integration): match offender-suffix in invalid-DLEQ assertion
robwoodgate May 15, 2026
a7f9bea
test(integration): flatten DLEQ-message assertion
robwoodgate May 15, 2026
1b4981f
chore(crypto): c8-ignore unreachable a==0 guards in NUT01
robwoodgate May 15, 2026
c0c64d3
test(crypto): add CurvePoint helper tests + c8-ignore type-narrows
robwoodgate May 15, 2026
672bca5
refactor(crypto): use pointFromHexG2 directly in v3-aware callers
robwoodgate May 15, 2026
d5a2a0c
refactor(crypto): drop dead parseMintPubKey + MintPubKey union
robwoodgate May 15, 2026
a50f7ac
fix(crypto): correct isBlsKeyset hex parse + 12-char base64 collision
robwoodgate May 15, 2026
04bbb8c
refactor(crypto): tighten isBlsKeyset to canonical hex lengths
robwoodgate May 15, 2026
0b78d18
docs: correct stale v0/v1/v2 keyset naming in two places
robwoodgate May 15, 2026
833981f
fix(crypto): reject identity points in BLS verify to avoid generic Error
robwoodgate May 15, 2026
52ea7dc
fix(crypto): reject identity points at G1/G2 parse boundary
robwoodgate May 15, 2026
2417fcd
fix(crypto): bind mint signature amount to requested output amount
robwoodgate May 15, 2026
8120b9e
test: bump BLS round-trip timeout to absorb cross-env contention
robwoodgate May 15, 2026
2edb318
docs(api): regenerate report for checkProofsStates ProofLike narrowing
robwoodgate May 15, 2026
fe2ca59
test: cover v3-touched error paths in OutputData and utils/core
robwoodgate May 16, 2026
acf96b5
fix(crypto): close NUT-12 amount-validation gap and unify DLEQ helpers
robwoodgate May 16, 2026
6a335ce
fix(model): map toProof parse failures to CTSError with NUT-09 hint
robwoodgate May 16, 2026
36377b5
fix(crypto): harden BLS batch verification against malformed input
robwoodgate May 16, 2026
94e8b8e
fix(crypto): stream sha256 to avoid spread-arg limit in batch derive
robwoodgate May 16, 2026
8078d40
docs(wallet): clarify proofStatesStream graceful-end contract
robwoodgate May 16, 2026
36152d8
feat(wallet)!: proofStatesStream throws on wallet errors
robwoodgate May 16, 2026
9897d09
fix(utils): tighten mapShortKeysetIds length gate
robwoodgate May 17, 2026
4e1ee36
fix(crypto): tighten isBlsKeyset to v3 (0x02) only
robwoodgate May 18, 2026
4784e5c
fix(crypto): align BLS v3 with NUT-00/13 spec hardening
robwoodgate May 21, 2026
3c2c864
test(crypto): pin NUT-00 v3 hex vectors (Y/K/C_1/C_2/challenge)
robwoodgate May 21, 2026
3bfaa9f
fix(utils): lowercase unit and pubkey hex in V2/V3 keyset id derivation
robwoodgate May 21, 2026
31371a6
fix(crypto): remove deprecated DLEQ helper from v5 API
robwoodgate May 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ NUT_IMAGE_RC ?= cashubtc/nutshell:0.18.2
NUT_IMAGE ?= cashubtc/nutshell:0.20.0
NUT_NAME ?= cashu-dev-nutshell

# BLS (v3) Nutshell: no published image yet — build from a local checkout that
# carries v3 support. Default path assumes the worktree sibling layout used
# during the BLS bring-up (../nutshell on feature/bls12-381-v3-keyset, ≥0.21.0
# which emits v3 keysets by default; see cashu/core/base.py).
NUT_BLS_PATH ?= ../nutshell
NUT_BLS_IMAGE ?= cashu-dev-nutshell-bls:local
NUT_BLS_NAME ?= cashu-dev-nutshell-bls

# ------------------------
# Docker envs per dependency
# ------------------------
Expand All @@ -43,7 +51,8 @@ NUT_ENVS = \
-e FAKEWALLET_DELAY_PAYMENT=TRUE \
-e FAKEWALLET_DELAY_OUTGOING_PAYMENT=$(FAKE_DELAY) \
-e FAKEWALLET_DELAY_INCOMING_PAYMENT=$(FAKE_DELAY) \
-e MINT_TRANSACTION_RATE_LIMIT_PER_MINUTE=$(RATE_LIMIT_PM)
-e MINT_TRANSACTION_RATE_LIMIT_PER_MINUTE=$(RATE_LIMIT_PM) \
-e MINT_GLOBAL_RATE_LIMIT_PER_MINUTE=$(RATE_LIMIT_PM)

# ------------------------
# Platform flag
Expand Down Expand Up @@ -86,6 +95,7 @@ print-mint-images:
@echo "CDK_IMAGE_RC=$(CDK_IMAGE_RC)"
@echo "NUT_IMAGE=$(NUT_IMAGE)"
@echo "NUT_IMAGE_RC=$(NUT_IMAGE_RC)"
@echo "NUT_BLS_IMAGE=$(NUT_BLS_IMAGE) (built from $(NUT_BLS_PATH))"

# ------------------------
# Nutshell Targets
Expand Down Expand Up @@ -113,3 +123,23 @@ nutshell-stable-down:

nutshell-rc-down:
$(MAKE) nutshell-down NUT_NAME=cashu-dev-nutshell-rc

# ------------------------
# Nutshell BLS (v3) Targets
# ------------------------
# Built natively (no PLATFORM_FLAG): the base image (python:3.10-slim) is
# multi-arch, and BLS keygen through Rosetta is unusably slow on arm64 hosts.
.PHONY: nutshell-bls-build nutshell-bls-up nutshell-bls-down

nutshell-bls-build:
$(DOCKER) build -t $(NUT_BLS_IMAGE) $(NUT_BLS_PATH)

nutshell-bls-up: nutshell-bls-build
-$(DOCKER) rm -f -v $(NUT_BLS_NAME) >/dev/null 2>&1 || true
$(DOCKER) run -d --name $(NUT_BLS_NAME) \
-p $(BIND_ADDR):$(PORT):3338 \
$(NUT_ENVS) \
$(NUT_BLS_IMAGE) poetry run mint

nutshell-bls-down:
-$(DOCKER) rm -f -v $(NUT_BLS_NAME)
17 changes: 9 additions & 8 deletions docs-src/wallet_events/proof_state_streams.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,20 @@
import { CheckStateEnum } from '@cashu/cashu-ts';
const ac = new AbortController();
(async () => {
for await (const u of wallet.on.proofStatesStream(proofs, { signal: ac.signal })) {
if (u.state === CheckStateEnum.SPENT) {
console.log('Spent proof', u.proof.id);
try {
for await (const u of wallet.on.proofStatesStream(proofs, { signal: ac.signal })) {
if (u.state === CheckStateEnum.SPENT) {
console.log('Spent proof', u.proof.id);
}
}
} catch (e) {
if ((e as Error).name === 'AbortError') return; // ac.abort() ended the loop
console.error('Stream error', e); // websocket / mint RPC failure
}
})();

// later
ac.abort();
```

> **Note:** the subscription is sent to the mint on the first iteration, not when
> `proofStatesStream` is called. Per
> [NUT-17](https://github.com/cashubtc/nuts/blob/main/17.md) the mint replays the
> _current_ state on subscribe, so the latest state is never lost — only intermediate
> transitions before the first iteration are collapsed into that snapshot.
The iterator ends cleanly when the abort signal fires or the consumer breaks out of the loop. Wallet errors (WebSocket failure, RPC error from the mint) are thrown from the iterator — wrap in `try/catch` to recover.
84 changes: 80 additions & 4 deletions etc/cashu-ts.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

```ts

import { Fp2 } from '@noble/curves/abstract/tower.js';
import { WeierstrassPoint } from '@noble/curves/abstract/weierstrass.js';

// @public
Expand Down Expand Up @@ -134,6 +135,12 @@ export class AmountWithUnitError extends CTSError {
constructor(message: string);
}

// @public (undocumented)
export function asBlsG1Point(pt: G1Point): CurvePoint;

// @public (undocumented)
export function asSecpPoint(pt: WeierstrassPoint<bigint>): CurvePoint;

// @public
export function assertSecretKind(allowed: SecretKind | SecretKind[], secret: Secret | string): Secret;

Expand Down Expand Up @@ -205,15 +212,34 @@ export type BatchMintRequest = {
signatures?: Array<string | null>;
};

// @public
export function batchVerifyUnblindedSignatureBls(items: Array<{
K2: G2Point;
C: G1Point;
secret: Uint8Array;
}>): boolean;

// @public
export function blindMessage(secret: Uint8Array, r?: bigint): RawBlindedMessage;

// @public
export function blindMessageBls(secret: Uint8Array, r?: bigint): RawBlindedMessage;

// @public (undocumented)
export type BlindSignature = {
C_: WeierstrassPoint<bigint>;
id: string;
};

// @public
export const BLS_FR_ORDER: bigint;

// @public
export const BLS_G2_GENERATOR: WeierstrassPoint<Fp2>;

// @public
export const BLS_HASH_TO_CURVE_DST = "CASHU_BLS12_381_G1_XMD:SHA-256_SSWU_RO_";

// @public (undocumented)
export type CancellerLike = SubscriptionCanceller | Promise<SubscriptionCanceller>;

Expand Down Expand Up @@ -272,6 +298,9 @@ export class ConsoleLogger implements Logger {
// @public (undocumented)
export function constructUnblindedSignature(blindSig: BlindSignature, r: bigint, secret: Uint8Array, key: WeierstrassPoint<bigint>): UnblindedSignature;

// @public (undocumented)
export function constructUnblindedSignatureBls(blindSig: BlindSignature, r: bigint, secret: Uint8Array): UnblindedSignature;

// @public
export interface CounterRange {
// (undocumented)
Expand Down Expand Up @@ -303,6 +332,9 @@ export function createAuthWallet(mintUrl: string, options?: {
// @public (undocumented)
export function createBlindSignature(B_: WeierstrassPoint<bigint>, privateKey: Uint8Array, id: string): BlindSignature;

// @public
export function createBlindSignatureBls(B_: G1Point, privateKey: Uint8Array, id: string): BlindSignature;

// @public
export const createDLEQProof: (B_: WeierstrassPoint<bigint>, a: Uint8Array) => DLEQ;

Expand Down Expand Up @@ -347,6 +379,15 @@ export class CTSError extends Error {
readonly cause?: unknown;
}

// @public
export type CurvePoint = {
kind: 'secp';
pt: WeierstrassPoint<bigint>;
} | {
kind: 'blsG1';
pt: G1Point;
};

// @public
export function decodePaymentRequest(paymentRequest: string): PaymentRequest_2;

Expand Down Expand Up @@ -418,6 +459,12 @@ export type Enumerate<N extends number, Acc extends number[] = []> = Acc['length
// @public
export function findSigningKey(pubkey: string, privkeys: string | string[]): string;

// @public (undocumented)
export type G1Point = WeierstrassPoint<bigint>;

// @public (undocumented)
export type G2Point = WeierstrassPoint<Fp2>;

// @public
export function getDataField(secret: Secret | string): string;

Expand All @@ -435,6 +482,9 @@ export function getEncodedToken(token: Token, opts?: {
// @public
export function getEncodedTokenBinary(token: Token): Uint8Array;

// @public
export function getG2PubKeyFromPrivKey(privKey: Uint8Array): Uint8Array<ArrayBufferLike>;

// @public
export function getHTLCWitnessPreimage(witness: Proof['witness']): string | undefined;

Expand Down Expand Up @@ -574,6 +624,9 @@ export function hash_e(pubkeys: Array<WeierstrassPoint<bigint>>): Uint8Array;
// @public (undocumented)
export function hashToCurve(secret: Uint8Array): WeierstrassPoint<bigint>;

// @public (undocumented)
export function hashToCurveBls(secret: Uint8Array): G1Point;

// @public
export type HasKeysetId = {
id: string;
Expand Down Expand Up @@ -617,6 +670,9 @@ export function injectWebSocketImpl(ws: typeof WebSocket): void;
// @public (undocumented)
export type IntRange<F extends number, T extends number> = Exclude<Enumerate<T>, Enumerate<F>>;

// @public
export function isBlsKeyset(keysetId: string): boolean;

// @public
export function isHTLCSpendAuthorised(proof: Proof, logger?: Logger, message?: string): boolean;

Expand Down Expand Up @@ -1566,6 +1622,18 @@ export function pointFromBytes(bytes: Uint8Array): WeierstrassPoint<bigint>;
// @public (undocumented)
export function pointFromHex(hex: string): WeierstrassPoint<bigint>;

// @public
export function pointFromHexAuto(hex: string): CurvePoint;

// @public (undocumented)
export function pointFromHexG1(hex: string): G1Point;

// @public (undocumented)
export function pointFromHexG2(hex: string): G2Point;

// @public (undocumented)
export function pointToHex(p: CurvePoint): string;

// @public
export type PostRestorePayload = {
outputs: SerializedBlindedMessage[];
Expand Down Expand Up @@ -2012,8 +2080,8 @@ export type UnblindedSignature = {
// @public (undocumented)
export function unblindSignature(C_: WeierstrassPoint<bigint>, r: bigint, A: WeierstrassPoint<bigint>): WeierstrassPoint<bigint>;

// @public @deprecated (undocumented)
export function verifyDleqIfPresent(proof: Proof, keyset: HasKeysetKeys): boolean;
// @public
export function unblindSignatureBls(C_: G1Point, r: bigint): G1Point;

// @public (undocumented)
export const verifyDLEQProof: (dleq: DLEQ, B_: WeierstrassPoint<bigint>, C_: WeierstrassPoint<bigint>, A: WeierstrassPoint<bigint>) => boolean;
Expand All @@ -2035,9 +2103,17 @@ export function verifyMintQuoteSignature(pubkey: string, quote: string, blindedM
// @public
export function verifyP2PKSpendingConditions(proof: Proof, logger?: Logger, message?: string): P2PKVerificationResult;

// @public (undocumented)
// @public
export function verifyProofsForReceive(proofs: ProofLike[], getKeyset: (id: string) => HasKeysetKeys, opts?: {
requireDleq?: boolean;
}): void;

// @public
export function verifyUnblindedSignature(proof: UnblindedSignature, privKey: Uint8Array): boolean;

// @public
export function verifyUnblindedSignatureBls(K2: G2Point, C: G1Point, secret: Uint8Array): boolean;

// @public
export class Wallet {
constructor(mint: Mint | string, options?: {
Expand Down Expand Up @@ -2071,7 +2147,7 @@ export class Wallet {
checkMintQuoteBolt11(quote: string | MintQuoteBolt11Response): Promise<MintQuoteBolt11Response>;
checkMintQuoteBolt12(quote: string): Promise<MintQuoteBolt12Response>;
checkMintQuoteOnchain(quote: string): Promise<MintQuoteOnchainResponse>;
checkProofsStates(proofs: Array<Pick<Proof, 'secret'>>): Promise<ProofState[]>;
checkProofsStates(proofs: Array<Pick<ProofLike, 'secret' | 'id'>>): Promise<ProofState[]>;
completeBatchMint(batchPreview: BatchMintPreview<Pick<MintQuoteBaseResponse, 'quote'>>): Promise<Proof[]>;
completeMelt<TQuote extends Pick<MeltQuoteBaseResponse, 'quote'> = MeltQuoteBaseResponse>(meltPreview: MeltPreview<TQuote>, privkey?: string | string[], options?: CompleteMeltOptions): Promise<MeltProofsResponse<TQuote>>;
// @deprecated (undocumented)
Expand Down
14 changes: 7 additions & 7 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ Run `make print-mint-images` to see which versions are pinned. The auth demos ha

## Examples

| File | Mint required | Description |
| ------------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `simpleWallet_example.ts` | `DEV=1 make nutshell-up` (or `cdk-up`) | End-to-end BOLT11 mint, send, receive, and melt against a fake-wallet LN backend. |
| `bolt12Wallet_example.ts` | `DEV=1 make cdk-up` | Reusable BOLT12 offer flow: mint via BOLT11, pay the offer, mint again from accumulated payments. CDK's fakewallet handles both BOLT11 and BOLT12. |
| `onchain_example.ts` | none (uses public test mint) | Onchain (NUT-30) mint and melt against `https://onchain.cashudevkit.org` on Mutinynet. **Interactive** — pauses while you fund the printed address from the Mutinynet faucet, then continues automatically once the mint detects 2 confirmations. |
| `auth_mint/` | Keycloak + CDK mint via docker | OAuth2 / OIDC blind-auth (NUT-21 / NUT-22) demos. See `auth_mint/Makefile` (`make up`, `make demo-device`, `make down`). |
| `paymentApi_example.js` | — | Code snippet for receiving locked ecash inside a Firebase Cloud Function. Not runnable standalone. |
| File | Mint required | Description |
| ------------------------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `simpleWallet_example.ts` | `DEV=1 make nutshell-up` (or `cdk-up`) | End-to-end BOLT11 mint, send, receive, and melt against a fake-wallet LN backend. |
| `bolt12Wallet_example.ts` | `DEV=1 make cdk-up` | Reusable BOLT12 offer flow: mint via BOLT11, pay the offer, mint again from accumulated payments. CDK's fakewallet handles both BOLT11 and BOLT12. |
| `onchain_example.ts` | none (uses public test mint) | Onchain (NUT-30) mint and melt against `https://onchain.cashudevkit.org` on Mutinynet. **Interactive** — pauses while you fund the printed address from the Mutinynet faucet, then continues automatically once the mint detects 2 confirmations. |
| `auth_mint/` | Keycloak + CDK mint via docker, **or** Keycloak + locally-built Nutshell BLS mint | OAuth2 / OIDC blind-auth (NUT-21 / NUT-22) demos. CDK variant: `make up`, `make demo` (or `demo-device` / `demo-pkce`), `make down`. Nutshell BLS variant (exercises v3 BLS BAT verification): `make nutshell-up`, `make nutshell-demo` (or `nutshell-demo-device` / `nutshell-demo-pkce`), `make nutshell-down` — requires a sibling `../nutshell` checkout on a branch with cashubtc/nutshell#1004 (override path via `NUT_BLS_PATH=…`). |
| `paymentApi_example.js` | — | Code snippet for receiving locked ecash inside a Firebase Cloud Function. Not runnable standalone. |

## Notes

Expand Down
47 changes: 47 additions & 0 deletions examples/auth_mint/Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# One-liner setup / teardown for CDK Mint + Keycloak demo
#
# CDK targets (default compose): up / down / demo / demo-ci / logs / clean
# Nutshell BLS targets: nutshell-up / nutshell-down / nutshell-demo
# nutshell-demo-ci / nutshell-logs / nutshell-clean
# Nutshell builds from $(NUT_BLS_PATH) (default ../../../nutshell).

COMPOSE = docker compose
COMPOSE_NUT = $(COMPOSE) -f docker-compose-nutshell.yml
DEMO_CMD = npx tsx auth_password_example.ts
DEMO_DEVA = npx tsx auth_device_example.ts
DEMO_PKCE = npx tsx auth_pkce_example.ts
Expand Down Expand Up @@ -43,3 +49,44 @@ demo-pkce:
clean: down
@echo "🧽 Removing any leftover volumes..."
docker volume prune -f

# ------------------------
# Nutshell BLS (v3) variant — Keycloak + locally-built Nutshell auth mint
# ------------------------
.PHONY: nutshell-up nutshell-down nutshell-demo nutshell-demo-device nutshell-demo-pkce nutshell-demo-ci nutshell-logs nutshell-clean

nutshell-demo-ci:
$(COMPOSE_NUT) up -d --build --force-recreate
@sleep 20
$(DEMO_CMD)
$(COMPOSE_NUT) down -v

nutshell-up:
@echo "🚀 Starting Keycloak + Nutshell (BLS, built from $(or $(NUT_BLS_PATH),../../../nutshell))..."
$(COMPOSE_NUT) up -d --build --force-recreate
@echo "⌛ Waiting for Keycloak + mint to be ready (approx 20s)..."
@sleep 20
@echo "✅ Containers started. Run 'make nutshell-demo' to execute the auth flow."

nutshell-down:
@echo "🧹 Stopping and removing Nutshell containers..."
$(COMPOSE_NUT) down -v

nutshell-logs:
$(COMPOSE_NUT) logs -f

nutshell-demo:
@echo "🧪 Running PASSWORD Auth demo against Nutshell mint..."
$(DEMO_CMD)

nutshell-demo-device:
@echo "🧪 Running DEVICE Auth demo against Nutshell mint..."
$(DEMO_DEVA)

nutshell-demo-pkce:
@echo "🧪 Running PKCE Auth demo against Nutshell mint..."
$(DEMO_PKCE)

nutshell-clean: nutshell-down
@echo "🧽 Removing any leftover volumes..."
docker volume prune -f
1 change: 1 addition & 0 deletions examples/auth_mint/cashu-realm.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"realm": "cashu",
"enabled": true,
"sslRequired": "none",

"defaultRoles": ["offline_access", "uma_authorization"],

Expand Down
Loading
Loading