1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
[]
= "https://mint.thesimplekid.dev/"
= "127.0.0.1"
= 8085
= ""
# input_fee_ppk = 0
# enable_info_page = true
# Set keyset version preference.
# true = Force upgrade to V2 (Version01).
# false = Force downgrade to V1 (Version00).
# If unset (default), existing keysets are preserved, but new ones use V2.
# use_keyset_v2 = true
[]
# Prefer explicit fields over inline tables for readability and ease of overrides
= 600
= 120
[]
# Where to output logs: "stderr" (standard error stream), "file", or "both" (default: "both")
# output = "both"
# Log level for console output (default: "info")
# console_level = "info"
# Log level for file output (default: "debug")
# file_level = "debug"
[]
= false
# address = "127.0.0.1"
# port = 8086
#[prometheus]
#enabled = true
#address = "127.0.0.1"
#port = 9090
#
[]
# memory or redis
= "memory"
= 60
= 60
# `key_prefix` and `connection_string` required for redis
# key_prefix = "mintd"
# connection_string = "redis://localhost"
# For redis-cluster:
# use_cluster = true
# cluster_nodes = ["redis://node1:6379", "redis://node2:6379"]
# NOTE: If [mint_management_rpc] is enabled these values will only be used on first start up.
# Further changes must be made through the rpc.
[]
# name = "cdk-mintd mutiney net mint"
# Hex pubkey of mint
# pubkey = ""
# description = "These are not real sats for testing only"
# description_long = "A longer mint for testing"
# motd = "Hello world"
# icon_url = "https://this-is-a-mint-icon-url.com/icon.png"
# contact_email = "hello@cashu.me"
# Nostr pubkey of mint (Hex)
# contact_nostr_public_key = ""
# tos_url = "https://example.com/terms-of-service"
[]
# Database engine (sqlite/postgres) defaults to sqlite
= "sqlite"
# PostgreSQL configuration (when engine = "postgres")
[]
# PostgreSQL connection URL
# Can also be set via CDK_MINTD_POSTGRES_URL or CDK_MINTD_DATABASE_URL environment variables
# Environment variables take precedence over config file settings
= "postgresql://user:password@localhost:5432/cdk_mint"
# TLS mode: "disable", "prefer", "require" (optional, defaults to "disable")
= "disable"
# Maximum number of connections in the pool (optional, defaults to 20)
= 20
# Connection timeout in seconds (optional, defaults to 10)
= 10
# Auth database configuration (optional, only used when auth is enabled)
[]
# PostgreSQL connection URL for authentication database
# Can also be set via CDK_MINTD_AUTH_POSTGRES_URL environment variable
# Environment variables take precedence over config file settings
= "postgresql://user:password@localhost:5432/cdk_mint_auth"
# TLS mode: "disable", "prefer", "require" (optional, defaults to "disable")
= "disable"
# Maximum number of connections in the pool (optional, defaults to 20)
= 20
# Connection timeout in seconds (optional, defaults to 10)
= 10
# Lightning backends. Use [ln] for a single backend, or repeat [[ln]] for one
# backend per unit. Duplicate (unit, method) pairs are rejected at startup.
# [[ln]]
# ln_backend = "cln"
# unit = "sat"
# [[ln]]
# ln_backend = "lnbits"
# unit = "msat"
#
# Fake wallet multi-unit testing uses one fakewallet [[ln]] entry per unit:
# [[ln]]
# ln_backend = "fakewallet"
# unit = "sat"
# [[ln]]
# ln_backend = "fakewallet"
# unit = "usd"
[]
# Required ln backend `cln`, `lnd`, `fakewallet`, 'lnbits', 'ldknode' or 'none' (if onchain is enabled)
# NOTE: fakewallet is isolated testing mode and cannot be mixed with real payment backends.
= "fakewallet"
# unit = "sat" # Optional, defaults to "sat"
# min_mint=1
# max_mint=500000
# min_melt=1
# max_melt=500000
[]
# Required onchain backend `bdk`, `fakewallet`, or `none`.
# If `ln_backend` is set to `none`, `onchain_backend` MUST be set to a valid backend (e.g., `bdk`).
# Use `fakewallet` with `ln_backend = "fakewallet"` for fully fake rails, or with
# `ln_backend = "none"` for fake onchain-only testing.
= "fakewallet"
# min_mint=1000
# max_mint=1000000
# min_melt=1000
# max_melt=1000000
# [bdk]
# mnemonic = "your twelve or twenty-four word mnemonic phrase here"
# network = "regtest" # REQUIRED: mainnet, testnet, signet, regtest (no default)
# num_confs = 3 # Number of confirmations required (must be >= 1; 0 is rejected)
# min_receive_amount_sat = 1000 # Minimum inbound amount that counts toward minting
# min_send_amount_sat = 546 # Minimum outbound melt/send amount (must be >= 1)
# chain_source_type = "bitcoinrpc" # esplora, bitcoinrpc
#
# # Bitcoin RPC configuration (when chain_source_type = "bitcoinrpc")
# # If omitted, defaults to 127.0.0.1:18443 with user/pass
# # bitcoind_rpc_host = "127.0.0.1"
# # bitcoind_rpc_port = 18443
# # bitcoind_rpc_user = "user"
# # bitcoind_rpc_password = "pass"
#
# # Esplora configuration (when chain_source_type = "esplora")
# # esplora_url = "https://mutinynet.com/api"
# # Keep low for public Esplora servers to avoid rate limits.
# # esplora_parallel_requests = 1
#
# # === Onchain batch + fee-estimation config (BDK) ===
# #
# # Outgoing melts are batched into a single on-chain transaction per tier.
# # Quotes are issued *before* BDK builds the final transaction, so the
# # reserved fee is an upper-bound estimate. Any excess is returned to the
# # wallet as change in the melt flow. The defaults intentionally
# # over-reserve to avoid under-quoting (which would fail the melt at
# # broadcast time).
# #
# # At low fee rates (e.g. ~1 sat/vB on testnet/signet/regtest), the fixed
# # safety margin dominates the reserve. For a 1000-sat P2WPKH melt at
# # ~1 sat/vB, the actual paid fee is typically ~140-280 sats while the
# # default reserve quotes ~700-900 sats. Operators running on low-fee
# # networks should lower `quote_fixed_safety_sat` and
# # `quote_safety_multiplier`; the defaults are tuned for mainnet where
# # fee-rate spikes between quote and broadcast are common.
# #
# # Every field below has a matching CDK_MINTD_BDK_* env-var override; see
# # crates/cdk-mintd/src/env_vars/bdk.rs.
# # [bdk.batch_config]
# # By default only Immediate is exposed. Uncomment and choose any subset of
# # the existing tiers to expose more fee options; order defines fee_index.
# # Warning: Standard and Economy delay transaction construction so more
# # melts can share one on-chain transaction. On mints without high melt
# # volume, delayed batching increases the chance that a quote fails at
# # consumption time because fee conditions or available coins changed
# # before broadcast. Low-volume mints should keep Immediate only.
# # fee_options = ["immediate", "standard", "economy"]
# #
# # # --- Batching cadence ---
# # poll_interval_secs = 30 # batch processor wake/check interval
# # max_batch_size = 50 # max intents per batch transaction
# # target_block_time_secs = 600 # maps advertised blocks to default wait time
# # standard_deadline_secs = 3600 # optional override; default is 6 blocks * target_block_time_secs
# # economy_deadline_secs = 86400 # optional override; default is 144 blocks * target_block_time_secs
# #
# # # --- Fee-rate sourcing ---
# # fee_fallback_sat_per_vb = 2.0 # used only if chain source errors
# # fee_cache_ttl_secs = 60 # how long to reuse a tier's rate
# #
# # # --- Quote-time safety margins ---
# # quote_max_input_count = 24 # cap on inputs reserved in the vbyte estimate
# # quote_fixed_safety_sat = 500 # flat sats added after the raw fee estimate
# # quote_safety_multiplier = 1.25 # multiplicative padding on the raw estimate
# #
# # Example overrides for low-fee networks (signet / testnet / regtest):
# # quote_fixed_safety_sat = 100
# # quote_safety_multiplier = 1.10
# #
# # Note: a few input-weight heuristics in crates/cdk-bdk/src/fee.rs
# # (QUOTE_INPUT_VBYTES, the +1 padding input) are hard-coded and cannot be
# # tuned via config. They contribute a smaller but non-zero over-estimate.
# [cln]
# rpc_path = "/path/to/.lightning/bitcoin/lightning-rpc"
# bolt12 = true # Optional, defaults to true
# expose_private_channels = false # Optional, defaults to false. Include private channel route hints in bolt11 invoices.
# fee_percent = 0.02 # Optional, defaults to 2%
# reserve_fee_min = 2 # Optional, defaults to 2 sats
# [lnbits]
# admin_api_key = ""
# invoice_api_key = ""
# lnbits_api = ""
# fee_percent = 0.02 # Optional, defaults to 2%
# reserve_fee_min = 2 # Optional, defaults to 2 sats
# Note: Only LNBits v1 API is supported (websocket-based)
# [lnd]
# address = "https://localhost:10009"
# cert_file = "/path/to/.lnd/tls.cert"
# macaroon_file = "/path/to/.lnd/data/chain/bitcoin/mainnet/admin.macaroon"
# fee_percent = 0.02 # Optional, defaults to 2%
# reserve_fee_min = 2 # Optional, defaults to 2 sats
# [ldk_node]
# fee_percent = 0.02 # Optional, defaults to 2%
# reserve_fee_min = 2 # Optional, defaults to 2 sats
# bitcoin_network = "signet" # REQUIRED: mainnet, testnet, signet, regtest (no default)
# chain_source_type = "esplora" # esplora, bitcoinrpc
#
# # IMPORTANT: LDK Node Seed Configuration
# # For NEW nodes: ldk_node_mnemonic MUST be set. This is the BIP39 mnemonic used to derive
# # the LDK node's keys. Keep this secure and backed up!
# # For EXISTING nodes: If omitted, the node will use its stored seed from the storage directory.
# # This maintains backward compatibility with nodes created before this configuration was added.
# ldk_node_mnemonic = "your twelve or twenty-four word mnemonic phrase here"
#
# # Mutinynet configuration (recommended for testing)
# esplora_url = "https://mutinynet.com/api"
# gossip_source_type = "rgs" # Use RGS for better performance
# rgs_url = "https://rgs.mutinynet.com/snapshot/0"
# storage_dir_path = "~/.cdk-ldk-node/mutinynet"
# log_dir_path = ".cdk-ldk-node/ldk-node/ldk_node.log"
#
# # Testnet configuration
# # bitcoin_network = "testnet"
# # esplora_url = "https://blockstream.info/testnet/api"
# # rgs_url = "https://rapidsync.lightningdevkit.org/snapshot"
# # storage_dir_path = "~/.cdk-ldk-node/testnet"
#
# # Mainnet configuration (CAUTION: Real Bitcoin!)
# # bitcoin_network = "mainnet"
# # esplora_url = "https://blockstream.info/api"
# # rgs_url = "https://rapidsync.lightningdevkit.org/snapshot"
# # storage_dir_path = "~/.cdk-ldk-node/mainnet"
#
# # Bitcoin RPC configuration (when chain_source_type = "bitcoinrpc")
# bitcoind_rpc_host = "127.0.0.1"
# bitcoind_rpc_port = 18443
# bitcoind_rpc_user = "testuser"
# bitcoind_rpc_password = "testpass"
#
# # Node configuration
# ldk_node_host = "127.0.0.1"
# ldk_node_port = 8090
#
# # Gossip source configuration
# gossip_source_type = "p2p" # p2p (direct peer-to-peer) or rgs (rapid gossip sync)
#
# # Webserver configuration for LDK node management interface
# webserver_host = "127.0.0.1" # Default: 127.0.0.1
# webserver_port = 0 # 0 = auto-assign available port
[]
= 0.02
= 1
# Custom payment methods advertised by the fake wallet.
# Each table entry scopes a method to one unit.
= [
{ = "paypal", = "sat" },
{ = "venmo", = "usd" },
]
# Bare method names are enabled for every supported unit:
# custom_payment_methods = ["paypal"]
#
# Set to [] to disable fake custom methods:
# custom_payment_methods = []
= 1
= 3
# Optional keyset rotations to create inactive/expired test keysets
# Each rotation creates a keyset that gets rotated out during mint build
# unit: currency unit (e.g. "sat", "usd")
# version: "v1" (Version00) or "v2" (Version01)
# input_fee_ppk: input fee in parts per thousand (default: 0)
# expired: if true, keyset is created with a past expiry timestamp (default: false)
#
# [[fake_wallet.keyset_rotations]]
# unit = "sat"
# version = "v1"
# input_fee_ppk = 0
# expired = true
#
# [[fake_wallet.keyset_rotations]]
# unit = "sat"
# version = "v2"
# input_fee_ppk = 0
# expired = false
# [grpc_processor]
# gRPC Payment Processor configuration
# addr = "127.0.0.1"
# port = 50051
# tls_dir = "/path/to/tls"
#
# Note: To support custom payment methods (e.g., paypal, venmo, cashapp),
# your gRPC payment processor should return them in the `custom` field of
# the get_settings() response. The mint will automatically create routes
# for these methods (e.g., /v1/mint/quote/paypal, /v1/mint/paypal, etc.)
# [auth]
# Set to true to enable authentication features (defaults to false)
# auth_enabled = false
# openid_discovery = "http://127.0.0.1:8080/realms/cdk-test-realm/.well-known/openid-configuration"
# openid_client_id = "cashu-client"
# mint_max_bat=50
# Authentication settings for endpoints
# Options: "clear", "blind", "none" (none = disabled)
# mint = "blind"
# get_mint_quote = "none"
# check_mint_quote = "none"
# melt = "none"
# get_melt_quote = "none"
# check_melt_quote = "none"
# swap = "blind"
# restore = "blind"
# check_proof_state = "none"
# Transaction limits for DoS protection (optional, defaults shown)
[]
# Maximum number of inputs allowed per transaction (swap/melt)
= 1000
# Maximum number of outputs allowed per transaction (mint/swap/melt)
= 1000