diff --git a/src/index.ts b/src/index.ts index acb940e..a06ad01 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,5 +6,6 @@ export * as l402 from "./l402"; export * as boostagrams from "./podcasting2/boostagrams"; export * as fiat from "./utils/fiat"; export * as nostr from "./utils/nostr"; +export * from "./utils/Amount"; export { fetchWithL402, sendBoostagram, LightningAddress, Invoice }; export * from "./types"; diff --git a/src/utils/Amount.test.ts b/src/utils/Amount.test.ts new file mode 100644 index 0000000..f12b890 --- /dev/null +++ b/src/utils/Amount.test.ts @@ -0,0 +1,20 @@ +import { resolveAmount, SATS } from "./Amount"; + +describe("Amount", () => { + test("SATS", async () => { + const amount = SATS(10); + expect(amount.satoshi).toBe(10); + }); + test("resolveAmount", async () => { + const resolved = await resolveAmount({ satoshi: 10 }); + expect(resolved.satoshi).toBe(10); + expect(resolved.millisat).toBe(10_000); + }); + test("resolveAmount async", async () => { + const resolved = await resolveAmount({ + satoshi: new Promise((resolve) => setTimeout(() => resolve(10), 300)), + }); + expect(resolved.satoshi).toBe(10); + expect(resolved.millisat).toBe(10_000); + }); +}); diff --git a/src/utils/Amount.ts b/src/utils/Amount.ts new file mode 100644 index 0000000..480f2f1 --- /dev/null +++ b/src/utils/Amount.ts @@ -0,0 +1,22 @@ +/** + * An amount in satoshis + */ +export type Amount = { satoshi: number } | { satoshi: Promise }; + +export const SATS: (amount: number) => Amount = (amount) => ({ + satoshi: amount, +}); + +/** + * Resolve a satoshi amount, possibly from a promise (e.g. from fiat conversion) + */ +export async function resolveAmount( + amount: Amount, +): Promise<{ satoshi: number; millisat: number }> { + const satoshi = await Promise.resolve(amount.satoshi); + + return { + satoshi: satoshi, + millisat: satoshi * 1000, + }; +} diff --git a/src/utils/fiat/FiatAmount.test.ts b/src/utils/fiat/FiatAmount.test.ts new file mode 100644 index 0000000..b644a54 --- /dev/null +++ b/src/utils/fiat/FiatAmount.test.ts @@ -0,0 +1,29 @@ +import { resolveAmount } from "../Amount"; +import { USD } from "./FiatAmount"; +import fetchMock from "jest-fetch-mock"; + +describe("FiatAmount", () => { + test("interoperable with Amount", async () => { + fetchMock.mockIf(/.*/, (_) => { + return Promise.resolve( + JSON.stringify({ + code: "USD", + symbol: "$", + rate: "77135.00", + rate_float: 77135.0, + rate_cents: 7713500, + USD: { + code: "USD", + symbol: "$", + rate: "77135.00", + rate_float: 77135.0, + rate_cents: 7713500, + }, + }), + ); + }); + const fiatAmount = USD(1); + const resolved = await resolveAmount(fiatAmount); + expect(resolved.satoshi).toBeGreaterThan(0); + }); +}); diff --git a/src/utils/fiat/FiatAmount.ts b/src/utils/fiat/FiatAmount.ts new file mode 100644 index 0000000..2fef228 --- /dev/null +++ b/src/utils/fiat/FiatAmount.ts @@ -0,0 +1,21 @@ +import { fiat } from "../.."; + +/** + * An amount in a fiat currency represented in satoshis + */ +export class FiatAmount { + satoshi: Promise; + constructor(amount: number, currency: string) { + this.satoshi = fiat.getSatoshiValue({ + amount, + currency, + }); + } +} + +// Most popular fiat currencies +export const USD = (amount: number) => new FiatAmount(amount, "USD"); +export const EUR = (amount: number) => new FiatAmount(amount, "EUR"); +export const JPY = (amount: number) => new FiatAmount(amount, "JPY"); +export const GBP = (amount: number) => new FiatAmount(amount, "GBP"); +export const CHF = (amount: number) => new FiatAmount(amount, "CHF"); diff --git a/src/utils/fiat.ts b/src/utils/fiat/fiat.ts similarity index 100% rename from src/utils/fiat.ts rename to src/utils/fiat/fiat.ts diff --git a/src/utils/fiat/index.ts b/src/utils/fiat/index.ts new file mode 100644 index 0000000..7550293 --- /dev/null +++ b/src/utils/fiat/index.ts @@ -0,0 +1,2 @@ +export * from "./fiat"; +export * from "./FiatAmount";