From 21f94f95ea35930b9c649e7e730cbb732cb4a4a5 Mon Sep 17 00:00:00 2001 From: Alex Lewin <43247027+alexlwn123@users.noreply.github.com> Date: Sun, 10 Nov 2024 15:11:58 +0000 Subject: [PATCH] Alex/lightning docs (#97) * chore: update balance docs * feat: add payInvoiceSync to lightning service * feat: add createInvoice, payInvoice docs pages * feat: add timeout param to waitForReceive * feat: improve lightning docs * chore: add changesets --- .changeset/hot-shirts-drum.md | 6 ++ .prettierignore | 5 +- docs/.vitepress/sidebar.ts | 16 ++-- .../BalanceService/getBalance.md | 5 +- .../BalanceService/subscribeBalance.md | 9 +-- .../LightningService/createInvoice.md | 41 ++++++++++ .../LightningService/payInvoice.md | 58 ++++++++++++++ .../core-web/src/services/LightningService.ts | 79 ++++++++++++++++++- 8 files changed, 198 insertions(+), 21 deletions(-) create mode 100644 .changeset/hot-shirts-drum.md create mode 100644 docs/core/FedimintWallet/LightningService/createInvoice.md create mode 100644 docs/core/FedimintWallet/LightningService/payInvoice.md diff --git a/.changeset/hot-shirts-drum.md b/.changeset/hot-shirts-drum.md new file mode 100644 index 0000000..6132e26 --- /dev/null +++ b/.changeset/hot-shirts-drum.md @@ -0,0 +1,6 @@ +--- +'@fedimint/core-web': patch +--- + +Added optional timeout parameter to lightning.waitForReceive() +Added lightning.waitForSend() diff --git a/.prettierignore b/.prettierignore index 2de70eb..89261e6 100644 --- a/.prettierignore +++ b/.prettierignore @@ -6,4 +6,7 @@ packages/wasm-bundler/** examples/bare-js/** tmp/** *.html -packages/*/dist/** \ No newline at end of file +packages/*/dist/** +docs/core/FedimintWallet/BalanceService/subscribeBalance.md +docs/core/FedimintWallet/LightningService/createInvoice.md +docs/core/FedimintWallet/LightningService/payInvoice.md diff --git a/docs/.vitepress/sidebar.ts b/docs/.vitepress/sidebar.ts index d56ab5a..6dd73ec 100644 --- a/docs/.vitepress/sidebar.ts +++ b/docs/.vitepress/sidebar.ts @@ -34,7 +34,7 @@ export function getSidebar() { const FedimintWalletSidebar = [ { - text: 'FedimintWallet', + text: 'Core', link: '.', base: '/core/FedimintWallet/', items: [ @@ -50,10 +50,10 @@ const FedimintWalletSidebar = [ text: 'joinFederation()', link: 'joinFederation', }, - { - text: 'initialize()', - link: 'initialize', - }, + // { + // text: 'initialize()', + // link: 'initialize', + // }, { text: 'isOpen()', link: 'isOpen', @@ -78,15 +78,13 @@ const FedimintWalletSidebar = [ text: 'LightningService', base: '/core/FedimintWallet/LightningService/', items: [ - { text: 'Docs TODO' }, - // { text: 'payInvoice()', link: 'payInvoice' }, - // { text: 'createInvoice()', link: 'createInvoice' }, + { text: 'payInvoice()', link: 'payInvoice' }, + { text: 'createInvoice()', link: 'createInvoice' }, // { // text: 'createInvoiceWithGateway()', // link: 'createInvoiceWithGateway', // }, // { text: 'subscribeInvoiceStatus()', link: 'subscribeInvoiceStatus' }, - // { text: 'subscribeLnPay()', link: 'subscribeLnPay' }, // { text: 'subscribeLnReceive()', link: 'subscribeLnReceive' }, // { text: 'listGateways()', link: 'listGateways' }, // { text: 'getGateway()', link: 'getGateway' }, diff --git a/docs/core/FedimintWallet/BalanceService/getBalance.md b/docs/core/FedimintWallet/BalanceService/getBalance.md index ba3bdc7..8af1adf 100644 --- a/docs/core/FedimintWallet/BalanceService/getBalance.md +++ b/docs/core/FedimintWallet/BalanceService/getBalance.md @@ -9,10 +9,9 @@ Get the current balance of the wallet. import { FedimintWallet } from '@fedimint/core-web' const wallet = new FedimintWallet() -wallet.open() +await wallet.open() -// ---cut--- -const mSats = await wallet.balance.getBalance() +const mSats = await wallet.balance.getBalance() // [!code focus] // 1000 mSats = 1 satoshi ``` diff --git a/docs/core/FedimintWallet/BalanceService/subscribeBalance.md b/docs/core/FedimintWallet/BalanceService/subscribeBalance.md index 610e779..53d6ac9 100644 --- a/docs/core/FedimintWallet/BalanceService/subscribeBalance.md +++ b/docs/core/FedimintWallet/BalanceService/subscribeBalance.md @@ -10,11 +10,10 @@ import { FedimintWallet } from '@fedimint/core-web' const wallet = new FedimintWallet() wallet.open() -// ---cut--- -const unsubscribe = wallet.balance.subscribeBalance((mSats) => { - console.log('Balance updated:', mSats) - // 1000 mSats = 1 satoshi -}) +const unsubscribe = wallet.balance.subscribeBalance((mSats) => { // [!code focus] + console.log('Balance updated:', mSats) // [!code focus] + // 1000 mSats = 1 satoshi // [!code focus] +}) // [!code focus] // ...Cleanup Later unsubscribe() diff --git a/docs/core/FedimintWallet/LightningService/createInvoice.md b/docs/core/FedimintWallet/LightningService/createInvoice.md new file mode 100644 index 0000000..8ce44dd --- /dev/null +++ b/docs/core/FedimintWallet/LightningService/createInvoice.md @@ -0,0 +1,41 @@ +# Receive Lightning + +### `lightning.createInvoice()` + +Create a Lightning Invoice for a given amount. Returns a `CreateBolt11Response` object containing details about the created invoice. + +You can use `subscribeLnReceive` to track the payment status and `waitForReceive` to wait for the payment to be received. + +```ts twoslash +// @esModuleInterop +import { FedimintWallet } from '@fedimint/core-web' +import type { LnReceiveState } from '@fedimint/core-web' + +const wallet = new FedimintWallet() +wallet.open() + +const { operation_id, invoice } = await wallet.lightning.createInvoice( // [!code focus] + 10_000, // msats // [!code focus] + 'This is an invoice description', // [!code focus] +) // [!code focus] + +console.log(operation_id) // operation id for the invoice +console.log(invoice) // bolt11 invoice + +const unsubscribe = wallet.lightning.subscribeLnReceive( // [!code focus] + operation_id, // [!code focus] + (state: LnReceiveState) => console.log(state), // [!code focus] + (error: string) => console.error(error), // [!code focus] +) // [!code focus] + +// ...Cleanup Later +unsubscribe() + +try { + const timeoutMs = 10000 + await wallet.lightning.waitForReceive(operation_id, timeoutMs) // [!code focus] + console.log('Payment Received!') +} catch (error) { + console.error(error) // Timeout waiting for payment +} +``` diff --git a/docs/core/FedimintWallet/LightningService/payInvoice.md b/docs/core/FedimintWallet/LightningService/payInvoice.md new file mode 100644 index 0000000..cb281ea --- /dev/null +++ b/docs/core/FedimintWallet/LightningService/payInvoice.md @@ -0,0 +1,58 @@ +# Send Lightning + +### `lightning.payInvoiceSync(invoice: string)` + +Helper function to pay an invoice and resolve when the payment is confirmed or fails. + +```ts twoslash +// @esModuleInterop +import { FedimintWallet } from '@fedimint/core-web' + +const wallet = new FedimintWallet() +wallet.open() + +const result = await wallet.lightning.payInvoiceSync( // [!code focus] + 'lnbc...', // bolt11 invoice // [!code focus] +) // [!code focus] + +if (result.success) { + console.log(result.data.preimage) // preimage of the settled payment + console.log(result.data.feeMsats) // fee paid in msats +} +``` + +### `lightning.payInvoice(invoice: string)` + +Attempt to pay a lightning invoice. Returns an `OutgoingLightningPayment` object containing details about the in-flight payment. + +You can use `subscribeLnPay` to track the payment status and `waitForPay` to wait for the payment to be confirmed or fail. + +```ts twoslash +// @esModuleInterop +import { FedimintWallet } from '@fedimint/core-web' +import type { LnPayState } from '@fedimint/core-web' + +const wallet = new FedimintWallet() +wallet.open() + +const { contract_id, fee } = await wallet.lightning.payInvoice( // [!code focus] + 'lnbc...', // bolt11 invoice // [!code focus] +) // [!code focus] + +console.log(contract_id) // in flight lightning payment id + +const unsubscribe = wallet.lightning.subscribeLnPay( // [!code focus] + contract_id, // [!code focus] + (state: LnPayState) => console.log(state), // State of the payment // [!code focus] + (error: string) => console.error(error), // [!code focus] +) + +// ...Cleanup Later +unsubscribe() + +const result = await wallet.lightning.waitForPay(contract_id) // [!code focus] + +if (result.success) { + console.log(result.data.preimage) // preimage of the settled payment +} +``` diff --git a/packages/core-web/src/services/LightningService.ts b/packages/core-web/src/services/LightningService.ts index d270a14..eb6cbed 100644 --- a/packages/core-web/src/services/LightningService.ts +++ b/packages/core-web/src/services/LightningService.ts @@ -87,6 +87,43 @@ export class LightningService { }) } + async payInvoiceSync( + invoice: string, + timeoutMs: number = 10000, + gatewayInfo?: GatewayInfo, + extraMeta?: JSONObject, + ): Promise< + | { success: false } + | { + success: true + data: { feeMsats: number; preimage: string } + } + > { + return new Promise(async (resolve, reject) => { + const { contract_id, fee } = await this.payInvoice( + invoice, + gatewayInfo, + extraMeta, + ) + + const unsubscribe = this.subscribeLnPay(contract_id, (res) => { + if (typeof res !== 'string' && 'success' in res) { + clearTimeout(timeoutId) + unsubscribe() + resolve({ + success: true, + data: { feeMsats: fee, preimage: res.success.preimage }, + }) + } + }) + + const timeoutId = setTimeout(() => { + unsubscribe() + reject(new Error('Timeout waiting for pay')) + }, timeoutMs) + }) + } + // TODO: Document subscribeLnClaim( operationId: string, @@ -122,6 +159,40 @@ export class LightningService { return unsubscribe } + async waitForPay(operationId: string): Promise< + | { success: false } + | { + success: true + data: { preimage: string } + } + > { + return new Promise((resolve, reject) => { + let unsubscribe: () => void + const timeoutId = setTimeout(() => { + reject(new Error('Timeout waiting for receive')) + }, 15000) + + unsubscribe = this.subscribeLnPay( + operationId, + (res) => { + if (typeof res !== 'string' && 'success' in res) { + clearTimeout(timeoutId) + unsubscribe() + resolve({ + success: true, + data: { preimage: res.success.preimage }, + }) + } + }, + (error) => { + clearTimeout(timeoutId) + unsubscribe() + reject(error) + }, + ) + }) + } + // TODO: Document subscribeLnReceive( operationId: string, @@ -139,13 +210,15 @@ export class LightningService { return unsubscribe } - // TODO: Document - async waitForReceive(operationId: string): Promise { + async waitForReceive( + operationId: string, + timeoutMs: number = 15000, + ): Promise { return new Promise((resolve, reject) => { let unsubscribe: () => void const timeoutId = setTimeout(() => { reject(new Error('Timeout waiting for receive')) - }, 15000) + }, timeoutMs) unsubscribe = this.subscribeLnReceive( operationId,