Compare commits
5 commits
Author | SHA1 | Date | |
---|---|---|---|
d5e91a356d | |||
c1d309ba09 | |||
03163e9f4a | |||
3bbeb113a7 | |||
4a177547fb |
5 changed files with 42 additions and 22 deletions
BIN
bun.lockb
BIN
bun.lockb
Binary file not shown.
|
@ -17,7 +17,7 @@
|
||||||
"typescript": "^5.3.2"
|
"typescript": "^5.3.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cashu/cashu-ts": "^1.2.1",
|
"@cashu/cashu-ts": "^2.0.0",
|
||||||
"@nostr-dev-kit/ndk": "^2.10.7"
|
"@nostr-dev-kit/ndk": "^2.10.7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
46
src/cashu.ts
46
src/cashu.ts
|
@ -1,6 +1,6 @@
|
||||||
import {getDecodedToken, type Proof} from "@cashu/cashu-ts";
|
import { CashuMint, CashuWallet, getDecodedToken, getEncodedToken } from "@cashu/cashu-ts";
|
||||||
import type {TokenEntry} from "@cashu/cashu-ts";
|
import type { Token } from "@cashu/cashu-ts";
|
||||||
import {getMailSubscriptionDurationForSats} from "./general.ts";
|
import { getMailSubscriptionDurationForSats } from "./general.ts";
|
||||||
|
|
||||||
class InvalidTokenException extends Error {
|
class InvalidTokenException extends Error {
|
||||||
constructor(message: string) {
|
constructor(message: string) {
|
||||||
|
@ -20,31 +20,39 @@ export class TokenInfo {
|
||||||
] as const;
|
] as const;
|
||||||
private static readonly MIN_AMOUNT = 21 as const;
|
private static readonly MIN_AMOUNT = 21 as const;
|
||||||
|
|
||||||
public readonly tokens: TokenEntry[];
|
public readonly token: Token;
|
||||||
public readonly amount: number;
|
public readonly amount: number;
|
||||||
public readonly mint: string;
|
|
||||||
public readonly proofs: Proof[];
|
get mint() {
|
||||||
|
return this.token.mint;
|
||||||
|
}
|
||||||
|
|
||||||
|
get proofs() {
|
||||||
|
return this.token.proofs;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(protected readonly tokenString: string) {
|
constructor(protected readonly tokenString: string) {
|
||||||
const decodedTokenData = getDecodedToken(tokenString);
|
const token = getDecodedToken(tokenString);
|
||||||
const tokens = decodedTokenData.token;
|
|
||||||
const amount = tokens.flatMap(t => t.proofs).reduce((c, x) => c + x.amount, 0);
|
|
||||||
|
|
||||||
if (decodedTokenData.unit !== 'sat')
|
const amount = token.proofs.reduce((c, x) => c + x.amount, 0);
|
||||||
throw new InvalidTokenException('Invalid token format. We only accept tokens denominated in sats');
|
|
||||||
if(decodedTokenData.token.length === 0)
|
if (!TokenInfo.ALLOWED_MINTS.includes(token.mint))
|
||||||
throw new InvalidTokenException('Invalid token format. We only accept tokens with at least one proof');
|
|
||||||
if (tokens.slice(1).some(t => t.mint !== tokens[0].mint))
|
|
||||||
throw new InvalidTokenException('Invalid token format. We only accept tokens with the same mint');
|
|
||||||
if (!TokenInfo.ALLOWED_MINTS.includes(tokens[0].mint))
|
|
||||||
throw new InvalidTokenException('Unsupported mint');
|
throw new InvalidTokenException('Unsupported mint');
|
||||||
if (amount < TokenInfo.MIN_AMOUNT)
|
if (amount < TokenInfo.MIN_AMOUNT)
|
||||||
throw new InvalidTokenException(`Invalid amount. Minimum required: ${TokenInfo.MIN_AMOUNT} sats`);
|
throw new InvalidTokenException(`Invalid amount. Minimum required: ${TokenInfo.MIN_AMOUNT} sats`);
|
||||||
|
|
||||||
this.tokens = tokens;
|
this.token = token;
|
||||||
this.amount = amount;
|
this.amount = amount;
|
||||||
this.mint = tokens[0].mint;
|
}
|
||||||
this.proofs = tokens.flatMap(t => t.proofs);
|
|
||||||
|
async receive(): Promise<string> {
|
||||||
|
const mint = new CashuMint(this.mint);
|
||||||
|
const wallet = new CashuWallet(mint);
|
||||||
|
const newToken = await wallet.receive(this.tokenString);
|
||||||
|
return getEncodedToken({
|
||||||
|
mint: this.mint,
|
||||||
|
proofs: newToken
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
export * from "./cashu";
|
export * from "./cashu.ts";
|
||||||
export * from "./general";
|
export * from "./general.ts";
|
||||||
export * from "./nostr.ts";
|
export * from "./nostr.ts";
|
||||||
export * from "./email.ts";
|
export * from "./email.ts";
|
12
src/nostr.ts
12
src/nostr.ts
|
@ -1,6 +1,7 @@
|
||||||
import NDK, {NDKEvent, NDKPrivateKeySigner, NDKUser} from "@nostr-dev-kit/ndk";
|
import NDK, {NDKEvent, NDKPrivateKeySigner, NDKUser} from "@nostr-dev-kit/ndk";
|
||||||
import {generateSecretKey} from "nostr-tools";
|
import {generateSecretKey} from "nostr-tools";
|
||||||
import {randomTimeUpTo2DaysInThePast} from "./general.ts";
|
import {randomTimeUpTo2DaysInThePast} from "./general.ts";
|
||||||
|
import {decode as nip19Decode, npubEncode} from "nostr-tools/nip19";
|
||||||
|
|
||||||
export async function encryptEventForRecipient(
|
export async function encryptEventForRecipient(
|
||||||
ndk: NDK,
|
ndk: NDK,
|
||||||
|
@ -25,3 +26,14 @@ export async function encryptEventForRecipient(
|
||||||
giftWrap.ndk = ndk;
|
giftWrap.ndk = ndk;
|
||||||
return giftWrap;
|
return giftWrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function npubToPubKeyString(npub: string) {
|
||||||
|
const decoded = nip19Decode(npub);
|
||||||
|
if (decoded.type !== 'npub')
|
||||||
|
throw new Error('Invalid npub');
|
||||||
|
return decoded.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function pubKeyStringToNpub(pubKey: string) {
|
||||||
|
return npubEncode(pubKey);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue