⚠️ Upgrading to version 3.0.0 will come with breaking changes! Please follow the migration guide for a smooth transition to the new version.
Version 3 uses new class names:
CashuWallet is now Wallet
CashuMint is now Mint
A wallet can be instantiated by passing a Mint instance, as before, or simply by passing in a mintUrl.
You MUST now call the loadMint() method to complete wallet init.
example:
const mintUrl = 'http://localhost:3338';
const wallet1 = new Wallet(mintUrl); // unit is 'sat'
await wallet1.loadMint(); // wallet is now ready to use
The sub-module exports for the Crypto Library have been removed. All functions are now exported from the main library index.
example:
import { signP2PKProofs } from '@cashu/cashu-ts/crypto/client/NUT11';
import { isP2PKSpendAuthorised } from '@cashu/cashu-ts/crypto/mint/NUT11';
is now:
import { signP2PKProofs, isP2PKSpendAuthorised } from '@cashu/cashu-ts';
Some crypto types have been deduplicated to the main library types:
Proof is now RawProofMintKeys is now RawMintKeysKeyset and KeysetWithKeys have been removed as unusedFunction signature changes:
signP2PKProofs: The optional beStrict param has been replaced with a logger.// third (optional) param:
signP2PKProofs = (
proofs: Proof[], privateKey: string | string[], beStrict = false
): Proof[]
// is now a logger:
signP2PKProofs = (
proofs: Proof[], privateKey: string | string[], logger: Logger = NULL_LOGGER
): Proof[]
OutputType and OutputConfigThe output model for send, receive, mintProofs, and meltProofs has been simplified.
Instead of juggling keepFactory, outputData, and multiple option types, you now use:
OutputType — a tagged union describing one output strategy (random, deterministic, p2pk, etc).OutputConfig — combines keep and send OutputTypes when sending.These are passed as the FOURTH parameter where needed, or expressed more naturally via the new WalletOps fluent builder API.
Example:
// before
const { keep, send } = await wallet.send(amount, proofs, {
includeFees: true,
pubkey: bytesToHex(pubKeyBob),
});
// after (using fluent builder)
const { keep, send } = await wallet.ops
.send(amount, proofs)
.asP2PK({ pubkey: bytesToHex(pubKeyBob) })
.includeFees(true)
.run();
// or using the forth param directly
const customConfig: OutputConfig = {
send: { type: 'p2pk', options: { pubkey: bytesToHex(pubKeyBob) } },
keep: { type: 'deterministic', counter: 0 }, // optional keep shaping
};
const { keep, send } = await wallet.send(
amount,
proofs,
{ includeFees: true },
customConfig, // forth param
);
The builder makes intent explicit and eliminates the need for extra boilerplate.
See the README and integration tests for more usage examples.
OutputData helpers only require id and keys, so OutputDataLike and OutputDataFactory now default to HasKeysetKeys, which just includes id and keys.
This may show up as a TypeScript error when assigning a factory that takes MintKeys to OutputDataFactory without a type argument.
If you want richer typing at the call site, use the new generics: OutputDataLike<YourType> and OutputDataFactory<YourType>.
For example, if your custom factory is typed to MintKeys, declare it as OutputDataFactory<MintKeys>.
// Factory typed to MintKeys
const customFactory: OutputDataFactory<MintKeys> = (amount, keyset) => {
return OutputData.createRandomData(amount, keyset)[0];
};
// Factory typed to default (HasKeysetKeys: { id, keys })
const customFactory: OutputDataFactory = (amount, keysetKeys) => {
return OutputData.createRandomData(amount, keysetKeys)[0];
};
LogLevel is no longer exported as a const object with uppercase values.
It is now a simple string union of lowercase level names.
Fatal level has also been removed:
// New LogLevel shape (lowercase, no 'fatal' level)
export type LogLevel = 'error' | 'warn' | 'info' | 'debug' | 'trace';
// before
const logger = new ConsoleLogger(LogLevel.DEBUG);
// after
const logger = new ConsoleLogger('debug');
This change simplifies the API by removing the enum-like wrapper, avoids the need for extra imports, and makes configuration easier when log levels are provided from JSON or environment variables (which are typically lowercase).
Update any code that referenced LogLevel.XYZ to pass the lowercase string literal instead.
Wallet no longer manages keysets and keys itself. Instead, these are delegated to the KeyChain class, accessed via wallet.keyChain.
The following wallet methods are affected:
wallet.getKeys(id?) -> wallet.keyChain.getKeyset(id?)wallet.getActiveKeyset() -> wallet.keyChain.getCheapestKeyset()wallet.getKeySets() -> wallet.keyChain.getKeysets()wallet.getAllKeys() -> wallet.keyChain.getAllKeys()getDecodedToken signature updategetDecodedToken now prefers a string[] of full keyset IDs as its second argument.
The older signature that accepted keyset-like objects is deprecated.
This matters for keysets v2 support: when decoding outside a wallet instance, pass the full list of keyset IDs the token might reference, for example from wallet.keyChain.getAllKeysetIds().
// before
const token = getDecodedToken(tokenString);
// after
const token = getDecodedToken(tokenString, wallet.keyChain.getAllKeysetIds());
If you already have a wallet for the token's mint and unit, prefer wallet.decodeToken(tokenString).
For pre-wallet init, you can use the new getTokenMetadata function to inspect a token string and find out which mint and unit the token belongs to.
Treat the extracted mint as untrusted input. Validate it against your own trusted-mint policy before creating a Wallet or calling loadMint(), especially in server-side code.
NOTE: Although still optional, the second parameter of getDecodedToken is REQUIRED if you wish to support keysets v2.
Wallet no longer manages subscription events itself. Instead, these are delegated to the WalletEvents class, accessed via wallet.on.
The following wallet methods are affected:
wallet.onMintQuoteUpdates() -> wallet.on.mintQuoteUpdates()wallet.onMeltQuotePaid() -> wallet.on.meltQuotePaid()wallet.onMintQuotePaid() -> wallet.on.mintQuotePaid()wallet.onMeltQuoteUpdates() -> wallet.on.meltQuoteUpdates()wallet.onProofStateUpdates() -> wallet.on.proofStateUpdates()See the README for full details of the WalletEvents API.
The following constants are no longer available:
DEFAULT_DENOMINATION_TARGETDEFAULT_UNITTOKEN_VERSIONTOKEN_PREFIXMintStatic methods The Mint class no longer has static methods. If you wish to call a mint method, simply instantiate a mint first, then call the instance method.
The following method names have changed:
The second parameter (was customRequest) is now an options object in the following methods:
- async meltBolt11(
meltPayload: MeltPayload,
options?: {
customRequest?: RequestFn;
preferAsync?: boolean;
}
)
- async meltBolt12(
meltPayload: MeltPayload,
options?: {
customRequest?: RequestFn;
preferAsync?: boolean;
}
)
Clear and Blind authentication have been simplified and enhanced. Here are the highlights:
CashuAuthMint / CashuAuthWallet have been removed.AuthManager provides "Batteries Included" CAT/BAT management.createAuthWallet() helper wires up a fully authenticated wallet session.OIDCAuth class handles the mechanics of OIDC authenticationauthTokenGetter param with options, including an authProvider.Before: new Mint(mintUrl, customRequest?, legacyAuthTokenGetter?)
After: new Mint(mintUrl, options?: {customRequest?, authProvider?, logger?})
See the examples/auth_mint/ folder for examples of using these in all supported flows.