diff --git a/.clippy.toml b/.clippy.toml index be64409c8d..4972822f13 100644 --- a/.clippy.toml +++ b/.clippy.toml @@ -1 +1 @@ -msrv = "1.63.0" \ No newline at end of file +msrv = "1.85.0" diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index d32c55cd5d..80b724e0e2 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -1,8 +1,6 @@ name: Security Audit on: workflow_dispatch: - schedule: - - cron: '0 0 * * *' jobs: audit: diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml index ef049ad851..cf5c491fea 100644 --- a/.github/workflows/benchmarks.yml +++ b/.github/workflows/benchmarks.yml @@ -1,10 +1,6 @@ name: CI Checks - Benchmarks -on: [push, pull_request] - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true +on: [workflow_dispatch] jobs: benchmark: diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml new file mode 100644 index 0000000000..3766a338f3 --- /dev/null +++ b/.github/workflows/claude-code-review.yml @@ -0,0 +1,59 @@ +name: Claude Code Review + +on: + workflow_dispatch: + inputs: + pr_number: + description: "Pull request number to review" + required: true + type: number + +concurrency: + group: ${{ github.workflow }}-${{ inputs.pr_number }} + cancel-in-progress: true + +jobs: + claude-review: + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + issues: write + id-token: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Minimize old Claude comments + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + REPO="${{ github.repository }}" + PR_NUMBER="${{ inputs.pr_number }}" + + # Minimize issue comments from claude[bot] + gh api "repos/$REPO/issues/$PR_NUMBER/comments" --jq '.[] | select(.user.login == "claude[bot]") | .node_id' | while read -r node_id; do + if [ -n "$node_id" ]; then + echo "Minimizing comment: $node_id" + gh api graphql -f query=' + mutation($id: ID!) { + minimizeComment(input: {subjectId: $id, classifier: OUTDATED}) { + minimizedComment { isMinimized } + } + }' -f id="$node_id" || true + fi + done + + - name: Run Claude Code Review + id: claude-review + uses: anthropics/claude-code-action@v1 + with: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + plugin_marketplaces: 'https://github.com/anthropics/claude-code.git' + plugins: 'code-review@claude-code-plugins' + prompt: '/code-review:code-review --comment ${{ github.repository }}/pull/${{ inputs.pr_number }}' + claude_args: | + --allowedTools "Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh api:*),Bash(git log:*),Bash(git diff:*),Bash(git blame:*),Read,Glob,Grep" diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml new file mode 100644 index 0000000000..46c58eebb0 --- /dev/null +++ b/.github/workflows/claude.yml @@ -0,0 +1,41 @@ +name: Claude Code + +on: + workflow_dispatch: + inputs: + prompt: + description: "Prompt for Claude Code" + required: true + type: string + +jobs: + claude: + runs-on: ubuntu-latest + permissions: + contents: write # Allow creating branches/commits + pull-requests: write # Allow pushing to PR branches + issues: write # Allow updating issue comments + id-token: write + actions: read # Required for Claude to read CI results on PRs + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Full history for git operations + + - name: Run Claude Code + id: claude + uses: anthropics/claude-code-action@v1 + with: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + + # This is an optional setting that allows Claude to read CI results on PRs + additional_permissions: | + actions: read + + prompt: ${{ inputs.prompt }} + + # Optional: Add claude_args to customize behavior and configuration + # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md + # or https://code.claude.com/docs/en/cli-reference for available options + # claude_args: '--allowed-tools Bash(gh pr:*)' diff --git a/.github/workflows/cln-integration.yml b/.github/workflows/cln-integration.yml index 32e7b74c02..db9a16d41b 100644 --- a/.github/workflows/cln-integration.yml +++ b/.github/workflows/cln-integration.yml @@ -1,10 +1,6 @@ name: CI Checks - CLN Integration Tests -on: [push, pull_request] - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true +on: [workflow_dispatch] jobs: check-cln: diff --git a/.github/workflows/cron-weekly-rustfmt.yml b/.github/workflows/cron-weekly-rustfmt.yml index d6326f03bd..a92a9984c3 100644 --- a/.github/workflows/cron-weekly-rustfmt.yml +++ b/.github/workflows/cron-weekly-rustfmt.yml @@ -1,16 +1,14 @@ -name: Nightly rustfmt +name: Rustfmt (manual) permissions: contents: write pull-requests: write on: - schedule: - - cron: "0 0 * * 0" # runs weekly on Sunday at 00:00 - workflow_dispatch: # allows manual triggering + workflow_dispatch: # manual only — cron schedule removed to avoid automated PRs jobs: format: - name: Nightly rustfmt + name: Rustfmt (manual) runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v5 diff --git a/.github/workflows/kotlin.yml b/.github/workflows/kotlin.yml index 01a840d600..736355f9c5 100644 --- a/.github/workflows/kotlin.yml +++ b/.github/workflows/kotlin.yml @@ -1,10 +1,6 @@ name: CI Checks - Kotlin Tests -on: [push, pull_request] - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true +on: [workflow_dispatch] jobs: check-kotlin: diff --git a/.github/workflows/lnd-integration.yml b/.github/workflows/lnd-integration.yml index f913e92ad5..43864cf517 100644 --- a/.github/workflows/lnd-integration.yml +++ b/.github/workflows/lnd-integration.yml @@ -1,10 +1,6 @@ name: CI Checks - LND Integration Tests -on: [push, pull_request] - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true +on: [workflow_dispatch] jobs: check-lnd: diff --git a/.github/workflows/publish-android.yml b/.github/workflows/publish-android.yml new file mode 100644 index 0000000000..0e6c3ba2e0 --- /dev/null +++ b/.github/workflows/publish-android.yml @@ -0,0 +1,86 @@ +name: Android Publish + +on: + release: + types: [published] + workflow_dispatch: + inputs: + version: + description: "Version/tag to publish (e.g., v0.7.0-rc.50 or 0.7.0-rc.50)" + required: true + +jobs: + publish: + runs-on: ubuntu-latest + permissions: + contents: write + packages: write + + steps: + - name: Normalize release version + id: version + shell: bash + run: | + VERSION="${{ github.event.inputs.version || github.event.release.tag_name || github.ref_name }}" + TAG="$VERSION" + if [[ "$TAG" != v* ]]; then + TAG="v$TAG" + fi + echo "tag=$TAG" >> "$GITHUB_OUTPUT" + echo "version=${TAG#v}" >> "$GITHUB_OUTPUT" + + - uses: actions/checkout@v4 + with: + ref: ${{ steps.version.outputs.tag }} + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + server-id: github + settings-path: ${{ github.workspace }} + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Install native build dependencies + run: sudo apt-get update && sudo apt-get install -y pkg-config protobuf-compiler + + - name: Set up Android SDK + uses: android-actions/setup-android@v3 + + - name: Set up Android NDK + id: setup-ndk + uses: nttld/setup-ndk@v1 + with: + ndk-version: r28c + add-to-path: true + + - name: Export Android NDK root + run: echo "ANDROID_NDK_ROOT=${{ steps.setup-ndk.outputs.ndk-path }}" >> "$GITHUB_ENV" + + - name: Generate Android bindings + run: scripts/uniffi_bindgen_generate_kotlin_android.sh + + - name: Build with Gradle + working-directory: bindings/kotlin/ldk-node-android + run: ./gradlew build -Pversion=${{ steps.version.outputs.version }} + + - name: Upload native debug symbols artifact + uses: actions/upload-artifact@v4 + with: + name: ldk-node-native-debug-symbols-${{ steps.version.outputs.version }} + path: bindings/kotlin/ldk-node-android/native-debug-symbols.zip + + - name: Upload native debug symbols to release + env: + GH_TOKEN: ${{ github.token }} + run: gh release upload "${{ steps.version.outputs.tag }}" bindings/kotlin/ldk-node-android/native-debug-symbols.zip --clobber + + - name: Publish to GitHub Packages + working-directory: bindings/kotlin/ldk-node-android + env: + GITHUB_ACTOR: ${{ github.actor }} + GITHUB_TOKEN: ${{ github.token }} + GITHUB_REPO: ${{ github.repository }} + run: ./gradlew publish -Pversion=${{ steps.version.outputs.version }} diff --git a/.github/workflows/publish-jvm.yml b/.github/workflows/publish-jvm.yml new file mode 100644 index 0000000000..e0ac5ac877 --- /dev/null +++ b/.github/workflows/publish-jvm.yml @@ -0,0 +1,56 @@ +name: JVM Publish + +on: + release: + types: [published] + workflow_dispatch: + inputs: + version: + description: "Version/tag to publish (e.g., v0.7.0-rc.54 or 0.7.0-rc.54)" + required: true + +jobs: + publish: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Normalize release version + id: version + shell: bash + run: | + VERSION="${{ github.event.inputs.version || github.event.release.tag_name || github.ref_name }}" + TAG="$VERSION" + if [[ "$TAG" != v* ]]; then + TAG="v$TAG" + fi + echo "tag=$TAG" >> "$GITHUB_OUTPUT" + echo "version=${TAG#v}" >> "$GITHUB_OUTPUT" + + - uses: actions/checkout@v4 + with: + ref: ${{ steps.version.outputs.tag }} + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + server-id: github + settings-path: ${{ github.workspace }} + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Build with Gradle + working-directory: bindings/kotlin/ldk-node-jvm + run: ./gradlew build -x test -Pversion=${{ steps.version.outputs.version }} + + - name: Publish to GitHub Packages + working-directory: bindings/kotlin/ldk-node-jvm + env: + GITHUB_ACTOR: ${{ github.actor }} + GITHUB_TOKEN: ${{ github.token }} + GITHUB_REPO: ${{ github.repository }} + run: ./gradlew publish -Pversion=${{ steps.version.outputs.version }} diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index d9bc978d14..8a76170232 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -1,10 +1,6 @@ name: CI Checks - Python Tests -on: [push, pull_request] - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true +on: [workflow_dispatch] jobs: check-python: diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 87249bd720..70e7d39789 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -1,10 +1,6 @@ name: CI Checks - Rust Tests -on: [push, pull_request] - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true +on: [workflow_dispatch] jobs: build: diff --git a/.github/workflows/semver.yml b/.github/workflows/semver.yml index 8472cbd2aa..9ba9c91c05 100644 --- a/.github/workflows/semver.yml +++ b/.github/workflows/semver.yml @@ -1,5 +1,5 @@ name: SemVer checks -on: [push, pull_request] +on: [workflow_dispatch] jobs: semver-checks: diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index 3410d09aa2..bed37f401e 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -1,10 +1,6 @@ name: CI Checks - Swift Tests -on: [push, pull_request] - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true +on: [workflow_dispatch] jobs: check-swift: diff --git a/.github/workflows/vss-integration.yml b/.github/workflows/vss-integration.yml index 8473ed4138..8868ff5a89 100644 --- a/.github/workflows/vss-integration.yml +++ b/.github/workflows/vss-integration.yml @@ -1,10 +1,6 @@ name: CI Checks - VSS Integration Tests -on: [push, pull_request] - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true +on: [workflow_dispatch] jobs: build-and-test: diff --git a/.gitignore b/.gitignore index 3d24bbceb5..bf2487f5af 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ # will have compiled files and executables /target/ /bindings/uniffi-bindgen/target/ +/bindings/kotlin/ldk-node-android/native-debug-symbols.zip # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html @@ -23,7 +24,20 @@ swift.swiftdoc # Ignore LDKNodeFFI.xcframework files /bindings/swift/LDKNodeFFI.xcframework -/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs -/bindings/kotlin/ldk-node-android/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.kt -/bindings/kotlin/ldk-node-jvm/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.kt -/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/ + +# Build artifacts +*.o +*.a +*.d + +# macOS Finder metadata (icon positions, view options) +.DS_Store + +# IDE and local files +.idea +.build +.cursor +.claude +*.local.* +.ai +.vscode diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..47db706923 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,291 @@ +# CLAUDE.md + +This file provides guidance to AI agents like Cursor/Claude Code/Codex/WARP when working with code in this repository. + +## Overview + +LDK Node is a ready-to-go Lightning node library built using LDK (Lightning Development Kit) and BDK (Bitcoin Development Kit). It provides a high-level interface for running a Lightning node with an integrated on-chain wallet. + +## Development Commands + +### Building +```bash +# Build the project +cargo build + +# Build with release optimizations +cargo build --release + +# Build with size optimizations +cargo build --profile=release-smaller +``` + +### Testing + +#### Unit tests (no external infrastructure needed) +```bash +cargo test --lib +``` + +#### Standard integration tests +Uses the `electrsd` crate to auto-download and spawn `bitcoind` + `electrs` binaries. +To use pre-downloaded binaries, set `BITCOIND_EXE` and `ELECTRS_EXE` env vars. + +On macOS, the default file descriptor limit (256) is too low for spawning `bitcoind` + +`electrs`. Raise it before running integration tests: + +Test files: `tests/integration_tests_rust.rs`, `tests/reorg_test.rs`, +`tests/multi_address_types_tests.rs` + +```bash +ulimit -n 10240 && cargo test +``` + +#### Run a specific test +```bash +cargo test test_name +``` + +#### Run tests with UniFFI bindings feature +```bash +cargo test --features "uniffi" +``` + +#### CLN integration tests +Requires Docker and `socat` for RPC socket forwarding. +```bash +docker compose -f docker-compose-cln.yml up -d +RUSTFLAGS="--cfg cln_test" cargo test --test integration_tests_cln +``` + +#### LND integration tests +Requires Docker and CMake (>=3.5, <4.0) for `lnd_grpc_rust`. +Set `LND_DATA_DIR`, `LND_CERT_PATH`, and `LND_MACAROON_PATH` env vars. +```bash +docker compose -f docker-compose-lnd.yml up -d +RUSTFLAGS="--cfg lnd_test" cargo test --test integration_tests_lnd +``` + +#### VSS integration tests +Requires PostgreSQL and a running VSS server (from `lightningdevkit/vss-server`). +Set `TEST_VSS_BASE_URL` env var. +```bash +RUSTFLAGS="--cfg vss_test" cargo test --test integration_tests_vss +``` + +### Code Quality +```bash +# Format code +cargo fmt + +# Check formatting without modifying +cargo fmt --check + +# Run clippy for linting +cargo clippy + +# Run clippy and fix issues +cargo clippy --fix +``` + +### Language Bindings +```bash +# Generate ALL bindings (Swift, Kotlin, Python) + xcframework archive +./bindgen.sh +``` +Individual scripts live under `scripts/` but should NOT be run directly — +`bindgen.sh` installs shared tooling once and sets the correct build profile. + +## Architecture + +### Core Components + +1. **Node** (`src/lib.rs`): The main entry point and primary abstraction. Manages the Lightning node's lifecycle and provides high-level operations like opening channels, sending payments, and handling events. + +2. **Builder** (`src/builder.rs`): Configures and constructs a Node instance with customizable settings for network, chain source, storage backend, and entropy source. + +3. **Payment System** (`src/payment/`): + - `bolt11.rs`: BOLT-11 invoice payments + - `bolt12.rs`: BOLT-12 offer payments + - `spontaneous.rs`: Spontaneous payments without invoices + - `onchain.rs`: On-chain Bitcoin transactions + - `unified_qr.rs`: Unified QR code generation for payments + +4. **Storage Backends** (`src/io/`): + - `sqlite_store/`: SQLite-based persistent storage + - `vss_store.rs`: Versioned Storage Service for remote backups + - FilesystemStore: File-based storage (via lightning-persister) + +5. **Chain Integration** (`src/chain/`): + - `bitcoind_rpc.rs`: Bitcoin Core RPC interface + - `electrum.rs`: Electrum server integration + - `esplora.rs`: Esplora block explorer API + +6. **Event System** (`src/event.rs`): Asynchronous event handling for channel updates, payments, and other node activities. + +### Key Design Patterns + +- **Modular Chain Sources**: Supports multiple chain data sources (Bitcoin Core, Electrum, Esplora) through a unified interface +- **Pluggable Storage**: Storage backend abstraction allows SQLite, filesystem, or custom implementations +- **Event-Driven Architecture**: Core operations emit events that must be handled by the application +- **Builder Pattern**: Node configuration uses a builder for flexible setup + +### Dependencies Structure + +The project heavily relies on the Lightning Development Kit ecosystem: +- `lightning-*`: Core LDK functionality (channel management, routing, invoices) +- `bdk_*`: Bitcoin wallet functionality +- `uniffi`: Multi-language bindings generation + +### Critical Files + +- `src/lib.rs`: Node struct and primary API +- `src/builder.rs`: Node configuration and initialization +- `src/payment/mod.rs`: Payment handling coordination +- `src/io/sqlite_store/mod.rs`: Primary storage implementation +- `bindings/ldk_node.udl`: UniFFI interface definition for language bindings + +--- +## PERSONA +You are an extremely strict senior Rust systems engineer with 15+ years shipping production cryptographic and distributed systems (e.g. HSM-backed consensus protocols, libp2p meshes, zk-proof coordinators, TLS implementations, hypercore, pubky, dht, blockchain nodes). + +Your job is not just to write or review code — it is to deliver code that would pass a full Trail of Bits + Rust unsafe + Jepsen-level audit on the first try. + +Follow this exact multi-stage process and never skip or summarize any stage, with +one exception for automated CI reviews (see below): + +**Automated CI code reviews (GitHub Actions):** When running as the `code-review` +plugin in GitHub Actions, build and test tools (Bash, cargo, etc.) are unavailable. +In this context: +- Run Stages 1, 2, 3, and 5 using static analysis only (Read, Grep, Glob). +- Skip Stage 4 (Testing) and Stage 6 (Build & CI Verification) entirely. + Do NOT attempt to run cargo, build, or test commands. +- For Stage 7, report only: (1) threat model notes, (2) critical issues found, + and (7) verification checklist — marking Stages 4 and 6 items as "N/A (CI)". + +Stage 1 – Threat Model & Architecture Review +- Explicitly write a concise threat model (adversaries, trust boundaries, failure modes). +- Check if the architecture is overly complex. Suggest simpler, proven designs if they exist (cite papers or real systems). +- Flag any violation of "pit of success" Rust design (fighting the borrow checker, over-use of Rc/RefCell, unnecessary async, etc.). + +Stage 2 – Cryptography Audit (zero tolerance) +- Constant-time execution +- Side-channel resistance (timing, cache, branching) +- Misuse-resistant API design (libsodium / rustls style) +- Nonce/IV uniqueness & randomness +- Key management, rotation, separation +- Authenticated encryption mandatory +- No banned primitives (MD5, SHA1, RSA-PKCS1v1_5, ECDSA deterministic nonce, etc.) +- Every crypto operation must be justified and cited + +Stage 3 – Rust Safety & Correctness Audit +- Every `unsafe` block justified with miri-proof invariants +- Send/Sync, Pin, lifetime, variance, interior mutability checks +- Panic safety, drop order, leak freedom +- Cancellation safety for async +- All public APIs have `#![forbid(unsafe_code)]` where possible + +Stage 4 – Testing Requirements (non-negotiable) +You must generate and show: +- 100% line and branch coverage (you will estimate and require missing tests) +- Property-based tests with proptest or proptest for all non-trivial logic +- Fuzz targets (afl/libfuzzer) for all parsers and crypto boundaries +- Integration tests that spawn multiple nodes and inject partitions (use loom or tokyo for concurrency, manual partitions for distributed) +- All tests must be shown in the final output and marked as passing (you will mentally execute or describe expected outcome) + +Stage 5 – Documentation & Commenting (audit-ready) +- Every public item has a top-level doc comment with: + - Purpose + - Safety preconditions + - Threat model considerations + - Examples (must compile with doctest) +- Every non-obvious private function has a short comment +- crate-level README with build instructions, threat model, and fuzzing guide +- All documentation must be shown and marked as doctests passing + +Stage 6 – Build & CI Verification +- Provide exact `Cargo.toml` changes needed +- Add required features/flags (e.g. `cargo miri test`, `cargo fuzz`, `cargo nextest`, etc.) +- Explicitly state that `cargo build --all-targets --locked` and `cargo test --all-targets` pass with no warnings + +Stage 7 – Final Structured Output +Only after completing all stages above, output in this exact order: + +1. Threat model & architecture improvements (or "none required") +2. Critical issues found (or "none") +3. Full refactored Cargo.toml +4. Full refactored source files (complete, copy-paste ready) +5. All new tests (property, fuzz, integration) shown in full +6. Documentation excerpts proving completeness +7. Final verification checklist with ✅ or ❌ for: + - Builds cleanly + - All tests pass + - Zero unsafe without justification + - Zero crypto footguns + - Documentation complete and doctests pass + - Architecture is minimal and correct + +Never say "trust me" or "in practice this would pass". You must demonstrate everything above explicitly. +If anything is missing or cannot be verified (outside of stages explicitly +marked as skipped for CI), you must fix it before declaring success. + +--- +## RULES +- ALWAYS edit AGENTS.md directly — CLAUDE.md, GEMINI.md, and WARP.md are symlinks and must not be edited or replaced with regular files +- NEVER delete or recreate symlinks (CLAUDE.md, GEMINI.md, WARP.md) — they are committed to git as mode 120000 +- NEVER suggest manually adding @Serializable annotations to generated Kotlin bindings +- ALWAYS run `cargo fmt` before committing to ensure consistent code formatting +- ALWAYS move imports to the top of the file when applicable (no inline imports in functions) +- ALWAYS add unit tests for new business logic — untested code will be flagged in review +- Run `./bindgen.sh` in the background when bindings need regeneration (it is long-running) + +## Bindings Generation Command +To regenerate ALL bindings (Swift, Kotlin, Python), run from the repo root: +```sh +./bindgen.sh +``` + +## Version Bumping Checklist +When bumping the version, ALWAYS update ALL of these files: +1. `Cargo.toml` - main crate version +2. `bindings/kotlin/ldk-node-android/gradle.properties` - Android version +3. `bindings/kotlin/ldk-node-jvm/gradle.properties` - JVM version +4. `bindings/python/pyproject.toml` - Python version +5. `Package.swift` - Swift tag (and checksum after building) +6. `CHANGELOG.md` - Add release notes section at top + +## CHANGELOG +- The Synonym fork maintains a SINGLE section at the top: `# X.X.X (Synonym Fork)` +- This section is **cumulative** — it contains ALL changes across ALL rc versions for this fork +- When bumping version, update the version in the existing heading (don't create new sections) +- All Synonym fork additions go under ONE `## Synonym Fork Additions` subsection +- New additions should be added at the TOP of the Synonym Fork Additions list +- Do NOT create separate sections for each rc version +- **GitHub release notes are NOT the full CHANGELOG** — see PR Release Workflow below + +## PR Release Workflow +- For PRs that bump version, ALWAYS create a release on the PR branch BEFORE merge +- **CRITICAL: Commit and push ALL changes to the branch BEFORE tagging.** The tag must + point to a commit that contains every change included in the release (CHANGELOG, version + bumps, bindings, etc.). Never tag uncommitted or unpushed work. +- Tag the last commit on the PR branch with the version from Cargo.toml (e.g., `v0.7.0-rc.6`) +- **CRITICAL: Before uploading `LDKNodeFFI.xcframework.zip`, ALWAYS verify the checksum matches `Package.swift`:** + ```bash + shasum -a 256 bindings/swift/LDKNodeFFI.xcframework.zip + # Compare output with the checksum value in Package.swift - they MUST match + ``` +- Create GitHub release as **published** (not draft) and **set as latest release**, with + same name as the tag, upload `LDKNodeFFI.xcframework.zip` +- **Release notes = DELTA only.** Describe only what changed since the previous release + (e.g., rc.31 notes list only changes since rc.30). Do NOT paste the full cumulative + CHANGELOG section — that covers all rc versions combined. Write concise notes covering + the PR's changes: bug fixes, features, optimizations, and binding/version updates. +- Release notes are for **consumers of the bindings** — cover only Rust code changes, + FFI changes, and binding updates. Do NOT include internal CI, documentation, or + workflow changes. +- **ALWAYS add release link at the end of PR description** (use `gh pr edit` to update the body): + ``` + ### Release + - [vN.N.N](link_to_release) + ``` +- Only add release as a comment if it's not your PR and you cannot edit the description diff --git a/CHANGELOG.md b/CHANGELOG.md index d03401d856..774f3ab644 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,240 @@ -# 0.7.0 - TODO +# 0.7.0-rc.63 (Synonym Fork) + +## Bug Fixes + +- Moved peer persistence to async KV storage so slow writes no longer hold the peer-store lock. +- Prevented Electrum runtime self-drop crashes and unbounded shutdown waits. +- Scaled Electrum full-scan timeouts for additional wallets with the configured stop gap and batch + size. +- Return `OnchainWalletAccountNotRegistered` consistently for unloaded derived-account operations. +- Published stripped `ldk-node-android` artifacts with separate native debug symbols + and failed Android binding generation when generated JNI libraries lack usable symbols. +- Persist missing announced channel peers from the network graph during + build-time restore and after Rapid Gossip Sync graph updates. Automatic + recovery respects explicit disconnects and last-channel closes during the + current node instance; after restart, active restored channels may persist + peers again from the graph so they can reconnect. +- Fixed orphaned channel migration blocking node startup when the existing monitor + in the KV store can't be deserialized (e.g., `UnknownVersion` from a newer LDK + version). The migration now skips writing and lets the node start normally, + preserving the existing monitor data. +- Fixed HTLC timeout force-close during stale monitor recovery. The healing keysend + created HTLCs with a stale `cltv_expiry` (based on the ChannelManager's outdated + best block height for users offline >24h). When chain sync caught up, LDK + force-closed the channel (HTLCsTimedOut). Fix: sync the chain tip before sending + healing payments so HTLCs get a valid CLTV expiry. If sync fails, skip the keysend + to avoid the stale-CLTV force-close. +- Fixed native crash (SIGABRT) during stale channel monitor recovery. The + `CounterpartyCommitmentSecrets` store was not reset when force-syncing the + monitor's `update_id`, causing `provide_secret()` to fail validation after + a few commitment round-trips. The failed update triggered a + `ChannelMonitorUpdateStatus` mode mismatch panic in the ChannelManager. + Fix: reset the secrets store in `force_set_latest_update_id` so new secrets + build a fresh, consistent tree. (rust-lightning fork change) +- Added `BuildError::DangerousValue` variant to distinguish stale channel monitor failures from + the 19 other `ReadFailed` causes. Apps can now catch this specific error to trigger one-shot + recovery without false positives from unrelated I/O or deserialization errors. +- Added `set_accept_stale_channel_monitors` builder API for recovery from channel monitor desync + (e.g., after migration overwrote newer monitors with stale backup data). When enabled, + force-syncs stale monitor update_ids during build, defers chain sync, and sends probes to + trigger commitment round-trips that heal the monitor state. Depends on a patched rust-lightning + fork (`synonymdev/rust-lightning#0.2.2-accept-stale-monitors`). +- Fixed cumulative change-address derivation index leak during fee estimation and dry-run + transaction builds. BDK's `TxBuilder::finish()` advances the internal (change) keychain index + each time it's called; repeated fee estimations would burn through change addresses without + broadcasting any transaction. All dry-run and error-after-`finish()` paths now cancel the PSBT + to unmark the change address for reuse. +- Bumped `FEE_RATE_CACHE_UPDATE_TIMEOUT_SECS` and `TX_BROADCAST_TIMEOUT_SECS` from 5s to 15s. + The 5s node-level timeout fires before Electrum can complete a request (10s timeout), causing + `FeerateEstimationUpdateTimeout` on node start. +- Fixed external scores sync using `spawn_background_processor_task` (reserved for the single + LDK background processor), which caused a `debug_assert` panic. Switched to + `spawn_cancellable_background_task`. +- Fixed `PeerStore::add_peer` silently ignoring address updates for existing peers. When a peer's + IP address changes (e.g., LSP node migration), `add_peer` now upserts the socket address and + re-persists, instead of returning early. This fixes the issue where ldk-node's reconnection loop + would indefinitely use a stale cached IP after an LSP node IP change. + (See [upstream issue #700](https://github.com/lightningdevkit/ldk-node/issues/700)) +- Backported upstream Electrum sync fix (PR #4341): Skip unconfirmed `get_history` entries in + `ElectrumSyncClient`. Previously, mempool entries (height=0 or -1) were incorrectly treated as + confirmed, causing `get_merkle` to fail for 0-conf channel funding transactions. +- Fixed duplicate payment events (`PaymentReceived`, `PaymentSuccessful`, `PaymentFailed`) being + emitted when LDK replays events after node restart. +- Switched from forked rust-lightning (`ovitrif/rust-lightning#0.2-electrum-fix`) back to official + upstream crates.io releases. The Electrum sync fix (PR #4341) is now in upstream + `lightning-transaction-sync` v0.2.1. Also picks up `lightning` v0.2.2 fixes. +- Fixed FS→KV channel data migration blindly overwriting newer state. The migration now skips + writing a channel monitor when the KV store already holds one with a newer or equal `update_id`, + and skips the channel manager when one already exists. Read or deserialization failures fail-closed + to prevent silent data loss. + +## Synonym Fork Additions + +- Removed `set_accept_stale_channel_monitors` and the patched Synonym `rust-lightning` branch. + Stale channel-monitor mismatches now fail closed with `BuildError::DangerousValue`. + Lightning crates come from crates.io `0.2.0` again. +- Made explicit peer disconnect atomic with durable peer-store removal so persistence failures remain + visible and retryable. +- Added stable GNU build IDs to every Android ABI. +- Added rolling lookahead for derived on-chain accounts after their initial full scan. +- Added configurable Electrum batch size and stop gap for full scans of non-primary on-chain + wallets, while preserving the existing primary-wallet behavior and defaults. +- Added derived-account lifecycle parity with account-`0` wallets: configured accounts load on + build, registered accounts can be unloaded at runtime without deleting persisted BDK state, and + account-specific address metadata can be derived by index or range. +- Added derived on-chain wallet account support (`account_index >= 1`) from the node's master + seed: + - `export_onchain_wallet_account_xpub` / `add_onchain_wallet_account` / + `remove_onchain_wallet_account` (idempotent add; validates xpub; reserves account `0`); + `get_balance_for_onchain_wallet_account` / `list_onchain_wallet_accounts`; + `OnchainPayment::new_address_for_account` / + `new_address_info_for_account` / `address_info_for_account_at_index` / + `address_infos_for_account` / `reveal_receive_addresses_to_account`; + `OnchainWalletAccount` / `OnchainWalletAccountConfig` + - Runtime registration changes are not persisted. Configure registrations in + `Config::onchain_wallet_accounts` to load them on each build. BDK data remains persisted per + account after unload + - Derived accounts full-scan after registration, then use incremental sync. Apps issuing addresses + from an exported xpub can reveal their highest issued index to cover gaps beyond the rolling + lookahead; descriptor origins use the real account path; channel preflight requires an account-`0` + SegWit builder before counting non-Legacy (including derived) funds + - Bitcoind Listen synchronizes every wallet from its own checkpoint alongside the Lightning + listeners, handles shorter and equal-height forked tips, and replays the mempool when the + loaded account set changes + - Funds combine for balances, coin selection, and signing; primary receive/change stay on + account `0`; Legacy-primary funding builds/changes only on account-0 non-Legacy wallets + while derived UTXOs remain selectable as foreign inputs +- Added configurable routing scorer parameters `scoring_fee_params` and `scoring_decay_params` +- Added `AddressInfo` (`index`, `address`, `keychain`) and `KeychainKind`. +- Added `OnchainPayment` methods `new_address_info`, `new_address_info_for_type`, + `address_info_for_type_at_index`, `address_infos_for_type`, and + `reveal_receive_addresses_to`. Address peek APIs support external receive and + internal change keychains without advancing wallet cursors. Batch address peek + requests are capped at 10,000 addresses per call. +- Added pre-flight probe correlation: `Event::ProbeSuccessful` and `Event::ProbeFailed` (from LDK + probe lifecycle), plus `ProbeHandle` (`payment_id`, synthetic `payment_hash`) values returned + for probes actually dispatched by `Bolt11Payment::send_probes`, `send_probes_using_amount`, and + `SpontaneousPayment::send_probes` (some route paths may be skipped before dispatch). Match + handles to events by `payment_id` (and optionally `payment_hash`); these are not the BOLT11 + invoice payment hash. UniFFI: `dictionary ProbeHandle` in `ldk_node.udl`. +- Added `connection_timeout_secs` field to `ElectrumSyncConfig` (default: 10 s). This bounds + Electrum socket operations for both the BDK on-chain and LDK tx-sync clients, preventing Tokio's + blocking thread pool from being exhausted by threads stuck on dead sockets under total packet + loss (e.g. a captive portal on iOS). Set to `0` to disable; values above 255 are capped to + 255 and a warning is logged. + **Breaking change:** existing struct-literal construction of `ElectrumSyncConfig` must add the + new field or switch to `ElectrumSyncConfig { .., ..Default::default() }`. +- Added `OnchainPayment::calculate_send_all_fee()` to preview the fee for a drain / send-all + transaction before broadcasting (fee-calculation counterpart of `send_all_to_address`) +- Added runtime APIs for dynamic address type management: + - `Node::add_address_type_to_monitor()` and `add_address_type_to_monitor_with_mnemonic()` to add an address type to the monitored set + - `Node::remove_address_type_from_monitor()` to unload an address type (persisted state retained for re-add) + - `Node::set_primary_address_type()` and `set_primary_address_type_with_mnemonic()` to change the primary; previous primary is demoted to monitored + - New errors: `AddressTypeAlreadyMonitored`, `AddressTypeIsPrimary`, `AddressTypeNotMonitored`, `InvalidSeedBytes` + - Not persisted across restarts; re-apply on each start or set in `Config` for persistence +- Added multi-address type wallet support with a new `bdk-wallet-aggregate` crate: + - `AddressType` enum: `Legacy`, `NestedSegwit`, `NativeSegwit`, `Taproot` + - `NodeBuilder::set_address_type()` to configure the primary wallet address type + - `NodeBuilder::set_address_types_to_monitor()` to track funds across multiple address types + - `Node::get_balance_for_address_type()` to query per-wallet balances + - `Node::list_monitored_address_types()` to list loaded wallet types + - `OnchainPayment::new_address_for_type()` to generate addresses for a specific type + - `send_to_address` / `send_all_to_address`: unified coin selection pools UTXOs from all loaded wallets and selects optimally across the full set; `send_all` drains all wallets + - RBF and CPFP fee bumping work across wallets (cross-wallet inputs are re-signed) + - Channel funding uses unified coin selection across all SegWit wallets (NestedSegwit can fund channels; Legacy excluded per BOLT 2) + - Channel shutdown and destination scripts always use native witness addresses, with automatic fallback to a loaded NativeSegwit/Taproot wallet when the primary is Legacy or NestedSegwit + - Splicing is restricted to native witness primaries (NativeSegwit/Taproot); non-native primaries return a graceful error + - Change outputs go to the primary wallet + - Monitored wallets are synced in parallel alongside the primary (Esplora and Electrum) + - P2PKH and P2SH UTXOs are now handled in `OutputSpender` (previously panicked on non-witness scripts) + - Migration-safe persistence: existing NativeSegwit wallet data is read from the legacy (un-namespaced) storage location +- Upgraded to Kotlin 2.2.0 for compatibility with consuming apps using Kotlin 2.x +- Added JitPack support for `ldk-node-jvm` module to enable unit testing in consuming apps +- Added runtime-adjustable wallet sync intervals for battery optimization on mobile: + - `RuntimeSyncIntervals` struct with configurable `onchain_wallet_sync_interval_secs`, + `lightning_wallet_sync_interval_secs`, and `fee_rate_cache_update_interval_secs` + - `Node::update_sync_intervals()` to change intervals while the node is running + - `Node::current_sync_intervals()` to retrieve currently active intervals + - `RuntimeSyncIntervals::battery_saving()` preset (5min onchain, 2min lightning, 30min fees) + - Minimum 10-second interval enforced for all values + - Returns `BackgroundSyncNotEnabled` error if manual sync mode was configured at build time +- Optimized startup performance by parallelizing VSS reads and caching network graph locally: + - Parallelized early reads (node_metrics, payments, wallet) + - Parallelized channel monitors and scorer reads + - Parallelized tail reads (output_sweeper, event_queue, peer_store) + - Added local caching for network graph to avoid slow VSS reads on startup +- Added `claimable_on_close_sats` field to `ChannelDetails` struct. This field contains the + amount (in satoshis) that would be claimable if the channel were force-closed now, computed + from the channel monitor's `ClaimableOnChannelClose` balance. Returns `None` if no monitor + exists yet (pre-funding). This replaces the workaround of approximating the claimable amount + using `outbound_capacity_msat + counterparty_reserve`. +- Added reactive event system for wallet monitoring without polling: + - **Onchain Transaction Events** (fully implemented): + - `OnchainTransactionReceived`: Emitted when a new unconfirmed transaction is + first detected in the mempool (instant notification for incoming payments!) + - `OnchainTransactionConfirmed`: Emitted when a transaction receives confirmations + - `OnchainTransactionReplaced`: Emitted when a transaction is replaced (via RBF or different transaction using a common input). Includes the replaced transaction ID and the list of conflicting replacement transaction IDs. + - `OnchainTransactionReorged`: Emitted when a previously confirmed transaction + becomes unconfirmed due to a blockchain reorg + - `OnchainTransactionEvicted`: Emitted when a transaction is evicted from the mempool + - **Sync Completion Event** (fully implemented): + - `SyncCompleted`: Emitted when onchain wallet sync finishes successfully + - **Balance Change Event** (fully implemented): + - `BalanceChanged`: Emitted when onchain or Lightning balances change, allowing + applications to update balance displays immediately without polling +- Added `TransactionDetails`, `TxInput`, and `TxOutput` structs to provide comprehensive + transaction information in onchain events, including inputs and outputs. This enables + applications to analyze transaction data themselves to detect channel funding, closures, + and other transaction types. +- Added `Node::get_transaction_details()` method to retrieve transaction details for any + transaction ID that exists in the wallet, returning `None` if the transaction is not found. +- Added `Node::get_address_balance()` method to retrieve the current balance (in satoshis) for + any Bitcoin address. This queries the chain source (Esplora or Electrum) to get the balance. + Throws `InvalidAddress` if the address string cannot be parsed or doesn't match the node's + network. Returns 0 if the balance cannot be queried (e.g., chain source unavailable). Note: This + method is not available for BitcoindRpc chain source. +- Added `SyncType` enum to distinguish between onchain wallet sync, Lightning + wallet sync, and fee rate cache updates. +- Balance tracking is now persisted in `NodeMetrics` to detect changes across restarts. +- Added RBF (Replace-By-Fee) support via `OnchainPayment::bump_fee_by_rbf()` to replace + unconfirmed transactions with higher fee versions. Prevents RBF of channel funding + transactions to protect channel integrity. +- Added CPFP (Child-Pays-For-Parent) support via `OnchainPayment::accelerate_by_cpfp()` and + `OnchainPayment::calculate_cpfp_fee_rate()` to accelerate unconfirmed transactions by + creating child transactions with higher effective fee rates. +- Added UTXO management APIs: + - `OnchainPayment::list_spendable_outputs()`: Lists all UTXOs safe to spend (excludes channel funding UTXOs). + - `OnchainPayment::select_utxos_with_algorithm()`: Selects UTXOs using configurable coin selection algorithms (BranchAndBound, LargestFirst, OldestFirst, SingleRandomDraw). + - `SpendableUtxo` struct and `CoinSelectionAlgorithm` enum for UTXO management. +- Added fee estimation APIs: + - `OnchainPayment::calculate_total_fee()`: Calculates transaction fees before sending. + - `Bolt11Payment::estimate_routing_fees()`: Estimates Lightning routing fees before sending. + - `Bolt11Payment::estimate_routing_fees_using_amount()`: Estimates fees for amount-less invoices. +- Enhanced `OnchainPayment::send_to_address()` to accept optional `utxos_to_spend` parameter + for manual UTXO selection. +- Added `Config::include_untrusted_pending_in_spendable` option to control whether unconfirmed + funds from external sources are included in `spendable_onchain_balance_sats`. When set to `true`, + the spendable balance will include `untrusted_pending` UTXOs (unconfirmed transactions received + from external wallets). Default is `false` for safety, as spending unconfirmed external funds + carries risk of double-spending. This affects all balance reporting including `list_balances()` + and `BalanceChanged` events. +- Added `ChannelDataMigration` struct and `Builder::set_channel_data_migration()` method to migrate + channel data from external LDK implementations (e.g., react-native-ldk). The channel manager and + monitor data is written to the configured storage during build, before channel monitors are read. + Storage keys for monitors are derived from the funding outpoint. +- Added `derive_node_secret_from_mnemonic()` utility function to derive the node's secret key from a + BIP39 mnemonic, matching LDK's KeysManager derivation path (m/0'). This enables backup authentication + and key verification before the node starts, using the same derivation that a running Node instance + would use internally. + +# 0.7.0 - Dec. 3, 2025 + This seventh minor release introduces numerous new features, bug fixes, and API improvements. In particular, it adds support for channel Splicing, Async Payments, as well as sourcing chain data from a Bitcoin Core REST backend. ## Feature and API updates + - Experimental support for channel splicing has been added. (#677) - - **Note**: Splicing-related transactions might currently still get misclassified in the payment store. + - **Note**: Splicing-related transactions might currently still get misclassified in the payment store. - Support for serving and paying static invoices for Async Payments has been added. (#621, #632) - Sourcing chain data via Bitcoin Core's REST interface is now supported. (#526) - A new `Builder::set_chain_source_esplora_with_headers` method has been added @@ -22,8 +253,10 @@ This seventh minor release introduces numerous new features, bug fixes, and API - The `generate_entropy_mnemonic` method now supports specifying a word count. (#699) ## Bug Fixes and Improvements + - Robustness of the shutdown procedure has been improved, minimizing risk of blocking during `Node::stop`. (#592, #612, #619, #622) -- The VSS storage backend now supports 'lazy' deletes, allowing it to avoid unnecessary remote calls for certain operations. (#689) +- The VSS storage backend now supports 'lazy' deletes, allowing it to avoid + unnecessarily waiting on remote calls for certain operations. (#689, #722) - The encryption and obfuscation scheme used when storing data against a VSS backend has been improved. (#627) - Transient errors during `bitcoind` RPC chain synchronization are now retried with an exponential back-off. (#588) - Transactions evicted from the mempool are now correctly handled when syncing via `bitcoind` RPC/REST. (#605) @@ -37,6 +270,7 @@ This seventh minor release introduces numerous new features, bug fixes, and API - The node now listens on all provided listening addresses. (#644) ## Compatibility Notes + - The minimum supported Rust version (MSRV) has been bumped to `rustc` v1.85 (#606) - The LDK dependency has been bumped to v0.2. - The BDK dependency has been bumped to v2.2. (#656) @@ -46,17 +280,32 @@ This seventh minor release introduces numerous new features, bug fixes, and API - The `electrum-client` dependency has been bumped to v0.24.0. (#602) - For Kotlin/Android builds we now require 16kb page sizes, ensuring Play Store compatibility. (#625) -In total, this release features TODO files changed, TODO insertions, TODO -deletions in TODO commits from TODO authors in alphabetical order: +In total, this release features 77 files changed, 12350 insertions, 5708 +deletions in 264 commits from 14 authors in alphabetical order: -- TODO TODO +- aagbotemi +- alexanderwiederin +- Andrei +- Artur Gontijo +- benthecarman +- Chuks Agbakuru +- coreyphillips +- Elias Rohrer +- Enigbe +- Joost Jager +- Jeffrey Czyz +- moisesPomilio +- Martin Saposnic +- tosynthegeek # 0.6.2 - Aug. 14, 2025 + This patch release fixes a panic that could have been hit when syncing to a TLS-enabled Electrum server, as well as some minor issues when shutting down the node. ## Bug Fixes and Improvements + - If not set by the user, we now install a default `CryptoProvider` for the `rustls` TLS library. This fixes an issue that would have the node panic whenever they first try to access an Electrum server behind an `ssl://` @@ -73,15 +322,18 @@ deletions in 13 commits from 2 authors in alphabetical order: - moisesPomilio # 0.6.1 - Jun. 19, 2025 + This patch release fixes minor issues with the recently-exposed `Bolt11Invoice` type in bindings. ## Feature and API updates + - The `Bolt11Invoice::description` method is now exposed as `Bolt11Invoice::invoice_description` in bindings, to avoid collisions with a Swift standard method of same name (#576) ## Bug Fixes and Improvements + - The `Display` implementation of `Bolt11Invoice` is now exposed in bindings, (re-)allowing to render the invoice as a string. (#574) @@ -91,16 +343,19 @@ in 8 commits from 1 author in alphabetical order: - Elias Rohrer # 0.6.0 - Jun. 9, 2025 + This sixth minor release mainly fixes an issue that could have left the on-chain wallet unable to spend funds if transactions that had previously been accepted to the mempool ended up being evicted. ## Feature and API updates + - Onchain addresses are now validated against the expected network before use (#519). - The API methods on the `Bolt11Invoice` type are now exposed in bindings (#522). - The `UnifiedQrPayment::receive` flow no longer aborts if we're unable to generate a BOLT12 offer (#548). ## Bug Fixes and Improvements + - Previously, the node could potentially enter a state that would have left the onchain wallet unable spend any funds if previously-generated transactions had been first accepted, and then evicted from the mempool. This has been @@ -110,6 +365,7 @@ accepted to the mempool ended up being evicted. - The output of the `log` facade logger has been corrected (#547). ## Compatibility Notes + - The BDK dependency has been bumped to `bdk_wallet` v2.0 (#551). In total, this release features 20 files changed, 1188 insertions, 447 deletions, in 18 commits from 3 authors in alphabetical order: @@ -119,9 +375,11 @@ In total, this release features 20 files changed, 1188 insertions, 447 deletions - Elias Rohrer # 0.5.0 - Apr. 29, 2025 + Besides numerous API improvements and bugfixes this fifth minor release notably adds support for sourcing chain and fee rate data from an Electrum backend, requesting channels via the [bLIP-51 / LSPS1](https://github.com/lightning/blips/blob/master/blip-0051.md) protocol, as well as experimental support for operating as a [bLIP-52 / LSPS2](https://github.com/lightning/blips/blob/master/blip-0052.md) service. ## Feature and API updates + - The `PaymentSuccessful` event now exposes a `payment_preimage` field (#392). - The node now emits `PaymentForwarded` events for forwarded payments (#404). - The ability to send custom TLVs as part of spontaneous payments has been added (#411). @@ -135,7 +393,7 @@ Besides numerous API improvements and bugfixes this fifth minor release notably - On-chain transactions are now added to the internal payment store and exposed via `Node::list_payments` (#432). - Inbound announced channels are now rejected if not all requirements for operating as a forwarding node (set listening addresses and node alias) have been met (#467). - Initial support for operating as an bLIP-52 / LSPS2 service has been added (#420). - - **Note**: bLIP-52 / LSPS2 support is considered 'alpha'/'experimental' and should *not* yet be used in production. + - **Note**: bLIP-52 / LSPS2 support is considered 'alpha'/'experimental' and should _not_ yet be used in production. - The `Builder::set_entropy_seed_bytes` method now takes an array rather than a `Vec` (#493). - The builder will now return a `NetworkMismatch` error in case of network switching (#485). - The `Bolt11Jit` payment variant now exposes a field telling how much fee the LSP withheld (#497). @@ -145,6 +403,7 @@ Besides numerous API improvements and bugfixes this fifth minor release notably - The ability to sync the node via an Electrum backend has been added (#486). ## Bug Fixes and Improvements + - When syncing from Bitcoin Core RPC, syncing mempool entries has been made more efficient (#410, #465). - We now ensure the our configured fallback rates are used when the configured chain source would return huge bogus values during fee estimation (#430). - We now re-enabled trying to bump Anchor channel transactions for trusted counterparties in the `ContentiousClaimable` case to reduce the risk of losing funds in certain edge cases (#461). @@ -152,6 +411,7 @@ Besides numerous API improvements and bugfixes this fifth minor release notably - The `Node::remove_payment` now also removes the respective entry from the in-memory state, not only from the persisted payment store (#514). ## Compatibility Notes + - The filesystem logger was simplified and its default path changed to `ldk_node.log` in the configured storage directory (#394). - The BDK dependency has been bumped to `bdk_wallet` v1.0 (#426). - The LDK dependency has been bumped to `lightning` v0.1 (#426). @@ -192,7 +452,6 @@ In total, this release features 1 files changed, 40 insertions, 4 deletions in 3 - Fuyin - Elias Rohrer - # 0.4.1 - Oct 18, 2024 This patch release fixes a wallet syncing issue where full syncs were used instead of incremental syncs, and vice versa (#383). @@ -208,10 +467,11 @@ In total, this release features 3 files changed, 13 insertions, 9 deletions in 6 Besides numerous API improvements and bugfixes this fourth minor release notably adds support for sourcing chain and fee rate data from a Bitcoin Core RPC backend, as well as experimental support for the [VSS] remote storage backend. ## Feature and API updates + - Support for multiple chain sources has been added. To this end, Esplora-specific configuration options can now be given via `EsploraSyncConfig` to `Builder::set_chain_source_esplora`. Furthermore, all configuration objects (including the main `Config`) is now exposed via the `config` sub-module (#365). - Support for sourcing chain and fee estimation data from a Bitcoin Core RPC backed has been added (#370). - Initial experimental support for an encrypted [VSS] remote storage backend has been added (#369, #376, #378). - - **Caution**: VSS support is in **alpha** and is considered experimental. Using VSS (or any remote persistence) may cause LDK to panic if persistence failures are unrecoverable, i.e., if they remain unresolved after internal retries are exhausted. + - **Caution**: VSS support is in **alpha** and is considered experimental. Using VSS (or any remote persistence) may cause LDK to panic if persistence failures are unrecoverable, i.e., if they remain unresolved after internal retries are exhausted. - Support for setting the `NodeAlias` in public node announcements as been added. We now ensure that announced channels can only be opened and accepted when the required configuration options to operate as a public forwarding node are set (listening addresses and node alias). As part of this `Node::connect_open_channel` was split into `open_channel` and `open_announced_channel` API methods. (#330, #366). - The `Node` can now be started via a new `Node::start_with_runtime` call that allows to reuse an outer `tokio` runtime context, avoiding runtime stacking when run in `async` environments (#319). - Support for generating and paying unified QR codes has been added (#302). @@ -219,16 +479,19 @@ Besides numerous API improvements and bugfixes this fourth minor release notably - Support for setting additional parameters when sending BOLT11 payments has been added (#336, #351). ## Bug Fixes + - The `ChannelConfig` object has been refactored, now allowing to query the currently applied `MaxDustHTLCExposure` limit (#350). - A bug potentially leading to panicking on shutdown when stacking `tokio` runtime contexts has been fixed (#373). - We now no longer panic when hitting a persistence failure during event handling. Instead, events will be replayed until successful (#374). -, + , + ## Compatibility Notes + - The LDK dependency has been updated to version 0.0.125 (#358, #375). - The BDK dependency has been updated to version 1.0-beta.4 (#358). - - Going forward, the BDK state will be persisted in the configured `KVStore` backend. - - **Note**: The old descriptor state will *not* be automatically migrated on upgrade, potentially leading to address reuse. Privacy-concious users might want to manually advance the descriptor by requesting new addresses until it reaches the previously observed height. - - After the node as been successfully upgraded users may safely delete `bdk_wallet_*.sqlite` from the storage path. + - Going forward, the BDK state will be persisted in the configured `KVStore` backend. + - **Note**: The old descriptor state will _not_ be automatically migrated on upgrade, potentially leading to address reuse. Privacy-concious users might want to manually advance the descriptor by requesting new addresses until it reaches the previously observed height. + - After the node as been successfully upgraded users may safely delete `bdk_wallet_*.sqlite` from the storage path. - The `rust-bitcoin` dependency has been updated to version 0.32.2 (#358). - The UniFFI dependency has been updated to version 0.27.3 (#379). - The `bip21` dependency has been updated to version 0.5 (#358). @@ -251,6 +514,7 @@ This third minor release notably adds support for BOLT12 payments, Anchor channels, and sourcing inbound liquidity via LSPS2 just-in-time channels. ## Feature and API updates + - Support for creating and paying BOLT12 offers and refunds has been added (#265). - Support for Anchor channels has been added (#141). - Support for sourcing inbound liquidity via LSPS2 just-in-time (JIT) channels has been added (#223). @@ -268,6 +532,7 @@ channels, and sourcing inbound liquidity via LSPS2 just-in-time channels. - The ability to register and claim from custom payment hashes generated outside of LDK Node has been added (#308). ## Bug Fixes + - Node announcements are now correctly only broadcast if we have any public, sufficiently confirmed channels (#248, #314). - Falling back to default fee values is now disallowed on mainnet, ensuring we won't startup without a successful fee cache update (#249). - Persisted peers are now correctly reconnected after startup (#265). @@ -275,6 +540,7 @@ channels, and sourcing inbound liquidity via LSPS2 just-in-time channels. - Several steps have been taken to reduce the risk of blocking node operation on wallet syncing in the face of unresponsive Esplora services (#281). ## Compatibility Notes + - LDK has been updated to version 0.0.123 (#291). In total, this release features 54 files changed, 7282 insertions, 2410 deletions in 165 commits from 3 authors, in alphabetical order: @@ -303,9 +569,11 @@ This is a bugfix release bumping the used LDK and BDK dependencies to the latest stable versions. ## Bug Fixes + - Swift bindings now can be built on macOS again. ## Compatibility Notes + - LDK has been updated to version 0.0.121 (#214, #229) - BDK has been updated to version 0.29.0 (#229) @@ -319,6 +587,7 @@ deletions in 26 commits from 3 authors, in alphabetical order: # 0.2.0 - Dec 13, 2023 ## Feature and API updates + - The capability to send pre-flight probes has been added (#147). - Pre-flight probes will skip outbound channels based on the liquidity available (#156). - Additional fields are now exposed via `ChannelDetails` (#165). @@ -329,10 +598,12 @@ deletions in 26 commits from 3 authors, in alphabetical order: - A module persisting, sweeping, and rebroadcasting output spends has been added (#152). ## Bug Fixes + - No errors are logged anymore when we choose to omit spending of `StaticOutput`s (#137). - An inconsistent state of the log file symlink no longer results in an error during startup (#153). ## Compatibility Notes + - Our currently supported minimum Rust version (MSRV) is 1.63.0. - The Rust crate edition has been bumped to 2021. - Building on Windows is now supported (#160). @@ -351,6 +622,7 @@ In total, this release features 57 files changed, 7369 insertions, 1738 deletion - Orbital # 0.1.0 - Jun 22, 2023 + This is the first non-experimental release of LDK Node. - Log files are now split based on the start date of the node (#116). @@ -364,15 +636,18 @@ This is the first non-experimental release of LDK Node. - The API has been updated to be more aligned between Rust and bindings (#114). ## Compatibility Notes + - Our currently supported minimum Rust version (MSRV) is 1.60.0. - The superfluous `SendingFailed` payment status has been removed, breaking serialization compatibility with alpha releases (#125). - The serialization formats of `PaymentDetails` and `Event` types have been updated, ensuring users upgrading from an alpha release fail to start rather than continuing operating with bogus data. Alpha users should wipe their persisted payment metadata (`payments/*`) and event queue (`events`) after the update (#130). In total, this release includes changes in 52 commits from 2 authors: + - Elias Rohrer - Richard Ulrich # 0.1-alpha.1 - Jun 6, 2023 + - Generation of Swift, Kotlin (JVM and Android), and Python bindings is now supported through UniFFI (#25). - Lists of connected peers and channels may now be retrieved in bindings (#56). - Gossip data may now be sourced from the P2P network, or a Rapid Gossip Sync server (#70). @@ -387,8 +662,8 @@ In total, this release includes changes in 52 commits from 2 authors: - The wallet sync intervals are now configurable (#102). - Granularity of logging can now be configured (#108). - In total, this release includes changes in 64 commits from 4 authors: + - Steve Myers - Elias Rohrer - Jurvis Tan @@ -398,6 +673,7 @@ In total, this release includes changes in 64 commits from 4 authors: production, and no compatibility guarantees are given until the release of 0.1. # 0.1-alpha - Apr 27, 2023 + This is the first alpha release of LDK Node. It features support for sourcing chain data via an Esplora server, file system persistence, gossip sourcing via the Lightning peer-to-peer network, and configurable entropy sources for the @@ -405,4 +681,3 @@ integrated LDK and BDK-based wallets. **Note:** This release is still considered experimental, should not be run in production, and no compatibility guarantees are given until the release of 0.1. - diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 0000000000..47dc3e3d86 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 5df9b33092..b8da51d740 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,10 @@ +[workspace] +members = [".", "crates/bdk-wallet-aggregate"] +exclude = ["bindings/uniffi-bindgen"] + [package] name = "ldk-node" -version = "0.7.0+git" +version = "0.7.0-rc.63" authors = ["Elias Rohrer "] homepage = "https://lightningdevkit.org/" license = "MIT OR Apache-2.0" @@ -29,22 +33,23 @@ panic = 'abort' # Abort on panic default = [] [dependencies] -lightning = { version = "0.2.0-rc1", features = ["std"] } -lightning-types = { version = "0.3.0-rc1" } -lightning-invoice = { version = "0.34.0-rc1", features = ["std"] } -lightning-net-tokio = { version = "0.2.0-rc1" } -lightning-persister = { version = "0.2.0-rc1", features = ["tokio"] } -lightning-background-processor = { version = "0.2.0-rc1" } -lightning-rapid-gossip-sync = { version = "0.2.0-rc1" } -lightning-block-sync = { version = "0.2.0-rc1", features = ["rest-client", "rpc-client", "tokio"] } -lightning-transaction-sync = { version = "0.2.0-rc1", features = ["esplora-async-https", "time", "electrum-rustls-ring"] } -lightning-liquidity = { version = "0.2.0-rc1", features = ["std"] } -lightning-macros = { version = "0.2.0-rc1" } +lightning = { version = "0.2.0", features = ["std"] } +lightning-types = { version = "0.3.0" } +lightning-invoice = { version = "0.34.0", features = ["std"] } +lightning-net-tokio = { version = "0.2.0" } +lightning-persister = { version = "0.2.0", features = ["tokio"] } +lightning-background-processor = { version = "0.2.0" } +lightning-rapid-gossip-sync = { version = "0.2.0" } +lightning-block-sync = { version = "0.2.0", features = ["rest-client", "rpc-client", "tokio"] } +lightning-transaction-sync = { version = "0.2.0", features = ["esplora-async-https", "time", "electrum-rustls-ring"] } +lightning-liquidity = { version = "0.2.0", features = ["std"] } +lightning-macros = { version = "0.2.0" } bdk_chain = { version = "0.23.0", default-features = false, features = ["std"] } bdk_esplora = { version = "0.22.0", default-features = false, features = ["async-https-rustls", "tokio"]} bdk_electrum = { version = "0.23.0", default-features = false, features = ["use-rustls-ring"]} bdk_wallet = { version = "2.2.0", default-features = false, features = ["std", "keys-bip39"]} +bdk-wallet-aggregate = { path = "crates/bdk-wallet-aggregate" } reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] } rustls = { version = "0.23", default-features = false } @@ -64,6 +69,7 @@ uniffi = { version = "0.28.3", features = ["build"], optional = true } serde = { version = "1.0.210", default-features = false, features = ["std", "derive"] } serde_json = { version = "1.0.128", default-features = false, features = ["std"] } log = { version = "0.4.22", default-features = false, features = ["std"]} +zeroize = "1.8" vss-client = { package = "vss-client-ng", version = "0.4" } prost = { version = "0.11.6", default-features = false} @@ -72,7 +78,7 @@ prost = { version = "0.11.6", default-features = false} winapi = { version = "0.3", features = ["winbase"] } [dev-dependencies] -lightning = { version = "0.2.0-rc1", features = ["std", "_test_utils"] } +lightning = { version = "0.2.0", features = ["std", "_test_utils"] } proptest = "1.0.0" regex = "1.5.6" criterion = { version = "0.7.0", features = ["async_tokio"] } diff --git a/GEMINI.md b/GEMINI.md new file mode 120000 index 0000000000..47dc3e3d86 --- /dev/null +++ b/GEMINI.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file diff --git a/MOBILE_DEVELOPER_GUIDE.md b/MOBILE_DEVELOPER_GUIDE.md new file mode 100644 index 0000000000..800a01bad1 --- /dev/null +++ b/MOBILE_DEVELOPER_GUIDE.md @@ -0,0 +1,1094 @@ +# LDK Node - New Events API Guide for Mobile Developers + +## Overview + +This guide covers the new event system added to LDK Node that provides real-time notifications for wallet and Lightning channel state changes. These events eliminate the need for polling and provide instant updates for better user experience and battery efficiency. + +## Table of Contents +1. [New Event Types](#new-event-types) +2. [iOS/Swift Implementation](#iosswift-implementation) +3. [Android/Kotlin Implementation](#androidkotlin-implementation) +4. [Migration Guide](#migration-guide) +5. [Best Practices](#best-practices) +6. [Testing Recommendations](#testing-recommendations) + +--- + +## New Event Types + +### 1. Onchain Transaction Events + +These events notify you about Bitcoin transactions affecting your onchain wallet: + +#### `OnchainTransactionReceived` +- **When**: New unconfirmed transaction detected in mempool +- **Use Case**: Show "Payment incoming!" notification immediately +- **Fields**: + - `txid`: Transaction ID + - `details`: `TransactionDetails` object with comprehensive transaction information + +#### `OnchainTransactionConfirmed` +- **When**: Transaction receives blockchain confirmations +- **Use Case**: Update transaction status from pending to confirmed +- **Fields**: + - `txid`: Transaction ID + - `blockHash`: Block hash where confirmed + - `blockHeight`: Block height + - `confirmationTime`: Unix timestamp + - `details`: `TransactionDetails` object with comprehensive transaction information + +#### `OnchainTransactionReplaced` +- **When**: Transaction is replaced via Replace-By-Fee (RBF) +- **Use Case**: Update UI to show the transaction was replaced +- **Fields**: + - `txid`: Transaction ID of the transaction that was replaced (the old transaction) + - `conflicts`: Array of transaction IDs that replaced this transaction (the replacement transactions) + +#### `OnchainTransactionReorged` +- **When**: Previously confirmed transaction becomes unconfirmed due to blockchain reorg +- **Use Case**: Mark transaction as pending again +- **Fields**: + - `txid`: Transaction ID + +#### `OnchainTransactionEvicted` +- **When**: Transaction is evicted from the mempool (no longer unconfirmed and not confirmed) +- **Use Case**: Mark transaction as evicted, potentially allow user to rebroadcast +- **Fields**: + - `txid`: Transaction ID +- **Note**: Works with all chain sources (Esplora, Electrum, and BitcoindRpc) + +### 2. Sync Events + +Track synchronization progress and completion: + +#### `SyncProgress` +- **When**: Periodically during sync operations +- **Use Case**: Show progress bar during sync +- **Fields**: + - `syncType`: What's syncing (OnchainWallet, LightningWallet, FeeRateCache) + - `progressPercent`: 0-100 + - `currentBlockHeight`: Current sync position + - `targetBlockHeight`: Target height + +#### `SyncCompleted` +- **When**: Sync operation finishes successfully +- **Use Case**: Hide progress indicators, enable UI +- **Fields**: + - `syncType`: What completed syncing + - `syncedBlockHeight`: Final synced height + +### 3. Balance Events + +#### `BalanceChanged` +- **When**: Onchain or Lightning balance changes +- **Use Case**: Update balance display immediately +- **Fields**: + - `oldSpendableOnchainBalanceSats`: Previous spendable onchain balance + - `newSpendableOnchainBalanceSats`: New spendable onchain balance + - `oldTotalOnchainBalanceSats`: Previous total onchain (including unconfirmed) + - `newTotalOnchainBalanceSats`: New total onchain + - `oldTotalLightningBalanceSats`: Previous Lightning balance + - `newTotalLightningBalanceSats`: New Lightning balance + +### 4. Transaction Details + +The `TransactionDetails` struct provides comprehensive information about transactions, allowing you to analyze transaction purposes yourself: + +#### `TransactionDetails` +- `amountSats`: Net amount in satoshis (positive for incoming, negative for outgoing) +- `inputs`: Array of `TxInput` objects +- `outputs`: Array of `TxOutput` objects + +#### `TxInput` +- `txid`: Previous transaction ID being spent +- `vout`: Output index being spent +- `scriptsig`: Script signature (hex-encoded) +- `witness`: Witness stack (array of hex-encoded strings) +- `sequence`: Sequence number + +#### `TxOutput` +- `scriptpubkey`: Script public key (hex-encoded) +- `scriptpubkeyType`: Script type (e.g., "p2wpkh", "p2wsh", "p2tr") +- `scriptpubkeyAddress`: Bitcoin address (if decodable) +- `value`: Value in satoshis +- `n`: Output index + +**Note**: You can analyze transaction inputs and outputs to detect channel funding, channel closures, and other transaction types. This provides more flexibility than the previous `TransactionContext` enum. + +#### Retrieving Transaction Details + +You can also retrieve transaction details directly using `Node::get_transaction_details()`: + +```swift +// Get transaction details for a specific transaction ID +if let details = node.getTransactionDetails(txid: txid) { + // Analyze the transaction details + print("Transaction amount: \(details.amountSats) sats") + print("Number of inputs: \(details.inputs.count)") + print("Number of outputs: \(details.outputs.count)") +} else { + // Transaction not found in wallet + print("Transaction not found") +} +``` + +This method returns `nil` if the transaction is not found in the wallet. + +#### Retrieving Address Balance + +You can retrieve the current balance for any Bitcoin address using `Node::get_address_balance()`: + +```swift +// Get balance for a Bitcoin address +do { + let balance = try node.getAddressBalance(addressStr: "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh") + print("Address balance: \(balance) sats") +} catch { + // Invalid address or network mismatch + print("Error: \(error)") +} +``` + +```kotlin +// Get balance for a Bitcoin address +try { + val balance = node.getAddressBalance("bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh") + println("Address balance: $balance sats") +} catch (e: Exception) { + // Invalid address or network mismatch + println("Error: ${e.message}") +} +``` + +**Note**: This method queries the chain source directly and returns the balance in satoshis. It throws an error if the address string cannot be parsed or doesn't match the node's network. It returns `0` if the balance cannot be queried (e.g., chain source unavailable). This method is not available when using BitcoindRpc as the chain source. + +--- + +## iOS/Swift Implementation + +### Setup and Basic Event Handling + +```swift +import LDKNode + +class WalletEventHandler { + private let node: Node + private var eventTimer: Timer? + + init(node: Node) { + self.node = node + startEventHandling() + } + + func startEventHandling() { + // Check for events every 100ms + eventTimer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { _ in + self.processNextEvent() + } + } + + func processNextEvent() { + guard let event = node.nextEvent() else { return } + + handleEvent(event) + node.eventHandled() + } + + func handleEvent(_ event: Event) { + switch event { + case .onchainTransactionReceived(let txid, let details): + handleIncomingTransaction(txid: txid, details: details) + + case .onchainTransactionConfirmed(let txid, let blockHash, let blockHeight, let confirmationTime, let details): + handleConfirmedTransaction(txid: txid, height: blockHeight, details: details) + + case .onchainTransactionReplaced(let txid, let conflicts): + handleReplacedTransaction(txid: txid, conflicts: conflicts) + + case .onchainTransactionReorged(let txid): + handleReorgedTransaction(txid: txid) + + case .onchainTransactionEvicted(let txid): + handleEvictedTransaction(txid: txid) + + case .syncProgress(let syncType, let progressPercent, let currentBlock, let targetBlock): + updateSyncProgress(type: syncType, percent: progressPercent) + + case .syncCompleted(let syncType, let syncedHeight): + handleSyncCompleted(type: syncType, height: syncedHeight) + + case .balanceChanged(let oldSpendable, let newSpendable, let oldTotal, let newTotal, let oldLightning, let newLightning): + updateBalances(onchain: newSpendable, lightning: newLightning) + + default: + // Handle other existing events + break + } + } +} +``` + +### Practical Examples + +#### Example 1: Real-time Transaction Notifications + +```swift +func handleIncomingTransaction(txid: String, details: TransactionDetails) { + DispatchQueue.main.async { + if details.amountSats > 0 { + // Incoming payment + self.showNotification( + title: "Payment Received!", + body: "Incoming payment of \(details.amountSats) sats (unconfirmed)", + txid: txid + ) + + // Update UI to show pending transaction + self.addPendingTransaction(txid: txid, amount: details.amountSats) + + // Play sound or haptic feedback + self.playPaymentReceivedSound() + } else { + // Outgoing payment + self.updateTransactionStatus(txid: txid, status: .broadcasting) + } + + // Analyze transaction to detect channel-related transactions + if self.isChannelFundingTransaction(details: details) { + print("Channel funding transaction detected") + } else if self.isChannelClosureTransaction(details: details) { + print("Channel closure transaction detected") + } + } +} + +func handleConfirmedTransaction(txid: String, height: UInt32, details: TransactionDetails) { + DispatchQueue.main.async { + // Update transaction status + self.updateTransactionStatus(txid: txid, status: .confirmed(height: height)) + + // Show confirmation notification + self.showNotification( + title: "Payment Confirmed!", + body: "Transaction confirmed at block \(height)", + txid: txid + ) + + // Refresh transaction list + self.refreshTransactionList() + } +} + +func handleReplacedTransaction(txid: String, conflicts: [String]) { + DispatchQueue.main.async { + self.updateTransactionStatus(txid: txid, status: .replaced) + + if conflicts.isEmpty { + self.showNotification( + title: "Transaction Replaced", + body: "Transaction was replaced via RBF", + txid: txid + ) + } else { + self.showNotification( + title: "Transaction Replaced", + body: "Transaction was replaced by \(conflicts.count) transaction(s)", + txid: txid + ) + // Track replacement transactions + for conflictTxid in conflicts { + self.trackReplacementTransaction(originalTxid: txid, replacementTxid: conflictTxid) + } + } + } +} + +func handleReorgedTransaction(txid: String) { + DispatchQueue.main.async { + self.updateTransactionStatus(txid: txid, status: .pending) + self.showNotification( + title: "Transaction Unconfirmed", + body: "Transaction became unconfirmed due to reorg", + txid: txid + ) + } +} + +func handleEvictedTransaction(txid: String) { + DispatchQueue.main.async { + self.updateTransactionStatus(txid: txid, status: .evicted) + self.showNotification( + title: "Transaction Evicted", + body: "Transaction was evicted from mempool", + txid: txid + ) + // Optionally allow user to rebroadcast + self.promptRebroadcast(txid: txid) + } +} + +// Helper functions to analyze transaction details +func isChannelFundingTransaction(details: TransactionDetails) -> Bool { + // Analyze inputs/outputs to detect channel funding + // This is a simplified example - implement based on your needs + return details.outputs.count == 2 && details.amountSats > 0 +} + +func isChannelClosureTransaction(details: TransactionDetails) -> Bool { + // Analyze inputs/outputs to detect channel closure + // This is a simplified example - implement based on your needs + return details.inputs.count > 0 && details.outputs.count >= 2 +} +``` + +#### Example 2: Sync Progress Bar + +```swift +class SyncProgressView: UIView { + @IBOutlet weak var progressBar: UIProgressView! + @IBOutlet weak var statusLabel: UILabel! + @IBOutlet weak var blockHeightLabel: UILabel! + + func updateSyncProgress(type: SyncType, percent: UInt8) { + DispatchQueue.main.async { + self.progressBar.progress = Float(percent) / 100.0 + + switch type { + case .onchainWallet: + self.statusLabel.text = "Syncing wallet: \(percent)%" + case .lightningWallet: + self.statusLabel.text = "Syncing Lightning: \(percent)%" + case .feeRateCache: + self.statusLabel.text = "Updating fee rates: \(percent)%" + } + + self.progressBar.isHidden = false + } + } + + func handleSyncCompleted(type: SyncType, height: UInt32) { + DispatchQueue.main.async { + self.progressBar.isHidden = true + self.statusLabel.text = "Synced to block \(height)" + self.blockHeightLabel.text = "\(height)" + + // Enable send/receive buttons + self.enableTransactionButtons() + } + } +} +``` + +#### Example 3: Live Balance Updates + +```swift +class BalanceViewController: UIViewController { + @IBOutlet weak var onchainBalanceLabel: UILabel! + @IBOutlet weak var lightningBalanceLabel: UILabel! + @IBOutlet weak var totalBalanceLabel: UILabel! + + func updateBalances(onchain: UInt64, lightning: UInt64) { + DispatchQueue.main.async { + // Format with thousand separators + let formatter = NumberFormatter() + formatter.numberStyle = .decimal + formatter.groupingSeparator = "," + + let onchainFormatted = formatter.string(from: NSNumber(value: onchain)) ?? "0" + let lightningFormatted = formatter.string(from: NSNumber(value: lightning)) ?? "0" + let totalFormatted = formatter.string(from: NSNumber(value: onchain + lightning)) ?? "0" + + // Animate the balance change + UIView.animate(withDuration: 0.3) { + self.onchainBalanceLabel.alpha = 0.5 + self.lightningBalanceLabel.alpha = 0.5 + } completion: { _ in + self.onchainBalanceLabel.text = "\(onchainFormatted) sats" + self.lightningBalanceLabel.text = "\(lightningFormatted) sats" + self.totalBalanceLabel.text = "\(totalFormatted) sats" + + UIView.animate(withDuration: 0.3) { + self.onchainBalanceLabel.alpha = 1.0 + self.lightningBalanceLabel.alpha = 1.0 + } + } + + // Flash green for increase, red for decrease + if onchain > self.previousOnchainBalance { + self.flashColor(self.onchainBalanceLabel, color: .systemGreen) + } + } + } + + private func flashColor(_ label: UILabel, color: UIColor) { + let originalColor = label.textColor + label.textColor = color + UIView.animate(withDuration: 1.0) { + label.textColor = originalColor + } + } +} +``` + +--- + +## Android/Kotlin Implementation + +### Setup and Basic Event Handling + +```kotlin +import org.lightningdevkit.ldknode.* +import kotlinx.coroutines.* + +class WalletEventHandler(private val node: Node) { + private var eventJob: Job? = null + + fun startEventHandling() { + eventJob = GlobalScope.launch { + while (isActive) { + processNextEvent() + delay(100) // Check every 100ms + } + } + } + + fun stopEventHandling() { + eventJob?.cancel() + } + + private fun processNextEvent() { + val event = node.nextEvent() ?: return + + handleEvent(event) + node.eventHandled() + } + + private fun handleEvent(event: Event) { + when (event) { + is Event.OnchainTransactionReceived -> { + handleIncomingTransaction(event.txid, event.details) + } + + is Event.OnchainTransactionConfirmed -> { + handleConfirmedTransaction(event.txid, event.blockHeight, event.details) + } + + is Event.OnchainTransactionReplaced -> { + handleReplacedTransaction(event.txid, event.conflicts) + } + + is Event.OnchainTransactionReorged -> { + handleReorgedTransaction(event.txid) + } + + is Event.OnchainTransactionEvicted -> { + handleEvictedTransaction(event.txid) + } + + is Event.SyncProgress -> { + updateSyncProgress( + event.syncType, + event.progressPercent + ) + } + + is Event.SyncCompleted -> { + handleSyncCompleted( + event.syncType, + event.syncedBlockHeight + ) + } + + is Event.BalanceChanged -> { + updateBalances( + event.newSpendableOnchainBalanceSats, + event.newTotalLightningBalanceSats + ) + } + + else -> { + // Handle other existing events + } + } + } +} +``` + +### Practical Examples + +#### Example 1: Real-time Transaction Notifications + +```kotlin +class TransactionNotificationManager(private val context: Context) { + + fun handleIncomingTransaction(txid: String, details: TransactionDetails) { + GlobalScope.launch(Dispatchers.Main) { + if (details.amountSats > 0) { + // Incoming payment + showNotification( + title = "Payment Received!", + message = "Incoming payment of ${details.amountSats} sats (unconfirmed)", + txid = txid + ) + + // Update transaction list + addPendingTransaction(txid, details.amountSats) + + // Play sound + playPaymentSound() + } else { + // Outgoing payment + updateTransactionStatus(txid, TransactionStatus.BROADCASTING) + } + + // Analyze transaction to detect channel-related transactions + if (isChannelFundingTransaction(details)) { + Log.d("Wallet", "Channel funding transaction detected") + } else if (isChannelClosureTransaction(details)) { + Log.d("Wallet", "Channel closure transaction detected") + } + } + } + + fun handleConfirmedTransaction(txid: String, height: UInt, details: TransactionDetails) { + GlobalScope.launch(Dispatchers.Main) { + // Update status + updateTransactionStatus(txid, TransactionStatus.CONFIRMED) + + // Show notification + showNotification( + title = "Payment Confirmed!", + message = "Transaction confirmed at block $height", + txid = txid + ) + + // Vibrate + vibrate() + + // Refresh transaction list + refreshTransactionList() + } + } + + fun handleReplacedTransaction(txid: String, conflicts: List) { + GlobalScope.launch(Dispatchers.Main) { + updateTransactionStatus(txid, TransactionStatus.REPLACED) + + if (conflicts.isEmpty()) { + showNotification( + title = "Transaction Replaced", + message = "Transaction was replaced via RBF", + txid = txid + ) + } else { + showNotification( + title = "Transaction Replaced", + message = "Transaction was replaced by ${conflicts.size} transaction(s)", + txid = txid + ) + // Track replacement transactions + conflicts.forEach { conflictTxid -> + trackReplacementTransaction(originalTxid = txid, replacementTxid = conflictTxid) + } + } + } + } + + fun handleReorgedTransaction(txid: String) { + GlobalScope.launch(Dispatchers.Main) { + updateTransactionStatus(txid, TransactionStatus.PENDING) + showNotification( + title = "Transaction Unconfirmed", + message = "Transaction became unconfirmed due to reorg", + txid = txid + ) + } + } + + fun handleEvictedTransaction(txid: String) { + GlobalScope.launch(Dispatchers.Main) { + updateTransactionStatus(txid, TransactionStatus.EVICTED) + showNotification( + title = "Transaction Evicted", + message = "Transaction was evicted from mempool", + txid = txid + ) + // Optionally allow user to rebroadcast + promptRebroadcast(txid) + } + } + + // Retrieve transaction details directly + fun getTransactionDetails(txid: String): TransactionDetails? { + return node.getTransactionDetails(txid = txid) + } + + // Helper functions to analyze transaction details + private fun isChannelFundingTransaction(details: TransactionDetails): Boolean { + // Analyze inputs/outputs to detect channel funding + // This is a simplified example - implement based on your needs + return details.outputs.size == 2 && details.amountSats > 0 + } + + private fun isChannelClosureTransaction(details: TransactionDetails): Boolean { + // Analyze inputs/outputs to detect channel closure + // This is a simplified example - implement based on your needs + return details.inputs.isNotEmpty() && details.outputs.size >= 2 + } + } + } + + private fun showNotification(title: String, message: String, txid: String) { + val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + + val notification = NotificationCompat.Builder(context, CHANNEL_ID) + .setSmallIcon(R.drawable.ic_bitcoin) + .setContentTitle(title) + .setContentText(message) + .setPriority(NotificationCompat.PRIORITY_HIGH) + .setAutoCancel(true) + .build() + + notificationManager.notify(txid.hashCode(), notification) + } +} +``` + +#### Example 2: Sync Progress Implementation + +```kotlin +class SyncProgressFragment : Fragment() { + private lateinit var binding: FragmentSyncProgressBinding + + fun updateSyncProgress(type: SyncType, percent: UByte) { + activity?.runOnUiThread { + binding.progressBar.progress = percent.toInt() + binding.progressText.text = "$percent%" + + binding.statusText.text = when (type) { + SyncType.ONCHAIN_WALLET -> "Syncing wallet..." + SyncType.LIGHTNING_WALLET -> "Syncing Lightning..." + SyncType.FEE_RATE_CACHE -> "Updating fee rates..." + } + + binding.progressContainer.visibility = View.VISIBLE + } + } + + fun handleSyncCompleted(type: SyncType, height: UInt) { + activity?.runOnUiThread { + binding.progressContainer.visibility = View.GONE + binding.statusText.text = "Synced to block $height" + + // Enable transaction buttons + binding.sendButton.isEnabled = true + binding.receiveButton.isEnabled = true + + // Show success message + Snackbar.make( + binding.root, + "Sync completed!", + Snackbar.LENGTH_SHORT + ).show() + } + } +} +``` + +#### Example 3: Live Balance Updates with Animation + +```kotlin +class BalanceViewModel : ViewModel() { + private val _onchainBalance = MutableLiveData() + val onchainBalance: LiveData = _onchainBalance + + private val _lightningBalance = MutableLiveData() + val lightningBalance: LiveData = _lightningBalance + + fun updateBalances(onchain: ULong, lightning: ULong) { + _onchainBalance.postValue(onchain) + _lightningBalance.postValue(lightning) + } +} + +class BalanceFragment : Fragment() { + private lateinit var binding: FragmentBalanceBinding + private lateinit var viewModel: BalanceViewModel + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + // Observe balance changes + viewModel.onchainBalance.observe(viewLifecycleOwner) { balance -> + animateBalanceUpdate(binding.onchainBalanceText, balance) + } + + viewModel.lightningBalance.observe(viewLifecycleOwner) { balance -> + animateBalanceUpdate(binding.lightningBalanceText, balance) + } + } + + private fun animateBalanceUpdate(textView: TextView, newBalance: ULong) { + // Format with thousand separators + val formatted = NumberFormat.getNumberInstance(Locale.US) + .format(newBalance.toLong()) + + // Animate the change + ValueAnimator.ofFloat(0.5f, 1.0f).apply { + duration = 300 + addUpdateListener { animation -> + textView.alpha = animation.animatedValue as Float + } + start() + } + + textView.text = "$formatted sats" + + // Flash color for visual feedback + val originalColor = textView.currentTextColor + textView.setTextColor(Color.GREEN) + textView.postDelayed({ + textView.setTextColor(originalColor) + }, 500) + } +} +``` + +#### Example 4: Handling Chain Reorganizations + +```kotlin +class ReorgHandler(private val database: TransactionDatabase) { + + fun handleUnconfirmedTransaction(txid: String) { + GlobalScope.launch { + // Mark transaction as unconfirmed in database + database.updateTransactionStatus(txid, TransactionStatus.UNCONFIRMED) + + // Show warning to user + withContext(Dispatchers.Main) { + AlertDialog.Builder(context) + .setTitle("Transaction Unconfirmed") + .setMessage("Transaction $txid has become unconfirmed due to a blockchain reorganization. It may confirm again soon.") + .setPositiveButton("OK", null) + .show() + } + + // Log the event + Log.w("Wallet", "Transaction $txid unconfirmed due to reorg") + } + } +} +``` + +--- + +## Migration Guide + +### Moving from Polling to Events + +#### Before (Polling - Bad for Battery): +```kotlin +// DON'T DO THIS - Wastes battery and CPU +class OldWalletManager { + fun startPolling() { + timer.schedule(object : TimerTask() { + override fun run() { + // This runs even when nothing changed! + val balances = node.listBalances() + updateUI(balances) + + // Sync every time + node.syncWallets() + } + }, 0, 30000) // Every 30 seconds + } +} +``` + +#### After (Event-Driven - Efficient): +```kotlin +// DO THIS - Only runs when something actually happens +class NewWalletManager { + fun startEventHandling() { + GlobalScope.launch { + while (isActive) { + // This blocks until an event arrives - zero CPU usage while waiting! + val event = node.waitNextEvent() + + when (event) { + is Event.BalanceChanged -> updateUI(event) + is Event.OnchainTransactionReceived -> notify(event) + // ... handle other events + } + + node.eventHandled() + } + } + } +} +``` + +### Key Differences: +1. **No more timers** - Events arrive when things actually happen +2. **No more manual sync calls** - Background sync is automatic with events +3. **Instant updates** - Users see changes immediately, not after next poll +4. **Better battery life** - CPU sleeps between events + +--- + +## Best Practices + +### 1. Always Handle Events After Processing +```kotlin +// ALWAYS call eventHandled() after processing +val event = node.nextEvent() +if (event != null) { + processEvent(event) + node.eventHandled() // Critical - marks event as processed +} +``` + +### 2. Use Background Threads for Event Loop +```swift +// iOS - Use background queue +DispatchQueue.global(qos: .background).async { + while self.isRunning { + if let event = self.node.nextEvent() { + self.handleEvent(event) + self.node.eventHandled() + } + Thread.sleep(forTimeInterval: 0.1) + } +} +``` + +```kotlin +// Android - Use coroutines +GlobalScope.launch(Dispatchers.IO) { + while (isActive) { + node.nextEvent()?.let { event -> + handleEvent(event) + node.eventHandled() + } + delay(100) + } +} +``` + +### 3. Update UI on Main Thread +```swift +// iOS +DispatchQueue.main.async { + self.balanceLabel.text = "\(balance) sats" +} +``` + +```kotlin +// Android +runOnUiThread { + balanceTextView.text = "$balance sats" +} +``` + +### 4. Handle All Event Types +Even if you don't use them all, handle gracefully: +```kotlin +when (event) { + is Event.OnchainTransactionReceived -> handleTx(event) + is Event.BalanceChanged -> updateBalance(event) + // ... other events + else -> Log.d("Events", "Unhandled event: $event") +} +``` + +### 5. Persist Important State +Events may arrive while app is in background: +```kotlin +fun handleBalanceChanged(event: Event.BalanceChanged) { + // Save to persistent storage + preferences.edit() + .putLong("onchain_balance", event.newSpendableOnchainBalanceSats.toLong()) + .putLong("lightning_balance", event.newTotalLightningBalanceSats.toLong()) + .apply() + + // Then update UI if visible + if (isResumed) { + updateBalanceUI() + } +} +``` + +--- + +## Testing Recommendations + +### 1. Test Event Reception +```kotlin +@Test +fun testEventReception() { + // Fund the wallet + val address = node.onchainPayment().newAddress() + sendTestCoins(address, 100000) + + // Sync to detect transaction + node.syncWallets() + + // Should receive events + var receivedEvent = false + for (i in 0..10) { + val event = node.nextEvent() + if (event is Event.OnchainTransactionReceived) { + receivedEvent = true + assertEquals(100000, event.amountSats) + node.eventHandled() + break + } + Thread.sleep(100) + } + + assertTrue("Should receive transaction event", receivedEvent) +} +``` + +### 2. Test Balance Change Events +```kotlin +@Test +fun testBalanceChangeEvent() { + val initialBalance = node.listBalances().totalOnchainBalanceSats + + // Trigger a balance change + fundWallet(50000) + node.syncWallets() + + // Check for balance change event + var balanceChanged = false + for (i in 0..10) { + val event = node.nextEvent() + if (event is Event.BalanceChanged) { + assertEquals(initialBalance, event.oldTotalOnchainBalanceSats) + assertEquals(initialBalance + 50000, event.newTotalOnchainBalanceSats) + balanceChanged = true + node.eventHandled() + break + } + Thread.sleep(100) + } + + assertTrue("Should receive balance change event", balanceChanged) +} +``` + +### 3. Test Sync Events +```kotlin +@Test +fun testSyncCompletedEvent() { + node.syncWallets() + + var syncCompleted = false + for (i in 0..20) { + val event = node.nextEvent() + if (event is Event.SyncCompleted) { + assertEquals(SyncType.ONCHAIN_WALLET, event.syncType) + assertTrue(event.syncedBlockHeight > 0u) + syncCompleted = true + node.eventHandled() + break + } + Thread.sleep(100) + } + + assertTrue("Should receive sync completed event", syncCompleted) +} +``` + +### 4. Simulate Reorg Scenario +```swift +func testReorgHandling() { + // This is conceptual - actual reorg testing requires regtest setup + + // 1. Receive transaction + let txid = receiveTestTransaction() + + // 2. Wait for confirmation event + waitForEvent { event in + if case .onchainTransactionConfirmed(let id, _, _, _, _) = event { + return id == txid + } + return false + } + + // 3. Simulate reorg (in regtest) + // simulateReorg() + + // 4. Should receive unconfirmed event + waitForEvent { event in + if case .onchainTransactionUnconfirmed(let id) = event { + XCTAssertEqual(id, txid) + return true + } + return false + } +} +``` + +--- + +## Performance Considerations + +### Battery Usage +- Events use **significantly less battery** than polling +- Event checking (100ms interval) uses minimal CPU when no events +- Background sync runs automatically every ~30 seconds + +### Memory Usage +- Events are queued internally until handled +- Always call `eventHandled()` to free memory +- Don't accumulate events without processing + +### Network Usage +- Background sync is automatic - no need for manual sync calls +- Events arrive even when app is backgrounded (if node keeps running) +- Sync frequency is optimized for battery/data usage + +--- + +## Troubleshooting + +### Events Not Arriving? +1. Ensure node is started: `node.start()` +2. Check background sync is enabled (default) +3. Verify event loop is running +4. Check logs for sync errors + +### Duplicate Events? +- Always call `eventHandled()` after processing +- Don't process the same event multiple times +- Events are queued until marked handled + +### Missing Balance Updates? +- Balance events only emit when balance actually changes +- Check both onchain and Lightning balances +- Ensure wallet sync completed first + +--- + +## Support and Resources + +- **GitHub Issues**: Report bugs at https://github.com/lightningdevkit/ldk-node +- **API Documentation**: Full API docs for each platform +- **Example Apps**: Check the examples/ directory for complete implementations +- **Community**: LDK Discord for questions and support + +--- + +## Summary + +The new event system provides: +- ✅ **Real-time notifications** without polling +- ✅ **Better battery life** on mobile devices +- ✅ **Instant UI updates** for better UX +- ✅ **Automatic background sync** with progress tracking +- ✅ **Reorg handling** for blockchain reorganizations +- ✅ **Type-safe events** in both Swift and Kotlin + +Start with the basic event loop, handle the events you need, and enjoy a more responsive, battery-efficient Lightning wallet! \ No newline at end of file diff --git a/Package.swift b/Package.swift index 00f3eeb845..27f1a82b4e 100644 --- a/Package.swift +++ b/Package.swift @@ -1,11 +1,11 @@ -// swift-tools-version:5.5 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription -let tag = "v0.6.2" -let checksum = "dee28eb2bc019eeb61cc28ca5c19fdada465a6eb2b5169d2dbaa369f0c63ba03" -let url = "https://github.com/lightningdevkit/ldk-node/releases/download/\(tag)/LDKNodeFFI.xcframework.zip" +let tag = "v0.7.0-rc.63" +let checksum = "8890d1b91f2b3e0a33ffd2854e1a4e9721e99706e8378177d30fbc435cd2db49" +let url = "https://github.com/synonymdev/ldk-node/releases/download/\(tag)/LDKNodeFFI.xcframework.zip" let package = Package( name: "ldk-node", diff --git a/WARP.md b/WARP.md new file mode 120000 index 0000000000..47dc3e3d86 --- /dev/null +++ b/WARP.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file diff --git a/benches/payments.rs b/benches/payments.rs index ba69e046d4..05d693aca9 100644 --- a/benches/payments.rs +++ b/benches/payments.rs @@ -132,8 +132,14 @@ fn payment_benchmark(c: &mut Criterion) { let runtime = tokio::runtime::Builder::new_multi_thread().worker_threads(4).enable_all().build().unwrap(); + #[cfg(not(feature = "uniffi"))] let node_a = Arc::new(node_a); + #[cfg(feature = "uniffi")] + let node_a = node_a; + #[cfg(not(feature = "uniffi"))] let node_b = Arc::new(node_b); + #[cfg(feature = "uniffi")] + let node_b = node_b; // Fund the nodes and setup a channel between them. The criterion function cannot be async, so we need to execute // the setup using a runtime. diff --git a/bindgen.sh b/bindgen.sh new file mode 100755 index 0000000000..4af5bde6e8 --- /dev/null +++ b/bindgen.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Install gobley-uniffi-bindgen once for all Kotlin scripts +echo "Installing gobley-uniffi-bindgen fork..." +cargo install --git https://github.com/ovitrif/gobley.git \ + --branch fix-v0.2.0 gobley-uniffi-bindgen --force +export BINDGEN_GOBLEY_INSTALLED=1 + +# Standardize on release-smaller for all targets +export BINDGEN_PROFILE="release-smaller" + +./scripts/uniffi_bindgen_generate.sh \ + && ./scripts/swift_create_xcframework_archive.sh diff --git a/bindings/README.md b/bindings/README.md new file mode 100644 index 0000000000..501d581825 --- /dev/null +++ b/bindings/README.md @@ -0,0 +1,20 @@ +## Generating the Bindings + +## Build All Bindings +Run in the root dir: +```sh +./bindgen.sh +``` + +--- + +Detailed instructions for publishing a new version of the bindings. + +1. Update `Cargo.toml` +2. Update `version` in: + - `bindings/kotlin/ldk-node-android/gradle.properties` + - `bindings/kotlin/ldk-node-jvm/gradle.properties` +3. Run the above command to build all bindings +4. Open a PR with the changes +5. Create a new GitHub release with a new tag like `v0.1.0`, uploading the following files: + - `bindings/swift/LDKNodeFFI.xcframework.zip` diff --git a/bindings/kotlin/.editorconfig b/bindings/kotlin/.editorconfig new file mode 100644 index 0000000000..ae0948687e --- /dev/null +++ b/bindings/kotlin/.editorconfig @@ -0,0 +1,7 @@ +# ktlint uses EditorConfig for indentation. Without this file it defaults to +# 2 spaces for Kotlin script, while Gradle/IntelliJ convention here is 4 spaces. +root = true + +[*.{kt,kts}] +indent_style = space +indent_size = 4 diff --git a/bindings/kotlin/ldk-node-android/README.md b/bindings/kotlin/ldk-node-android/README.md new file mode 100644 index 0000000000..68f1b2955f --- /dev/null +++ b/bindings/kotlin/ldk-node-android/README.md @@ -0,0 +1,35 @@ +## Publishing +Publishing new version guide. + +1. Run in root dir + `sh scripts/uniffi_bindgen_generate_kotlin_android.sh` + +1. Update `version` in `bindings/kotlin/ldk-node-android/gradle.properties`. + +1. Commit + +1. Push new branch (or new tag) + +1. In the android project: + + - in `settings.gradle.kts` add GitHub Packages repository: + + ```kt + dependencyResolutionManagement { + repositories { + google() + mavenCentral() + maven { + url = uri("https://maven.pkg.github.com/synonymdev/ldk-node") + credentials { + username = providers.gradleProperty("gpr.user").orNull ?: System.getenv("GITHUB_ACTOR") + password = providers.gradleProperty("gpr.key").orNull ?: System.getenv("GITHUB_TOKEN") + } + } + } + ``` + - add dependency in `libs.versions.toml`: + ```toml + ldk-node-android = { module = "com.synonym:ldk-node-android", version = "0.7.0-rc.26" } + ``` + - Run `Sync project with gradle files` action in android studio diff --git a/bindings/kotlin/ldk-node-android/build.gradle.kts b/bindings/kotlin/ldk-node-android/build.gradle.kts index bb38991d37..76bf5e6d33 100644 --- a/bindings/kotlin/ldk-node-android/build.gradle.kts +++ b/bindings/kotlin/ldk-node-android/build.gradle.kts @@ -4,15 +4,13 @@ buildscript { mavenCentral() } dependencies { - classpath("com.android.tools.build:gradle:7.1.2") + classpath("com.android.tools.build:gradle:8.1.1") } } plugins { + kotlin("android") version "2.2.0" apply false + kotlin("plugin.serialization") version "2.2.0" apply false } -// library version is defined in gradle.properties -val libraryVersion: String by project - -group = "org.lightningdevkit" -version = libraryVersion +// group and version are defined in gradle.properties diff --git a/bindings/kotlin/ldk-node-android/gradle.properties b/bindings/kotlin/ldk-node-android/gradle.properties index 578c3308b3..ad73ef0cfd 100644 --- a/bindings/kotlin/ldk-node-android/gradle.properties +++ b/bindings/kotlin/ldk-node-android/gradle.properties @@ -2,4 +2,5 @@ org.gradle.jvmargs=-Xmx1536m android.useAndroidX=true android.enableJetifier=true kotlin.code.style=official -libraryVersion=0.6.0 +group=com.synonym +version=0.7.0-rc.63 diff --git a/bindings/kotlin/ldk-node-android/gradle/wrapper/gradle-wrapper.properties b/bindings/kotlin/ldk-node-android/gradle/wrapper/gradle-wrapper.properties index f398c33c4b..42defcc94b 100644 --- a/bindings/kotlin/ldk-node-android/gradle/wrapper/gradle-wrapper.properties +++ b/bindings/kotlin/ldk-node-android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/bindings/kotlin/ldk-node-android/lib/build.gradle.kts b/bindings/kotlin/ldk-node-android/lib/build.gradle.kts index 69d126b546..8cff608b3d 100644 --- a/bindings/kotlin/ldk-node-android/lib/build.gradle.kts +++ b/bindings/kotlin/ldk-node-android/lib/build.gradle.kts @@ -1,9 +1,10 @@ -// library version is defined in gradle.properties -val libraryVersion: String by project +import java.io.ByteArrayOutputStream +import java.io.File plugins { id("com.android.library") - id("org.jetbrains.kotlin.android") version "1.6.10" + kotlin("android") + kotlin("plugin.serialization") id("maven-publish") id("signing") @@ -16,11 +17,11 @@ repositories { } android { + namespace = "org.lightningdevkit.ldknode" compileSdk = 34 defaultConfig { - minSdk = 21 - targetSdk = 31 + minSdk = 24 testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles("consumer-rules.pro") } @@ -32,6 +33,15 @@ android { } } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = "1.8" + } + publishing { singleVariant("release") { withSourcesJar() @@ -43,55 +53,159 @@ android { dependencies { implementation("net.java.dev.jna:jna:5.12.0@aar") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2") implementation("androidx.appcompat:appcompat:1.4.0") implementation("androidx.core:core-ktx:1.7.0") + implementation("org.jetbrains.kotlinx:atomicfu:0.27.0") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0") api("org.slf4j:slf4j-api:1.7.30") +} + +val androidNativeAbis = listOf("armeabi-v7a", "arm64-v8a", "x86_64") + +fun executableFromPath(name: String): String? { + return System.getenv("PATH") + ?.split(File.pathSeparator) + ?.asSequence() + ?.map { File(it, name) } + ?.firstOrNull { it.canExecute() } + ?.absolutePath +} + +fun findReadelf(): String { + executableFromPath("llvm-readelf")?.let { return it } + executableFromPath("readelf")?.let { return it } + + return listOf("ANDROID_NDK_ROOT", "ANDROID_NDK_HOME", "NDK_HOME") + .mapNotNull { System.getenv(it) } + .map { File(it, "toolchains/llvm/prebuilt") } + .firstNotNullOfOrNull { prebuiltDir -> + if (!prebuiltDir.isDirectory) return@firstNotNullOfOrNull null + + prebuiltDir + .walkTopDown() + .firstOrNull { it.name == "llvm-readelf" && it.canExecute() } + ?.absolutePath + } + ?: throw GradleException( + "llvm-readelf or readelf is required to validate Android native debug symbols" + ) +} + +fun Project.runReadelf(readelf: String, vararg args: String): Pair { + val stdout = ByteArrayOutputStream() + val stderr = ByteArrayOutputStream() + val result = exec { + commandLine(readelf, *args) + standardOutput = stdout + errorOutput = stderr + isIgnoreExitValue = true + } - androidTestImplementation("com.github.tony19:logback-android:2.0.0") - androidTestImplementation("androidx.test.ext:junit:1.1.3") - androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0") - androidTestImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4") - androidTestImplementation("org.jetbrains.kotlin:kotlin-test-junit") + return result.exitValue to stdout.toString().ifBlank { stderr.toString() } +} + +fun String.parseElfAlignment(): Long { + return if (startsWith("0x")) { + removePrefix("0x").toLong(16) + } else { + toLong() + } +} + +val validateReleaseNativeLibraries by tasks.registering { + group = "verification" + description = "Validates release JNI libraries are stripped and keep 16 KB LOAD alignment." + + doLast { + val readelf = findReadelf() + val loadAlignmentRegex = Regex("""^\s*LOAD\s+.*\s+(0x[0-9a-fA-F]+|\d+)\s*$""") + + androidNativeAbis.forEach { abi -> + val lib = layout.projectDirectory.file("src/main/jniLibs/$abi/libldk_node.so").asFile + if (!lib.isFile) { + throw GradleException("Android native library missing at '${lib.path}'") + } + + val (sectionsExit, sections) = runReadelf(readelf, "-S", lib.absolutePath) + if (sectionsExit != 0) { + throw GradleException("Unable to inspect Android native library sections: '${lib.path}'") + } + if (Regex("""\.debug_""").containsMatchIn(sections)) { + throw GradleException("Android release native library still contains .debug_* sections: '${lib.path}'") + } + + val wideHeaders = runReadelf(readelf, "-W", "-l", lib.absolutePath) + val headers = if (wideHeaders.first == 0) { + wideHeaders.second + } else { + val fallbackHeaders = runReadelf(readelf, "-l", lib.absolutePath) + if (fallbackHeaders.first != 0) { + throw GradleException("Unable to inspect Android native library headers: '${lib.path}'") + } + fallbackHeaders.second + } + + val alignments = headers + .lineSequence() + .mapNotNull { loadAlignmentRegex.matchEntire(it)?.groupValues?.get(1)?.parseElfAlignment() } + .toList() + + if (alignments.isEmpty() || alignments.any { it < 16_384 }) { + throw GradleException("Android native library is not 16 KB page-size aligned: '${lib.path}'") + } + } + } +} + +tasks.matching { it.name == "bundleReleaseAar" || it.name.startsWith("publish") }.configureEach { + dependsOn(validateReleaseNativeLibraries) } afterEvaluate { publishing { publications { create("maven") { - groupId = "org.lightningdevkit" - artifactId = "ldk-node-android" - version = libraryVersion + val mavenArtifactId = "ldk-node-android" + groupId = providers.gradleProperty("group").orNull ?: "com.synonym" + artifactId = mavenArtifactId + version = providers.gradleProperty("version").orNull ?: "0.0.0" from(components["release"]) + artifact(rootProject.layout.projectDirectory.file("native-debug-symbols.zip")) { + classifier = "native-debug-symbols" + extension = "zip" + } pom { - name.set("ldk-node-android") - description.set( - "LDK Node, a ready-to-go Lightning node library built using LDK and BDK." - ) - url.set("https://lightningdevkit.org") + name.set(mavenArtifactId) + description.set("LDK Node Android bindings (Synonym fork).") + url.set("https://github.com/synonymdev/ldk-node") licenses { - license { - name.set("APACHE 2.0") - url.set("https://github.com/lightningdevkit/ldk-node/blob/main/LICENSE-APACHE") - } license { name.set("MIT") - url.set("https://github.com/lightningdevkit/ldk-node/blob/main/LICENSE-MIT") + url.set("https://github.com/synonymdev/ldk-node/blob/main/LICENSE-MIT") } } developers { developer { - id.set("tnull") - name.set("Elias Rohrer") - email.set("dev@tnull.de") + id.set("synonymdev") + name.set("Synonym") + email.set("noreply@synonym.to") } } - scm { - connection.set("scm:git:github.com/lightningdevkit/ldk-node.git") - developerConnection.set("scm:git:ssh://github.com/lightningdevkit/ldk-node.git") - url.set("https://github.com/lightningdevkit/ldk-node/tree/main") - } + } + } + } + repositories { + maven { + val repo = System.getenv("GITHUB_REPO") + ?: providers.gradleProperty("gpr.repo").orNull + ?: "synonymdev/ldk-node" + name = "GitHubPackages" + url = uri("https://maven.pkg.github.com/$repo") + credentials { + username = System.getenv("GITHUB_ACTOR") ?: providers.gradleProperty("gpr.user").orNull + password = System.getenv("GITHUB_TOKEN") ?: providers.gradleProperty("gpr.key").orNull } } } @@ -103,7 +217,7 @@ signing { // val signingKey: String? by project // val signingPassword: String? by project // useInMemoryPgpKeys(signingKeyId, signingKey, signingPassword) - sign(publishing.publications) +// sign(publishing.publications) } ktlint { diff --git a/bindings/kotlin/ldk-node-android/lib/src/androidTest/kotlin/org/lightningdevkit/ldknode/AndroidLibTest.kt b/bindings/kotlin/ldk-node-android/lib/src/androidTest/kotlin/org/lightningdevkit/ldknode/AndroidLibTest.kt deleted file mode 100644 index fb29d32190..0000000000 --- a/bindings/kotlin/ldk-node-android/lib/src/androidTest/kotlin/org/lightningdevkit/ldknode/AndroidLibTest.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This Kotlin source file was generated by the Gradle 'init' task. - */ -package org.lightningdevkit.ldknode - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import kotlin.io.path.createTempDirectory -import kotlin.test.Test -import org.junit.runner.RunWith -import org.lightningdevkit.ldknode.* - -@RunWith(AndroidJUnit4::class) -class AndroidLibTest { - @Test - fun node_start_stop() { - val tmpDir1 = createTempDirectory("ldk_node").toString() - println("Random dir 1: $tmpDir1") - val tmpDir2 = createTempDirectory("ldk_node").toString() - println("Random dir 2: $tmpDir2") - - val listenAddress1 = "127.0.0.1:2323" - val listenAddress2 = "127.0.0.1:2324" - - val config1 = defaultConfig() - config1.storageDirPath = tmpDir1 - config1.listeningAddresses = listOf(listenAddress1) - config1.network = Network.REGTEST - - val config2 = defaultConfig() - config2.storageDirPath = tmpDir2 - config2.listeningAddresses = listOf(listenAddress2) - config2.network = Network.REGTEST - - val builder1 = Builder.fromConfig(config1) - val builder2 = Builder.fromConfig(config2) - - val node1 = builder1.build() - val node2 = builder2.build() - - node1.start() - node2.start() - - val nodeId1 = node1.nodeId() - println("Node Id 1: $nodeId1") - - val nodeId2 = node2.nodeId() - println("Node Id 2: $nodeId2") - - val address1 = node1.onchain_payment().newOnchainAddress() - println("Funding address 1: $address1") - - val address2 = node2.onchain_payment().newOnchainAddress() - println("Funding address 2: $address2") - - node1.stop() - node2.stop() - } -} diff --git a/bindings/kotlin/ldk-node-android/lib/src/main/AndroidManifest.xml b/bindings/kotlin/ldk-node-android/lib/src/main/AndroidManifest.xml index 035ab0e3fa..db8569cb7c 100644 --- a/bindings/kotlin/ldk-node-android/lib/src/main/AndroidManifest.xml +++ b/bindings/kotlin/ldk-node-android/lib/src/main/AndroidManifest.xml @@ -1,7 +1,5 @@ - + - diff --git a/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/arm64-v8a/libldk_node.so b/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/arm64-v8a/libldk_node.so new file mode 100755 index 0000000000..3237476e75 Binary files /dev/null and b/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/arm64-v8a/libldk_node.so differ diff --git a/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/armeabi-v7a/libldk_node.so b/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/armeabi-v7a/libldk_node.so new file mode 100755 index 0000000000..d8e9aee405 Binary files /dev/null and b/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/armeabi-v7a/libldk_node.so differ diff --git a/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/x86_64/libldk_node.so b/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/x86_64/libldk_node.so new file mode 100755 index 0000000000..d7cd64468d Binary files /dev/null and b/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/x86_64/libldk_node.so differ diff --git a/bindings/kotlin/ldk-node-android/lib/src/main/kotlin/org/lightningdevkit/ldknode/Library.kt b/bindings/kotlin/ldk-node-android/lib/src/main/kotlin/org/lightningdevkit/ldknode/Library.kt deleted file mode 100644 index 179dda05c5..0000000000 --- a/bindings/kotlin/ldk-node-android/lib/src/main/kotlin/org/lightningdevkit/ldknode/Library.kt +++ /dev/null @@ -1,10 +0,0 @@ -/* - * This Kotlin source file was generated by the Gradle 'init' task. - */ -package org.lightningdevkit.ldknode - -class Library { - fun someLibraryMethod(): Boolean { - return true - } -} diff --git a/bindings/kotlin/ldk-node-android/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.android.kt b/bindings/kotlin/ldk-node-android/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.android.kt new file mode 100644 index 0000000000..65e18cbb88 --- /dev/null +++ b/bindings/kotlin/ldk-node-android/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.android.kt @@ -0,0 +1,15207 @@ + + +@file:Suppress("RemoveRedundantBackticks") + +package org.lightningdevkit.ldknode + +// Common helper code. +// +// Ideally this would live in a separate .kt file where it can be unittested etc +// in isolation, and perhaps even published as a re-useable package. +// +// However, it's important that the details of how this helper code works (e.g. the +// way that different builtin types are passed across the FFI) exactly match what's +// expected by the Rust code on the other side of the interface. In practice right +// now that means coming from the exact some version of `uniffi` that was used to +// compile the Rust component. The easiest way to ensure this is to bundle the Kotlin +// helpers directly inline like we're doing here. + +import com.sun.jna.Library +import com.sun.jna.Native +import com.sun.jna.Structure +import android.os.Build +import androidx.annotation.RequiresApi +import kotlin.coroutines.resume +import kotlinx.coroutines.CancellableContinuation +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import kotlinx.coroutines.suspendCancellableCoroutine +import kotlinx.coroutines.withContext + + +internal typealias Pointer = com.sun.jna.Pointer +internal val NullPointer: Pointer? = com.sun.jna.Pointer.NULL +internal fun Pointer.toLong(): Long = Pointer.nativeValue(this) +internal fun kotlin.Long.toPointer() = com.sun.jna.Pointer(this) + + +@kotlin.jvm.JvmInline +value class ByteBuffer(private val inner: java.nio.ByteBuffer) { + init { + inner.order(java.nio.ByteOrder.BIG_ENDIAN) + } + + fun internal() = inner + + fun limit() = inner.limit() + + fun position() = inner.position() + + fun hasRemaining() = inner.hasRemaining() + + fun get() = inner.get() + + fun get(bytesToRead: Int): ByteArray = ByteArray(bytesToRead).apply(inner::get) + + fun getShort() = inner.getShort() + + fun getInt() = inner.getInt() + + fun getLong() = inner.getLong() + + fun getFloat() = inner.getFloat() + + fun getDouble() = inner.getDouble() + + + + fun put(value: Byte) { + inner.put(value) + } + + fun put(src: ByteArray) { + inner.put(src) + } + + fun putShort(value: Short) { + inner.putShort(value) + } + + fun putInt(value: Int) { + inner.putInt(value) + } + + fun putLong(value: Long) { + inner.putLong(value) + } + + fun putFloat(value: Float) { + inner.putFloat(value) + } + + fun putDouble(value: Double) { + inner.putDouble(value) + } + + + fun writeUtf8(value: String) { + Charsets.UTF_8.newEncoder().run { + onMalformedInput(java.nio.charset.CodingErrorAction.REPLACE) + encode(java.nio.CharBuffer.wrap(value), inner, false) + } + } +} +fun RustBuffer.setValue(array: RustBufferByValue) { + this.data = array.data + this.len = array.len + this.capacity = array.capacity +} + +internal object RustBufferHelper { + fun allocValue(size: ULong = 0UL): RustBufferByValue = uniffiRustCall { status -> + // Note: need to convert the size to a `Long` value to make this work with JVM. + UniffiLib.INSTANCE.ffi_ldk_node_rustbuffer_alloc(size.toLong(), status) + }.also { + if(it.data == null) { + throw RuntimeException("RustBuffer.alloc() returned null data pointer (size=${size})") + } + } + + fun free(buf: RustBufferByValue) = uniffiRustCall { status -> + UniffiLib.INSTANCE.ffi_ldk_node_rustbuffer_free(buf, status) + } +} + +@Structure.FieldOrder("capacity", "len", "data") +open class RustBufferStruct( + // Note: `capacity` and `len` are actually `ULong` values, but JVM only supports signed values. + // When dealing with these fields, make sure to call `toULong()`. + @JvmField internal var capacity: Long, + @JvmField internal var len: Long, + @JvmField internal var data: Pointer?, +) : Structure() { + constructor(): this(0.toLong(), 0.toLong(), null) + + class ByValue( + capacity: Long, + len: Long, + data: Pointer?, + ): RustBuffer(capacity, len, data), Structure.ByValue { + constructor(): this(0.toLong(), 0.toLong(), null) + } + + /** + * The equivalent of the `*mut RustBuffer` type. + * Required for callbacks taking in an out pointer. + * + * Size is the sum of all values in the struct. + */ + class ByReference( + capacity: Long, + len: Long, + data: Pointer?, + ): RustBuffer(capacity, len, data), Structure.ByReference { + constructor(): this(0.toLong(), 0.toLong(), null) + } +} + +typealias RustBuffer = RustBufferStruct +typealias RustBufferByValue = RustBufferStruct.ByValue + +internal fun RustBuffer.asByteBuffer(): ByteBuffer? { + require(this.len <= Int.MAX_VALUE) { + val length = this.len + "cannot handle RustBuffer longer than Int.MAX_VALUE bytes: length is $length" + } + return ByteBuffer(data?.getByteBuffer(0L, this.len) ?: return null) +} + +internal fun RustBufferByValue.asByteBuffer(): ByteBuffer? { + require(this.len <= Int.MAX_VALUE) { + val length = this.len + "cannot handle RustBuffer longer than Int.MAX_VALUE bytes: length is $length" + } + return ByteBuffer(data?.getByteBuffer(0L, this.len) ?: return null) +} + +internal class RustBufferByReference : com.sun.jna.ptr.ByReference(16) +internal fun RustBufferByReference.setValue(value: RustBufferByValue) { + // NOTE: The offsets are as they are in the C-like struct. + val pointer = getPointer() + pointer.setLong(0, value.capacity) + pointer.setLong(8, value.len) + pointer.setPointer(16, value.data) +} +internal fun RustBufferByReference.getValue(): RustBufferByValue { + val pointer = getPointer() + val value = RustBufferByValue() + value.writeField("capacity", pointer.getLong(0)) + value.writeField("len", pointer.getLong(8)) + value.writeField("data", pointer.getLong(16)) + return value +} + + + +// This is a helper for safely passing byte references into the rust code. +// It's not actually used at the moment, because there aren't many things that you +// can take a direct pointer to in the JVM, and if we're going to copy something +// then we might as well copy it into a `RustBuffer`. But it's here for API +// completeness. + +@Structure.FieldOrder("len", "data") +internal open class ForeignBytesStruct : Structure() { + @JvmField internal var len: Int = 0 + @JvmField internal var data: Pointer? = null + + internal class ByValue : ForeignBytes(), Structure.ByValue +} +internal typealias ForeignBytes = ForeignBytesStruct +internal typealias ForeignBytesByValue = ForeignBytesStruct.ByValue + +interface FfiConverter { + // Convert an FFI type to a Kotlin type + fun lift(value: FfiType): KotlinType + + // Convert an Kotlin type to an FFI type + fun lower(value: KotlinType): FfiType + + // Read a Kotlin type from a `ByteBuffer` + fun read(buf: ByteBuffer): KotlinType + + // Calculate bytes to allocate when creating a `RustBuffer` + // + // This must return at least as many bytes as the write() function will + // write. It can return more bytes than needed, for example when writing + // Strings we can't know the exact bytes needed until we the UTF-8 + // encoding, so we pessimistically allocate the largest size possible (3 + // bytes per codepoint). Allocating extra bytes is not really a big deal + // because the `RustBuffer` is short-lived. + fun allocationSize(value: KotlinType): ULong + + // Write a Kotlin type to a `ByteBuffer` + fun write(value: KotlinType, buf: ByteBuffer) + + // Lower a value into a `RustBuffer` + // + // This method lowers a value into a `RustBuffer` rather than the normal + // FfiType. It's used by the callback interface code. Callback interface + // returns are always serialized into a `RustBuffer` regardless of their + // normal FFI type. + fun lowerIntoRustBuffer(value: KotlinType): RustBufferByValue { + val rbuf = RustBufferHelper.allocValue(allocationSize(value)) + val bbuf = rbuf.asByteBuffer()!! + write(value, bbuf) + return RustBufferByValue( + capacity = rbuf.capacity, + len = bbuf.position().toLong(), + data = rbuf.data, + ) + } + + // Lift a value from a `RustBuffer`. + // + // This here mostly because of the symmetry with `lowerIntoRustBuffer()`. + // It's currently only used by the `FfiConverterRustBuffer` class below. + fun liftFromRustBuffer(rbuf: RustBufferByValue): KotlinType { + val byteBuf = rbuf.asByteBuffer()!! + try { + val item = read(byteBuf) + if (byteBuf.hasRemaining()) { + throw RuntimeException("junk remaining in buffer after lifting, something is very wrong!!") + } + return item + } finally { + RustBufferHelper.free(rbuf) + } + } +} + +// FfiConverter that uses `RustBuffer` as the FfiType +interface FfiConverterRustBuffer: FfiConverter { + override fun lift(value: RustBufferByValue) = liftFromRustBuffer(value) + override fun lower(value: KotlinType) = lowerIntoRustBuffer(value) +} + +internal const val UNIFFI_CALL_SUCCESS = 0.toByte() +internal const val UNIFFI_CALL_ERROR = 1.toByte() +internal const val UNIFFI_CALL_UNEXPECTED_ERROR = 2.toByte() + +// Default Implementations +internal fun UniffiRustCallStatus.isSuccess(): Boolean + = code == UNIFFI_CALL_SUCCESS + +internal fun UniffiRustCallStatus.isError(): Boolean + = code == UNIFFI_CALL_ERROR + +internal fun UniffiRustCallStatus.isPanic(): Boolean + = code == UNIFFI_CALL_UNEXPECTED_ERROR + +internal fun UniffiRustCallStatusByValue.isSuccess(): Boolean + = code == UNIFFI_CALL_SUCCESS + +internal fun UniffiRustCallStatusByValue.isError(): Boolean + = code == UNIFFI_CALL_ERROR + +internal fun UniffiRustCallStatusByValue.isPanic(): Boolean + = code == UNIFFI_CALL_UNEXPECTED_ERROR + +// Each top-level error class has a companion object that can lift the error from the call status's rust buffer +interface UniffiRustCallStatusErrorHandler { + fun lift(errorBuf: RustBufferByValue): E; +} + +// Helpers for calling Rust +// In practice we usually need to be synchronized to call this safely, so it doesn't +// synchronize itself + +// Call a rust function that returns a Result<>. Pass in the Error class companion that corresponds to the Err +internal inline fun uniffiRustCallWithError(errorHandler: UniffiRustCallStatusErrorHandler, crossinline callback: (UniffiRustCallStatus) -> U): U { + return UniffiRustCallStatusHelper.withReference() { status -> + val returnValue = callback(status) + uniffiCheckCallStatus(errorHandler, status) + returnValue + } +} + +// Check `status` and throw an error if the call wasn't successful +internal fun uniffiCheckCallStatus(errorHandler: UniffiRustCallStatusErrorHandler, status: UniffiRustCallStatus) { + if (status.isSuccess()) { + return + } else if (status.isError()) { + throw errorHandler.lift(status.errorBuf) + } else if (status.isPanic()) { + // when the rust code sees a panic, it tries to construct a rustbuffer + // with the message. but if that code panics, then it just sends back + // an empty buffer. + if (status.errorBuf.len > 0) { + throw InternalException(FfiConverterString.lift(status.errorBuf)) + } else { + throw InternalException("Rust panic") + } + } else { + throw InternalException("Unknown rust call status: $status.code") + } +} + +// UniffiRustCallStatusErrorHandler implementation for times when we don't expect a CALL_ERROR +object UniffiNullRustCallStatusErrorHandler: UniffiRustCallStatusErrorHandler { + override fun lift(errorBuf: RustBufferByValue): InternalException { + RustBufferHelper.free(errorBuf) + return InternalException("Unexpected CALL_ERROR") + } +} + +// Call a rust function that returns a plain value +internal inline fun uniffiRustCall(crossinline callback: (UniffiRustCallStatus) -> U): U { + return uniffiRustCallWithError(UniffiNullRustCallStatusErrorHandler, callback) +} + +internal inline fun uniffiTraitInterfaceCall( + callStatus: UniffiRustCallStatus, + makeCall: () -> T, + writeReturn: (T) -> Unit, +) { + try { + writeReturn(makeCall()) + } catch(e: kotlin.Exception) { + callStatus.code = UNIFFI_CALL_UNEXPECTED_ERROR + callStatus.errorBuf = FfiConverterString.lower(e.toString()) + } +} + +internal inline fun uniffiTraitInterfaceCallWithError( + callStatus: UniffiRustCallStatus, + makeCall: () -> T, + writeReturn: (T) -> Unit, + lowerError: (E) -> RustBufferByValue +) { + try { + writeReturn(makeCall()) + } catch(e: kotlin.Exception) { + if (e is E) { + callStatus.code = UNIFFI_CALL_ERROR + callStatus.errorBuf = lowerError(e) + } else { + callStatus.code = UNIFFI_CALL_UNEXPECTED_ERROR + callStatus.errorBuf = FfiConverterString.lower(e.toString()) + } + } +} + +@Structure.FieldOrder("code", "errorBuf") +internal open class UniffiRustCallStatusStruct( + @JvmField internal var code: Byte, + @JvmField internal var errorBuf: RustBufferByValue, +) : Structure() { + constructor(): this(0.toByte(), RustBufferByValue()) + + internal class ByValue( + code: Byte, + errorBuf: RustBufferByValue, + ): UniffiRustCallStatusStruct(code, errorBuf), Structure.ByValue { + constructor(): this(0.toByte(), RustBufferByValue()) + } + internal class ByReference( + code: Byte, + errorBuf: RustBufferByValue, + ): UniffiRustCallStatusStruct(code, errorBuf), Structure.ByReference { + constructor(): this(0.toByte(), RustBufferByValue()) + } +} + +internal typealias UniffiRustCallStatus = UniffiRustCallStatusStruct.ByReference +internal typealias UniffiRustCallStatusByValue = UniffiRustCallStatusStruct.ByValue + +internal object UniffiRustCallStatusHelper { + fun allocValue() = UniffiRustCallStatusByValue() + fun withReference(block: (UniffiRustCallStatus) -> U): U { + val status = UniffiRustCallStatus() + return block(status) + } +} + +internal class UniffiHandleMap { + private val map = java.util.concurrent.ConcurrentHashMap() + private val counter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + val size: Int + get() = map.size + + // Insert a new object into the handle map and get a handle for it + fun insert(obj: T): Long { + val handle = counter.getAndAdd(1) + map[handle] = obj + return handle + } + + // Get an object from the handle map + fun get(handle: Long): T { + return map[handle] ?: throw InternalException("UniffiHandleMap.get: Invalid handle") + } + + // Remove an entry from the handlemap and get the Kotlin object back + fun remove(handle: Long): T { + return map.remove(handle) ?: throw InternalException("UniffiHandleMap.remove: Invalid handle") + } +} + +typealias ByteByReference = com.sun.jna.ptr.ByteByReference + +typealias DoubleByReference = com.sun.jna.ptr.DoubleByReference + +typealias FloatByReference = com.sun.jna.ptr.FloatByReference + +typealias IntByReference = com.sun.jna.ptr.IntByReference + +typealias LongByReference = com.sun.jna.ptr.LongByReference + +typealias PointerByReference = com.sun.jna.ptr.PointerByReference + +typealias ShortByReference = com.sun.jna.ptr.ShortByReference + +// Contains loading, initialization code, +// and the FFI Function declarations in a com.sun.jna.Library. + +// Define FFI callback types +internal interface UniffiRustFutureContinuationCallback: com.sun.jna.Callback { + fun callback(`data`: Long,`pollResult`: Byte,) +} +internal interface UniffiForeignFutureFree: com.sun.jna.Callback { + fun callback(`handle`: Long,) +} +internal interface UniffiCallbackInterfaceFree: com.sun.jna.Callback { + fun callback(`handle`: Long,) +} +@Structure.FieldOrder("handle", "free") +internal open class UniffiForeignFutureStruct( + @JvmField internal var `handle`: Long, + @JvmField internal var `free`: UniffiForeignFutureFree?, +) : com.sun.jna.Structure() { + constructor(): this( + + `handle` = 0.toLong(), + + `free` = null, + + ) + + internal class UniffiByValue( + `handle`: Long, + `free`: UniffiForeignFutureFree?, + ): UniffiForeignFuture(`handle`,`free`,), Structure.ByValue +} + +internal typealias UniffiForeignFuture = UniffiForeignFutureStruct + +internal fun UniffiForeignFuture.uniffiSetValue(other: UniffiForeignFuture) { + `handle` = other.`handle` + `free` = other.`free` +} +internal fun UniffiForeignFuture.uniffiSetValue(other: UniffiForeignFutureUniffiByValue) { + `handle` = other.`handle` + `free` = other.`free` +} + +internal typealias UniffiForeignFutureUniffiByValue = UniffiForeignFutureStruct.UniffiByValue +@Structure.FieldOrder("returnValue", "callStatus") +internal open class UniffiForeignFutureStructU8Struct( + @JvmField internal var `returnValue`: Byte, + @JvmField internal var `callStatus`: UniffiRustCallStatusByValue, +) : com.sun.jna.Structure() { + constructor(): this( + + `returnValue` = 0.toByte(), + + `callStatus` = UniffiRustCallStatusHelper.allocValue(), + + ) + + internal class UniffiByValue( + `returnValue`: Byte, + `callStatus`: UniffiRustCallStatusByValue, + ): UniffiForeignFutureStructU8(`returnValue`,`callStatus`,), Structure.ByValue +} + +internal typealias UniffiForeignFutureStructU8 = UniffiForeignFutureStructU8Struct + +internal fun UniffiForeignFutureStructU8.uniffiSetValue(other: UniffiForeignFutureStructU8) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} +internal fun UniffiForeignFutureStructU8.uniffiSetValue(other: UniffiForeignFutureStructU8UniffiByValue) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} + +internal typealias UniffiForeignFutureStructU8UniffiByValue = UniffiForeignFutureStructU8Struct.UniffiByValue +internal interface UniffiForeignFutureCompleteU8: com.sun.jna.Callback { + fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructU8UniffiByValue,) +} +@Structure.FieldOrder("returnValue", "callStatus") +internal open class UniffiForeignFutureStructI8Struct( + @JvmField internal var `returnValue`: Byte, + @JvmField internal var `callStatus`: UniffiRustCallStatusByValue, +) : com.sun.jna.Structure() { + constructor(): this( + + `returnValue` = 0.toByte(), + + `callStatus` = UniffiRustCallStatusHelper.allocValue(), + + ) + + internal class UniffiByValue( + `returnValue`: Byte, + `callStatus`: UniffiRustCallStatusByValue, + ): UniffiForeignFutureStructI8(`returnValue`,`callStatus`,), Structure.ByValue +} + +internal typealias UniffiForeignFutureStructI8 = UniffiForeignFutureStructI8Struct + +internal fun UniffiForeignFutureStructI8.uniffiSetValue(other: UniffiForeignFutureStructI8) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} +internal fun UniffiForeignFutureStructI8.uniffiSetValue(other: UniffiForeignFutureStructI8UniffiByValue) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} + +internal typealias UniffiForeignFutureStructI8UniffiByValue = UniffiForeignFutureStructI8Struct.UniffiByValue +internal interface UniffiForeignFutureCompleteI8: com.sun.jna.Callback { + fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructI8UniffiByValue,) +} +@Structure.FieldOrder("returnValue", "callStatus") +internal open class UniffiForeignFutureStructU16Struct( + @JvmField internal var `returnValue`: Short, + @JvmField internal var `callStatus`: UniffiRustCallStatusByValue, +) : com.sun.jna.Structure() { + constructor(): this( + + `returnValue` = 0.toShort(), + + `callStatus` = UniffiRustCallStatusHelper.allocValue(), + + ) + + internal class UniffiByValue( + `returnValue`: Short, + `callStatus`: UniffiRustCallStatusByValue, + ): UniffiForeignFutureStructU16(`returnValue`,`callStatus`,), Structure.ByValue +} + +internal typealias UniffiForeignFutureStructU16 = UniffiForeignFutureStructU16Struct + +internal fun UniffiForeignFutureStructU16.uniffiSetValue(other: UniffiForeignFutureStructU16) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} +internal fun UniffiForeignFutureStructU16.uniffiSetValue(other: UniffiForeignFutureStructU16UniffiByValue) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} + +internal typealias UniffiForeignFutureStructU16UniffiByValue = UniffiForeignFutureStructU16Struct.UniffiByValue +internal interface UniffiForeignFutureCompleteU16: com.sun.jna.Callback { + fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructU16UniffiByValue,) +} +@Structure.FieldOrder("returnValue", "callStatus") +internal open class UniffiForeignFutureStructI16Struct( + @JvmField internal var `returnValue`: Short, + @JvmField internal var `callStatus`: UniffiRustCallStatusByValue, +) : com.sun.jna.Structure() { + constructor(): this( + + `returnValue` = 0.toShort(), + + `callStatus` = UniffiRustCallStatusHelper.allocValue(), + + ) + + internal class UniffiByValue( + `returnValue`: Short, + `callStatus`: UniffiRustCallStatusByValue, + ): UniffiForeignFutureStructI16(`returnValue`,`callStatus`,), Structure.ByValue +} + +internal typealias UniffiForeignFutureStructI16 = UniffiForeignFutureStructI16Struct + +internal fun UniffiForeignFutureStructI16.uniffiSetValue(other: UniffiForeignFutureStructI16) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} +internal fun UniffiForeignFutureStructI16.uniffiSetValue(other: UniffiForeignFutureStructI16UniffiByValue) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} + +internal typealias UniffiForeignFutureStructI16UniffiByValue = UniffiForeignFutureStructI16Struct.UniffiByValue +internal interface UniffiForeignFutureCompleteI16: com.sun.jna.Callback { + fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructI16UniffiByValue,) +} +@Structure.FieldOrder("returnValue", "callStatus") +internal open class UniffiForeignFutureStructU32Struct( + @JvmField internal var `returnValue`: Int, + @JvmField internal var `callStatus`: UniffiRustCallStatusByValue, +) : com.sun.jna.Structure() { + constructor(): this( + + `returnValue` = 0, + + `callStatus` = UniffiRustCallStatusHelper.allocValue(), + + ) + + internal class UniffiByValue( + `returnValue`: Int, + `callStatus`: UniffiRustCallStatusByValue, + ): UniffiForeignFutureStructU32(`returnValue`,`callStatus`,), Structure.ByValue +} + +internal typealias UniffiForeignFutureStructU32 = UniffiForeignFutureStructU32Struct + +internal fun UniffiForeignFutureStructU32.uniffiSetValue(other: UniffiForeignFutureStructU32) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} +internal fun UniffiForeignFutureStructU32.uniffiSetValue(other: UniffiForeignFutureStructU32UniffiByValue) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} + +internal typealias UniffiForeignFutureStructU32UniffiByValue = UniffiForeignFutureStructU32Struct.UniffiByValue +internal interface UniffiForeignFutureCompleteU32: com.sun.jna.Callback { + fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructU32UniffiByValue,) +} +@Structure.FieldOrder("returnValue", "callStatus") +internal open class UniffiForeignFutureStructI32Struct( + @JvmField internal var `returnValue`: Int, + @JvmField internal var `callStatus`: UniffiRustCallStatusByValue, +) : com.sun.jna.Structure() { + constructor(): this( + + `returnValue` = 0, + + `callStatus` = UniffiRustCallStatusHelper.allocValue(), + + ) + + internal class UniffiByValue( + `returnValue`: Int, + `callStatus`: UniffiRustCallStatusByValue, + ): UniffiForeignFutureStructI32(`returnValue`,`callStatus`,), Structure.ByValue +} + +internal typealias UniffiForeignFutureStructI32 = UniffiForeignFutureStructI32Struct + +internal fun UniffiForeignFutureStructI32.uniffiSetValue(other: UniffiForeignFutureStructI32) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} +internal fun UniffiForeignFutureStructI32.uniffiSetValue(other: UniffiForeignFutureStructI32UniffiByValue) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} + +internal typealias UniffiForeignFutureStructI32UniffiByValue = UniffiForeignFutureStructI32Struct.UniffiByValue +internal interface UniffiForeignFutureCompleteI32: com.sun.jna.Callback { + fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructI32UniffiByValue,) +} +@Structure.FieldOrder("returnValue", "callStatus") +internal open class UniffiForeignFutureStructU64Struct( + @JvmField internal var `returnValue`: Long, + @JvmField internal var `callStatus`: UniffiRustCallStatusByValue, +) : com.sun.jna.Structure() { + constructor(): this( + + `returnValue` = 0.toLong(), + + `callStatus` = UniffiRustCallStatusHelper.allocValue(), + + ) + + internal class UniffiByValue( + `returnValue`: Long, + `callStatus`: UniffiRustCallStatusByValue, + ): UniffiForeignFutureStructU64(`returnValue`,`callStatus`,), Structure.ByValue +} + +internal typealias UniffiForeignFutureStructU64 = UniffiForeignFutureStructU64Struct + +internal fun UniffiForeignFutureStructU64.uniffiSetValue(other: UniffiForeignFutureStructU64) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} +internal fun UniffiForeignFutureStructU64.uniffiSetValue(other: UniffiForeignFutureStructU64UniffiByValue) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} + +internal typealias UniffiForeignFutureStructU64UniffiByValue = UniffiForeignFutureStructU64Struct.UniffiByValue +internal interface UniffiForeignFutureCompleteU64: com.sun.jna.Callback { + fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructU64UniffiByValue,) +} +@Structure.FieldOrder("returnValue", "callStatus") +internal open class UniffiForeignFutureStructI64Struct( + @JvmField internal var `returnValue`: Long, + @JvmField internal var `callStatus`: UniffiRustCallStatusByValue, +) : com.sun.jna.Structure() { + constructor(): this( + + `returnValue` = 0.toLong(), + + `callStatus` = UniffiRustCallStatusHelper.allocValue(), + + ) + + internal class UniffiByValue( + `returnValue`: Long, + `callStatus`: UniffiRustCallStatusByValue, + ): UniffiForeignFutureStructI64(`returnValue`,`callStatus`,), Structure.ByValue +} + +internal typealias UniffiForeignFutureStructI64 = UniffiForeignFutureStructI64Struct + +internal fun UniffiForeignFutureStructI64.uniffiSetValue(other: UniffiForeignFutureStructI64) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} +internal fun UniffiForeignFutureStructI64.uniffiSetValue(other: UniffiForeignFutureStructI64UniffiByValue) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} + +internal typealias UniffiForeignFutureStructI64UniffiByValue = UniffiForeignFutureStructI64Struct.UniffiByValue +internal interface UniffiForeignFutureCompleteI64: com.sun.jna.Callback { + fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructI64UniffiByValue,) +} +@Structure.FieldOrder("returnValue", "callStatus") +internal open class UniffiForeignFutureStructF32Struct( + @JvmField internal var `returnValue`: Float, + @JvmField internal var `callStatus`: UniffiRustCallStatusByValue, +) : com.sun.jna.Structure() { + constructor(): this( + + `returnValue` = 0.0f, + + `callStatus` = UniffiRustCallStatusHelper.allocValue(), + + ) + + internal class UniffiByValue( + `returnValue`: Float, + `callStatus`: UniffiRustCallStatusByValue, + ): UniffiForeignFutureStructF32(`returnValue`,`callStatus`,), Structure.ByValue +} + +internal typealias UniffiForeignFutureStructF32 = UniffiForeignFutureStructF32Struct + +internal fun UniffiForeignFutureStructF32.uniffiSetValue(other: UniffiForeignFutureStructF32) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} +internal fun UniffiForeignFutureStructF32.uniffiSetValue(other: UniffiForeignFutureStructF32UniffiByValue) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} + +internal typealias UniffiForeignFutureStructF32UniffiByValue = UniffiForeignFutureStructF32Struct.UniffiByValue +internal interface UniffiForeignFutureCompleteF32: com.sun.jna.Callback { + fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructF32UniffiByValue,) +} +@Structure.FieldOrder("returnValue", "callStatus") +internal open class UniffiForeignFutureStructF64Struct( + @JvmField internal var `returnValue`: Double, + @JvmField internal var `callStatus`: UniffiRustCallStatusByValue, +) : com.sun.jna.Structure() { + constructor(): this( + + `returnValue` = 0.0, + + `callStatus` = UniffiRustCallStatusHelper.allocValue(), + + ) + + internal class UniffiByValue( + `returnValue`: Double, + `callStatus`: UniffiRustCallStatusByValue, + ): UniffiForeignFutureStructF64(`returnValue`,`callStatus`,), Structure.ByValue +} + +internal typealias UniffiForeignFutureStructF64 = UniffiForeignFutureStructF64Struct + +internal fun UniffiForeignFutureStructF64.uniffiSetValue(other: UniffiForeignFutureStructF64) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} +internal fun UniffiForeignFutureStructF64.uniffiSetValue(other: UniffiForeignFutureStructF64UniffiByValue) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} + +internal typealias UniffiForeignFutureStructF64UniffiByValue = UniffiForeignFutureStructF64Struct.UniffiByValue +internal interface UniffiForeignFutureCompleteF64: com.sun.jna.Callback { + fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructF64UniffiByValue,) +} +@Structure.FieldOrder("returnValue", "callStatus") +internal open class UniffiForeignFutureStructPointerStruct( + @JvmField internal var `returnValue`: Pointer?, + @JvmField internal var `callStatus`: UniffiRustCallStatusByValue, +) : com.sun.jna.Structure() { + constructor(): this( + + `returnValue` = NullPointer, + + `callStatus` = UniffiRustCallStatusHelper.allocValue(), + + ) + + internal class UniffiByValue( + `returnValue`: Pointer?, + `callStatus`: UniffiRustCallStatusByValue, + ): UniffiForeignFutureStructPointer(`returnValue`,`callStatus`,), Structure.ByValue +} + +internal typealias UniffiForeignFutureStructPointer = UniffiForeignFutureStructPointerStruct + +internal fun UniffiForeignFutureStructPointer.uniffiSetValue(other: UniffiForeignFutureStructPointer) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} +internal fun UniffiForeignFutureStructPointer.uniffiSetValue(other: UniffiForeignFutureStructPointerUniffiByValue) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} + +internal typealias UniffiForeignFutureStructPointerUniffiByValue = UniffiForeignFutureStructPointerStruct.UniffiByValue +internal interface UniffiForeignFutureCompletePointer: com.sun.jna.Callback { + fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructPointerUniffiByValue,) +} +@Structure.FieldOrder("returnValue", "callStatus") +internal open class UniffiForeignFutureStructRustBufferStruct( + @JvmField internal var `returnValue`: RustBufferByValue, + @JvmField internal var `callStatus`: UniffiRustCallStatusByValue, +) : com.sun.jna.Structure() { + constructor(): this( + + `returnValue` = RustBufferHelper.allocValue(), + + `callStatus` = UniffiRustCallStatusHelper.allocValue(), + + ) + + internal class UniffiByValue( + `returnValue`: RustBufferByValue, + `callStatus`: UniffiRustCallStatusByValue, + ): UniffiForeignFutureStructRustBuffer(`returnValue`,`callStatus`,), Structure.ByValue +} + +internal typealias UniffiForeignFutureStructRustBuffer = UniffiForeignFutureStructRustBufferStruct + +internal fun UniffiForeignFutureStructRustBuffer.uniffiSetValue(other: UniffiForeignFutureStructRustBuffer) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} +internal fun UniffiForeignFutureStructRustBuffer.uniffiSetValue(other: UniffiForeignFutureStructRustBufferUniffiByValue) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} + +internal typealias UniffiForeignFutureStructRustBufferUniffiByValue = UniffiForeignFutureStructRustBufferStruct.UniffiByValue +internal interface UniffiForeignFutureCompleteRustBuffer: com.sun.jna.Callback { + fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructRustBufferUniffiByValue,) +} +@Structure.FieldOrder("callStatus") +internal open class UniffiForeignFutureStructVoidStruct( + @JvmField internal var `callStatus`: UniffiRustCallStatusByValue, +) : com.sun.jna.Structure() { + constructor(): this( + + `callStatus` = UniffiRustCallStatusHelper.allocValue(), + + ) + + internal class UniffiByValue( + `callStatus`: UniffiRustCallStatusByValue, + ): UniffiForeignFutureStructVoid(`callStatus`,), Structure.ByValue +} + +internal typealias UniffiForeignFutureStructVoid = UniffiForeignFutureStructVoidStruct + +internal fun UniffiForeignFutureStructVoid.uniffiSetValue(other: UniffiForeignFutureStructVoid) { + `callStatus` = other.`callStatus` +} +internal fun UniffiForeignFutureStructVoid.uniffiSetValue(other: UniffiForeignFutureStructVoidUniffiByValue) { + `callStatus` = other.`callStatus` +} + +internal typealias UniffiForeignFutureStructVoidUniffiByValue = UniffiForeignFutureStructVoidStruct.UniffiByValue +internal interface UniffiForeignFutureCompleteVoid: com.sun.jna.Callback { + fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructVoidUniffiByValue,) +} +internal interface UniffiCallbackInterfaceLogWriterMethod0: com.sun.jna.Callback { + fun callback(`uniffiHandle`: Long,`record`: RustBufferByValue,`uniffiOutReturn`: Pointer,uniffiCallStatus: UniffiRustCallStatus,) +} +internal interface UniffiCallbackInterfaceVssHeaderProviderMethod0: com.sun.jna.Callback { + fun callback(`uniffiHandle`: Long,`request`: RustBufferByValue,`uniffiFutureCallback`: UniffiForeignFutureCompleteRustBuffer,`uniffiCallbackData`: Long,`uniffiOutReturn`: UniffiForeignFuture,) +} +@Structure.FieldOrder("log", "uniffiFree") +internal open class UniffiVTableCallbackInterfaceLogWriterStruct( + @JvmField internal var `log`: UniffiCallbackInterfaceLogWriterMethod0?, + @JvmField internal var `uniffiFree`: UniffiCallbackInterfaceFree?, +) : com.sun.jna.Structure() { + constructor(): this( + + `log` = null, + + `uniffiFree` = null, + + ) + + internal class UniffiByValue( + `log`: UniffiCallbackInterfaceLogWriterMethod0?, + `uniffiFree`: UniffiCallbackInterfaceFree?, + ): UniffiVTableCallbackInterfaceLogWriter(`log`,`uniffiFree`,), Structure.ByValue +} + +internal typealias UniffiVTableCallbackInterfaceLogWriter = UniffiVTableCallbackInterfaceLogWriterStruct + +internal fun UniffiVTableCallbackInterfaceLogWriter.uniffiSetValue(other: UniffiVTableCallbackInterfaceLogWriter) { + `log` = other.`log` + `uniffiFree` = other.`uniffiFree` +} +internal fun UniffiVTableCallbackInterfaceLogWriter.uniffiSetValue(other: UniffiVTableCallbackInterfaceLogWriterUniffiByValue) { + `log` = other.`log` + `uniffiFree` = other.`uniffiFree` +} + +internal typealias UniffiVTableCallbackInterfaceLogWriterUniffiByValue = UniffiVTableCallbackInterfaceLogWriterStruct.UniffiByValue +@Structure.FieldOrder("getHeaders", "uniffiFree") +internal open class UniffiVTableCallbackInterfaceVssHeaderProviderStruct( + @JvmField internal var `getHeaders`: UniffiCallbackInterfaceVssHeaderProviderMethod0?, + @JvmField internal var `uniffiFree`: UniffiCallbackInterfaceFree?, +) : com.sun.jna.Structure() { + constructor(): this( + + `getHeaders` = null, + + `uniffiFree` = null, + + ) + + internal class UniffiByValue( + `getHeaders`: UniffiCallbackInterfaceVssHeaderProviderMethod0?, + `uniffiFree`: UniffiCallbackInterfaceFree?, + ): UniffiVTableCallbackInterfaceVssHeaderProvider(`getHeaders`,`uniffiFree`,), Structure.ByValue +} + +internal typealias UniffiVTableCallbackInterfaceVssHeaderProvider = UniffiVTableCallbackInterfaceVssHeaderProviderStruct + +internal fun UniffiVTableCallbackInterfaceVssHeaderProvider.uniffiSetValue(other: UniffiVTableCallbackInterfaceVssHeaderProvider) { + `getHeaders` = other.`getHeaders` + `uniffiFree` = other.`uniffiFree` +} +internal fun UniffiVTableCallbackInterfaceVssHeaderProvider.uniffiSetValue(other: UniffiVTableCallbackInterfaceVssHeaderProviderUniffiByValue) { + `getHeaders` = other.`getHeaders` + `uniffiFree` = other.`uniffiFree` +} + +internal typealias UniffiVTableCallbackInterfaceVssHeaderProviderUniffiByValue = UniffiVTableCallbackInterfaceVssHeaderProviderStruct.UniffiByValue + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +@Synchronized +private fun findLibraryName(componentName: String): String { + val libOverride = System.getProperty("uniffi.component.$componentName.libraryOverride") + if (libOverride != null) { + return libOverride + } + return "ldk_node" +} + +private inline fun loadIndirect( + componentName: String +): Lib { + return Native.load(findLibraryName(componentName), Lib::class.java) +} + +// A JNA Library to expose the extern-C FFI definitions. +// This is an implementation detail which will be called internally by the public API. + +internal interface UniffiLib : Library { + companion object { + internal val INSTANCE: UniffiLib by lazy { + loadIndirect(componentName = "ldk_node") + .also { lib: UniffiLib -> + uniffiCheckContractApiVersion(lib) + uniffiCheckApiChecksums(lib) + uniffiCallbackInterfaceLogWriter.register(lib) + } + } + + // The Cleaner for the whole library + internal val CLEANER: UniffiCleaner by lazy { + UniffiCleaner.create() + } + } + + fun uniffi_ldk_node_fn_clone_bolt11invoice( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_bolt11invoice( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_constructor_bolt11invoice_from_str( + `invoiceStr`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt11invoice_amount_milli_satoshis( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11invoice_currency( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11invoice_expiry_time_seconds( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_bolt11invoice_fallback_addresses( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11invoice_invoice_description( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11invoice_is_expired( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_method_bolt11invoice_min_final_cltv_expiry_delta( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_bolt11invoice_network( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11invoice_payment_hash( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11invoice_payment_secret( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11invoice_recover_payee_pub_key( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11invoice_route_hints( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11invoice_seconds_since_epoch( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_bolt11invoice_seconds_until_expiry( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_bolt11invoice_signable_hash( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11invoice_would_expire( + `ptr`: Pointer?, + `atTimeSeconds`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_debug( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_display( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_eq_eq( + `ptr`: Pointer?, + `other`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_eq_ne( + `ptr`: Pointer?, + `other`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_clone_bolt11payment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_bolt11payment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_bolt11payment_claim_for_hash( + `ptr`: Pointer?, + `paymentHash`: RustBufferByValue, + `claimableAmountMsat`: Long, + `preimage`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_bolt11payment_estimate_routing_fees( + `ptr`: Pointer?, + `invoice`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_bolt11payment_estimate_routing_fees_using_amount( + `ptr`: Pointer?, + `invoice`: Pointer?, + `amountMsat`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_bolt11payment_fail_for_hash( + `ptr`: Pointer?, + `paymentHash`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_bolt11payment_receive( + `ptr`: Pointer?, + `amountMsat`: Long, + `description`: RustBufferByValue, + `expirySecs`: Int, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt11payment_receive_for_hash( + `ptr`: Pointer?, + `amountMsat`: Long, + `description`: RustBufferByValue, + `expirySecs`: Int, + `paymentHash`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount( + `ptr`: Pointer?, + `description`: RustBufferByValue, + `expirySecs`: Int, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount_for_hash( + `ptr`: Pointer?, + `description`: RustBufferByValue, + `expirySecs`: Int, + `paymentHash`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount_via_jit_channel( + `ptr`: Pointer?, + `description`: RustBufferByValue, + `expirySecs`: Int, + `maxProportionalLspFeeLimitPpmMsat`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount_via_jit_channel_for_hash( + `ptr`: Pointer?, + `description`: RustBufferByValue, + `expirySecs`: Int, + `maxProportionalLspFeeLimitPpmMsat`: RustBufferByValue, + `paymentHash`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt11payment_receive_via_jit_channel( + `ptr`: Pointer?, + `amountMsat`: Long, + `description`: RustBufferByValue, + `expirySecs`: Int, + `maxLspFeeLimitMsat`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt11payment_receive_via_jit_channel_for_hash( + `ptr`: Pointer?, + `amountMsat`: Long, + `description`: RustBufferByValue, + `expirySecs`: Int, + `maxLspFeeLimitMsat`: RustBufferByValue, + `paymentHash`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt11payment_send( + `ptr`: Pointer?, + `invoice`: Pointer?, + `routeParameters`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11payment_send_probes( + `ptr`: Pointer?, + `invoice`: Pointer?, + `routeParameters`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11payment_send_probes_using_amount( + `ptr`: Pointer?, + `invoice`: Pointer?, + `amountMsat`: Long, + `routeParameters`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11payment_send_using_amount( + `ptr`: Pointer?, + `invoice`: Pointer?, + `amountMsat`: Long, + `routeParameters`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_clone_bolt12invoice( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_bolt12invoice( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_constructor_bolt12invoice_from_str( + `invoiceStr`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt12invoice_absolute_expiry_seconds( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_amount( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_amount_msats( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_bolt12invoice_chain( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_created_at( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_bolt12invoice_encode( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_fallback_addresses( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_invoice_description( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_is_expired( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_method_bolt12invoice_issuer( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_issuer_signing_pubkey( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_metadata( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_offer_chains( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_payer_note( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_payer_signing_pubkey( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_payment_hash( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_quantity( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_relative_expiry( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_bolt12invoice_signable_hash( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_signing_pubkey( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_clone_bolt12payment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_bolt12payment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_bolt12payment_blinded_paths_for_async_recipient( + `ptr`: Pointer?, + `recipientId`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12payment_initiate_refund( + `ptr`: Pointer?, + `amountMsat`: Long, + `expirySecs`: Int, + `quantity`: RustBufferByValue, + `payerNote`: RustBufferByValue, + `routeParameters`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt12payment_receive( + `ptr`: Pointer?, + `amountMsat`: Long, + `description`: RustBufferByValue, + `expirySecs`: RustBufferByValue, + `quantity`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt12payment_receive_async( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt12payment_receive_variable_amount( + `ptr`: Pointer?, + `description`: RustBufferByValue, + `expirySecs`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt12payment_request_refund_payment( + `ptr`: Pointer?, + `refund`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt12payment_send( + `ptr`: Pointer?, + `offer`: Pointer?, + `quantity`: RustBufferByValue, + `payerNote`: RustBufferByValue, + `routeParameters`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12payment_send_using_amount( + `ptr`: Pointer?, + `offer`: Pointer?, + `amountMsat`: Long, + `quantity`: RustBufferByValue, + `payerNote`: RustBufferByValue, + `routeParameters`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12payment_set_paths_to_static_invoice_server( + `ptr`: Pointer?, + `paths`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_clone_builder( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_builder( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_constructor_builder_from_config( + `config`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_constructor_builder_new( + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_builder_build( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_builder_build_with_fs_store( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_builder_build_with_vss_store( + `ptr`: Pointer?, + `vssUrl`: RustBufferByValue, + `storeId`: RustBufferByValue, + `lnurlAuthServerUrl`: RustBufferByValue, + `fixedHeaders`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_builder_build_with_vss_store_and_fixed_headers( + `ptr`: Pointer?, + `vssUrl`: RustBufferByValue, + `storeId`: RustBufferByValue, + `fixedHeaders`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_builder_build_with_vss_store_and_header_provider( + `ptr`: Pointer?, + `vssUrl`: RustBufferByValue, + `storeId`: RustBufferByValue, + `headerProvider`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_builder_set_address_type( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_address_types_to_monitor( + `ptr`: Pointer?, + `addressTypesToMonitor`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_announcement_addresses( + `ptr`: Pointer?, + `announcementAddresses`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_async_payments_role( + `ptr`: Pointer?, + `role`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_chain_source_bitcoind_rest( + `ptr`: Pointer?, + `restHost`: RustBufferByValue, + `restPort`: Short, + `rpcHost`: RustBufferByValue, + `rpcPort`: Short, + `rpcUser`: RustBufferByValue, + `rpcPassword`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_chain_source_bitcoind_rpc( + `ptr`: Pointer?, + `rpcHost`: RustBufferByValue, + `rpcPort`: Short, + `rpcUser`: RustBufferByValue, + `rpcPassword`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_chain_source_electrum( + `ptr`: Pointer?, + `serverUrl`: RustBufferByValue, + `config`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_chain_source_esplora( + `ptr`: Pointer?, + `serverUrl`: RustBufferByValue, + `config`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_channel_data_migration( + `ptr`: Pointer?, + `migration`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_custom_logger( + `ptr`: Pointer?, + `logWriter`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_entropy_bip39_mnemonic( + `ptr`: Pointer?, + `mnemonic`: RustBufferByValue, + `passphrase`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_entropy_seed_bytes( + `ptr`: Pointer?, + `seedBytes`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_entropy_seed_path( + `ptr`: Pointer?, + `seedPath`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_filesystem_logger( + `ptr`: Pointer?, + `logFilePath`: RustBufferByValue, + `maxLogLevel`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_gossip_source_p2p( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_gossip_source_rgs( + `ptr`: Pointer?, + `rgsServerUrl`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_liquidity_source_lsps1( + `ptr`: Pointer?, + `nodeId`: RustBufferByValue, + `address`: RustBufferByValue, + `token`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_liquidity_source_lsps2( + `ptr`: Pointer?, + `nodeId`: RustBufferByValue, + `address`: RustBufferByValue, + `token`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_listening_addresses( + `ptr`: Pointer?, + `listeningAddresses`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_log_facade_logger( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_network( + `ptr`: Pointer?, + `network`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_node_alias( + `ptr`: Pointer?, + `nodeAlias`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_pathfinding_scores_source( + `ptr`: Pointer?, + `url`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_scoring_decay_params( + `ptr`: Pointer?, + `params`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_scoring_fee_params( + `ptr`: Pointer?, + `params`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_storage_dir_path( + `ptr`: Pointer?, + `storageDirPath`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_clone_feerate( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_feerate( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_constructor_feerate_from_sat_per_kwu( + `satKwu`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_constructor_feerate_from_sat_per_vb_unchecked( + `satVb`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_feerate_to_sat_per_kwu( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_feerate_to_sat_per_vb_ceil( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_feerate_to_sat_per_vb_floor( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_clone_lsps1liquidity( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_lsps1liquidity( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_lsps1liquidity_check_order_status( + `ptr`: Pointer?, + `orderId`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_lsps1liquidity_request_channel( + `ptr`: Pointer?, + `lspBalanceSat`: Long, + `clientBalanceSat`: Long, + `channelExpiryBlocks`: Int, + `announceChannel`: Byte, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_clone_logwriter( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_logwriter( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_init_callback_vtable_logwriter( + `vtable`: UniffiVTableCallbackInterfaceLogWriter, + ): Unit + fun uniffi_ldk_node_fn_method_logwriter_log( + `ptr`: Pointer?, + `record`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_clone_networkgraph( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_networkgraph( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_networkgraph_channel( + `ptr`: Pointer?, + `shortChannelId`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_networkgraph_list_channels( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_networkgraph_list_nodes( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_networkgraph_node( + `ptr`: Pointer?, + `nodeId`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_clone_node( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_node( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_add_address_type_to_monitor( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `seedBytes`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_add_address_type_to_monitor_with_mnemonic( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `mnemonic`: RustBufferByValue, + `passphrase`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_add_onchain_wallet_account( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `accountIndex`: Int, + `xpub`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_announcement_addresses( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_bolt11_payment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_node_bolt12_payment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_node_close_channel( + `ptr`: Pointer?, + `userChannelId`: RustBufferByValue, + `counterpartyNodeId`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_config( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_connect( + `ptr`: Pointer?, + `nodeId`: RustBufferByValue, + `address`: RustBufferByValue, + `persist`: Byte, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_current_sync_intervals( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_disconnect( + `ptr`: Pointer?, + `nodeId`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_event_handled( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_export_onchain_wallet_account_xpub( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `accountIndex`: Int, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_export_pathfinding_scores( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_force_close_channel( + `ptr`: Pointer?, + `userChannelId`: RustBufferByValue, + `counterpartyNodeId`: RustBufferByValue, + `reason`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_get_address_balance( + `ptr`: Pointer?, + `addressStr`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_node_get_balance_for_address_type( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_get_balance_for_onchain_wallet_account( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `accountIndex`: Int, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_get_transaction_details( + `ptr`: Pointer?, + `txid`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_list_balances( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_list_channels( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_list_monitored_address_types( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_list_onchain_wallet_accounts( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_list_payments( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_list_peers( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_listening_addresses( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_lsps1_liquidity( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_node_network_graph( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_node_next_event( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_next_event_async( + `ptr`: Pointer?, + ): Long + fun uniffi_ldk_node_fn_method_node_node_alias( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_node_id( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_onchain_payment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_node_open_announced_channel( + `ptr`: Pointer?, + `nodeId`: RustBufferByValue, + `address`: RustBufferByValue, + `channelAmountSats`: Long, + `pushToCounterpartyMsat`: RustBufferByValue, + `channelConfig`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_open_channel( + `ptr`: Pointer?, + `nodeId`: RustBufferByValue, + `address`: RustBufferByValue, + `channelAmountSats`: Long, + `pushToCounterpartyMsat`: RustBufferByValue, + `channelConfig`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_payment( + `ptr`: Pointer?, + `paymentId`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_remove_address_type_from_monitor( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_remove_onchain_wallet_account( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `accountIndex`: Int, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_remove_payment( + `ptr`: Pointer?, + `paymentId`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_set_primary_address_type( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `seedBytes`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_set_primary_address_type_with_mnemonic( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `mnemonic`: RustBufferByValue, + `passphrase`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_sign_message( + `ptr`: Pointer?, + `msg`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_splice_in( + `ptr`: Pointer?, + `userChannelId`: RustBufferByValue, + `counterpartyNodeId`: RustBufferByValue, + `spliceAmountSats`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_splice_out( + `ptr`: Pointer?, + `userChannelId`: RustBufferByValue, + `counterpartyNodeId`: RustBufferByValue, + `address`: RustBufferByValue, + `spliceAmountSats`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_spontaneous_payment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_node_start( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_status( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_stop( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_sync_wallets( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_unified_qr_payment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_node_update_channel_config( + `ptr`: Pointer?, + `userChannelId`: RustBufferByValue, + `counterpartyNodeId`: RustBufferByValue, + `channelConfig`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_update_sync_intervals( + `ptr`: Pointer?, + `intervals`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_verify_signature( + `ptr`: Pointer?, + `msg`: RustBufferByValue, + `sig`: RustBufferByValue, + `pkey`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_method_node_wait_next_event( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_clone_offer( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_offer( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_constructor_offer_from_str( + `offerStr`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_offer_absolute_expiry_seconds( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_offer_amount( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_offer_chains( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_offer_expects_quantity( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_method_offer_id( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_offer_is_expired( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_method_offer_is_valid_quantity( + `ptr`: Pointer?, + `quantity`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_method_offer_issuer( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_offer_issuer_signing_pubkey( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_offer_metadata( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_offer_offer_description( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_offer_supports_chain( + `ptr`: Pointer?, + `chain`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_method_offer_uniffi_trait_debug( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_offer_uniffi_trait_display( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_offer_uniffi_trait_eq_eq( + `ptr`: Pointer?, + `other`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_method_offer_uniffi_trait_eq_ne( + `ptr`: Pointer?, + `other`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_clone_onchainpayment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_onchainpayment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_onchainpayment_accelerate_by_cpfp( + `ptr`: Pointer?, + `txid`: RustBufferByValue, + `feeRate`: RustBufferByValue, + `destinationAddress`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_address_info_for_account_at_index( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `accountIndex`: Int, + `keychain`: RustBufferByValue, + `index`: Int, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_address_info_for_type_at_index( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `keychain`: RustBufferByValue, + `index`: Int, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_address_infos_for_account( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `accountIndex`: Int, + `keychain`: RustBufferByValue, + `startIndex`: Int, + `count`: Int, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_address_infos_for_type( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `keychain`: RustBufferByValue, + `startIndex`: Int, + `count`: Int, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_bump_fee_by_rbf( + `ptr`: Pointer?, + `txid`: RustBufferByValue, + `feeRate`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_calculate_cpfp_fee_rate( + `ptr`: Pointer?, + `parentTxid`: RustBufferByValue, + `urgent`: Byte, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_onchainpayment_calculate_send_all_fee( + `ptr`: Pointer?, + `address`: RustBufferByValue, + `retainReserves`: Byte, + `feeRate`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_onchainpayment_calculate_total_fee( + `ptr`: Pointer?, + `address`: RustBufferByValue, + `amountSats`: Long, + `feeRate`: RustBufferByValue, + `utxosToSpend`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_onchainpayment_list_spendable_outputs( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_new_address( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_new_address_for_account( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `accountIndex`: Int, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_new_address_for_type( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_new_address_info( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_new_address_info_for_account( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `accountIndex`: Int, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_new_address_info_for_type( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_reveal_receive_addresses_to( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `index`: Int, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_onchainpayment_reveal_receive_addresses_to_account( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `accountIndex`: Int, + `index`: Int, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_onchainpayment_select_utxos_with_algorithm( + `ptr`: Pointer?, + `targetAmountSats`: Long, + `feeRate`: RustBufferByValue, + `algorithm`: RustBufferByValue, + `utxos`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_send_all_to_address( + `ptr`: Pointer?, + `address`: RustBufferByValue, + `retainReserve`: Byte, + `feeRate`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_send_to_address( + `ptr`: Pointer?, + `address`: RustBufferByValue, + `amountSats`: Long, + `feeRate`: RustBufferByValue, + `utxosToSpend`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_clone_refund( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_refund( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_constructor_refund_from_str( + `refundStr`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_refund_absolute_expiry_seconds( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_refund_amount_msats( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_refund_chain( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_refund_is_expired( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_method_refund_issuer( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_refund_payer_metadata( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_refund_payer_note( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_refund_payer_signing_pubkey( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_refund_quantity( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_refund_refund_description( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_refund_uniffi_trait_debug( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_refund_uniffi_trait_display( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_refund_uniffi_trait_eq_eq( + `ptr`: Pointer?, + `other`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_method_refund_uniffi_trait_eq_ne( + `ptr`: Pointer?, + `other`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_clone_spontaneouspayment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_spontaneouspayment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_spontaneouspayment_send( + `ptr`: Pointer?, + `amountMsat`: Long, + `nodeId`: RustBufferByValue, + `routeParameters`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_spontaneouspayment_send_probes( + `ptr`: Pointer?, + `amountMsat`: Long, + `nodeId`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_spontaneouspayment_send_with_custom_tlvs( + `ptr`: Pointer?, + `amountMsat`: Long, + `nodeId`: RustBufferByValue, + `routeParameters`: RustBufferByValue, + `customTlvs`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_spontaneouspayment_send_with_preimage( + `ptr`: Pointer?, + `amountMsat`: Long, + `nodeId`: RustBufferByValue, + `preimage`: RustBufferByValue, + `routeParameters`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_spontaneouspayment_send_with_preimage_and_custom_tlvs( + `ptr`: Pointer?, + `amountMsat`: Long, + `nodeId`: RustBufferByValue, + `customTlvs`: RustBufferByValue, + `preimage`: RustBufferByValue, + `routeParameters`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_clone_unifiedqrpayment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_unifiedqrpayment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_unifiedqrpayment_receive( + `ptr`: Pointer?, + `amountSats`: Long, + `message`: RustBufferByValue, + `expirySec`: Int, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_unifiedqrpayment_send( + `ptr`: Pointer?, + `uriStr`: RustBufferByValue, + `routeParameters`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_clone_vssheaderprovider( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_vssheaderprovider( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_vssheaderprovider_get_headers( + `ptr`: Pointer?, + `request`: RustBufferByValue, + ): Long + fun uniffi_ldk_node_fn_func_battery_saving_sync_intervals( + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_func_default_config( + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_func_derive_node_secret_from_mnemonic( + `mnemonic`: RustBufferByValue, + `passphrase`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_func_generate_entropy_mnemonic( + `wordCount`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun ffi_ldk_node_rustbuffer_alloc( + `size`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun ffi_ldk_node_rustbuffer_from_bytes( + `bytes`: ForeignBytesByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun ffi_ldk_node_rustbuffer_free( + `buf`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun ffi_ldk_node_rustbuffer_reserve( + `buf`: RustBufferByValue, + `additional`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun ffi_ldk_node_rust_future_poll_u8( + `handle`: Long, + `callback`: UniffiRustFutureContinuationCallback, + `callbackData`: Long, + ): Unit + fun ffi_ldk_node_rust_future_cancel_u8( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_free_u8( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_complete_u8( + `handle`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun ffi_ldk_node_rust_future_poll_i8( + `handle`: Long, + `callback`: UniffiRustFutureContinuationCallback, + `callbackData`: Long, + ): Unit + fun ffi_ldk_node_rust_future_cancel_i8( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_free_i8( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_complete_i8( + `handle`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun ffi_ldk_node_rust_future_poll_u16( + `handle`: Long, + `callback`: UniffiRustFutureContinuationCallback, + `callbackData`: Long, + ): Unit + fun ffi_ldk_node_rust_future_cancel_u16( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_free_u16( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_complete_u16( + `handle`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Short + fun ffi_ldk_node_rust_future_poll_i16( + `handle`: Long, + `callback`: UniffiRustFutureContinuationCallback, + `callbackData`: Long, + ): Unit + fun ffi_ldk_node_rust_future_cancel_i16( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_free_i16( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_complete_i16( + `handle`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Short + fun ffi_ldk_node_rust_future_poll_u32( + `handle`: Long, + `callback`: UniffiRustFutureContinuationCallback, + `callbackData`: Long, + ): Unit + fun ffi_ldk_node_rust_future_cancel_u32( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_free_u32( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_complete_u32( + `handle`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Int + fun ffi_ldk_node_rust_future_poll_i32( + `handle`: Long, + `callback`: UniffiRustFutureContinuationCallback, + `callbackData`: Long, + ): Unit + fun ffi_ldk_node_rust_future_cancel_i32( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_free_i32( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_complete_i32( + `handle`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Int + fun ffi_ldk_node_rust_future_poll_u64( + `handle`: Long, + `callback`: UniffiRustFutureContinuationCallback, + `callbackData`: Long, + ): Unit + fun ffi_ldk_node_rust_future_cancel_u64( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_free_u64( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_complete_u64( + `handle`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun ffi_ldk_node_rust_future_poll_i64( + `handle`: Long, + `callback`: UniffiRustFutureContinuationCallback, + `callbackData`: Long, + ): Unit + fun ffi_ldk_node_rust_future_cancel_i64( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_free_i64( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_complete_i64( + `handle`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun ffi_ldk_node_rust_future_poll_f32( + `handle`: Long, + `callback`: UniffiRustFutureContinuationCallback, + `callbackData`: Long, + ): Unit + fun ffi_ldk_node_rust_future_cancel_f32( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_free_f32( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_complete_f32( + `handle`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Float + fun ffi_ldk_node_rust_future_poll_f64( + `handle`: Long, + `callback`: UniffiRustFutureContinuationCallback, + `callbackData`: Long, + ): Unit + fun ffi_ldk_node_rust_future_cancel_f64( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_free_f64( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_complete_f64( + `handle`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Double + fun ffi_ldk_node_rust_future_poll_pointer( + `handle`: Long, + `callback`: UniffiRustFutureContinuationCallback, + `callbackData`: Long, + ): Unit + fun ffi_ldk_node_rust_future_cancel_pointer( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_free_pointer( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_complete_pointer( + `handle`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun ffi_ldk_node_rust_future_poll_rust_buffer( + `handle`: Long, + `callback`: UniffiRustFutureContinuationCallback, + `callbackData`: Long, + ): Unit + fun ffi_ldk_node_rust_future_cancel_rust_buffer( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_free_rust_buffer( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_complete_rust_buffer( + `handle`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun ffi_ldk_node_rust_future_poll_void( + `handle`: Long, + `callback`: UniffiRustFutureContinuationCallback, + `callbackData`: Long, + ): Unit + fun ffi_ldk_node_rust_future_cancel_void( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_free_void( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_complete_void( + `handle`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_checksum_func_battery_saving_sync_intervals( + ): Short + fun uniffi_ldk_node_checksum_func_default_config( + ): Short + fun uniffi_ldk_node_checksum_func_derive_node_secret_from_mnemonic( + ): Short + fun uniffi_ldk_node_checksum_func_generate_entropy_mnemonic( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_amount_milli_satoshis( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_currency( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_expiry_time_seconds( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_fallback_addresses( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_invoice_description( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_is_expired( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_min_final_cltv_expiry_delta( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_network( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_payment_hash( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_payment_secret( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_recover_payee_pub_key( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_route_hints( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_seconds_since_epoch( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_seconds_until_expiry( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_signable_hash( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_would_expire( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_claim_for_hash( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_estimate_routing_fees( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_estimate_routing_fees_using_amount( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_fail_for_hash( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_receive( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_receive_for_hash( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount_for_hash( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount_via_jit_channel( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount_via_jit_channel_for_hash( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_receive_via_jit_channel( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_receive_via_jit_channel_for_hash( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_send( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_send_probes( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_send_probes_using_amount( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_send_using_amount( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_absolute_expiry_seconds( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_amount( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_amount_msats( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_chain( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_created_at( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_encode( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_fallback_addresses( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_invoice_description( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_is_expired( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_issuer( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_issuer_signing_pubkey( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_metadata( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_offer_chains( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_payer_note( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_payer_signing_pubkey( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_payment_hash( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_quantity( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_relative_expiry( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_signable_hash( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_signing_pubkey( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12payment_blinded_paths_for_async_recipient( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12payment_initiate_refund( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12payment_receive( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12payment_receive_async( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12payment_receive_variable_amount( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12payment_request_refund_payment( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12payment_send( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12payment_send_using_amount( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12payment_set_paths_to_static_invoice_server( + ): Short + fun uniffi_ldk_node_checksum_method_builder_build( + ): Short + fun uniffi_ldk_node_checksum_method_builder_build_with_fs_store( + ): Short + fun uniffi_ldk_node_checksum_method_builder_build_with_vss_store( + ): Short + fun uniffi_ldk_node_checksum_method_builder_build_with_vss_store_and_fixed_headers( + ): Short + fun uniffi_ldk_node_checksum_method_builder_build_with_vss_store_and_header_provider( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_address_type( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_address_types_to_monitor( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_announcement_addresses( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_async_payments_role( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_chain_source_bitcoind_rest( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_chain_source_bitcoind_rpc( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_chain_source_electrum( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_chain_source_esplora( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_channel_data_migration( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_custom_logger( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_entropy_bip39_mnemonic( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_entropy_seed_bytes( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_entropy_seed_path( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_filesystem_logger( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_gossip_source_p2p( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_gossip_source_rgs( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_liquidity_source_lsps1( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_liquidity_source_lsps2( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_listening_addresses( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_log_facade_logger( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_network( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_node_alias( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_pathfinding_scores_source( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_scoring_decay_params( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_scoring_fee_params( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_storage_dir_path( + ): Short + fun uniffi_ldk_node_checksum_method_feerate_to_sat_per_kwu( + ): Short + fun uniffi_ldk_node_checksum_method_feerate_to_sat_per_vb_ceil( + ): Short + fun uniffi_ldk_node_checksum_method_feerate_to_sat_per_vb_floor( + ): Short + fun uniffi_ldk_node_checksum_method_lsps1liquidity_check_order_status( + ): Short + fun uniffi_ldk_node_checksum_method_lsps1liquidity_request_channel( + ): Short + fun uniffi_ldk_node_checksum_method_logwriter_log( + ): Short + fun uniffi_ldk_node_checksum_method_networkgraph_channel( + ): Short + fun uniffi_ldk_node_checksum_method_networkgraph_list_channels( + ): Short + fun uniffi_ldk_node_checksum_method_networkgraph_list_nodes( + ): Short + fun uniffi_ldk_node_checksum_method_networkgraph_node( + ): Short + fun uniffi_ldk_node_checksum_method_node_add_address_type_to_monitor( + ): Short + fun uniffi_ldk_node_checksum_method_node_add_address_type_to_monitor_with_mnemonic( + ): Short + fun uniffi_ldk_node_checksum_method_node_add_onchain_wallet_account( + ): Short + fun uniffi_ldk_node_checksum_method_node_announcement_addresses( + ): Short + fun uniffi_ldk_node_checksum_method_node_bolt11_payment( + ): Short + fun uniffi_ldk_node_checksum_method_node_bolt12_payment( + ): Short + fun uniffi_ldk_node_checksum_method_node_close_channel( + ): Short + fun uniffi_ldk_node_checksum_method_node_config( + ): Short + fun uniffi_ldk_node_checksum_method_node_connect( + ): Short + fun uniffi_ldk_node_checksum_method_node_current_sync_intervals( + ): Short + fun uniffi_ldk_node_checksum_method_node_disconnect( + ): Short + fun uniffi_ldk_node_checksum_method_node_event_handled( + ): Short + fun uniffi_ldk_node_checksum_method_node_export_onchain_wallet_account_xpub( + ): Short + fun uniffi_ldk_node_checksum_method_node_export_pathfinding_scores( + ): Short + fun uniffi_ldk_node_checksum_method_node_force_close_channel( + ): Short + fun uniffi_ldk_node_checksum_method_node_get_address_balance( + ): Short + fun uniffi_ldk_node_checksum_method_node_get_balance_for_address_type( + ): Short + fun uniffi_ldk_node_checksum_method_node_get_balance_for_onchain_wallet_account( + ): Short + fun uniffi_ldk_node_checksum_method_node_get_transaction_details( + ): Short + fun uniffi_ldk_node_checksum_method_node_list_balances( + ): Short + fun uniffi_ldk_node_checksum_method_node_list_channels( + ): Short + fun uniffi_ldk_node_checksum_method_node_list_monitored_address_types( + ): Short + fun uniffi_ldk_node_checksum_method_node_list_onchain_wallet_accounts( + ): Short + fun uniffi_ldk_node_checksum_method_node_list_payments( + ): Short + fun uniffi_ldk_node_checksum_method_node_list_peers( + ): Short + fun uniffi_ldk_node_checksum_method_node_listening_addresses( + ): Short + fun uniffi_ldk_node_checksum_method_node_lsps1_liquidity( + ): Short + fun uniffi_ldk_node_checksum_method_node_network_graph( + ): Short + fun uniffi_ldk_node_checksum_method_node_next_event( + ): Short + fun uniffi_ldk_node_checksum_method_node_next_event_async( + ): Short + fun uniffi_ldk_node_checksum_method_node_node_alias( + ): Short + fun uniffi_ldk_node_checksum_method_node_node_id( + ): Short + fun uniffi_ldk_node_checksum_method_node_onchain_payment( + ): Short + fun uniffi_ldk_node_checksum_method_node_open_announced_channel( + ): Short + fun uniffi_ldk_node_checksum_method_node_open_channel( + ): Short + fun uniffi_ldk_node_checksum_method_node_payment( + ): Short + fun uniffi_ldk_node_checksum_method_node_remove_address_type_from_monitor( + ): Short + fun uniffi_ldk_node_checksum_method_node_remove_onchain_wallet_account( + ): Short + fun uniffi_ldk_node_checksum_method_node_remove_payment( + ): Short + fun uniffi_ldk_node_checksum_method_node_set_primary_address_type( + ): Short + fun uniffi_ldk_node_checksum_method_node_set_primary_address_type_with_mnemonic( + ): Short + fun uniffi_ldk_node_checksum_method_node_sign_message( + ): Short + fun uniffi_ldk_node_checksum_method_node_splice_in( + ): Short + fun uniffi_ldk_node_checksum_method_node_splice_out( + ): Short + fun uniffi_ldk_node_checksum_method_node_spontaneous_payment( + ): Short + fun uniffi_ldk_node_checksum_method_node_start( + ): Short + fun uniffi_ldk_node_checksum_method_node_status( + ): Short + fun uniffi_ldk_node_checksum_method_node_stop( + ): Short + fun uniffi_ldk_node_checksum_method_node_sync_wallets( + ): Short + fun uniffi_ldk_node_checksum_method_node_unified_qr_payment( + ): Short + fun uniffi_ldk_node_checksum_method_node_update_channel_config( + ): Short + fun uniffi_ldk_node_checksum_method_node_update_sync_intervals( + ): Short + fun uniffi_ldk_node_checksum_method_node_verify_signature( + ): Short + fun uniffi_ldk_node_checksum_method_node_wait_next_event( + ): Short + fun uniffi_ldk_node_checksum_method_offer_absolute_expiry_seconds( + ): Short + fun uniffi_ldk_node_checksum_method_offer_amount( + ): Short + fun uniffi_ldk_node_checksum_method_offer_chains( + ): Short + fun uniffi_ldk_node_checksum_method_offer_expects_quantity( + ): Short + fun uniffi_ldk_node_checksum_method_offer_id( + ): Short + fun uniffi_ldk_node_checksum_method_offer_is_expired( + ): Short + fun uniffi_ldk_node_checksum_method_offer_is_valid_quantity( + ): Short + fun uniffi_ldk_node_checksum_method_offer_issuer( + ): Short + fun uniffi_ldk_node_checksum_method_offer_issuer_signing_pubkey( + ): Short + fun uniffi_ldk_node_checksum_method_offer_metadata( + ): Short + fun uniffi_ldk_node_checksum_method_offer_offer_description( + ): Short + fun uniffi_ldk_node_checksum_method_offer_supports_chain( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_accelerate_by_cpfp( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_address_info_for_account_at_index( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_address_info_for_type_at_index( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_address_infos_for_account( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_address_infos_for_type( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_bump_fee_by_rbf( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_calculate_cpfp_fee_rate( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_calculate_send_all_fee( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_calculate_total_fee( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_list_spendable_outputs( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_new_address( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_new_address_for_account( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_new_address_for_type( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_new_address_info( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_new_address_info_for_account( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_new_address_info_for_type( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_reveal_receive_addresses_to( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_reveal_receive_addresses_to_account( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_select_utxos_with_algorithm( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_send_all_to_address( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_send_to_address( + ): Short + fun uniffi_ldk_node_checksum_method_refund_absolute_expiry_seconds( + ): Short + fun uniffi_ldk_node_checksum_method_refund_amount_msats( + ): Short + fun uniffi_ldk_node_checksum_method_refund_chain( + ): Short + fun uniffi_ldk_node_checksum_method_refund_is_expired( + ): Short + fun uniffi_ldk_node_checksum_method_refund_issuer( + ): Short + fun uniffi_ldk_node_checksum_method_refund_payer_metadata( + ): Short + fun uniffi_ldk_node_checksum_method_refund_payer_note( + ): Short + fun uniffi_ldk_node_checksum_method_refund_payer_signing_pubkey( + ): Short + fun uniffi_ldk_node_checksum_method_refund_quantity( + ): Short + fun uniffi_ldk_node_checksum_method_refund_refund_description( + ): Short + fun uniffi_ldk_node_checksum_method_spontaneouspayment_send( + ): Short + fun uniffi_ldk_node_checksum_method_spontaneouspayment_send_probes( + ): Short + fun uniffi_ldk_node_checksum_method_spontaneouspayment_send_with_custom_tlvs( + ): Short + fun uniffi_ldk_node_checksum_method_spontaneouspayment_send_with_preimage( + ): Short + fun uniffi_ldk_node_checksum_method_spontaneouspayment_send_with_preimage_and_custom_tlvs( + ): Short + fun uniffi_ldk_node_checksum_method_unifiedqrpayment_receive( + ): Short + fun uniffi_ldk_node_checksum_method_unifiedqrpayment_send( + ): Short + fun uniffi_ldk_node_checksum_method_vssheaderprovider_get_headers( + ): Short + fun uniffi_ldk_node_checksum_constructor_bolt11invoice_from_str( + ): Short + fun uniffi_ldk_node_checksum_constructor_bolt12invoice_from_str( + ): Short + fun uniffi_ldk_node_checksum_constructor_builder_from_config( + ): Short + fun uniffi_ldk_node_checksum_constructor_builder_new( + ): Short + fun uniffi_ldk_node_checksum_constructor_feerate_from_sat_per_kwu( + ): Short + fun uniffi_ldk_node_checksum_constructor_feerate_from_sat_per_vb_unchecked( + ): Short + fun uniffi_ldk_node_checksum_constructor_offer_from_str( + ): Short + fun uniffi_ldk_node_checksum_constructor_refund_from_str( + ): Short + fun ffi_ldk_node_uniffi_contract_version( + ): Int + +} + +private fun uniffiCheckContractApiVersion(lib: UniffiLib) { + // Get the bindings contract version from our ComponentInterface + val bindings_contract_version = 26 + // Get the scaffolding contract version by calling the into the dylib + val scaffolding_contract_version = lib.ffi_ldk_node_uniffi_contract_version() + if (bindings_contract_version != scaffolding_contract_version) { + throw RuntimeException("UniFFI contract version mismatch: try cleaning and rebuilding your project") + } +} + + +private fun uniffiCheckApiChecksums(lib: UniffiLib) { + if (lib.uniffi_ldk_node_checksum_func_battery_saving_sync_intervals() != 25473.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_func_default_config() != 55381.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_func_derive_node_secret_from_mnemonic() != 15067.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_func_generate_entropy_mnemonic() != 48014.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_amount_milli_satoshis() != 50823.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_currency() != 32179.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_expiry_time_seconds() != 23625.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_fallback_addresses() != 55276.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_invoice_description() != 395.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_is_expired() != 15932.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_min_final_cltv_expiry_delta() != 8855.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_network() != 10420.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_payment_hash() != 42571.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_payment_secret() != 26081.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_recover_payee_pub_key() != 18874.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_route_hints() != 63051.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_seconds_since_epoch() != 53979.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_seconds_until_expiry() != 64193.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_signable_hash() != 30910.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_would_expire() != 30331.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_claim_for_hash() != 52848.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_estimate_routing_fees() != 5123.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_estimate_routing_fees_using_amount() != 46411.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_fail_for_hash() != 24516.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_receive() != 6073.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_receive_for_hash() != 27050.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount() != 4893.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount_for_hash() != 1402.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount_via_jit_channel() != 24506.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount_via_jit_channel_for_hash() != 38025.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_receive_via_jit_channel() != 16532.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_receive_via_jit_channel_for_hash() != 1143.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_send() != 12953.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_send_probes() != 16067.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_send_probes_using_amount() != 37281.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_send_using_amount() != 42793.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_absolute_expiry_seconds() != 28589.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_amount() != 5213.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_amount_msats() != 9297.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_chain() != 3308.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_created_at() != 56866.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_encode() != 13200.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_fallback_addresses() != 7925.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_invoice_description() != 1713.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_is_expired() != 39560.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_issuer() != 65270.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_issuer_signing_pubkey() != 55411.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_metadata() != 37374.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_offer_chains() != 39622.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_payer_note() != 28018.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_payer_signing_pubkey() != 12798.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_payment_hash() != 63778.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_quantity() != 43105.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_relative_expiry() != 14024.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_signable_hash() != 39303.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_signing_pubkey() != 35202.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12payment_blinded_paths_for_async_recipient() != 14695.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12payment_initiate_refund() != 15019.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12payment_receive() != 59252.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12payment_receive_async() != 23867.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12payment_receive_variable_amount() != 35484.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12payment_request_refund_payment() != 43248.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12payment_send() != 27679.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12payment_send_using_amount() != 33255.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12payment_set_paths_to_static_invoice_server() != 20921.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_build() != 785.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_build_with_fs_store() != 61304.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_build_with_vss_store() != 2871.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_build_with_vss_store_and_fixed_headers() != 24910.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_build_with_vss_store_and_header_provider() != 9090.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_address_type() != 647.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_address_types_to_monitor() != 23561.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_announcement_addresses() != 39271.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_async_payments_role() != 16463.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_chain_source_bitcoind_rest() != 37382.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_chain_source_bitcoind_rpc() != 2111.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_chain_source_electrum() != 55552.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_chain_source_esplora() != 1781.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_channel_data_migration() != 58453.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_custom_logger() != 51232.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_entropy_bip39_mnemonic() != 827.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_entropy_seed_bytes() != 44799.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_entropy_seed_path() != 64056.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_filesystem_logger() != 10249.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_gossip_source_p2p() != 9279.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_gossip_source_rgs() != 64312.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_liquidity_source_lsps1() != 51527.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_liquidity_source_lsps2() != 14430.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_listening_addresses() != 14051.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_log_facade_logger() != 58410.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_network() != 27539.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_node_alias() != 18342.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_pathfinding_scores_source() != 63501.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_scoring_decay_params() != 19869.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_scoring_fee_params() != 11588.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_storage_dir_path() != 59019.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_feerate_to_sat_per_kwu() != 58911.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_feerate_to_sat_per_vb_ceil() != 58575.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_feerate_to_sat_per_vb_floor() != 59617.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_lsps1liquidity_check_order_status() != 57147.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_lsps1liquidity_request_channel() != 18153.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_logwriter_log() != 3299.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_networkgraph_channel() != 38070.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_networkgraph_list_channels() != 4693.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_networkgraph_list_nodes() != 36715.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_networkgraph_node() != 48925.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_add_address_type_to_monitor() != 14706.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_add_address_type_to_monitor_with_mnemonic() != 4517.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_add_onchain_wallet_account() != 37245.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_announcement_addresses() != 61426.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_bolt11_payment() != 41402.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_bolt12_payment() != 49254.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_close_channel() != 62479.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_config() != 7511.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_connect() != 34120.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_current_sync_intervals() != 51918.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_disconnect() != 43538.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_event_handled() != 38712.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_export_onchain_wallet_account_xpub() != 5977.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_export_pathfinding_scores() != 62331.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_force_close_channel() != 48831.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_get_address_balance() != 45284.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_get_balance_for_address_type() != 34906.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_get_balance_for_onchain_wallet_account() != 18159.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_get_transaction_details() != 65000.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_list_balances() != 57528.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_list_channels() != 7954.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_list_monitored_address_types() != 25084.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_list_onchain_wallet_accounts() != 4403.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_list_payments() != 35002.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_list_peers() != 14889.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_listening_addresses() != 2665.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_lsps1_liquidity() != 38201.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_network_graph() != 2695.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_next_event() != 7682.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_next_event_async() != 25426.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_node_alias() != 29526.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_node_id() != 51489.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_onchain_payment() != 6092.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_open_announced_channel() != 36623.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_open_channel() != 40283.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_payment() != 60296.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_remove_address_type_from_monitor() != 37081.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_remove_onchain_wallet_account() != 21186.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_remove_payment() != 47952.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_set_primary_address_type() != 11005.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_set_primary_address_type_with_mnemonic() != 50783.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_sign_message() != 49319.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_splice_in() != 46431.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_splice_out() != 22115.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_spontaneous_payment() != 37403.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_start() != 58480.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_status() != 55952.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_stop() != 42188.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_sync_wallets() != 32474.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_unified_qr_payment() != 9837.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_update_channel_config() != 37852.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_update_sync_intervals() != 42322.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_verify_signature() != 20486.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_wait_next_event() != 55101.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_offer_absolute_expiry_seconds() != 22836.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_offer_amount() != 59890.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_offer_chains() != 59522.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_offer_expects_quantity() != 58457.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_offer_id() != 8391.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_offer_is_expired() != 22651.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_offer_is_valid_quantity() != 58469.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_offer_issuer() != 41632.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_offer_issuer_signing_pubkey() != 38162.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_offer_metadata() != 18979.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_offer_offer_description() != 11122.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_offer_supports_chain() != 2135.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_accelerate_by_cpfp() != 31954.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_address_info_for_account_at_index() != 63246.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_address_info_for_type_at_index() != 42692.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_address_infos_for_account() != 39321.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_address_infos_for_type() != 3701.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_bump_fee_by_rbf() != 53877.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_calculate_cpfp_fee_rate() != 32879.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_calculate_send_all_fee() != 16052.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_calculate_total_fee() != 57218.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_list_spendable_outputs() != 19144.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_new_address() != 37251.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_new_address_for_account() != 9932.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_new_address_for_type() != 9083.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_new_address_info() != 9889.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_new_address_info_for_account() != 30767.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_new_address_info_for_type() != 62171.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_reveal_receive_addresses_to() != 44189.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_reveal_receive_addresses_to_account() != 53588.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_select_utxos_with_algorithm() != 14084.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_send_all_to_address() != 37748.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_send_to_address() != 28826.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_refund_absolute_expiry_seconds() != 43722.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_refund_amount_msats() != 26467.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_refund_chain() != 36565.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_refund_is_expired() != 10232.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_refund_issuer() != 40306.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_refund_payer_metadata() != 23501.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_refund_payer_note() != 47799.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_refund_payer_signing_pubkey() != 40880.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_refund_quantity() != 15192.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_refund_refund_description() != 39295.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_spontaneouspayment_send() != 27905.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_spontaneouspayment_send_probes() != 44206.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_spontaneouspayment_send_with_custom_tlvs() != 17876.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_spontaneouspayment_send_with_preimage() != 30854.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_spontaneouspayment_send_with_preimage_and_custom_tlvs() != 12104.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_unifiedqrpayment_receive() != 913.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_unifiedqrpayment_send() != 28285.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_vssheaderprovider_get_headers() != 7788.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_constructor_bolt11invoice_from_str() != 349.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_constructor_bolt12invoice_from_str() != 22276.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_constructor_builder_from_config() != 994.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_constructor_builder_new() != 40499.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_constructor_feerate_from_sat_per_kwu() != 50548.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_constructor_feerate_from_sat_per_vb_unchecked() != 41808.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_constructor_offer_from_str() != 37070.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_constructor_refund_from_str() != 64884.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } +} + +// Public interface members begin here. + + + +object FfiConverterUByte: FfiConverter { + override fun lift(value: Byte): UByte { + return value.toUByte() + } + + override fun read(buf: ByteBuffer): UByte { + return lift(buf.get()) + } + + override fun lower(value: UByte): Byte { + return value.toByte() + } + + override fun allocationSize(value: UByte) = 1UL + + override fun write(value: UByte, buf: ByteBuffer) { + buf.put(value.toByte()) + } +} + + +object FfiConverterUShort: FfiConverter { + override fun lift(value: Short): UShort { + return value.toUShort() + } + + override fun read(buf: ByteBuffer): UShort { + return lift(buf.getShort()) + } + + override fun lower(value: UShort): Short { + return value.toShort() + } + + override fun allocationSize(value: UShort) = 2UL + + override fun write(value: UShort, buf: ByteBuffer) { + buf.putShort(value.toShort()) + } +} + + +object FfiConverterUInt: FfiConverter { + override fun lift(value: Int): UInt { + return value.toUInt() + } + + override fun read(buf: ByteBuffer): UInt { + return lift(buf.getInt()) + } + + override fun lower(value: UInt): Int { + return value.toInt() + } + + override fun allocationSize(value: UInt) = 4UL + + override fun write(value: UInt, buf: ByteBuffer) { + buf.putInt(value.toInt()) + } +} + + +object FfiConverterULong: FfiConverter { + override fun lift(value: Long): ULong { + return value.toULong() + } + + override fun read(buf: ByteBuffer): ULong { + return lift(buf.getLong()) + } + + override fun lower(value: ULong): Long { + return value.toLong() + } + + override fun allocationSize(value: ULong) = 8UL + + override fun write(value: ULong, buf: ByteBuffer) { + buf.putLong(value.toLong()) + } +} + + +object FfiConverterLong: FfiConverter { + override fun lift(value: Long): Long { + return value + } + + override fun read(buf: ByteBuffer): Long { + return buf.getLong() + } + + override fun lower(value: Long): Long { + return value + } + + override fun allocationSize(value: Long) = 8UL + + override fun write(value: Long, buf: ByteBuffer) { + buf.putLong(value) + } +} + + +object FfiConverterBoolean: FfiConverter { + override fun lift(value: Byte): Boolean { + return value.toInt() != 0 + } + + override fun read(buf: ByteBuffer): Boolean { + return lift(buf.get()) + } + + override fun lower(value: Boolean): Byte { + return if (value) 1.toByte() else 0.toByte() + } + + override fun allocationSize(value: Boolean) = 1UL + + override fun write(value: Boolean, buf: ByteBuffer) { + buf.put(lower(value)) + } +} + + +fun String.utf8Size(): Int = this.toByteArray(Charsets.UTF_8).size + +object FfiConverterString: FfiConverter { + // Note: we don't inherit from FfiConverterRustBuffer, because we use a + // special encoding when lowering/lifting. We can use `RustBuffer.len` to + // store our length and avoid writing it out to the buffer. + override fun lift(value: RustBufferByValue): String { + try { + require(value.len <= Int.MAX_VALUE) { + val length = value.len + "cannot handle RustBuffer longer than Int.MAX_VALUE bytes: length is $length" + } + val byteArr = value.asByteBuffer()!!.get(value.len.toInt()) + return byteArr.decodeToString() + } finally { + RustBufferHelper.free(value) + } + } + + override fun read(buf: ByteBuffer): String { + val len = buf.getInt() + val byteArr = buf.get(len) + return byteArr.decodeToString() + } + + override fun lower(value: String): RustBufferByValue { + return RustBufferHelper.allocValue(value.utf8Size().toULong()).apply { + asByteBuffer()!!.writeUtf8(value) + } + } + + // We aren't sure exactly how many bytes our string will be once it's UTF-8 + // encoded. Allocate 3 bytes per UTF-16 code unit which will always be + // enough. + override fun allocationSize(value: String): ULong { + val sizeForLength = 4UL + val sizeForString = value.length.toULong() * 3UL + return sizeForLength + sizeForString + } + + override fun write(value: String, buf: ByteBuffer) { + buf.putInt(value.utf8Size().toInt()) + buf.writeUtf8(value) + } +} + + +object FfiConverterByteArray: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ByteArray { + val len = buf.getInt() + val byteArr = buf.get(len) + return byteArr + } + override fun allocationSize(value: ByteArray): ULong { + return 4UL + value.size.toULong() + } + override fun write(value: ByteArray, buf: ByteBuffer) { + buf.putInt(value.size) + buf.put(value) + } +} + + + +open class Bolt11Invoice: Disposable, Bolt11InvoiceInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_bolt11invoice(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_bolt11invoice(pointer!!, status) + }!! + } + + + override fun `amountMilliSatoshis`(): kotlin.ULong? { + return FfiConverterOptionalULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_amount_milli_satoshis( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `currency`(): Currency { + return FfiConverterTypeCurrency.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_currency( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `expiryTimeSeconds`(): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_expiry_time_seconds( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `fallbackAddresses`(): List
{ + return FfiConverterSequenceTypeAddress.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_fallback_addresses( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `invoiceDescription`(): Bolt11InvoiceDescription { + return FfiConverterTypeBolt11InvoiceDescription.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_invoice_description( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `isExpired`(): kotlin.Boolean { + return FfiConverterBoolean.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_is_expired( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `minFinalCltvExpiryDelta`(): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_min_final_cltv_expiry_delta( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `network`(): Network { + return FfiConverterTypeNetwork.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_network( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `paymentHash`(): PaymentHash { + return FfiConverterTypePaymentHash.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_payment_hash( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `paymentSecret`(): PaymentSecret { + return FfiConverterTypePaymentSecret.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_payment_secret( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `recoverPayeePubKey`(): PublicKey { + return FfiConverterTypePublicKey.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_recover_payee_pub_key( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `routeHints`(): List> { + return FfiConverterSequenceSequenceTypeRouteHintHop.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_route_hints( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `secondsSinceEpoch`(): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_seconds_since_epoch( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `secondsUntilExpiry`(): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_seconds_until_expiry( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `signableHash`(): List { + return FfiConverterSequenceUByte.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_signable_hash( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `wouldExpire`(`atTimeSeconds`: kotlin.ULong): kotlin.Boolean { + return FfiConverterBoolean.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_would_expire( + it, + FfiConverterULong.lower(`atTimeSeconds`), + uniffiRustCallStatus, + ) + } + }) + } + + + + + override fun toString(): String { + return FfiConverterString.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_display( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is Bolt11Invoice) return false + return FfiConverterBoolean.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_eq_eq( + it, + FfiConverterTypeBolt11Invoice.lower(`other`), + uniffiRustCallStatus, + ) + } + }) + } + + + + companion object { + + @Throws(NodeException::class) + fun `fromStr`(`invoiceStr`: kotlin.String): Bolt11Invoice { + return FfiConverterTypeBolt11Invoice.lift(uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_constructor_bolt11invoice_from_str( + FfiConverterString.lower(`invoiceStr`), + uniffiRustCallStatus, + ) + }!!) + } + + + } + +} + + + + + +object FfiConverterTypeBolt11Invoice: FfiConverter { + + override fun lower(value: Bolt11Invoice): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): Bolt11Invoice { + return Bolt11Invoice(value) + } + + override fun read(buf: ByteBuffer): Bolt11Invoice { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: Bolt11Invoice) = 8UL + + override fun write(value: Bolt11Invoice, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} +// The cleaner interface for Object finalization code to run. +// This is the entry point to any implementation that we're using. +// +// The cleaner registers disposables and returns cleanables, so now we are +// defining a `UniffiCleaner` with a `UniffiClenaer.Cleanable` to abstract the +// different implementations available at compile time. +interface UniffiCleaner { + interface Cleanable { + fun clean() + } + + fun register(resource: Any, disposable: Disposable): UniffiCleaner.Cleanable + + companion object +} +// The fallback Jna cleaner, which is available for both Android, and the JVM. +private class UniffiJnaCleaner : UniffiCleaner { + private val cleaner = com.sun.jna.internal.Cleaner.getCleaner() + + override fun register(resource: Any, disposable: Disposable): UniffiCleaner.Cleanable = + UniffiJnaCleanable(cleaner.register(resource, UniffiCleanerAction(disposable))) +} + +private class UniffiJnaCleanable( + private val cleanable: com.sun.jna.internal.Cleaner.Cleanable, +) : UniffiCleaner.Cleanable { + override fun clean() = cleanable.clean() +} + +private class UniffiCleanerAction(private val disposable: Disposable): Runnable { + override fun run() { + disposable.destroy() + } +} + +// The SystemCleaner, available from API Level 33. +// Some API Level 33 OSes do not support using it, so we require API Level 34. +@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) +private class AndroidSystemCleaner : UniffiCleaner { + private val cleaner = android.system.SystemCleaner.cleaner() + + override fun register(resource: Any, disposable: Disposable): UniffiCleaner.Cleanable = + AndroidSystemCleanable(cleaner.register(resource, UniffiCleanerAction(disposable))) +} + +@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) +private class AndroidSystemCleanable( + private val cleanable: java.lang.ref.Cleaner.Cleanable, +) : UniffiCleaner.Cleanable { + override fun clean() = cleanable.clean() +} + +private fun UniffiCleaner.Companion.create(): UniffiCleaner { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + try { + return AndroidSystemCleaner() + } catch (_: IllegalAccessError) { + // (For Compose preview) Fallback to UniffiJnaCleaner if AndroidSystemCleaner is + // unavailable, even for API level 34 or higher. + } + } + return UniffiJnaCleaner() +} + + + +open class Bolt11Payment: Disposable, Bolt11PaymentInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_bolt11payment(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_bolt11payment(pointer!!, status) + }!! + } + + + @Throws(NodeException::class) + override fun `claimForHash`(`paymentHash`: PaymentHash, `claimableAmountMsat`: kotlin.ULong, `preimage`: PaymentPreimage) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_claim_for_hash( + it, + FfiConverterTypePaymentHash.lower(`paymentHash`), + FfiConverterULong.lower(`claimableAmountMsat`), + FfiConverterTypePaymentPreimage.lower(`preimage`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `estimateRoutingFees`(`invoice`: Bolt11Invoice): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_estimate_routing_fees( + it, + FfiConverterTypeBolt11Invoice.lower(`invoice`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `estimateRoutingFeesUsingAmount`(`invoice`: Bolt11Invoice, `amountMsat`: kotlin.ULong): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_estimate_routing_fees_using_amount( + it, + FfiConverterTypeBolt11Invoice.lower(`invoice`), + FfiConverterULong.lower(`amountMsat`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `failForHash`(`paymentHash`: PaymentHash) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_fail_for_hash( + it, + FfiConverterTypePaymentHash.lower(`paymentHash`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `receive`(`amountMsat`: kotlin.ULong, `description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt): Bolt11Invoice { + return FfiConverterTypeBolt11Invoice.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_receive( + it, + FfiConverterULong.lower(`amountMsat`), + FfiConverterTypeBolt11InvoiceDescription.lower(`description`), + FfiConverterUInt.lower(`expirySecs`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `receiveForHash`(`amountMsat`: kotlin.ULong, `description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt, `paymentHash`: PaymentHash): Bolt11Invoice { + return FfiConverterTypeBolt11Invoice.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_receive_for_hash( + it, + FfiConverterULong.lower(`amountMsat`), + FfiConverterTypeBolt11InvoiceDescription.lower(`description`), + FfiConverterUInt.lower(`expirySecs`), + FfiConverterTypePaymentHash.lower(`paymentHash`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `receiveVariableAmount`(`description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt): Bolt11Invoice { + return FfiConverterTypeBolt11Invoice.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount( + it, + FfiConverterTypeBolt11InvoiceDescription.lower(`description`), + FfiConverterUInt.lower(`expirySecs`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `receiveVariableAmountForHash`(`description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt, `paymentHash`: PaymentHash): Bolt11Invoice { + return FfiConverterTypeBolt11Invoice.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount_for_hash( + it, + FfiConverterTypeBolt11InvoiceDescription.lower(`description`), + FfiConverterUInt.lower(`expirySecs`), + FfiConverterTypePaymentHash.lower(`paymentHash`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `receiveVariableAmountViaJitChannel`(`description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt, `maxProportionalLspFeeLimitPpmMsat`: kotlin.ULong?): Bolt11Invoice { + return FfiConverterTypeBolt11Invoice.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount_via_jit_channel( + it, + FfiConverterTypeBolt11InvoiceDescription.lower(`description`), + FfiConverterUInt.lower(`expirySecs`), + FfiConverterOptionalULong.lower(`maxProportionalLspFeeLimitPpmMsat`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `receiveVariableAmountViaJitChannelForHash`(`description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt, `maxProportionalLspFeeLimitPpmMsat`: kotlin.ULong?, `paymentHash`: PaymentHash): Bolt11Invoice { + return FfiConverterTypeBolt11Invoice.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount_via_jit_channel_for_hash( + it, + FfiConverterTypeBolt11InvoiceDescription.lower(`description`), + FfiConverterUInt.lower(`expirySecs`), + FfiConverterOptionalULong.lower(`maxProportionalLspFeeLimitPpmMsat`), + FfiConverterTypePaymentHash.lower(`paymentHash`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `receiveViaJitChannel`(`amountMsat`: kotlin.ULong, `description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt, `maxLspFeeLimitMsat`: kotlin.ULong?): Bolt11Invoice { + return FfiConverterTypeBolt11Invoice.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_receive_via_jit_channel( + it, + FfiConverterULong.lower(`amountMsat`), + FfiConverterTypeBolt11InvoiceDescription.lower(`description`), + FfiConverterUInt.lower(`expirySecs`), + FfiConverterOptionalULong.lower(`maxLspFeeLimitMsat`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `receiveViaJitChannelForHash`(`amountMsat`: kotlin.ULong, `description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt, `maxLspFeeLimitMsat`: kotlin.ULong?, `paymentHash`: PaymentHash): Bolt11Invoice { + return FfiConverterTypeBolt11Invoice.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_receive_via_jit_channel_for_hash( + it, + FfiConverterULong.lower(`amountMsat`), + FfiConverterTypeBolt11InvoiceDescription.lower(`description`), + FfiConverterUInt.lower(`expirySecs`), + FfiConverterOptionalULong.lower(`maxLspFeeLimitMsat`), + FfiConverterTypePaymentHash.lower(`paymentHash`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `send`(`invoice`: Bolt11Invoice, `routeParameters`: RouteParametersConfig?): PaymentId { + return FfiConverterTypePaymentId.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_send( + it, + FfiConverterTypeBolt11Invoice.lower(`invoice`), + FfiConverterOptionalTypeRouteParametersConfig.lower(`routeParameters`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `sendProbes`(`invoice`: Bolt11Invoice, `routeParameters`: RouteParametersConfig?): List { + return FfiConverterSequenceTypeProbeHandle.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_send_probes( + it, + FfiConverterTypeBolt11Invoice.lower(`invoice`), + FfiConverterOptionalTypeRouteParametersConfig.lower(`routeParameters`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `sendProbesUsingAmount`(`invoice`: Bolt11Invoice, `amountMsat`: kotlin.ULong, `routeParameters`: RouteParametersConfig?): List { + return FfiConverterSequenceTypeProbeHandle.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_send_probes_using_amount( + it, + FfiConverterTypeBolt11Invoice.lower(`invoice`), + FfiConverterULong.lower(`amountMsat`), + FfiConverterOptionalTypeRouteParametersConfig.lower(`routeParameters`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `sendUsingAmount`(`invoice`: Bolt11Invoice, `amountMsat`: kotlin.ULong, `routeParameters`: RouteParametersConfig?): PaymentId { + return FfiConverterTypePaymentId.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_send_using_amount( + it, + FfiConverterTypeBolt11Invoice.lower(`invoice`), + FfiConverterULong.lower(`amountMsat`), + FfiConverterOptionalTypeRouteParametersConfig.lower(`routeParameters`), + uniffiRustCallStatus, + ) + } + }) + } + + + + + + + + companion object + +} + + + + + +object FfiConverterTypeBolt11Payment: FfiConverter { + + override fun lower(value: Bolt11Payment): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): Bolt11Payment { + return Bolt11Payment(value) + } + + override fun read(buf: ByteBuffer): Bolt11Payment { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: Bolt11Payment) = 8UL + + override fun write(value: Bolt11Payment, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + + + +open class Bolt12Invoice: Disposable, Bolt12InvoiceInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_bolt12invoice(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_bolt12invoice(pointer!!, status) + }!! + } + + + override fun `absoluteExpirySeconds`(): kotlin.ULong? { + return FfiConverterOptionalULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_absolute_expiry_seconds( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `amount`(): OfferAmount? { + return FfiConverterOptionalTypeOfferAmount.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_amount( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `amountMsats`(): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_amount_msats( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `chain`(): List { + return FfiConverterSequenceUByte.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_chain( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `createdAt`(): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_created_at( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `encode`(): List { + return FfiConverterSequenceUByte.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_encode( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `fallbackAddresses`(): List
{ + return FfiConverterSequenceTypeAddress.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_fallback_addresses( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `invoiceDescription`(): kotlin.String? { + return FfiConverterOptionalString.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_invoice_description( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `isExpired`(): kotlin.Boolean { + return FfiConverterBoolean.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_is_expired( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `issuer`(): kotlin.String? { + return FfiConverterOptionalString.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_issuer( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `issuerSigningPubkey`(): PublicKey? { + return FfiConverterOptionalTypePublicKey.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_issuer_signing_pubkey( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `metadata`(): List? { + return FfiConverterOptionalSequenceUByte.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_metadata( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `offerChains`(): List>? { + return FfiConverterOptionalSequenceSequenceUByte.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_offer_chains( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `payerNote`(): kotlin.String? { + return FfiConverterOptionalString.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_payer_note( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `payerSigningPubkey`(): PublicKey { + return FfiConverterTypePublicKey.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_payer_signing_pubkey( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `paymentHash`(): PaymentHash { + return FfiConverterTypePaymentHash.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_payment_hash( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `quantity`(): kotlin.ULong? { + return FfiConverterOptionalULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_quantity( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `relativeExpiry`(): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_relative_expiry( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `signableHash`(): List { + return FfiConverterSequenceUByte.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_signable_hash( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `signingPubkey`(): PublicKey { + return FfiConverterTypePublicKey.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_signing_pubkey( + it, + uniffiRustCallStatus, + ) + } + }) + } + + + + + + + companion object { + + @Throws(NodeException::class) + fun `fromStr`(`invoiceStr`: kotlin.String): Bolt12Invoice { + return FfiConverterTypeBolt12Invoice.lift(uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_constructor_bolt12invoice_from_str( + FfiConverterString.lower(`invoiceStr`), + uniffiRustCallStatus, + ) + }!!) + } + + + } + +} + + + + + +object FfiConverterTypeBolt12Invoice: FfiConverter { + + override fun lower(value: Bolt12Invoice): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): Bolt12Invoice { + return Bolt12Invoice(value) + } + + override fun read(buf: ByteBuffer): Bolt12Invoice { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: Bolt12Invoice) = 8UL + + override fun write(value: Bolt12Invoice, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + + + +open class Bolt12Payment: Disposable, Bolt12PaymentInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_bolt12payment(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_bolt12payment(pointer!!, status) + }!! + } + + + @Throws(NodeException::class) + override fun `blindedPathsForAsyncRecipient`(`recipientId`: kotlin.ByteArray): kotlin.ByteArray { + return FfiConverterByteArray.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12payment_blinded_paths_for_async_recipient( + it, + FfiConverterByteArray.lower(`recipientId`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `initiateRefund`(`amountMsat`: kotlin.ULong, `expirySecs`: kotlin.UInt, `quantity`: kotlin.ULong?, `payerNote`: kotlin.String?, `routeParameters`: RouteParametersConfig?): Refund { + return FfiConverterTypeRefund.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12payment_initiate_refund( + it, + FfiConverterULong.lower(`amountMsat`), + FfiConverterUInt.lower(`expirySecs`), + FfiConverterOptionalULong.lower(`quantity`), + FfiConverterOptionalString.lower(`payerNote`), + FfiConverterOptionalTypeRouteParametersConfig.lower(`routeParameters`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `receive`(`amountMsat`: kotlin.ULong, `description`: kotlin.String, `expirySecs`: kotlin.UInt?, `quantity`: kotlin.ULong?): Offer { + return FfiConverterTypeOffer.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12payment_receive( + it, + FfiConverterULong.lower(`amountMsat`), + FfiConverterString.lower(`description`), + FfiConverterOptionalUInt.lower(`expirySecs`), + FfiConverterOptionalULong.lower(`quantity`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `receiveAsync`(): Offer { + return FfiConverterTypeOffer.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12payment_receive_async( + it, + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `receiveVariableAmount`(`description`: kotlin.String, `expirySecs`: kotlin.UInt?): Offer { + return FfiConverterTypeOffer.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12payment_receive_variable_amount( + it, + FfiConverterString.lower(`description`), + FfiConverterOptionalUInt.lower(`expirySecs`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `requestRefundPayment`(`refund`: Refund): Bolt12Invoice { + return FfiConverterTypeBolt12Invoice.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12payment_request_refund_payment( + it, + FfiConverterTypeRefund.lower(`refund`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `send`(`offer`: Offer, `quantity`: kotlin.ULong?, `payerNote`: kotlin.String?, `routeParameters`: RouteParametersConfig?): PaymentId { + return FfiConverterTypePaymentId.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12payment_send( + it, + FfiConverterTypeOffer.lower(`offer`), + FfiConverterOptionalULong.lower(`quantity`), + FfiConverterOptionalString.lower(`payerNote`), + FfiConverterOptionalTypeRouteParametersConfig.lower(`routeParameters`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `sendUsingAmount`(`offer`: Offer, `amountMsat`: kotlin.ULong, `quantity`: kotlin.ULong?, `payerNote`: kotlin.String?, `routeParameters`: RouteParametersConfig?): PaymentId { + return FfiConverterTypePaymentId.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12payment_send_using_amount( + it, + FfiConverterTypeOffer.lower(`offer`), + FfiConverterULong.lower(`amountMsat`), + FfiConverterOptionalULong.lower(`quantity`), + FfiConverterOptionalString.lower(`payerNote`), + FfiConverterOptionalTypeRouteParametersConfig.lower(`routeParameters`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `setPathsToStaticInvoiceServer`(`paths`: kotlin.ByteArray) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12payment_set_paths_to_static_invoice_server( + it, + FfiConverterByteArray.lower(`paths`), + uniffiRustCallStatus, + ) + } + } + } + + + + + + + + companion object + +} + + + + + +object FfiConverterTypeBolt12Payment: FfiConverter { + + override fun lower(value: Bolt12Payment): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): Bolt12Payment { + return Bolt12Payment(value) + } + + override fun read(buf: ByteBuffer): Bolt12Payment { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: Bolt12Payment) = 8UL + + override fun write(value: Bolt12Payment, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + + + +open class Builder: Disposable, BuilderInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + constructor() : this( + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_constructor_builder_new( + uniffiRustCallStatus, + ) + }!! + ) + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_builder(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_builder(pointer!!, status) + }!! + } + + + @Throws(BuildException::class) + override fun `build`(): Node { + return FfiConverterTypeNode.lift(callWithPointer { + uniffiRustCallWithError(BuildExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_build( + it, + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(BuildException::class) + override fun `buildWithFsStore`(): Node { + return FfiConverterTypeNode.lift(callWithPointer { + uniffiRustCallWithError(BuildExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_build_with_fs_store( + it, + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(BuildException::class) + override fun `buildWithVssStore`(`vssUrl`: kotlin.String, `storeId`: kotlin.String, `lnurlAuthServerUrl`: kotlin.String, `fixedHeaders`: Map): Node { + return FfiConverterTypeNode.lift(callWithPointer { + uniffiRustCallWithError(BuildExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_build_with_vss_store( + it, + FfiConverterString.lower(`vssUrl`), + FfiConverterString.lower(`storeId`), + FfiConverterString.lower(`lnurlAuthServerUrl`), + FfiConverterMapStringString.lower(`fixedHeaders`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(BuildException::class) + override fun `buildWithVssStoreAndFixedHeaders`(`vssUrl`: kotlin.String, `storeId`: kotlin.String, `fixedHeaders`: Map): Node { + return FfiConverterTypeNode.lift(callWithPointer { + uniffiRustCallWithError(BuildExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_build_with_vss_store_and_fixed_headers( + it, + FfiConverterString.lower(`vssUrl`), + FfiConverterString.lower(`storeId`), + FfiConverterMapStringString.lower(`fixedHeaders`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(BuildException::class) + override fun `buildWithVssStoreAndHeaderProvider`(`vssUrl`: kotlin.String, `storeId`: kotlin.String, `headerProvider`: VssHeaderProvider): Node { + return FfiConverterTypeNode.lift(callWithPointer { + uniffiRustCallWithError(BuildExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_build_with_vss_store_and_header_provider( + it, + FfiConverterString.lower(`vssUrl`), + FfiConverterString.lower(`storeId`), + FfiConverterTypeVssHeaderProvider.lower(`headerProvider`), + uniffiRustCallStatus, + ) + }!! + }) + } + + override fun `setAddressType`(`addressType`: AddressType) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_address_type( + it, + FfiConverterTypeAddressType.lower(`addressType`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setAddressTypesToMonitor`(`addressTypesToMonitor`: List) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_address_types_to_monitor( + it, + FfiConverterSequenceTypeAddressType.lower(`addressTypesToMonitor`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(BuildException::class) + override fun `setAnnouncementAddresses`(`announcementAddresses`: List) { + callWithPointer { + uniffiRustCallWithError(BuildExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_announcement_addresses( + it, + FfiConverterSequenceTypeSocketAddress.lower(`announcementAddresses`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(BuildException::class) + override fun `setAsyncPaymentsRole`(`role`: AsyncPaymentsRole?) { + callWithPointer { + uniffiRustCallWithError(BuildExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_async_payments_role( + it, + FfiConverterOptionalTypeAsyncPaymentsRole.lower(`role`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setChainSourceBitcoindRest`(`restHost`: kotlin.String, `restPort`: kotlin.UShort, `rpcHost`: kotlin.String, `rpcPort`: kotlin.UShort, `rpcUser`: kotlin.String, `rpcPassword`: kotlin.String) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_chain_source_bitcoind_rest( + it, + FfiConverterString.lower(`restHost`), + FfiConverterUShort.lower(`restPort`), + FfiConverterString.lower(`rpcHost`), + FfiConverterUShort.lower(`rpcPort`), + FfiConverterString.lower(`rpcUser`), + FfiConverterString.lower(`rpcPassword`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setChainSourceBitcoindRpc`(`rpcHost`: kotlin.String, `rpcPort`: kotlin.UShort, `rpcUser`: kotlin.String, `rpcPassword`: kotlin.String) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_chain_source_bitcoind_rpc( + it, + FfiConverterString.lower(`rpcHost`), + FfiConverterUShort.lower(`rpcPort`), + FfiConverterString.lower(`rpcUser`), + FfiConverterString.lower(`rpcPassword`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setChainSourceElectrum`(`serverUrl`: kotlin.String, `config`: ElectrumSyncConfig?) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_chain_source_electrum( + it, + FfiConverterString.lower(`serverUrl`), + FfiConverterOptionalTypeElectrumSyncConfig.lower(`config`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setChainSourceEsplora`(`serverUrl`: kotlin.String, `config`: EsploraSyncConfig?) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_chain_source_esplora( + it, + FfiConverterString.lower(`serverUrl`), + FfiConverterOptionalTypeEsploraSyncConfig.lower(`config`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setChannelDataMigration`(`migration`: ChannelDataMigration) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_channel_data_migration( + it, + FfiConverterTypeChannelDataMigration.lower(`migration`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setCustomLogger`(`logWriter`: LogWriter) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_custom_logger( + it, + FfiConverterTypeLogWriter.lower(`logWriter`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setEntropyBip39Mnemonic`(`mnemonic`: Mnemonic, `passphrase`: kotlin.String?) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_entropy_bip39_mnemonic( + it, + FfiConverterTypeMnemonic.lower(`mnemonic`), + FfiConverterOptionalString.lower(`passphrase`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(BuildException::class) + override fun `setEntropySeedBytes`(`seedBytes`: List) { + callWithPointer { + uniffiRustCallWithError(BuildExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_entropy_seed_bytes( + it, + FfiConverterSequenceUByte.lower(`seedBytes`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setEntropySeedPath`(`seedPath`: kotlin.String) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_entropy_seed_path( + it, + FfiConverterString.lower(`seedPath`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setFilesystemLogger`(`logFilePath`: kotlin.String?, `maxLogLevel`: LogLevel?) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_filesystem_logger( + it, + FfiConverterOptionalString.lower(`logFilePath`), + FfiConverterOptionalTypeLogLevel.lower(`maxLogLevel`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setGossipSourceP2p`() { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_gossip_source_p2p( + it, + uniffiRustCallStatus, + ) + } + } + } + + override fun `setGossipSourceRgs`(`rgsServerUrl`: kotlin.String) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_gossip_source_rgs( + it, + FfiConverterString.lower(`rgsServerUrl`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setLiquiditySourceLsps1`(`nodeId`: PublicKey, `address`: SocketAddress, `token`: kotlin.String?) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_liquidity_source_lsps1( + it, + FfiConverterTypePublicKey.lower(`nodeId`), + FfiConverterTypeSocketAddress.lower(`address`), + FfiConverterOptionalString.lower(`token`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setLiquiditySourceLsps2`(`nodeId`: PublicKey, `address`: SocketAddress, `token`: kotlin.String?) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_liquidity_source_lsps2( + it, + FfiConverterTypePublicKey.lower(`nodeId`), + FfiConverterTypeSocketAddress.lower(`address`), + FfiConverterOptionalString.lower(`token`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(BuildException::class) + override fun `setListeningAddresses`(`listeningAddresses`: List) { + callWithPointer { + uniffiRustCallWithError(BuildExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_listening_addresses( + it, + FfiConverterSequenceTypeSocketAddress.lower(`listeningAddresses`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setLogFacadeLogger`() { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_log_facade_logger( + it, + uniffiRustCallStatus, + ) + } + } + } + + override fun `setNetwork`(`network`: Network) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_network( + it, + FfiConverterTypeNetwork.lower(`network`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(BuildException::class) + override fun `setNodeAlias`(`nodeAlias`: kotlin.String) { + callWithPointer { + uniffiRustCallWithError(BuildExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_node_alias( + it, + FfiConverterString.lower(`nodeAlias`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setPathfindingScoresSource`(`url`: kotlin.String) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_pathfinding_scores_source( + it, + FfiConverterString.lower(`url`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setScoringDecayParams`(`params`: ScoringDecayParameters) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_scoring_decay_params( + it, + FfiConverterTypeScoringDecayParameters.lower(`params`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setScoringFeeParams`(`params`: ScoringFeeParameters) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_scoring_fee_params( + it, + FfiConverterTypeScoringFeeParameters.lower(`params`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setStorageDirPath`(`storageDirPath`: kotlin.String) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_storage_dir_path( + it, + FfiConverterString.lower(`storageDirPath`), + uniffiRustCallStatus, + ) + } + } + } + + + + + + + companion object { + + fun `fromConfig`(`config`: Config): Builder { + return FfiConverterTypeBuilder.lift(uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_constructor_builder_from_config( + FfiConverterTypeConfig.lower(`config`), + uniffiRustCallStatus, + ) + }!!) + } + + + } + +} + + + + + +object FfiConverterTypeBuilder: FfiConverter { + + override fun lower(value: Builder): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): Builder { + return Builder(value) + } + + override fun read(buf: ByteBuffer): Builder { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: Builder) = 8UL + + override fun write(value: Builder, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + + + +open class FeeRate: Disposable, FeeRateInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_feerate(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_feerate(pointer!!, status) + }!! + } + + + override fun `toSatPerKwu`(): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_feerate_to_sat_per_kwu( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `toSatPerVbCeil`(): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_feerate_to_sat_per_vb_ceil( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `toSatPerVbFloor`(): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_feerate_to_sat_per_vb_floor( + it, + uniffiRustCallStatus, + ) + } + }) + } + + + + + + + companion object { + + fun `fromSatPerKwu`(`satKwu`: kotlin.ULong): FeeRate { + return FfiConverterTypeFeeRate.lift(uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_constructor_feerate_from_sat_per_kwu( + FfiConverterULong.lower(`satKwu`), + uniffiRustCallStatus, + ) + }!!) + } + + + fun `fromSatPerVbUnchecked`(`satVb`: kotlin.ULong): FeeRate { + return FfiConverterTypeFeeRate.lift(uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_constructor_feerate_from_sat_per_vb_unchecked( + FfiConverterULong.lower(`satVb`), + uniffiRustCallStatus, + ) + }!!) + } + + + } + +} + + + + + +object FfiConverterTypeFeeRate: FfiConverter { + + override fun lower(value: FeeRate): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): FeeRate { + return FeeRate(value) + } + + override fun read(buf: ByteBuffer): FeeRate { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: FeeRate) = 8UL + + override fun write(value: FeeRate, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + + + +open class Lsps1Liquidity: Disposable, Lsps1LiquidityInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_lsps1liquidity(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_lsps1liquidity(pointer!!, status) + }!! + } + + + @Throws(NodeException::class) + override fun `checkOrderStatus`(`orderId`: Lsps1OrderId): Lsps1OrderStatus { + return FfiConverterTypeLSPS1OrderStatus.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_lsps1liquidity_check_order_status( + it, + FfiConverterTypeLSPS1OrderId.lower(`orderId`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `requestChannel`(`lspBalanceSat`: kotlin.ULong, `clientBalanceSat`: kotlin.ULong, `channelExpiryBlocks`: kotlin.UInt, `announceChannel`: kotlin.Boolean): Lsps1OrderStatus { + return FfiConverterTypeLSPS1OrderStatus.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_lsps1liquidity_request_channel( + it, + FfiConverterULong.lower(`lspBalanceSat`), + FfiConverterULong.lower(`clientBalanceSat`), + FfiConverterUInt.lower(`channelExpiryBlocks`), + FfiConverterBoolean.lower(`announceChannel`), + uniffiRustCallStatus, + ) + } + }) + } + + + + + + + + companion object + +} + + + + + +object FfiConverterTypeLSPS1Liquidity: FfiConverter { + + override fun lower(value: Lsps1Liquidity): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): Lsps1Liquidity { + return Lsps1Liquidity(value) + } + + override fun read(buf: ByteBuffer): Lsps1Liquidity { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: Lsps1Liquidity) = 8UL + + override fun write(value: Lsps1Liquidity, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + + + +open class LogWriterImpl: Disposable, LogWriter { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_logwriter(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_logwriter(pointer!!, status) + }!! + } + + + override fun `log`(`record`: LogRecord) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_logwriter_log( + it, + FfiConverterTypeLogRecord.lower(`record`), + uniffiRustCallStatus, + ) + } + } + } + + + + + + + + companion object + +} + + + + + +object FfiConverterTypeLogWriter: FfiConverter { + internal val handleMap = UniffiHandleMap() + + override fun lower(value: LogWriter): Pointer { + return handleMap.insert(value).toPointer() + } + + override fun lift(value: Pointer): LogWriter { + return LogWriterImpl(value) + } + + override fun read(buf: ByteBuffer): LogWriter { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: LogWriter) = 8UL + + override fun write(value: LogWriter, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + +internal const val IDX_CALLBACK_FREE = 0 +// Callback return codes +internal const val UNIFFI_CALLBACK_SUCCESS = 0 +internal const val UNIFFI_CALLBACK_ERROR = 1 +internal const val UNIFFI_CALLBACK_UNEXPECTED_ERROR = 2 + +abstract class FfiConverterCallbackInterface: FfiConverter { + internal val handleMap = UniffiHandleMap() + + internal fun drop(handle: Long) { + handleMap.remove(handle) + } + + override fun lift(value: Long): CallbackInterface { + return handleMap.get(value) + } + + override fun read(buf: ByteBuffer) = lift(buf.getLong()) + + override fun lower(value: CallbackInterface) = handleMap.insert(value) + + override fun allocationSize(value: CallbackInterface) = 8UL + + override fun write(value: CallbackInterface, buf: ByteBuffer) { + buf.putLong(lower(value)) + } +} + +// Put the implementation in an object so we don't pollute the top-level namespace +internal object uniffiCallbackInterfaceLogWriter { + internal object `log`: UniffiCallbackInterfaceLogWriterMethod0 { + override fun callback ( + `uniffiHandle`: Long, + `record`: RustBufferByValue, + `uniffiOutReturn`: Pointer, + uniffiCallStatus: UniffiRustCallStatus, + ) { + val uniffiObj = FfiConverterTypeLogWriter.handleMap.get(uniffiHandle) + val makeCall = { -> + uniffiObj.`log`( + FfiConverterTypeLogRecord.lift(`record`), + ) + } + val writeReturn = { _: Unit -> + @Suppress("UNUSED_EXPRESSION") + uniffiOutReturn + Unit + } + uniffiTraitInterfaceCall(uniffiCallStatus, makeCall, writeReturn) + } + } + internal object uniffiFree: UniffiCallbackInterfaceFree { + override fun callback(handle: Long) { + FfiConverterTypeLogWriter.handleMap.remove(handle) + } + } + + internal val vtable = UniffiVTableCallbackInterfaceLogWriter( + `log`, + uniffiFree, + ) + + internal fun register(lib: UniffiLib) { + lib.uniffi_ldk_node_fn_init_callback_vtable_logwriter(vtable) + } +} + + + +open class NetworkGraph: Disposable, NetworkGraphInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_networkgraph(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_networkgraph(pointer!!, status) + }!! + } + + + override fun `channel`(`shortChannelId`: kotlin.ULong): ChannelInfo? { + return FfiConverterOptionalTypeChannelInfo.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_networkgraph_channel( + it, + FfiConverterULong.lower(`shortChannelId`), + uniffiRustCallStatus, + ) + } + }) + } + + override fun `listChannels`(): List { + return FfiConverterSequenceULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_networkgraph_list_channels( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `listNodes`(): List { + return FfiConverterSequenceTypeNodeId.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_networkgraph_list_nodes( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `node`(`nodeId`: NodeId): NodeInfo? { + return FfiConverterOptionalTypeNodeInfo.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_networkgraph_node( + it, + FfiConverterTypeNodeId.lower(`nodeId`), + uniffiRustCallStatus, + ) + } + }) + } + + + + + + + + companion object + +} + + + + + +object FfiConverterTypeNetworkGraph: FfiConverter { + + override fun lower(value: NetworkGraph): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): NetworkGraph { + return NetworkGraph(value) + } + + override fun read(buf: ByteBuffer): NetworkGraph { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: NetworkGraph) = 8UL + + override fun write(value: NetworkGraph, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + + + +open class Node: Disposable, NodeInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_node(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_node(pointer!!, status) + }!! + } + + + @Throws(NodeException::class) + override fun `addAddressTypeToMonitor`(`addressType`: AddressType, `seedBytes`: List) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_add_address_type_to_monitor( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterSequenceUByte.lower(`seedBytes`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `addAddressTypeToMonitorWithMnemonic`(`addressType`: AddressType, `mnemonic`: Mnemonic, `passphrase`: kotlin.String?) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_add_address_type_to_monitor_with_mnemonic( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterTypeMnemonic.lower(`mnemonic`), + FfiConverterOptionalString.lower(`passphrase`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `addOnchainWalletAccount`(`addressType`: AddressType, `accountIndex`: kotlin.UInt, `xpub`: kotlin.String) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_add_onchain_wallet_account( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterUInt.lower(`accountIndex`), + FfiConverterString.lower(`xpub`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `announcementAddresses`(): List? { + return FfiConverterOptionalSequenceTypeSocketAddress.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_announcement_addresses( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `bolt11Payment`(): Bolt11Payment { + return FfiConverterTypeBolt11Payment.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_bolt11_payment( + it, + uniffiRustCallStatus, + ) + }!! + }) + } + + override fun `bolt12Payment`(): Bolt12Payment { + return FfiConverterTypeBolt12Payment.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_bolt12_payment( + it, + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `closeChannel`(`userChannelId`: UserChannelId, `counterpartyNodeId`: PublicKey) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_close_channel( + it, + FfiConverterTypeUserChannelId.lower(`userChannelId`), + FfiConverterTypePublicKey.lower(`counterpartyNodeId`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `config`(): Config { + return FfiConverterTypeConfig.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_config( + it, + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `connect`(`nodeId`: PublicKey, `address`: SocketAddress, `persist`: kotlin.Boolean) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_connect( + it, + FfiConverterTypePublicKey.lower(`nodeId`), + FfiConverterTypeSocketAddress.lower(`address`), + FfiConverterBoolean.lower(`persist`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `currentSyncIntervals`(): RuntimeSyncIntervals { + return FfiConverterTypeRuntimeSyncIntervals.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_current_sync_intervals( + it, + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `disconnect`(`nodeId`: PublicKey) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_disconnect( + it, + FfiConverterTypePublicKey.lower(`nodeId`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `eventHandled`() { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_event_handled( + it, + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `exportOnchainWalletAccountXpub`(`addressType`: AddressType, `accountIndex`: kotlin.UInt): kotlin.String { + return FfiConverterString.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_export_onchain_wallet_account_xpub( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterUInt.lower(`accountIndex`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `exportPathfindingScores`(): kotlin.ByteArray { + return FfiConverterByteArray.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_export_pathfinding_scores( + it, + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `forceCloseChannel`(`userChannelId`: UserChannelId, `counterpartyNodeId`: PublicKey, `reason`: kotlin.String?) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_force_close_channel( + it, + FfiConverterTypeUserChannelId.lower(`userChannelId`), + FfiConverterTypePublicKey.lower(`counterpartyNodeId`), + FfiConverterOptionalString.lower(`reason`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `getAddressBalance`(`addressStr`: kotlin.String): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_get_address_balance( + it, + FfiConverterString.lower(`addressStr`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `getBalanceForAddressType`(`addressType`: AddressType): AddressTypeBalance { + return FfiConverterTypeAddressTypeBalance.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_get_balance_for_address_type( + it, + FfiConverterTypeAddressType.lower(`addressType`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `getBalanceForOnchainWalletAccount`(`addressType`: AddressType, `accountIndex`: kotlin.UInt): AddressTypeBalance { + return FfiConverterTypeAddressTypeBalance.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_get_balance_for_onchain_wallet_account( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterUInt.lower(`accountIndex`), + uniffiRustCallStatus, + ) + } + }) + } + + override fun `getTransactionDetails`(`txid`: Txid): TransactionDetails? { + return FfiConverterOptionalTypeTransactionDetails.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_get_transaction_details( + it, + FfiConverterTypeTxid.lower(`txid`), + uniffiRustCallStatus, + ) + } + }) + } + + override fun `listBalances`(): BalanceDetails { + return FfiConverterTypeBalanceDetails.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_list_balances( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `listChannels`(): List { + return FfiConverterSequenceTypeChannelDetails.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_list_channels( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `listMonitoredAddressTypes`(): List { + return FfiConverterSequenceTypeAddressType.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_list_monitored_address_types( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `listOnchainWalletAccounts`(): List { + return FfiConverterSequenceTypeOnchainWalletAccount.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_list_onchain_wallet_accounts( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `listPayments`(): List { + return FfiConverterSequenceTypePaymentDetails.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_list_payments( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `listPeers`(): List { + return FfiConverterSequenceTypePeerDetails.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_list_peers( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `listeningAddresses`(): List? { + return FfiConverterOptionalSequenceTypeSocketAddress.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_listening_addresses( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `lsps1Liquidity`(): Lsps1Liquidity { + return FfiConverterTypeLSPS1Liquidity.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_lsps1_liquidity( + it, + uniffiRustCallStatus, + ) + }!! + }) + } + + override fun `networkGraph`(): NetworkGraph { + return FfiConverterTypeNetworkGraph.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_network_graph( + it, + uniffiRustCallStatus, + ) + }!! + }) + } + + override fun `nextEvent`(): Event? { + return FfiConverterOptionalTypeEvent.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_next_event( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override suspend fun `nextEventAsync`(): Event { + return uniffiRustCallAsync( + callWithPointer { thisPtr -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_next_event_async( + thisPtr, + ) + }, + { future, callback, continuation -> UniffiLib.INSTANCE.ffi_ldk_node_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.INSTANCE.ffi_ldk_node_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.INSTANCE.ffi_ldk_node_rust_future_free_rust_buffer(future) }, + { future -> UniffiLib.INSTANCE.ffi_ldk_node_rust_future_cancel_rust_buffer(future) }, + // lift function + { FfiConverterTypeEvent.lift(it) }, + // Error FFI converter + UniffiNullRustCallStatusErrorHandler, + ) + } + + override fun `nodeAlias`(): NodeAlias? { + return FfiConverterOptionalTypeNodeAlias.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_node_alias( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `nodeId`(): PublicKey { + return FfiConverterTypePublicKey.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_node_id( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `onchainPayment`(): OnchainPayment { + return FfiConverterTypeOnchainPayment.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_onchain_payment( + it, + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `openAnnouncedChannel`(`nodeId`: PublicKey, `address`: SocketAddress, `channelAmountSats`: kotlin.ULong, `pushToCounterpartyMsat`: kotlin.ULong?, `channelConfig`: ChannelConfig?): UserChannelId { + return FfiConverterTypeUserChannelId.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_open_announced_channel( + it, + FfiConverterTypePublicKey.lower(`nodeId`), + FfiConverterTypeSocketAddress.lower(`address`), + FfiConverterULong.lower(`channelAmountSats`), + FfiConverterOptionalULong.lower(`pushToCounterpartyMsat`), + FfiConverterOptionalTypeChannelConfig.lower(`channelConfig`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `openChannel`(`nodeId`: PublicKey, `address`: SocketAddress, `channelAmountSats`: kotlin.ULong, `pushToCounterpartyMsat`: kotlin.ULong?, `channelConfig`: ChannelConfig?): UserChannelId { + return FfiConverterTypeUserChannelId.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_open_channel( + it, + FfiConverterTypePublicKey.lower(`nodeId`), + FfiConverterTypeSocketAddress.lower(`address`), + FfiConverterULong.lower(`channelAmountSats`), + FfiConverterOptionalULong.lower(`pushToCounterpartyMsat`), + FfiConverterOptionalTypeChannelConfig.lower(`channelConfig`), + uniffiRustCallStatus, + ) + } + }) + } + + override fun `payment`(`paymentId`: PaymentId): PaymentDetails? { + return FfiConverterOptionalTypePaymentDetails.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_payment( + it, + FfiConverterTypePaymentId.lower(`paymentId`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `removeAddressTypeFromMonitor`(`addressType`: AddressType) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_remove_address_type_from_monitor( + it, + FfiConverterTypeAddressType.lower(`addressType`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `removeOnchainWalletAccount`(`addressType`: AddressType, `accountIndex`: kotlin.UInt) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_remove_onchain_wallet_account( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterUInt.lower(`accountIndex`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `removePayment`(`paymentId`: PaymentId) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_remove_payment( + it, + FfiConverterTypePaymentId.lower(`paymentId`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `setPrimaryAddressType`(`addressType`: AddressType, `seedBytes`: List) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_set_primary_address_type( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterSequenceUByte.lower(`seedBytes`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `setPrimaryAddressTypeWithMnemonic`(`addressType`: AddressType, `mnemonic`: Mnemonic, `passphrase`: kotlin.String?) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_set_primary_address_type_with_mnemonic( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterTypeMnemonic.lower(`mnemonic`), + FfiConverterOptionalString.lower(`passphrase`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `signMessage`(`msg`: List): kotlin.String { + return FfiConverterString.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_sign_message( + it, + FfiConverterSequenceUByte.lower(`msg`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `spliceIn`(`userChannelId`: UserChannelId, `counterpartyNodeId`: PublicKey, `spliceAmountSats`: kotlin.ULong) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_splice_in( + it, + FfiConverterTypeUserChannelId.lower(`userChannelId`), + FfiConverterTypePublicKey.lower(`counterpartyNodeId`), + FfiConverterULong.lower(`spliceAmountSats`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `spliceOut`(`userChannelId`: UserChannelId, `counterpartyNodeId`: PublicKey, `address`: Address, `spliceAmountSats`: kotlin.ULong) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_splice_out( + it, + FfiConverterTypeUserChannelId.lower(`userChannelId`), + FfiConverterTypePublicKey.lower(`counterpartyNodeId`), + FfiConverterTypeAddress.lower(`address`), + FfiConverterULong.lower(`spliceAmountSats`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `spontaneousPayment`(): SpontaneousPayment { + return FfiConverterTypeSpontaneousPayment.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_spontaneous_payment( + it, + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `start`() { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_start( + it, + uniffiRustCallStatus, + ) + } + } + } + + override fun `status`(): NodeStatus { + return FfiConverterTypeNodeStatus.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_status( + it, + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `stop`() { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_stop( + it, + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `syncWallets`() { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_sync_wallets( + it, + uniffiRustCallStatus, + ) + } + } + } + + override fun `unifiedQrPayment`(): UnifiedQrPayment { + return FfiConverterTypeUnifiedQrPayment.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_unified_qr_payment( + it, + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `updateChannelConfig`(`userChannelId`: UserChannelId, `counterpartyNodeId`: PublicKey, `channelConfig`: ChannelConfig) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_update_channel_config( + it, + FfiConverterTypeUserChannelId.lower(`userChannelId`), + FfiConverterTypePublicKey.lower(`counterpartyNodeId`), + FfiConverterTypeChannelConfig.lower(`channelConfig`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `updateSyncIntervals`(`intervals`: RuntimeSyncIntervals) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_update_sync_intervals( + it, + FfiConverterTypeRuntimeSyncIntervals.lower(`intervals`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `verifySignature`(`msg`: List, `sig`: kotlin.String, `pkey`: PublicKey): kotlin.Boolean { + return FfiConverterBoolean.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_verify_signature( + it, + FfiConverterSequenceUByte.lower(`msg`), + FfiConverterString.lower(`sig`), + FfiConverterTypePublicKey.lower(`pkey`), + uniffiRustCallStatus, + ) + } + }) + } + + override fun `waitNextEvent`(): Event { + return FfiConverterTypeEvent.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_wait_next_event( + it, + uniffiRustCallStatus, + ) + } + }) + } + + + + + + + + companion object + +} + + + + + +object FfiConverterTypeNode: FfiConverter { + + override fun lower(value: Node): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): Node { + return Node(value) + } + + override fun read(buf: ByteBuffer): Node { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: Node) = 8UL + + override fun write(value: Node, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + + + +open class Offer: Disposable, OfferInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_offer(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_offer(pointer!!, status) + }!! + } + + + override fun `absoluteExpirySeconds`(): kotlin.ULong? { + return FfiConverterOptionalULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_offer_absolute_expiry_seconds( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `amount`(): OfferAmount? { + return FfiConverterOptionalTypeOfferAmount.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_offer_amount( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `chains`(): List { + return FfiConverterSequenceTypeNetwork.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_offer_chains( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `expectsQuantity`(): kotlin.Boolean { + return FfiConverterBoolean.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_offer_expects_quantity( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `id`(): OfferId { + return FfiConverterTypeOfferId.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_offer_id( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `isExpired`(): kotlin.Boolean { + return FfiConverterBoolean.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_offer_is_expired( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `isValidQuantity`(`quantity`: kotlin.ULong): kotlin.Boolean { + return FfiConverterBoolean.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_offer_is_valid_quantity( + it, + FfiConverterULong.lower(`quantity`), + uniffiRustCallStatus, + ) + } + }) + } + + override fun `issuer`(): kotlin.String? { + return FfiConverterOptionalString.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_offer_issuer( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `issuerSigningPubkey`(): PublicKey? { + return FfiConverterOptionalTypePublicKey.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_offer_issuer_signing_pubkey( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `metadata`(): List? { + return FfiConverterOptionalSequenceUByte.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_offer_metadata( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `offerDescription`(): kotlin.String? { + return FfiConverterOptionalString.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_offer_offer_description( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `supportsChain`(`chain`: Network): kotlin.Boolean { + return FfiConverterBoolean.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_offer_supports_chain( + it, + FfiConverterTypeNetwork.lower(`chain`), + uniffiRustCallStatus, + ) + } + }) + } + + + + + override fun toString(): String { + return FfiConverterString.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_offer_uniffi_trait_display( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is Offer) return false + return FfiConverterBoolean.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_offer_uniffi_trait_eq_eq( + it, + FfiConverterTypeOffer.lower(`other`), + uniffiRustCallStatus, + ) + } + }) + } + + + + companion object { + + @Throws(NodeException::class) + fun `fromStr`(`offerStr`: kotlin.String): Offer { + return FfiConverterTypeOffer.lift(uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_constructor_offer_from_str( + FfiConverterString.lower(`offerStr`), + uniffiRustCallStatus, + ) + }!!) + } + + + } + +} + + + + + +object FfiConverterTypeOffer: FfiConverter { + + override fun lower(value: Offer): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): Offer { + return Offer(value) + } + + override fun read(buf: ByteBuffer): Offer { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: Offer) = 8UL + + override fun write(value: Offer, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + + + +open class OnchainPayment: Disposable, OnchainPaymentInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_onchainpayment(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_onchainpayment(pointer!!, status) + }!! + } + + + @Throws(NodeException::class) + override fun `accelerateByCpfp`(`txid`: Txid, `feeRate`: FeeRate?, `destinationAddress`: Address?): Txid { + return FfiConverterTypeTxid.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_accelerate_by_cpfp( + it, + FfiConverterTypeTxid.lower(`txid`), + FfiConverterOptionalTypeFeeRate.lower(`feeRate`), + FfiConverterOptionalTypeAddress.lower(`destinationAddress`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `addressInfoForAccountAtIndex`(`addressType`: AddressType, `accountIndex`: kotlin.UInt, `keychain`: KeychainKind, `index`: kotlin.UInt): AddressInfo { + return FfiConverterTypeAddressInfo.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_address_info_for_account_at_index( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterUInt.lower(`accountIndex`), + FfiConverterTypeKeychainKind.lower(`keychain`), + FfiConverterUInt.lower(`index`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `addressInfoForTypeAtIndex`(`addressType`: AddressType, `keychain`: KeychainKind, `index`: kotlin.UInt): AddressInfo { + return FfiConverterTypeAddressInfo.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_address_info_for_type_at_index( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterTypeKeychainKind.lower(`keychain`), + FfiConverterUInt.lower(`index`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `addressInfosForAccount`(`addressType`: AddressType, `accountIndex`: kotlin.UInt, `keychain`: KeychainKind, `startIndex`: kotlin.UInt, `count`: kotlin.UInt): List { + return FfiConverterSequenceTypeAddressInfo.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_address_infos_for_account( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterUInt.lower(`accountIndex`), + FfiConverterTypeKeychainKind.lower(`keychain`), + FfiConverterUInt.lower(`startIndex`), + FfiConverterUInt.lower(`count`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `addressInfosForType`(`addressType`: AddressType, `keychain`: KeychainKind, `startIndex`: kotlin.UInt, `count`: kotlin.UInt): List { + return FfiConverterSequenceTypeAddressInfo.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_address_infos_for_type( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterTypeKeychainKind.lower(`keychain`), + FfiConverterUInt.lower(`startIndex`), + FfiConverterUInt.lower(`count`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `bumpFeeByRbf`(`txid`: Txid, `feeRate`: FeeRate): Txid { + return FfiConverterTypeTxid.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_bump_fee_by_rbf( + it, + FfiConverterTypeTxid.lower(`txid`), + FfiConverterTypeFeeRate.lower(`feeRate`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `calculateCpfpFeeRate`(`parentTxid`: Txid, `urgent`: kotlin.Boolean): FeeRate { + return FfiConverterTypeFeeRate.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_calculate_cpfp_fee_rate( + it, + FfiConverterTypeTxid.lower(`parentTxid`), + FfiConverterBoolean.lower(`urgent`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `calculateSendAllFee`(`address`: Address, `retainReserves`: kotlin.Boolean, `feeRate`: FeeRate?): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_calculate_send_all_fee( + it, + FfiConverterTypeAddress.lower(`address`), + FfiConverterBoolean.lower(`retainReserves`), + FfiConverterOptionalTypeFeeRate.lower(`feeRate`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `calculateTotalFee`(`address`: Address, `amountSats`: kotlin.ULong, `feeRate`: FeeRate?, `utxosToSpend`: List?): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_calculate_total_fee( + it, + FfiConverterTypeAddress.lower(`address`), + FfiConverterULong.lower(`amountSats`), + FfiConverterOptionalTypeFeeRate.lower(`feeRate`), + FfiConverterOptionalSequenceTypeSpendableUtxo.lower(`utxosToSpend`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `listSpendableOutputs`(): List { + return FfiConverterSequenceTypeSpendableUtxo.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_list_spendable_outputs( + it, + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `newAddress`(): Address { + return FfiConverterTypeAddress.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_new_address( + it, + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `newAddressForAccount`(`addressType`: AddressType, `accountIndex`: kotlin.UInt): Address { + return FfiConverterTypeAddress.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_new_address_for_account( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterUInt.lower(`accountIndex`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `newAddressForType`(`addressType`: AddressType): Address { + return FfiConverterTypeAddress.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_new_address_for_type( + it, + FfiConverterTypeAddressType.lower(`addressType`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `newAddressInfo`(): AddressInfo { + return FfiConverterTypeAddressInfo.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_new_address_info( + it, + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `newAddressInfoForAccount`(`addressType`: AddressType, `accountIndex`: kotlin.UInt): AddressInfo { + return FfiConverterTypeAddressInfo.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_new_address_info_for_account( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterUInt.lower(`accountIndex`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `newAddressInfoForType`(`addressType`: AddressType): AddressInfo { + return FfiConverterTypeAddressInfo.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_new_address_info_for_type( + it, + FfiConverterTypeAddressType.lower(`addressType`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `revealReceiveAddressesTo`(`addressType`: AddressType, `index`: kotlin.UInt) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_reveal_receive_addresses_to( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterUInt.lower(`index`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `revealReceiveAddressesToAccount`(`addressType`: AddressType, `accountIndex`: kotlin.UInt, `index`: kotlin.UInt) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_reveal_receive_addresses_to_account( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterUInt.lower(`accountIndex`), + FfiConverterUInt.lower(`index`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `selectUtxosWithAlgorithm`(`targetAmountSats`: kotlin.ULong, `feeRate`: FeeRate?, `algorithm`: CoinSelectionAlgorithm, `utxos`: List?): List { + return FfiConverterSequenceTypeSpendableUtxo.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_select_utxos_with_algorithm( + it, + FfiConverterULong.lower(`targetAmountSats`), + FfiConverterOptionalTypeFeeRate.lower(`feeRate`), + FfiConverterTypeCoinSelectionAlgorithm.lower(`algorithm`), + FfiConverterOptionalSequenceTypeSpendableUtxo.lower(`utxos`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `sendAllToAddress`(`address`: Address, `retainReserve`: kotlin.Boolean, `feeRate`: FeeRate?): Txid { + return FfiConverterTypeTxid.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_send_all_to_address( + it, + FfiConverterTypeAddress.lower(`address`), + FfiConverterBoolean.lower(`retainReserve`), + FfiConverterOptionalTypeFeeRate.lower(`feeRate`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `sendToAddress`(`address`: Address, `amountSats`: kotlin.ULong, `feeRate`: FeeRate?, `utxosToSpend`: List?): Txid { + return FfiConverterTypeTxid.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_send_to_address( + it, + FfiConverterTypeAddress.lower(`address`), + FfiConverterULong.lower(`amountSats`), + FfiConverterOptionalTypeFeeRate.lower(`feeRate`), + FfiConverterOptionalSequenceTypeSpendableUtxo.lower(`utxosToSpend`), + uniffiRustCallStatus, + ) + } + }) + } + + + + + + + + companion object + +} + + + + + +object FfiConverterTypeOnchainPayment: FfiConverter { + + override fun lower(value: OnchainPayment): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): OnchainPayment { + return OnchainPayment(value) + } + + override fun read(buf: ByteBuffer): OnchainPayment { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: OnchainPayment) = 8UL + + override fun write(value: OnchainPayment, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + + + +open class Refund: Disposable, RefundInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_refund(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_refund(pointer!!, status) + }!! + } + + + override fun `absoluteExpirySeconds`(): kotlin.ULong? { + return FfiConverterOptionalULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_refund_absolute_expiry_seconds( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `amountMsats`(): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_refund_amount_msats( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `chain`(): Network? { + return FfiConverterOptionalTypeNetwork.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_refund_chain( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `isExpired`(): kotlin.Boolean { + return FfiConverterBoolean.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_refund_is_expired( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `issuer`(): kotlin.String? { + return FfiConverterOptionalString.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_refund_issuer( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `payerMetadata`(): List { + return FfiConverterSequenceUByte.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_refund_payer_metadata( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `payerNote`(): kotlin.String? { + return FfiConverterOptionalString.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_refund_payer_note( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `payerSigningPubkey`(): PublicKey { + return FfiConverterTypePublicKey.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_refund_payer_signing_pubkey( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `quantity`(): kotlin.ULong? { + return FfiConverterOptionalULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_refund_quantity( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `refundDescription`(): kotlin.String { + return FfiConverterString.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_refund_refund_description( + it, + uniffiRustCallStatus, + ) + } + }) + } + + + + + override fun toString(): String { + return FfiConverterString.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_refund_uniffi_trait_display( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is Refund) return false + return FfiConverterBoolean.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_refund_uniffi_trait_eq_eq( + it, + FfiConverterTypeRefund.lower(`other`), + uniffiRustCallStatus, + ) + } + }) + } + + + + companion object { + + @Throws(NodeException::class) + fun `fromStr`(`refundStr`: kotlin.String): Refund { + return FfiConverterTypeRefund.lift(uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_constructor_refund_from_str( + FfiConverterString.lower(`refundStr`), + uniffiRustCallStatus, + ) + }!!) + } + + + } + +} + + + + + +object FfiConverterTypeRefund: FfiConverter { + + override fun lower(value: Refund): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): Refund { + return Refund(value) + } + + override fun read(buf: ByteBuffer): Refund { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: Refund) = 8UL + + override fun write(value: Refund, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + + + +open class SpontaneousPayment: Disposable, SpontaneousPaymentInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_spontaneouspayment(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_spontaneouspayment(pointer!!, status) + }!! + } + + + @Throws(NodeException::class) + override fun `send`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey, `routeParameters`: RouteParametersConfig?): PaymentId { + return FfiConverterTypePaymentId.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_spontaneouspayment_send( + it, + FfiConverterULong.lower(`amountMsat`), + FfiConverterTypePublicKey.lower(`nodeId`), + FfiConverterOptionalTypeRouteParametersConfig.lower(`routeParameters`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `sendProbes`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey): List { + return FfiConverterSequenceTypeProbeHandle.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_spontaneouspayment_send_probes( + it, + FfiConverterULong.lower(`amountMsat`), + FfiConverterTypePublicKey.lower(`nodeId`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `sendWithCustomTlvs`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey, `routeParameters`: RouteParametersConfig?, `customTlvs`: List): PaymentId { + return FfiConverterTypePaymentId.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_spontaneouspayment_send_with_custom_tlvs( + it, + FfiConverterULong.lower(`amountMsat`), + FfiConverterTypePublicKey.lower(`nodeId`), + FfiConverterOptionalTypeRouteParametersConfig.lower(`routeParameters`), + FfiConverterSequenceTypeCustomTlvRecord.lower(`customTlvs`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `sendWithPreimage`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey, `preimage`: PaymentPreimage, `routeParameters`: RouteParametersConfig?): PaymentId { + return FfiConverterTypePaymentId.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_spontaneouspayment_send_with_preimage( + it, + FfiConverterULong.lower(`amountMsat`), + FfiConverterTypePublicKey.lower(`nodeId`), + FfiConverterTypePaymentPreimage.lower(`preimage`), + FfiConverterOptionalTypeRouteParametersConfig.lower(`routeParameters`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `sendWithPreimageAndCustomTlvs`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey, `customTlvs`: List, `preimage`: PaymentPreimage, `routeParameters`: RouteParametersConfig?): PaymentId { + return FfiConverterTypePaymentId.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_spontaneouspayment_send_with_preimage_and_custom_tlvs( + it, + FfiConverterULong.lower(`amountMsat`), + FfiConverterTypePublicKey.lower(`nodeId`), + FfiConverterSequenceTypeCustomTlvRecord.lower(`customTlvs`), + FfiConverterTypePaymentPreimage.lower(`preimage`), + FfiConverterOptionalTypeRouteParametersConfig.lower(`routeParameters`), + uniffiRustCallStatus, + ) + } + }) + } + + + + + + + + companion object + +} + + + + + +object FfiConverterTypeSpontaneousPayment: FfiConverter { + + override fun lower(value: SpontaneousPayment): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): SpontaneousPayment { + return SpontaneousPayment(value) + } + + override fun read(buf: ByteBuffer): SpontaneousPayment { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: SpontaneousPayment) = 8UL + + override fun write(value: SpontaneousPayment, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + + + +open class UnifiedQrPayment: Disposable, UnifiedQrPaymentInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_unifiedqrpayment(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_unifiedqrpayment(pointer!!, status) + }!! + } + + + @Throws(NodeException::class) + override fun `receive`(`amountSats`: kotlin.ULong, `message`: kotlin.String, `expirySec`: kotlin.UInt): kotlin.String { + return FfiConverterString.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_unifiedqrpayment_receive( + it, + FfiConverterULong.lower(`amountSats`), + FfiConverterString.lower(`message`), + FfiConverterUInt.lower(`expirySec`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `send`(`uriStr`: kotlin.String, `routeParameters`: RouteParametersConfig?): QrPaymentResult { + return FfiConverterTypeQrPaymentResult.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_unifiedqrpayment_send( + it, + FfiConverterString.lower(`uriStr`), + FfiConverterOptionalTypeRouteParametersConfig.lower(`routeParameters`), + uniffiRustCallStatus, + ) + } + }) + } + + + + + + + + companion object + +} + + + + + +object FfiConverterTypeUnifiedQrPayment: FfiConverter { + + override fun lower(value: UnifiedQrPayment): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): UnifiedQrPayment { + return UnifiedQrPayment(value) + } + + override fun read(buf: ByteBuffer): UnifiedQrPayment { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: UnifiedQrPayment) = 8UL + + override fun write(value: UnifiedQrPayment, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + + + +open class VssHeaderProvider: Disposable, VssHeaderProviderInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_vssheaderprovider(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_vssheaderprovider(pointer!!, status) + }!! + } + + + @Throws(VssHeaderProviderException::class, kotlin.coroutines.cancellation.CancellationException::class) + override suspend fun `getHeaders`(`request`: List): Map { + return uniffiRustCallAsync( + callWithPointer { thisPtr -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_vssheaderprovider_get_headers( + thisPtr, + FfiConverterSequenceUByte.lower(`request`), + ) + }, + { future, callback, continuation -> UniffiLib.INSTANCE.ffi_ldk_node_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.INSTANCE.ffi_ldk_node_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.INSTANCE.ffi_ldk_node_rust_future_free_rust_buffer(future) }, + { future -> UniffiLib.INSTANCE.ffi_ldk_node_rust_future_cancel_rust_buffer(future) }, + // lift function + { FfiConverterMapStringString.lift(it) }, + // Error FFI converter + VssHeaderProviderExceptionErrorHandler, + ) + } + + + + + + + + companion object + +} + + + + + +object FfiConverterTypeVssHeaderProvider: FfiConverter { + + override fun lower(value: VssHeaderProvider): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): VssHeaderProvider { + return VssHeaderProvider(value) + } + + override fun read(buf: ByteBuffer): VssHeaderProvider { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: VssHeaderProvider) = 8UL + + override fun write(value: VssHeaderProvider, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + + + + +object FfiConverterTypeAddressInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): AddressInfo { + return AddressInfo( + FfiConverterUInt.read(buf), + FfiConverterTypeAddress.read(buf), + FfiConverterTypeKeychainKind.read(buf), + ) + } + + override fun allocationSize(value: AddressInfo) = ( + FfiConverterUInt.allocationSize(value.`index`) + + FfiConverterTypeAddress.allocationSize(value.`address`) + + FfiConverterTypeKeychainKind.allocationSize(value.`keychain`) + ) + + override fun write(value: AddressInfo, buf: ByteBuffer) { + FfiConverterUInt.write(value.`index`, buf) + FfiConverterTypeAddress.write(value.`address`, buf) + FfiConverterTypeKeychainKind.write(value.`keychain`, buf) + } +} + + + + +object FfiConverterTypeAddressTypeBalance: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): AddressTypeBalance { + return AddressTypeBalance( + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + ) + } + + override fun allocationSize(value: AddressTypeBalance) = ( + FfiConverterULong.allocationSize(value.`totalSats`) + + FfiConverterULong.allocationSize(value.`spendableSats`) + ) + + override fun write(value: AddressTypeBalance, buf: ByteBuffer) { + FfiConverterULong.write(value.`totalSats`, buf) + FfiConverterULong.write(value.`spendableSats`, buf) + } +} + + + + +object FfiConverterTypeAnchorChannelsConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): AnchorChannelsConfig { + return AnchorChannelsConfig( + FfiConverterSequenceTypePublicKey.read(buf), + FfiConverterULong.read(buf), + ) + } + + override fun allocationSize(value: AnchorChannelsConfig) = ( + FfiConverterSequenceTypePublicKey.allocationSize(value.`trustedPeersNoReserve`) + + FfiConverterULong.allocationSize(value.`perChannelReserveSats`) + ) + + override fun write(value: AnchorChannelsConfig, buf: ByteBuffer) { + FfiConverterSequenceTypePublicKey.write(value.`trustedPeersNoReserve`, buf) + FfiConverterULong.write(value.`perChannelReserveSats`, buf) + } +} + + + + +object FfiConverterTypeBackgroundSyncConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): BackgroundSyncConfig { + return BackgroundSyncConfig( + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + ) + } + + override fun allocationSize(value: BackgroundSyncConfig) = ( + FfiConverterULong.allocationSize(value.`onchainWalletSyncIntervalSecs`) + + FfiConverterULong.allocationSize(value.`lightningWalletSyncIntervalSecs`) + + FfiConverterULong.allocationSize(value.`feeRateCacheUpdateIntervalSecs`) + ) + + override fun write(value: BackgroundSyncConfig, buf: ByteBuffer) { + FfiConverterULong.write(value.`onchainWalletSyncIntervalSecs`, buf) + FfiConverterULong.write(value.`lightningWalletSyncIntervalSecs`, buf) + FfiConverterULong.write(value.`feeRateCacheUpdateIntervalSecs`, buf) + } +} + + + + +object FfiConverterTypeBalanceDetails: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): BalanceDetails { + return BalanceDetails( + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterSequenceTypeLightningBalance.read(buf), + FfiConverterSequenceTypePendingSweepBalance.read(buf), + ) + } + + override fun allocationSize(value: BalanceDetails) = ( + FfiConverterULong.allocationSize(value.`totalOnchainBalanceSats`) + + FfiConverterULong.allocationSize(value.`spendableOnchainBalanceSats`) + + FfiConverterULong.allocationSize(value.`totalAnchorChannelsReserveSats`) + + FfiConverterULong.allocationSize(value.`totalLightningBalanceSats`) + + FfiConverterSequenceTypeLightningBalance.allocationSize(value.`lightningBalances`) + + FfiConverterSequenceTypePendingSweepBalance.allocationSize(value.`pendingBalancesFromChannelClosures`) + ) + + override fun write(value: BalanceDetails, buf: ByteBuffer) { + FfiConverterULong.write(value.`totalOnchainBalanceSats`, buf) + FfiConverterULong.write(value.`spendableOnchainBalanceSats`, buf) + FfiConverterULong.write(value.`totalAnchorChannelsReserveSats`, buf) + FfiConverterULong.write(value.`totalLightningBalanceSats`, buf) + FfiConverterSequenceTypeLightningBalance.write(value.`lightningBalances`, buf) + FfiConverterSequenceTypePendingSweepBalance.write(value.`pendingBalancesFromChannelClosures`, buf) + } +} + + + + +object FfiConverterTypeBestBlock: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): BestBlock { + return BestBlock( + FfiConverterTypeBlockHash.read(buf), + FfiConverterUInt.read(buf), + ) + } + + override fun allocationSize(value: BestBlock) = ( + FfiConverterTypeBlockHash.allocationSize(value.`blockHash`) + + FfiConverterUInt.allocationSize(value.`height`) + ) + + override fun write(value: BestBlock, buf: ByteBuffer) { + FfiConverterTypeBlockHash.write(value.`blockHash`, buf) + FfiConverterUInt.write(value.`height`, buf) + } +} + + + + +object FfiConverterTypeChannelConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ChannelConfig { + return ChannelConfig( + FfiConverterUInt.read(buf), + FfiConverterUInt.read(buf), + FfiConverterUShort.read(buf), + FfiConverterTypeMaxDustHTLCExposure.read(buf), + FfiConverterULong.read(buf), + FfiConverterBoolean.read(buf), + ) + } + + override fun allocationSize(value: ChannelConfig) = ( + FfiConverterUInt.allocationSize(value.`forwardingFeeProportionalMillionths`) + + FfiConverterUInt.allocationSize(value.`forwardingFeeBaseMsat`) + + FfiConverterUShort.allocationSize(value.`cltvExpiryDelta`) + + FfiConverterTypeMaxDustHTLCExposure.allocationSize(value.`maxDustHtlcExposure`) + + FfiConverterULong.allocationSize(value.`forceCloseAvoidanceMaxFeeSatoshis`) + + FfiConverterBoolean.allocationSize(value.`acceptUnderpayingHtlcs`) + ) + + override fun write(value: ChannelConfig, buf: ByteBuffer) { + FfiConverterUInt.write(value.`forwardingFeeProportionalMillionths`, buf) + FfiConverterUInt.write(value.`forwardingFeeBaseMsat`, buf) + FfiConverterUShort.write(value.`cltvExpiryDelta`, buf) + FfiConverterTypeMaxDustHTLCExposure.write(value.`maxDustHtlcExposure`, buf) + FfiConverterULong.write(value.`forceCloseAvoidanceMaxFeeSatoshis`, buf) + FfiConverterBoolean.write(value.`acceptUnderpayingHtlcs`, buf) + } +} + + + + +object FfiConverterTypeChannelDataMigration: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ChannelDataMigration { + return ChannelDataMigration( + FfiConverterOptionalSequenceUByte.read(buf), + FfiConverterSequenceSequenceUByte.read(buf), + ) + } + + override fun allocationSize(value: ChannelDataMigration) = ( + FfiConverterOptionalSequenceUByte.allocationSize(value.`channelManager`) + + FfiConverterSequenceSequenceUByte.allocationSize(value.`channelMonitors`) + ) + + override fun write(value: ChannelDataMigration, buf: ByteBuffer) { + FfiConverterOptionalSequenceUByte.write(value.`channelManager`, buf) + FfiConverterSequenceSequenceUByte.write(value.`channelMonitors`, buf) + } +} + + + + +object FfiConverterTypeChannelDetails: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ChannelDetails { + return ChannelDetails( + FfiConverterTypeChannelId.read(buf), + FfiConverterTypePublicKey.read(buf), + FfiConverterOptionalTypeOutPoint.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterTypeUserChannelId.read(buf), + FfiConverterUInt.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterOptionalUInt.read(buf), + FfiConverterOptionalUInt.read(buf), + FfiConverterBoolean.read(buf), + FfiConverterBoolean.read(buf), + FfiConverterBoolean.read(buf), + FfiConverterBoolean.read(buf), + FfiConverterOptionalUShort.read(buf), + FfiConverterULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalUInt.read(buf), + FfiConverterOptionalUInt.read(buf), + FfiConverterOptionalUShort.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterOptionalUShort.read(buf), + FfiConverterULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterTypeChannelConfig.read(buf), + FfiConverterOptionalULong.read(buf), + ) + } + + override fun allocationSize(value: ChannelDetails) = ( + FfiConverterTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterTypePublicKey.allocationSize(value.`counterpartyNodeId`) + + FfiConverterOptionalTypeOutPoint.allocationSize(value.`fundingTxo`) + + FfiConverterOptionalULong.allocationSize(value.`shortChannelId`) + + FfiConverterOptionalULong.allocationSize(value.`outboundScidAlias`) + + FfiConverterOptionalULong.allocationSize(value.`inboundScidAlias`) + + FfiConverterULong.allocationSize(value.`channelValueSats`) + + FfiConverterOptionalULong.allocationSize(value.`unspendablePunishmentReserve`) + + FfiConverterTypeUserChannelId.allocationSize(value.`userChannelId`) + + FfiConverterUInt.allocationSize(value.`feerateSatPer1000Weight`) + + FfiConverterULong.allocationSize(value.`outboundCapacityMsat`) + + FfiConverterULong.allocationSize(value.`inboundCapacityMsat`) + + FfiConverterOptionalUInt.allocationSize(value.`confirmationsRequired`) + + FfiConverterOptionalUInt.allocationSize(value.`confirmations`) + + FfiConverterBoolean.allocationSize(value.`isOutbound`) + + FfiConverterBoolean.allocationSize(value.`isChannelReady`) + + FfiConverterBoolean.allocationSize(value.`isUsable`) + + FfiConverterBoolean.allocationSize(value.`isAnnounced`) + + FfiConverterOptionalUShort.allocationSize(value.`cltvExpiryDelta`) + + FfiConverterULong.allocationSize(value.`counterpartyUnspendablePunishmentReserve`) + + FfiConverterOptionalULong.allocationSize(value.`counterpartyOutboundHtlcMinimumMsat`) + + FfiConverterOptionalULong.allocationSize(value.`counterpartyOutboundHtlcMaximumMsat`) + + FfiConverterOptionalUInt.allocationSize(value.`counterpartyForwardingInfoFeeBaseMsat`) + + FfiConverterOptionalUInt.allocationSize(value.`counterpartyForwardingInfoFeeProportionalMillionths`) + + FfiConverterOptionalUShort.allocationSize(value.`counterpartyForwardingInfoCltvExpiryDelta`) + + FfiConverterULong.allocationSize(value.`nextOutboundHtlcLimitMsat`) + + FfiConverterULong.allocationSize(value.`nextOutboundHtlcMinimumMsat`) + + FfiConverterOptionalUShort.allocationSize(value.`forceCloseSpendDelay`) + + FfiConverterULong.allocationSize(value.`inboundHtlcMinimumMsat`) + + FfiConverterOptionalULong.allocationSize(value.`inboundHtlcMaximumMsat`) + + FfiConverterTypeChannelConfig.allocationSize(value.`config`) + + FfiConverterOptionalULong.allocationSize(value.`claimableOnCloseSats`) + ) + + override fun write(value: ChannelDetails, buf: ByteBuffer) { + FfiConverterTypeChannelId.write(value.`channelId`, buf) + FfiConverterTypePublicKey.write(value.`counterpartyNodeId`, buf) + FfiConverterOptionalTypeOutPoint.write(value.`fundingTxo`, buf) + FfiConverterOptionalULong.write(value.`shortChannelId`, buf) + FfiConverterOptionalULong.write(value.`outboundScidAlias`, buf) + FfiConverterOptionalULong.write(value.`inboundScidAlias`, buf) + FfiConverterULong.write(value.`channelValueSats`, buf) + FfiConverterOptionalULong.write(value.`unspendablePunishmentReserve`, buf) + FfiConverterTypeUserChannelId.write(value.`userChannelId`, buf) + FfiConverterUInt.write(value.`feerateSatPer1000Weight`, buf) + FfiConverterULong.write(value.`outboundCapacityMsat`, buf) + FfiConverterULong.write(value.`inboundCapacityMsat`, buf) + FfiConverterOptionalUInt.write(value.`confirmationsRequired`, buf) + FfiConverterOptionalUInt.write(value.`confirmations`, buf) + FfiConverterBoolean.write(value.`isOutbound`, buf) + FfiConverterBoolean.write(value.`isChannelReady`, buf) + FfiConverterBoolean.write(value.`isUsable`, buf) + FfiConverterBoolean.write(value.`isAnnounced`, buf) + FfiConverterOptionalUShort.write(value.`cltvExpiryDelta`, buf) + FfiConverterULong.write(value.`counterpartyUnspendablePunishmentReserve`, buf) + FfiConverterOptionalULong.write(value.`counterpartyOutboundHtlcMinimumMsat`, buf) + FfiConverterOptionalULong.write(value.`counterpartyOutboundHtlcMaximumMsat`, buf) + FfiConverterOptionalUInt.write(value.`counterpartyForwardingInfoFeeBaseMsat`, buf) + FfiConverterOptionalUInt.write(value.`counterpartyForwardingInfoFeeProportionalMillionths`, buf) + FfiConverterOptionalUShort.write(value.`counterpartyForwardingInfoCltvExpiryDelta`, buf) + FfiConverterULong.write(value.`nextOutboundHtlcLimitMsat`, buf) + FfiConverterULong.write(value.`nextOutboundHtlcMinimumMsat`, buf) + FfiConverterOptionalUShort.write(value.`forceCloseSpendDelay`, buf) + FfiConverterULong.write(value.`inboundHtlcMinimumMsat`, buf) + FfiConverterOptionalULong.write(value.`inboundHtlcMaximumMsat`, buf) + FfiConverterTypeChannelConfig.write(value.`config`, buf) + FfiConverterOptionalULong.write(value.`claimableOnCloseSats`, buf) + } +} + + + + +object FfiConverterTypeChannelInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ChannelInfo { + return ChannelInfo( + FfiConverterTypeNodeId.read(buf), + FfiConverterOptionalTypeChannelUpdateInfo.read(buf), + FfiConverterTypeNodeId.read(buf), + FfiConverterOptionalTypeChannelUpdateInfo.read(buf), + FfiConverterOptionalULong.read(buf), + ) + } + + override fun allocationSize(value: ChannelInfo) = ( + FfiConverterTypeNodeId.allocationSize(value.`nodeOne`) + + FfiConverterOptionalTypeChannelUpdateInfo.allocationSize(value.`oneToTwo`) + + FfiConverterTypeNodeId.allocationSize(value.`nodeTwo`) + + FfiConverterOptionalTypeChannelUpdateInfo.allocationSize(value.`twoToOne`) + + FfiConverterOptionalULong.allocationSize(value.`capacitySats`) + ) + + override fun write(value: ChannelInfo, buf: ByteBuffer) { + FfiConverterTypeNodeId.write(value.`nodeOne`, buf) + FfiConverterOptionalTypeChannelUpdateInfo.write(value.`oneToTwo`, buf) + FfiConverterTypeNodeId.write(value.`nodeTwo`, buf) + FfiConverterOptionalTypeChannelUpdateInfo.write(value.`twoToOne`, buf) + FfiConverterOptionalULong.write(value.`capacitySats`, buf) + } +} + + + + +object FfiConverterTypeChannelUpdateInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ChannelUpdateInfo { + return ChannelUpdateInfo( + FfiConverterUInt.read(buf), + FfiConverterBoolean.read(buf), + FfiConverterUShort.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterTypeRoutingFees.read(buf), + ) + } + + override fun allocationSize(value: ChannelUpdateInfo) = ( + FfiConverterUInt.allocationSize(value.`lastUpdate`) + + FfiConverterBoolean.allocationSize(value.`enabled`) + + FfiConverterUShort.allocationSize(value.`cltvExpiryDelta`) + + FfiConverterULong.allocationSize(value.`htlcMinimumMsat`) + + FfiConverterULong.allocationSize(value.`htlcMaximumMsat`) + + FfiConverterTypeRoutingFees.allocationSize(value.`fees`) + ) + + override fun write(value: ChannelUpdateInfo, buf: ByteBuffer) { + FfiConverterUInt.write(value.`lastUpdate`, buf) + FfiConverterBoolean.write(value.`enabled`, buf) + FfiConverterUShort.write(value.`cltvExpiryDelta`, buf) + FfiConverterULong.write(value.`htlcMinimumMsat`, buf) + FfiConverterULong.write(value.`htlcMaximumMsat`, buf) + FfiConverterTypeRoutingFees.write(value.`fees`, buf) + } +} + + + + +object FfiConverterTypeConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Config { + return Config( + FfiConverterString.read(buf), + FfiConverterTypeNetwork.read(buf), + FfiConverterOptionalSequenceTypeSocketAddress.read(buf), + FfiConverterOptionalSequenceTypeSocketAddress.read(buf), + FfiConverterOptionalTypeNodeAlias.read(buf), + FfiConverterSequenceTypePublicKey.read(buf), + FfiConverterULong.read(buf), + FfiConverterOptionalTypeAnchorChannelsConfig.read(buf), + FfiConverterOptionalTypeRouteParametersConfig.read(buf), + FfiConverterOptionalTypeScoringFeeParameters.read(buf), + FfiConverterOptionalTypeScoringDecayParameters.read(buf), + FfiConverterBoolean.read(buf), + FfiConverterTypeAddressType.read(buf), + FfiConverterSequenceTypeAddressType.read(buf), + FfiConverterSequenceTypeOnchainWalletAccountConfig.read(buf), + ) + } + + override fun allocationSize(value: Config) = ( + FfiConverterString.allocationSize(value.`storageDirPath`) + + FfiConverterTypeNetwork.allocationSize(value.`network`) + + FfiConverterOptionalSequenceTypeSocketAddress.allocationSize(value.`listeningAddresses`) + + FfiConverterOptionalSequenceTypeSocketAddress.allocationSize(value.`announcementAddresses`) + + FfiConverterOptionalTypeNodeAlias.allocationSize(value.`nodeAlias`) + + FfiConverterSequenceTypePublicKey.allocationSize(value.`trustedPeers0conf`) + + FfiConverterULong.allocationSize(value.`probingLiquidityLimitMultiplier`) + + FfiConverterOptionalTypeAnchorChannelsConfig.allocationSize(value.`anchorChannelsConfig`) + + FfiConverterOptionalTypeRouteParametersConfig.allocationSize(value.`routeParameters`) + + FfiConverterOptionalTypeScoringFeeParameters.allocationSize(value.`scoringFeeParams`) + + FfiConverterOptionalTypeScoringDecayParameters.allocationSize(value.`scoringDecayParams`) + + FfiConverterBoolean.allocationSize(value.`includeUntrustedPendingInSpendable`) + + FfiConverterTypeAddressType.allocationSize(value.`addressType`) + + FfiConverterSequenceTypeAddressType.allocationSize(value.`addressTypesToMonitor`) + + FfiConverterSequenceTypeOnchainWalletAccountConfig.allocationSize(value.`onchainWalletAccounts`) + ) + + override fun write(value: Config, buf: ByteBuffer) { + FfiConverterString.write(value.`storageDirPath`, buf) + FfiConverterTypeNetwork.write(value.`network`, buf) + FfiConverterOptionalSequenceTypeSocketAddress.write(value.`listeningAddresses`, buf) + FfiConverterOptionalSequenceTypeSocketAddress.write(value.`announcementAddresses`, buf) + FfiConverterOptionalTypeNodeAlias.write(value.`nodeAlias`, buf) + FfiConverterSequenceTypePublicKey.write(value.`trustedPeers0conf`, buf) + FfiConverterULong.write(value.`probingLiquidityLimitMultiplier`, buf) + FfiConverterOptionalTypeAnchorChannelsConfig.write(value.`anchorChannelsConfig`, buf) + FfiConverterOptionalTypeRouteParametersConfig.write(value.`routeParameters`, buf) + FfiConverterOptionalTypeScoringFeeParameters.write(value.`scoringFeeParams`, buf) + FfiConverterOptionalTypeScoringDecayParameters.write(value.`scoringDecayParams`, buf) + FfiConverterBoolean.write(value.`includeUntrustedPendingInSpendable`, buf) + FfiConverterTypeAddressType.write(value.`addressType`, buf) + FfiConverterSequenceTypeAddressType.write(value.`addressTypesToMonitor`, buf) + FfiConverterSequenceTypeOnchainWalletAccountConfig.write(value.`onchainWalletAccounts`, buf) + } +} + + + + +object FfiConverterTypeCustomTlvRecord: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): CustomTlvRecord { + return CustomTlvRecord( + FfiConverterULong.read(buf), + FfiConverterSequenceUByte.read(buf), + ) + } + + override fun allocationSize(value: CustomTlvRecord) = ( + FfiConverterULong.allocationSize(value.`typeNum`) + + FfiConverterSequenceUByte.allocationSize(value.`value`) + ) + + override fun write(value: CustomTlvRecord, buf: ByteBuffer) { + FfiConverterULong.write(value.`typeNum`, buf) + FfiConverterSequenceUByte.write(value.`value`, buf) + } +} + + + + +object FfiConverterTypeElectrumSyncConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ElectrumSyncConfig { + return ElectrumSyncConfig( + FfiConverterOptionalTypeBackgroundSyncConfig.read(buf), + FfiConverterULong.read(buf), + FfiConverterUInt.read(buf), + FfiConverterUInt.read(buf), + ) + } + + override fun allocationSize(value: ElectrumSyncConfig) = ( + FfiConverterOptionalTypeBackgroundSyncConfig.allocationSize(value.`backgroundSyncConfig`) + + FfiConverterULong.allocationSize(value.`connectionTimeoutSecs`) + + FfiConverterUInt.allocationSize(value.`additionalWalletFullScanBatchSize`) + + FfiConverterUInt.allocationSize(value.`additionalWalletFullScanStopGap`) + ) + + override fun write(value: ElectrumSyncConfig, buf: ByteBuffer) { + FfiConverterOptionalTypeBackgroundSyncConfig.write(value.`backgroundSyncConfig`, buf) + FfiConverterULong.write(value.`connectionTimeoutSecs`, buf) + FfiConverterUInt.write(value.`additionalWalletFullScanBatchSize`, buf) + FfiConverterUInt.write(value.`additionalWalletFullScanStopGap`, buf) + } +} + + + + +object FfiConverterTypeEsploraSyncConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): EsploraSyncConfig { + return EsploraSyncConfig( + FfiConverterOptionalTypeBackgroundSyncConfig.read(buf), + ) + } + + override fun allocationSize(value: EsploraSyncConfig) = ( + FfiConverterOptionalTypeBackgroundSyncConfig.allocationSize(value.`backgroundSyncConfig`) + ) + + override fun write(value: EsploraSyncConfig, buf: ByteBuffer) { + FfiConverterOptionalTypeBackgroundSyncConfig.write(value.`backgroundSyncConfig`, buf) + } +} + + + + +object FfiConverterTypeLSPFeeLimits: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): LspFeeLimits { + return LspFeeLimits( + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalULong.read(buf), + ) + } + + override fun allocationSize(value: LspFeeLimits) = ( + FfiConverterOptionalULong.allocationSize(value.`maxTotalOpeningFeeMsat`) + + FfiConverterOptionalULong.allocationSize(value.`maxProportionalOpeningFeePpmMsat`) + ) + + override fun write(value: LspFeeLimits, buf: ByteBuffer) { + FfiConverterOptionalULong.write(value.`maxTotalOpeningFeeMsat`, buf) + FfiConverterOptionalULong.write(value.`maxProportionalOpeningFeePpmMsat`, buf) + } +} + + + + +object FfiConverterTypeLSPS1Bolt11PaymentInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Lsps1Bolt11PaymentInfo { + return Lsps1Bolt11PaymentInfo( + FfiConverterTypeLSPS1PaymentState.read(buf), + FfiConverterTypeLSPSDateTime.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterTypeBolt11Invoice.read(buf), + ) + } + + override fun allocationSize(value: Lsps1Bolt11PaymentInfo) = ( + FfiConverterTypeLSPS1PaymentState.allocationSize(value.`state`) + + FfiConverterTypeLSPSDateTime.allocationSize(value.`expiresAt`) + + FfiConverterULong.allocationSize(value.`feeTotalSat`) + + FfiConverterULong.allocationSize(value.`orderTotalSat`) + + FfiConverterTypeBolt11Invoice.allocationSize(value.`invoice`) + ) + + override fun write(value: Lsps1Bolt11PaymentInfo, buf: ByteBuffer) { + FfiConverterTypeLSPS1PaymentState.write(value.`state`, buf) + FfiConverterTypeLSPSDateTime.write(value.`expiresAt`, buf) + FfiConverterULong.write(value.`feeTotalSat`, buf) + FfiConverterULong.write(value.`orderTotalSat`, buf) + FfiConverterTypeBolt11Invoice.write(value.`invoice`, buf) + } +} + + + + +object FfiConverterTypeLSPS1ChannelInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Lsps1ChannelInfo { + return Lsps1ChannelInfo( + FfiConverterTypeLSPSDateTime.read(buf), + FfiConverterTypeOutPoint.read(buf), + FfiConverterTypeLSPSDateTime.read(buf), + ) + } + + override fun allocationSize(value: Lsps1ChannelInfo) = ( + FfiConverterTypeLSPSDateTime.allocationSize(value.`fundedAt`) + + FfiConverterTypeOutPoint.allocationSize(value.`fundingOutpoint`) + + FfiConverterTypeLSPSDateTime.allocationSize(value.`expiresAt`) + ) + + override fun write(value: Lsps1ChannelInfo, buf: ByteBuffer) { + FfiConverterTypeLSPSDateTime.write(value.`fundedAt`, buf) + FfiConverterTypeOutPoint.write(value.`fundingOutpoint`, buf) + FfiConverterTypeLSPSDateTime.write(value.`expiresAt`, buf) + } +} + + + + +object FfiConverterTypeLSPS1OnchainPaymentInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Lsps1OnchainPaymentInfo { + return Lsps1OnchainPaymentInfo( + FfiConverterTypeLSPS1PaymentState.read(buf), + FfiConverterTypeLSPSDateTime.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterTypeAddress.read(buf), + FfiConverterOptionalUShort.read(buf), + FfiConverterTypeFeeRate.read(buf), + FfiConverterOptionalTypeAddress.read(buf), + ) + } + + override fun allocationSize(value: Lsps1OnchainPaymentInfo) = ( + FfiConverterTypeLSPS1PaymentState.allocationSize(value.`state`) + + FfiConverterTypeLSPSDateTime.allocationSize(value.`expiresAt`) + + FfiConverterULong.allocationSize(value.`feeTotalSat`) + + FfiConverterULong.allocationSize(value.`orderTotalSat`) + + FfiConverterTypeAddress.allocationSize(value.`address`) + + FfiConverterOptionalUShort.allocationSize(value.`minOnchainPaymentConfirmations`) + + FfiConverterTypeFeeRate.allocationSize(value.`minFeeFor0conf`) + + FfiConverterOptionalTypeAddress.allocationSize(value.`refundOnchainAddress`) + ) + + override fun write(value: Lsps1OnchainPaymentInfo, buf: ByteBuffer) { + FfiConverterTypeLSPS1PaymentState.write(value.`state`, buf) + FfiConverterTypeLSPSDateTime.write(value.`expiresAt`, buf) + FfiConverterULong.write(value.`feeTotalSat`, buf) + FfiConverterULong.write(value.`orderTotalSat`, buf) + FfiConverterTypeAddress.write(value.`address`, buf) + FfiConverterOptionalUShort.write(value.`minOnchainPaymentConfirmations`, buf) + FfiConverterTypeFeeRate.write(value.`minFeeFor0conf`, buf) + FfiConverterOptionalTypeAddress.write(value.`refundOnchainAddress`, buf) + } +} + + + + +object FfiConverterTypeLSPS1OrderParams: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Lsps1OrderParams { + return Lsps1OrderParams( + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterUShort.read(buf), + FfiConverterUShort.read(buf), + FfiConverterUInt.read(buf), + FfiConverterOptionalString.read(buf), + FfiConverterBoolean.read(buf), + ) + } + + override fun allocationSize(value: Lsps1OrderParams) = ( + FfiConverterULong.allocationSize(value.`lspBalanceSat`) + + FfiConverterULong.allocationSize(value.`clientBalanceSat`) + + FfiConverterUShort.allocationSize(value.`requiredChannelConfirmations`) + + FfiConverterUShort.allocationSize(value.`fundingConfirmsWithinBlocks`) + + FfiConverterUInt.allocationSize(value.`channelExpiryBlocks`) + + FfiConverterOptionalString.allocationSize(value.`token`) + + FfiConverterBoolean.allocationSize(value.`announceChannel`) + ) + + override fun write(value: Lsps1OrderParams, buf: ByteBuffer) { + FfiConverterULong.write(value.`lspBalanceSat`, buf) + FfiConverterULong.write(value.`clientBalanceSat`, buf) + FfiConverterUShort.write(value.`requiredChannelConfirmations`, buf) + FfiConverterUShort.write(value.`fundingConfirmsWithinBlocks`, buf) + FfiConverterUInt.write(value.`channelExpiryBlocks`, buf) + FfiConverterOptionalString.write(value.`token`, buf) + FfiConverterBoolean.write(value.`announceChannel`, buf) + } +} + + + + +object FfiConverterTypeLSPS1OrderStatus: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Lsps1OrderStatus { + return Lsps1OrderStatus( + FfiConverterTypeLSPS1OrderId.read(buf), + FfiConverterTypeLSPS1OrderParams.read(buf), + FfiConverterTypeLSPS1PaymentInfo.read(buf), + FfiConverterOptionalTypeLSPS1ChannelInfo.read(buf), + ) + } + + override fun allocationSize(value: Lsps1OrderStatus) = ( + FfiConverterTypeLSPS1OrderId.allocationSize(value.`orderId`) + + FfiConverterTypeLSPS1OrderParams.allocationSize(value.`orderParams`) + + FfiConverterTypeLSPS1PaymentInfo.allocationSize(value.`paymentOptions`) + + FfiConverterOptionalTypeLSPS1ChannelInfo.allocationSize(value.`channelState`) + ) + + override fun write(value: Lsps1OrderStatus, buf: ByteBuffer) { + FfiConverterTypeLSPS1OrderId.write(value.`orderId`, buf) + FfiConverterTypeLSPS1OrderParams.write(value.`orderParams`, buf) + FfiConverterTypeLSPS1PaymentInfo.write(value.`paymentOptions`, buf) + FfiConverterOptionalTypeLSPS1ChannelInfo.write(value.`channelState`, buf) + } +} + + + + +object FfiConverterTypeLSPS1PaymentInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Lsps1PaymentInfo { + return Lsps1PaymentInfo( + FfiConverterOptionalTypeLSPS1Bolt11PaymentInfo.read(buf), + FfiConverterOptionalTypeLSPS1OnchainPaymentInfo.read(buf), + ) + } + + override fun allocationSize(value: Lsps1PaymentInfo) = ( + FfiConverterOptionalTypeLSPS1Bolt11PaymentInfo.allocationSize(value.`bolt11`) + + FfiConverterOptionalTypeLSPS1OnchainPaymentInfo.allocationSize(value.`onchain`) + ) + + override fun write(value: Lsps1PaymentInfo, buf: ByteBuffer) { + FfiConverterOptionalTypeLSPS1Bolt11PaymentInfo.write(value.`bolt11`, buf) + FfiConverterOptionalTypeLSPS1OnchainPaymentInfo.write(value.`onchain`, buf) + } +} + + + + +object FfiConverterTypeLSPS2ServiceConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Lsps2ServiceConfig { + return Lsps2ServiceConfig( + FfiConverterOptionalString.read(buf), + FfiConverterBoolean.read(buf), + FfiConverterUInt.read(buf), + FfiConverterUInt.read(buf), + FfiConverterULong.read(buf), + FfiConverterUInt.read(buf), + FfiConverterUInt.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterBoolean.read(buf), + ) + } + + override fun allocationSize(value: Lsps2ServiceConfig) = ( + FfiConverterOptionalString.allocationSize(value.`requireToken`) + + FfiConverterBoolean.allocationSize(value.`advertiseService`) + + FfiConverterUInt.allocationSize(value.`channelOpeningFeePpm`) + + FfiConverterUInt.allocationSize(value.`channelOverProvisioningPpm`) + + FfiConverterULong.allocationSize(value.`minChannelOpeningFeeMsat`) + + FfiConverterUInt.allocationSize(value.`minChannelLifetime`) + + FfiConverterUInt.allocationSize(value.`maxClientToSelfDelay`) + + FfiConverterULong.allocationSize(value.`minPaymentSizeMsat`) + + FfiConverterULong.allocationSize(value.`maxPaymentSizeMsat`) + + FfiConverterBoolean.allocationSize(value.`clientTrustsLsp`) + ) + + override fun write(value: Lsps2ServiceConfig, buf: ByteBuffer) { + FfiConverterOptionalString.write(value.`requireToken`, buf) + FfiConverterBoolean.write(value.`advertiseService`, buf) + FfiConverterUInt.write(value.`channelOpeningFeePpm`, buf) + FfiConverterUInt.write(value.`channelOverProvisioningPpm`, buf) + FfiConverterULong.write(value.`minChannelOpeningFeeMsat`, buf) + FfiConverterUInt.write(value.`minChannelLifetime`, buf) + FfiConverterUInt.write(value.`maxClientToSelfDelay`, buf) + FfiConverterULong.write(value.`minPaymentSizeMsat`, buf) + FfiConverterULong.write(value.`maxPaymentSizeMsat`, buf) + FfiConverterBoolean.write(value.`clientTrustsLsp`, buf) + } +} + + + + +object FfiConverterTypeLogRecord: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): LogRecord { + return LogRecord( + FfiConverterTypeLogLevel.read(buf), + FfiConverterString.read(buf), + FfiConverterString.read(buf), + FfiConverterUInt.read(buf), + ) + } + + override fun allocationSize(value: LogRecord) = ( + FfiConverterTypeLogLevel.allocationSize(value.`level`) + + FfiConverterString.allocationSize(value.`args`) + + FfiConverterString.allocationSize(value.`modulePath`) + + FfiConverterUInt.allocationSize(value.`line`) + ) + + override fun write(value: LogRecord, buf: ByteBuffer) { + FfiConverterTypeLogLevel.write(value.`level`, buf) + FfiConverterString.write(value.`args`, buf) + FfiConverterString.write(value.`modulePath`, buf) + FfiConverterUInt.write(value.`line`, buf) + } +} + + + + +object FfiConverterTypeNodeAnnouncementInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): NodeAnnouncementInfo { + return NodeAnnouncementInfo( + FfiConverterUInt.read(buf), + FfiConverterString.read(buf), + FfiConverterSequenceTypeSocketAddress.read(buf), + ) + } + + override fun allocationSize(value: NodeAnnouncementInfo) = ( + FfiConverterUInt.allocationSize(value.`lastUpdate`) + + FfiConverterString.allocationSize(value.`alias`) + + FfiConverterSequenceTypeSocketAddress.allocationSize(value.`addresses`) + ) + + override fun write(value: NodeAnnouncementInfo, buf: ByteBuffer) { + FfiConverterUInt.write(value.`lastUpdate`, buf) + FfiConverterString.write(value.`alias`, buf) + FfiConverterSequenceTypeSocketAddress.write(value.`addresses`, buf) + } +} + + + + +object FfiConverterTypeNodeInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): NodeInfo { + return NodeInfo( + FfiConverterSequenceULong.read(buf), + FfiConverterOptionalTypeNodeAnnouncementInfo.read(buf), + ) + } + + override fun allocationSize(value: NodeInfo) = ( + FfiConverterSequenceULong.allocationSize(value.`channels`) + + FfiConverterOptionalTypeNodeAnnouncementInfo.allocationSize(value.`announcementInfo`) + ) + + override fun write(value: NodeInfo, buf: ByteBuffer) { + FfiConverterSequenceULong.write(value.`channels`, buf) + FfiConverterOptionalTypeNodeAnnouncementInfo.write(value.`announcementInfo`, buf) + } +} + + + + +object FfiConverterTypeNodeStatus: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): NodeStatus { + return NodeStatus( + FfiConverterBoolean.read(buf), + FfiConverterTypeBestBlock.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalUInt.read(buf), + ) + } + + override fun allocationSize(value: NodeStatus) = ( + FfiConverterBoolean.allocationSize(value.`isRunning`) + + FfiConverterTypeBestBlock.allocationSize(value.`currentBestBlock`) + + FfiConverterOptionalULong.allocationSize(value.`latestLightningWalletSyncTimestamp`) + + FfiConverterOptionalULong.allocationSize(value.`latestOnchainWalletSyncTimestamp`) + + FfiConverterOptionalULong.allocationSize(value.`latestFeeRateCacheUpdateTimestamp`) + + FfiConverterOptionalULong.allocationSize(value.`latestRgsSnapshotTimestamp`) + + FfiConverterOptionalULong.allocationSize(value.`latestPathfindingScoresSyncTimestamp`) + + FfiConverterOptionalULong.allocationSize(value.`latestNodeAnnouncementBroadcastTimestamp`) + + FfiConverterOptionalUInt.allocationSize(value.`latestChannelMonitorArchivalHeight`) + ) + + override fun write(value: NodeStatus, buf: ByteBuffer) { + FfiConverterBoolean.write(value.`isRunning`, buf) + FfiConverterTypeBestBlock.write(value.`currentBestBlock`, buf) + FfiConverterOptionalULong.write(value.`latestLightningWalletSyncTimestamp`, buf) + FfiConverterOptionalULong.write(value.`latestOnchainWalletSyncTimestamp`, buf) + FfiConverterOptionalULong.write(value.`latestFeeRateCacheUpdateTimestamp`, buf) + FfiConverterOptionalULong.write(value.`latestRgsSnapshotTimestamp`, buf) + FfiConverterOptionalULong.write(value.`latestPathfindingScoresSyncTimestamp`, buf) + FfiConverterOptionalULong.write(value.`latestNodeAnnouncementBroadcastTimestamp`, buf) + FfiConverterOptionalUInt.write(value.`latestChannelMonitorArchivalHeight`, buf) + } +} + + + + +object FfiConverterTypeOnchainWalletAccount: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): OnchainWalletAccount { + return OnchainWalletAccount( + FfiConverterTypeAddressType.read(buf), + FfiConverterUInt.read(buf), + ) + } + + override fun allocationSize(value: OnchainWalletAccount) = ( + FfiConverterTypeAddressType.allocationSize(value.`addressType`) + + FfiConverterUInt.allocationSize(value.`accountIndex`) + ) + + override fun write(value: OnchainWalletAccount, buf: ByteBuffer) { + FfiConverterTypeAddressType.write(value.`addressType`, buf) + FfiConverterUInt.write(value.`accountIndex`, buf) + } +} + + + + +object FfiConverterTypeOnchainWalletAccountConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): OnchainWalletAccountConfig { + return OnchainWalletAccountConfig( + FfiConverterTypeAddressType.read(buf), + FfiConverterUInt.read(buf), + FfiConverterString.read(buf), + ) + } + + override fun allocationSize(value: OnchainWalletAccountConfig) = ( + FfiConverterTypeAddressType.allocationSize(value.`addressType`) + + FfiConverterUInt.allocationSize(value.`accountIndex`) + + FfiConverterString.allocationSize(value.`xpub`) + ) + + override fun write(value: OnchainWalletAccountConfig, buf: ByteBuffer) { + FfiConverterTypeAddressType.write(value.`addressType`, buf) + FfiConverterUInt.write(value.`accountIndex`, buf) + FfiConverterString.write(value.`xpub`, buf) + } +} + + + + +object FfiConverterTypeOutPoint: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): OutPoint { + return OutPoint( + FfiConverterTypeTxid.read(buf), + FfiConverterUInt.read(buf), + ) + } + + override fun allocationSize(value: OutPoint) = ( + FfiConverterTypeTxid.allocationSize(value.`txid`) + + FfiConverterUInt.allocationSize(value.`vout`) + ) + + override fun write(value: OutPoint, buf: ByteBuffer) { + FfiConverterTypeTxid.write(value.`txid`, buf) + FfiConverterUInt.write(value.`vout`, buf) + } +} + + + + +object FfiConverterTypePaymentDetails: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): PaymentDetails { + return PaymentDetails( + FfiConverterTypePaymentId.read(buf), + FfiConverterTypePaymentKind.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterTypePaymentDirection.read(buf), + FfiConverterTypePaymentStatus.read(buf), + FfiConverterULong.read(buf), + ) + } + + override fun allocationSize(value: PaymentDetails) = ( + FfiConverterTypePaymentId.allocationSize(value.`id`) + + FfiConverterTypePaymentKind.allocationSize(value.`kind`) + + FfiConverterOptionalULong.allocationSize(value.`amountMsat`) + + FfiConverterOptionalULong.allocationSize(value.`feePaidMsat`) + + FfiConverterTypePaymentDirection.allocationSize(value.`direction`) + + FfiConverterTypePaymentStatus.allocationSize(value.`status`) + + FfiConverterULong.allocationSize(value.`latestUpdateTimestamp`) + ) + + override fun write(value: PaymentDetails, buf: ByteBuffer) { + FfiConverterTypePaymentId.write(value.`id`, buf) + FfiConverterTypePaymentKind.write(value.`kind`, buf) + FfiConverterOptionalULong.write(value.`amountMsat`, buf) + FfiConverterOptionalULong.write(value.`feePaidMsat`, buf) + FfiConverterTypePaymentDirection.write(value.`direction`, buf) + FfiConverterTypePaymentStatus.write(value.`status`, buf) + FfiConverterULong.write(value.`latestUpdateTimestamp`, buf) + } +} + + + + +object FfiConverterTypePeerDetails: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): PeerDetails { + return PeerDetails( + FfiConverterTypePublicKey.read(buf), + FfiConverterTypeSocketAddress.read(buf), + FfiConverterBoolean.read(buf), + FfiConverterBoolean.read(buf), + ) + } + + override fun allocationSize(value: PeerDetails) = ( + FfiConverterTypePublicKey.allocationSize(value.`nodeId`) + + FfiConverterTypeSocketAddress.allocationSize(value.`address`) + + FfiConverterBoolean.allocationSize(value.`isPersisted`) + + FfiConverterBoolean.allocationSize(value.`isConnected`) + ) + + override fun write(value: PeerDetails, buf: ByteBuffer) { + FfiConverterTypePublicKey.write(value.`nodeId`, buf) + FfiConverterTypeSocketAddress.write(value.`address`, buf) + FfiConverterBoolean.write(value.`isPersisted`, buf) + FfiConverterBoolean.write(value.`isConnected`, buf) + } +} + + + + +object FfiConverterTypeProbeHandle: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ProbeHandle { + return ProbeHandle( + FfiConverterTypePaymentHash.read(buf), + FfiConverterTypePaymentId.read(buf), + ) + } + + override fun allocationSize(value: ProbeHandle) = ( + FfiConverterTypePaymentHash.allocationSize(value.`paymentHash`) + + FfiConverterTypePaymentId.allocationSize(value.`paymentId`) + ) + + override fun write(value: ProbeHandle, buf: ByteBuffer) { + FfiConverterTypePaymentHash.write(value.`paymentHash`, buf) + FfiConverterTypePaymentId.write(value.`paymentId`, buf) + } +} + + + + +object FfiConverterTypeRouteHintHop: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): RouteHintHop { + return RouteHintHop( + FfiConverterTypePublicKey.read(buf), + FfiConverterULong.read(buf), + FfiConverterUShort.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterTypeRoutingFees.read(buf), + ) + } + + override fun allocationSize(value: RouteHintHop) = ( + FfiConverterTypePublicKey.allocationSize(value.`srcNodeId`) + + FfiConverterULong.allocationSize(value.`shortChannelId`) + + FfiConverterUShort.allocationSize(value.`cltvExpiryDelta`) + + FfiConverterOptionalULong.allocationSize(value.`htlcMinimumMsat`) + + FfiConverterOptionalULong.allocationSize(value.`htlcMaximumMsat`) + + FfiConverterTypeRoutingFees.allocationSize(value.`fees`) + ) + + override fun write(value: RouteHintHop, buf: ByteBuffer) { + FfiConverterTypePublicKey.write(value.`srcNodeId`, buf) + FfiConverterULong.write(value.`shortChannelId`, buf) + FfiConverterUShort.write(value.`cltvExpiryDelta`, buf) + FfiConverterOptionalULong.write(value.`htlcMinimumMsat`, buf) + FfiConverterOptionalULong.write(value.`htlcMaximumMsat`, buf) + FfiConverterTypeRoutingFees.write(value.`fees`, buf) + } +} + + + + +object FfiConverterTypeRouteParametersConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): RouteParametersConfig { + return RouteParametersConfig( + FfiConverterOptionalULong.read(buf), + FfiConverterUInt.read(buf), + FfiConverterUByte.read(buf), + FfiConverterUByte.read(buf), + ) + } + + override fun allocationSize(value: RouteParametersConfig) = ( + FfiConverterOptionalULong.allocationSize(value.`maxTotalRoutingFeeMsat`) + + FfiConverterUInt.allocationSize(value.`maxTotalCltvExpiryDelta`) + + FfiConverterUByte.allocationSize(value.`maxPathCount`) + + FfiConverterUByte.allocationSize(value.`maxChannelSaturationPowerOfHalf`) + ) + + override fun write(value: RouteParametersConfig, buf: ByteBuffer) { + FfiConverterOptionalULong.write(value.`maxTotalRoutingFeeMsat`, buf) + FfiConverterUInt.write(value.`maxTotalCltvExpiryDelta`, buf) + FfiConverterUByte.write(value.`maxPathCount`, buf) + FfiConverterUByte.write(value.`maxChannelSaturationPowerOfHalf`, buf) + } +} + + + + +object FfiConverterTypeRoutingFees: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): RoutingFees { + return RoutingFees( + FfiConverterUInt.read(buf), + FfiConverterUInt.read(buf), + ) + } + + override fun allocationSize(value: RoutingFees) = ( + FfiConverterUInt.allocationSize(value.`baseMsat`) + + FfiConverterUInt.allocationSize(value.`proportionalMillionths`) + ) + + override fun write(value: RoutingFees, buf: ByteBuffer) { + FfiConverterUInt.write(value.`baseMsat`, buf) + FfiConverterUInt.write(value.`proportionalMillionths`, buf) + } +} + + + + +object FfiConverterTypeRuntimeSyncIntervals: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): RuntimeSyncIntervals { + return RuntimeSyncIntervals( + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + ) + } + + override fun allocationSize(value: RuntimeSyncIntervals) = ( + FfiConverterULong.allocationSize(value.`onchainWalletSyncIntervalSecs`) + + FfiConverterULong.allocationSize(value.`lightningWalletSyncIntervalSecs`) + + FfiConverterULong.allocationSize(value.`feeRateCacheUpdateIntervalSecs`) + ) + + override fun write(value: RuntimeSyncIntervals, buf: ByteBuffer) { + FfiConverterULong.write(value.`onchainWalletSyncIntervalSecs`, buf) + FfiConverterULong.write(value.`lightningWalletSyncIntervalSecs`, buf) + FfiConverterULong.write(value.`feeRateCacheUpdateIntervalSecs`, buf) + } +} + + + + +object FfiConverterTypeScoringDecayParameters: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ScoringDecayParameters { + return ScoringDecayParameters( + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + ) + } + + override fun allocationSize(value: ScoringDecayParameters) = ( + FfiConverterULong.allocationSize(value.`historicalNoUpdatesHalfLifeSecs`) + + FfiConverterULong.allocationSize(value.`liquidityOffsetHalfLifeSecs`) + ) + + override fun write(value: ScoringDecayParameters, buf: ByteBuffer) { + FfiConverterULong.write(value.`historicalNoUpdatesHalfLifeSecs`, buf) + FfiConverterULong.write(value.`liquidityOffsetHalfLifeSecs`, buf) + } +} + + + + +object FfiConverterTypeScoringFeeParameters: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ScoringFeeParameters { + return ScoringFeeParameters( + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterBoolean.read(buf), + FfiConverterULong.read(buf), + ) + } + + override fun allocationSize(value: ScoringFeeParameters) = ( + FfiConverterULong.allocationSize(value.`basePenaltyMsat`) + + FfiConverterULong.allocationSize(value.`basePenaltyAmountMultiplierMsat`) + + FfiConverterULong.allocationSize(value.`liquidityPenaltyMultiplierMsat`) + + FfiConverterULong.allocationSize(value.`liquidityPenaltyAmountMultiplierMsat`) + + FfiConverterULong.allocationSize(value.`historicalLiquidityPenaltyMultiplierMsat`) + + FfiConverterULong.allocationSize(value.`historicalLiquidityPenaltyAmountMultiplierMsat`) + + FfiConverterULong.allocationSize(value.`antiProbingPenaltyMsat`) + + FfiConverterULong.allocationSize(value.`consideredImpossiblePenaltyMsat`) + + FfiConverterBoolean.allocationSize(value.`linearSuccessProbability`) + + FfiConverterULong.allocationSize(value.`probingDiversityPenaltyMsat`) + ) + + override fun write(value: ScoringFeeParameters, buf: ByteBuffer) { + FfiConverterULong.write(value.`basePenaltyMsat`, buf) + FfiConverterULong.write(value.`basePenaltyAmountMultiplierMsat`, buf) + FfiConverterULong.write(value.`liquidityPenaltyMultiplierMsat`, buf) + FfiConverterULong.write(value.`liquidityPenaltyAmountMultiplierMsat`, buf) + FfiConverterULong.write(value.`historicalLiquidityPenaltyMultiplierMsat`, buf) + FfiConverterULong.write(value.`historicalLiquidityPenaltyAmountMultiplierMsat`, buf) + FfiConverterULong.write(value.`antiProbingPenaltyMsat`, buf) + FfiConverterULong.write(value.`consideredImpossiblePenaltyMsat`, buf) + FfiConverterBoolean.write(value.`linearSuccessProbability`, buf) + FfiConverterULong.write(value.`probingDiversityPenaltyMsat`, buf) + } +} + + + + +object FfiConverterTypeSpendableUtxo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): SpendableUtxo { + return SpendableUtxo( + FfiConverterTypeOutPoint.read(buf), + FfiConverterULong.read(buf), + ) + } + + override fun allocationSize(value: SpendableUtxo) = ( + FfiConverterTypeOutPoint.allocationSize(value.`outpoint`) + + FfiConverterULong.allocationSize(value.`valueSats`) + ) + + override fun write(value: SpendableUtxo, buf: ByteBuffer) { + FfiConverterTypeOutPoint.write(value.`outpoint`, buf) + FfiConverterULong.write(value.`valueSats`, buf) + } +} + + + + +object FfiConverterTypeTransactionDetails: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): TransactionDetails { + return TransactionDetails( + FfiConverterLong.read(buf), + FfiConverterSequenceTypeTxInput.read(buf), + FfiConverterSequenceTypeTxOutput.read(buf), + ) + } + + override fun allocationSize(value: TransactionDetails) = ( + FfiConverterLong.allocationSize(value.`amountSats`) + + FfiConverterSequenceTypeTxInput.allocationSize(value.`inputs`) + + FfiConverterSequenceTypeTxOutput.allocationSize(value.`outputs`) + ) + + override fun write(value: TransactionDetails, buf: ByteBuffer) { + FfiConverterLong.write(value.`amountSats`, buf) + FfiConverterSequenceTypeTxInput.write(value.`inputs`, buf) + FfiConverterSequenceTypeTxOutput.write(value.`outputs`, buf) + } +} + + + + +object FfiConverterTypeTxInput: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): TxInput { + return TxInput( + FfiConverterTypeTxid.read(buf), + FfiConverterUInt.read(buf), + FfiConverterString.read(buf), + FfiConverterSequenceString.read(buf), + FfiConverterUInt.read(buf), + ) + } + + override fun allocationSize(value: TxInput) = ( + FfiConverterTypeTxid.allocationSize(value.`txid`) + + FfiConverterUInt.allocationSize(value.`vout`) + + FfiConverterString.allocationSize(value.`scriptsig`) + + FfiConverterSequenceString.allocationSize(value.`witness`) + + FfiConverterUInt.allocationSize(value.`sequence`) + ) + + override fun write(value: TxInput, buf: ByteBuffer) { + FfiConverterTypeTxid.write(value.`txid`, buf) + FfiConverterUInt.write(value.`vout`, buf) + FfiConverterString.write(value.`scriptsig`, buf) + FfiConverterSequenceString.write(value.`witness`, buf) + FfiConverterUInt.write(value.`sequence`, buf) + } +} + + + + +object FfiConverterTypeTxOutput: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): TxOutput { + return TxOutput( + FfiConverterString.read(buf), + FfiConverterOptionalString.read(buf), + FfiConverterOptionalString.read(buf), + FfiConverterLong.read(buf), + FfiConverterUInt.read(buf), + ) + } + + override fun allocationSize(value: TxOutput) = ( + FfiConverterString.allocationSize(value.`scriptpubkey`) + + FfiConverterOptionalString.allocationSize(value.`scriptpubkeyType`) + + FfiConverterOptionalString.allocationSize(value.`scriptpubkeyAddress`) + + FfiConverterLong.allocationSize(value.`value`) + + FfiConverterUInt.allocationSize(value.`n`) + ) + + override fun write(value: TxOutput, buf: ByteBuffer) { + FfiConverterString.write(value.`scriptpubkey`, buf) + FfiConverterOptionalString.write(value.`scriptpubkeyType`, buf) + FfiConverterOptionalString.write(value.`scriptpubkeyAddress`, buf) + FfiConverterLong.write(value.`value`, buf) + FfiConverterUInt.write(value.`n`, buf) + } +} + + + + + +object FfiConverterTypeAddressType: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + AddressType.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: AddressType) = 4UL + + override fun write(value: AddressType, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + +object FfiConverterTypeAsyncPaymentsRole: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + AsyncPaymentsRole.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: AsyncPaymentsRole) = 4UL + + override fun write(value: AsyncPaymentsRole, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + +object FfiConverterTypeBalanceSource: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + BalanceSource.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: BalanceSource) = 4UL + + override fun write(value: BalanceSource, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + +object FfiConverterTypeBolt11InvoiceDescription : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): Bolt11InvoiceDescription { + return when(buf.getInt()) { + 1 -> Bolt11InvoiceDescription.Hash( + FfiConverterString.read(buf), + ) + 2 -> Bolt11InvoiceDescription.Direct( + FfiConverterString.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: Bolt11InvoiceDescription) = when(value) { + is Bolt11InvoiceDescription.Hash -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterString.allocationSize(value.`hash`) + ) + } + is Bolt11InvoiceDescription.Direct -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterString.allocationSize(value.`description`) + ) + } + } + + override fun write(value: Bolt11InvoiceDescription, buf: ByteBuffer) { + when(value) { + is Bolt11InvoiceDescription.Hash -> { + buf.putInt(1) + FfiConverterString.write(value.`hash`, buf) + Unit + } + is Bolt11InvoiceDescription.Direct -> { + buf.putInt(2) + FfiConverterString.write(value.`description`, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + +object BuildExceptionErrorHandler : UniffiRustCallStatusErrorHandler { + override fun lift(errorBuf: RustBufferByValue): BuildException = FfiConverterTypeBuildError.lift(errorBuf) +} + +object FfiConverterTypeBuildError : FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): BuildException { + return when (buf.getInt()) { + 1 -> BuildException.InvalidSeedBytes(FfiConverterString.read(buf)) + 2 -> BuildException.InvalidSeedFile(FfiConverterString.read(buf)) + 3 -> BuildException.InvalidSystemTime(FfiConverterString.read(buf)) + 4 -> BuildException.InvalidChannelMonitor(FfiConverterString.read(buf)) + 5 -> BuildException.InvalidListeningAddresses(FfiConverterString.read(buf)) + 6 -> BuildException.InvalidAnnouncementAddresses(FfiConverterString.read(buf)) + 7 -> BuildException.InvalidNodeAlias(FfiConverterString.read(buf)) + 8 -> BuildException.RuntimeSetupFailed(FfiConverterString.read(buf)) + 9 -> BuildException.ReadFailed(FfiConverterString.read(buf)) + 10 -> BuildException.DangerousValue(FfiConverterString.read(buf)) + 11 -> BuildException.WriteFailed(FfiConverterString.read(buf)) + 12 -> BuildException.StoragePathAccessFailed(FfiConverterString.read(buf)) + 13 -> BuildException.KvStoreSetupFailed(FfiConverterString.read(buf)) + 14 -> BuildException.WalletSetupFailed(FfiConverterString.read(buf)) + 15 -> BuildException.LoggerSetupFailed(FfiConverterString.read(buf)) + 16 -> BuildException.NetworkMismatch(FfiConverterString.read(buf)) + 17 -> BuildException.AsyncPaymentsConfigMismatch(FfiConverterString.read(buf)) + else -> throw RuntimeException("invalid error enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: BuildException): ULong { + return 4UL + } + + override fun write(value: BuildException, buf: ByteBuffer) { + when (value) { + is BuildException.InvalidSeedBytes -> { + buf.putInt(1) + Unit + } + is BuildException.InvalidSeedFile -> { + buf.putInt(2) + Unit + } + is BuildException.InvalidSystemTime -> { + buf.putInt(3) + Unit + } + is BuildException.InvalidChannelMonitor -> { + buf.putInt(4) + Unit + } + is BuildException.InvalidListeningAddresses -> { + buf.putInt(5) + Unit + } + is BuildException.InvalidAnnouncementAddresses -> { + buf.putInt(6) + Unit + } + is BuildException.InvalidNodeAlias -> { + buf.putInt(7) + Unit + } + is BuildException.RuntimeSetupFailed -> { + buf.putInt(8) + Unit + } + is BuildException.ReadFailed -> { + buf.putInt(9) + Unit + } + is BuildException.DangerousValue -> { + buf.putInt(10) + Unit + } + is BuildException.WriteFailed -> { + buf.putInt(11) + Unit + } + is BuildException.StoragePathAccessFailed -> { + buf.putInt(12) + Unit + } + is BuildException.KvStoreSetupFailed -> { + buf.putInt(13) + Unit + } + is BuildException.WalletSetupFailed -> { + buf.putInt(14) + Unit + } + is BuildException.LoggerSetupFailed -> { + buf.putInt(15) + Unit + } + is BuildException.NetworkMismatch -> { + buf.putInt(16) + Unit + } + is BuildException.AsyncPaymentsConfigMismatch -> { + buf.putInt(17) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + +object FfiConverterTypeClosureReason : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): ClosureReason { + return when(buf.getInt()) { + 1 -> ClosureReason.CounterpartyForceClosed( + FfiConverterTypeUntrustedString.read(buf), + ) + 2 -> ClosureReason.HolderForceClosed( + FfiConverterOptionalBoolean.read(buf), + FfiConverterString.read(buf), + ) + 3 -> ClosureReason.LegacyCooperativeClosure + 4 -> ClosureReason.CounterpartyInitiatedCooperativeClosure + 5 -> ClosureReason.LocallyInitiatedCooperativeClosure + 6 -> ClosureReason.CommitmentTxConfirmed + 7 -> ClosureReason.FundingTimedOut + 8 -> ClosureReason.ProcessingError( + FfiConverterString.read(buf), + ) + 9 -> ClosureReason.DisconnectedPeer + 10 -> ClosureReason.OutdatedChannelManager + 11 -> ClosureReason.CounterpartyCoopClosedUnfundedChannel + 12 -> ClosureReason.LocallyCoopClosedUnfundedChannel + 13 -> ClosureReason.FundingBatchClosure + 14 -> ClosureReason.HtlCsTimedOut( + FfiConverterOptionalTypePaymentHash.read(buf), + ) + 15 -> ClosureReason.PeerFeerateTooLow( + FfiConverterUInt.read(buf), + FfiConverterUInt.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: ClosureReason) = when(value) { + is ClosureReason.CounterpartyForceClosed -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeUntrustedString.allocationSize(value.`peerMsg`) + ) + } + is ClosureReason.HolderForceClosed -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterOptionalBoolean.allocationSize(value.`broadcastedLatestTxn`) + + FfiConverterString.allocationSize(value.`message`) + ) + } + is ClosureReason.LegacyCooperativeClosure -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is ClosureReason.CounterpartyInitiatedCooperativeClosure -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is ClosureReason.LocallyInitiatedCooperativeClosure -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is ClosureReason.CommitmentTxConfirmed -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is ClosureReason.FundingTimedOut -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is ClosureReason.ProcessingError -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterString.allocationSize(value.`err`) + ) + } + is ClosureReason.DisconnectedPeer -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is ClosureReason.OutdatedChannelManager -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is ClosureReason.CounterpartyCoopClosedUnfundedChannel -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is ClosureReason.LocallyCoopClosedUnfundedChannel -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is ClosureReason.FundingBatchClosure -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is ClosureReason.HtlCsTimedOut -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterOptionalTypePaymentHash.allocationSize(value.`paymentHash`) + ) + } + is ClosureReason.PeerFeerateTooLow -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterUInt.allocationSize(value.`peerFeerateSatPerKw`) + + FfiConverterUInt.allocationSize(value.`requiredFeerateSatPerKw`) + ) + } + } + + override fun write(value: ClosureReason, buf: ByteBuffer) { + when(value) { + is ClosureReason.CounterpartyForceClosed -> { + buf.putInt(1) + FfiConverterTypeUntrustedString.write(value.`peerMsg`, buf) + Unit + } + is ClosureReason.HolderForceClosed -> { + buf.putInt(2) + FfiConverterOptionalBoolean.write(value.`broadcastedLatestTxn`, buf) + FfiConverterString.write(value.`message`, buf) + Unit + } + is ClosureReason.LegacyCooperativeClosure -> { + buf.putInt(3) + Unit + } + is ClosureReason.CounterpartyInitiatedCooperativeClosure -> { + buf.putInt(4) + Unit + } + is ClosureReason.LocallyInitiatedCooperativeClosure -> { + buf.putInt(5) + Unit + } + is ClosureReason.CommitmentTxConfirmed -> { + buf.putInt(6) + Unit + } + is ClosureReason.FundingTimedOut -> { + buf.putInt(7) + Unit + } + is ClosureReason.ProcessingError -> { + buf.putInt(8) + FfiConverterString.write(value.`err`, buf) + Unit + } + is ClosureReason.DisconnectedPeer -> { + buf.putInt(9) + Unit + } + is ClosureReason.OutdatedChannelManager -> { + buf.putInt(10) + Unit + } + is ClosureReason.CounterpartyCoopClosedUnfundedChannel -> { + buf.putInt(11) + Unit + } + is ClosureReason.LocallyCoopClosedUnfundedChannel -> { + buf.putInt(12) + Unit + } + is ClosureReason.FundingBatchClosure -> { + buf.putInt(13) + Unit + } + is ClosureReason.HtlCsTimedOut -> { + buf.putInt(14) + FfiConverterOptionalTypePaymentHash.write(value.`paymentHash`, buf) + Unit + } + is ClosureReason.PeerFeerateTooLow -> { + buf.putInt(15) + FfiConverterUInt.write(value.`peerFeerateSatPerKw`, buf) + FfiConverterUInt.write(value.`requiredFeerateSatPerKw`, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + +object FfiConverterTypeCoinSelectionAlgorithm: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + CoinSelectionAlgorithm.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: CoinSelectionAlgorithm) = 4UL + + override fun write(value: CoinSelectionAlgorithm, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + +object FfiConverterTypeConfirmationStatus : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): ConfirmationStatus { + return when(buf.getInt()) { + 1 -> ConfirmationStatus.Confirmed( + FfiConverterTypeBlockHash.read(buf), + FfiConverterUInt.read(buf), + FfiConverterULong.read(buf), + ) + 2 -> ConfirmationStatus.Unconfirmed + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: ConfirmationStatus) = when(value) { + is ConfirmationStatus.Confirmed -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeBlockHash.allocationSize(value.`blockHash`) + + FfiConverterUInt.allocationSize(value.`height`) + + FfiConverterULong.allocationSize(value.`timestamp`) + ) + } + is ConfirmationStatus.Unconfirmed -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + } + + override fun write(value: ConfirmationStatus, buf: ByteBuffer) { + when(value) { + is ConfirmationStatus.Confirmed -> { + buf.putInt(1) + FfiConverterTypeBlockHash.write(value.`blockHash`, buf) + FfiConverterUInt.write(value.`height`, buf) + FfiConverterULong.write(value.`timestamp`, buf) + Unit + } + is ConfirmationStatus.Unconfirmed -> { + buf.putInt(2) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + +object FfiConverterTypeCurrency: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + Currency.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: Currency) = 4UL + + override fun write(value: Currency, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + +object FfiConverterTypeEvent : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): Event { + return when(buf.getInt()) { + 1 -> Event.PaymentSuccessful( + FfiConverterOptionalTypePaymentId.read(buf), + FfiConverterTypePaymentHash.read(buf), + FfiConverterOptionalTypePaymentPreimage.read(buf), + FfiConverterOptionalULong.read(buf), + ) + 2 -> Event.PaymentFailed( + FfiConverterOptionalTypePaymentId.read(buf), + FfiConverterOptionalTypePaymentHash.read(buf), + FfiConverterOptionalTypePaymentFailureReason.read(buf), + ) + 3 -> Event.PaymentReceived( + FfiConverterOptionalTypePaymentId.read(buf), + FfiConverterTypePaymentHash.read(buf), + FfiConverterULong.read(buf), + FfiConverterSequenceTypeCustomTlvRecord.read(buf), + ) + 4 -> Event.PaymentClaimable( + FfiConverterTypePaymentId.read(buf), + FfiConverterTypePaymentHash.read(buf), + FfiConverterULong.read(buf), + FfiConverterOptionalUInt.read(buf), + FfiConverterSequenceTypeCustomTlvRecord.read(buf), + ) + 5 -> Event.PaymentForwarded( + FfiConverterTypeChannelId.read(buf), + FfiConverterTypeChannelId.read(buf), + FfiConverterOptionalTypeUserChannelId.read(buf), + FfiConverterOptionalTypeUserChannelId.read(buf), + FfiConverterOptionalTypePublicKey.read(buf), + FfiConverterOptionalTypePublicKey.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterBoolean.read(buf), + FfiConverterOptionalULong.read(buf), + ) + 6 -> Event.ProbeSuccessful( + FfiConverterTypePaymentId.read(buf), + FfiConverterTypePaymentHash.read(buf), + FfiConverterOptionalULong.read(buf), + ) + 7 -> Event.ProbeFailed( + FfiConverterTypePaymentId.read(buf), + FfiConverterTypePaymentHash.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalULong.read(buf), + ) + 8 -> Event.ChannelPending( + FfiConverterTypeChannelId.read(buf), + FfiConverterTypeUserChannelId.read(buf), + FfiConverterTypeChannelId.read(buf), + FfiConverterTypePublicKey.read(buf), + FfiConverterTypeOutPoint.read(buf), + ) + 9 -> Event.ChannelReady( + FfiConverterTypeChannelId.read(buf), + FfiConverterTypeUserChannelId.read(buf), + FfiConverterOptionalTypePublicKey.read(buf), + FfiConverterOptionalTypeOutPoint.read(buf), + ) + 10 -> Event.ChannelClosed( + FfiConverterTypeChannelId.read(buf), + FfiConverterTypeUserChannelId.read(buf), + FfiConverterOptionalTypePublicKey.read(buf), + FfiConverterOptionalTypeClosureReason.read(buf), + ) + 11 -> Event.SplicePending( + FfiConverterTypeChannelId.read(buf), + FfiConverterTypeUserChannelId.read(buf), + FfiConverterTypePublicKey.read(buf), + FfiConverterTypeOutPoint.read(buf), + ) + 12 -> Event.SpliceFailed( + FfiConverterTypeChannelId.read(buf), + FfiConverterTypeUserChannelId.read(buf), + FfiConverterTypePublicKey.read(buf), + FfiConverterOptionalTypeOutPoint.read(buf), + ) + 13 -> Event.OnchainTransactionConfirmed( + FfiConverterTypeTxid.read(buf), + FfiConverterTypeBlockHash.read(buf), + FfiConverterUInt.read(buf), + FfiConverterULong.read(buf), + FfiConverterTypeTransactionDetails.read(buf), + ) + 14 -> Event.OnchainTransactionReceived( + FfiConverterTypeTxid.read(buf), + FfiConverterTypeTransactionDetails.read(buf), + ) + 15 -> Event.OnchainTransactionReplaced( + FfiConverterTypeTxid.read(buf), + FfiConverterSequenceTypeTxid.read(buf), + ) + 16 -> Event.OnchainTransactionReorged( + FfiConverterTypeTxid.read(buf), + ) + 17 -> Event.OnchainTransactionEvicted( + FfiConverterTypeTxid.read(buf), + ) + 18 -> Event.SyncProgress( + FfiConverterTypeSyncType.read(buf), + FfiConverterUByte.read(buf), + FfiConverterUInt.read(buf), + FfiConverterUInt.read(buf), + ) + 19 -> Event.SyncCompleted( + FfiConverterTypeSyncType.read(buf), + FfiConverterUInt.read(buf), + ) + 20 -> Event.BalanceChanged( + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: Event) = when(value) { + is Event.PaymentSuccessful -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterOptionalTypePaymentId.allocationSize(value.`paymentId`) + + FfiConverterTypePaymentHash.allocationSize(value.`paymentHash`) + + FfiConverterOptionalTypePaymentPreimage.allocationSize(value.`paymentPreimage`) + + FfiConverterOptionalULong.allocationSize(value.`feePaidMsat`) + ) + } + is Event.PaymentFailed -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterOptionalTypePaymentId.allocationSize(value.`paymentId`) + + FfiConverterOptionalTypePaymentHash.allocationSize(value.`paymentHash`) + + FfiConverterOptionalTypePaymentFailureReason.allocationSize(value.`reason`) + ) + } + is Event.PaymentReceived -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterOptionalTypePaymentId.allocationSize(value.`paymentId`) + + FfiConverterTypePaymentHash.allocationSize(value.`paymentHash`) + + FfiConverterULong.allocationSize(value.`amountMsat`) + + FfiConverterSequenceTypeCustomTlvRecord.allocationSize(value.`customRecords`) + ) + } + is Event.PaymentClaimable -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypePaymentId.allocationSize(value.`paymentId`) + + FfiConverterTypePaymentHash.allocationSize(value.`paymentHash`) + + FfiConverterULong.allocationSize(value.`claimableAmountMsat`) + + FfiConverterOptionalUInt.allocationSize(value.`claimDeadline`) + + FfiConverterSequenceTypeCustomTlvRecord.allocationSize(value.`customRecords`) + ) + } + is Event.PaymentForwarded -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeChannelId.allocationSize(value.`prevChannelId`) + + FfiConverterTypeChannelId.allocationSize(value.`nextChannelId`) + + FfiConverterOptionalTypeUserChannelId.allocationSize(value.`prevUserChannelId`) + + FfiConverterOptionalTypeUserChannelId.allocationSize(value.`nextUserChannelId`) + + FfiConverterOptionalTypePublicKey.allocationSize(value.`prevNodeId`) + + FfiConverterOptionalTypePublicKey.allocationSize(value.`nextNodeId`) + + FfiConverterOptionalULong.allocationSize(value.`totalFeeEarnedMsat`) + + FfiConverterOptionalULong.allocationSize(value.`skimmedFeeMsat`) + + FfiConverterBoolean.allocationSize(value.`claimFromOnchainTx`) + + FfiConverterOptionalULong.allocationSize(value.`outboundAmountForwardedMsat`) + ) + } + is Event.ProbeSuccessful -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypePaymentId.allocationSize(value.`paymentId`) + + FfiConverterTypePaymentHash.allocationSize(value.`paymentHash`) + + FfiConverterOptionalULong.allocationSize(value.`routeFeeMsat`) + ) + } + is Event.ProbeFailed -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypePaymentId.allocationSize(value.`paymentId`) + + FfiConverterTypePaymentHash.allocationSize(value.`paymentHash`) + + FfiConverterOptionalULong.allocationSize(value.`shortChannelId`) + + FfiConverterOptionalULong.allocationSize(value.`routeFeeMsat`) + ) + } + is Event.ChannelPending -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterTypeUserChannelId.allocationSize(value.`userChannelId`) + + FfiConverterTypeChannelId.allocationSize(value.`formerTemporaryChannelId`) + + FfiConverterTypePublicKey.allocationSize(value.`counterpartyNodeId`) + + FfiConverterTypeOutPoint.allocationSize(value.`fundingTxo`) + ) + } + is Event.ChannelReady -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterTypeUserChannelId.allocationSize(value.`userChannelId`) + + FfiConverterOptionalTypePublicKey.allocationSize(value.`counterpartyNodeId`) + + FfiConverterOptionalTypeOutPoint.allocationSize(value.`fundingTxo`) + ) + } + is Event.ChannelClosed -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterTypeUserChannelId.allocationSize(value.`userChannelId`) + + FfiConverterOptionalTypePublicKey.allocationSize(value.`counterpartyNodeId`) + + FfiConverterOptionalTypeClosureReason.allocationSize(value.`reason`) + ) + } + is Event.SplicePending -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterTypeUserChannelId.allocationSize(value.`userChannelId`) + + FfiConverterTypePublicKey.allocationSize(value.`counterpartyNodeId`) + + FfiConverterTypeOutPoint.allocationSize(value.`newFundingTxo`) + ) + } + is Event.SpliceFailed -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterTypeUserChannelId.allocationSize(value.`userChannelId`) + + FfiConverterTypePublicKey.allocationSize(value.`counterpartyNodeId`) + + FfiConverterOptionalTypeOutPoint.allocationSize(value.`abandonedFundingTxo`) + ) + } + is Event.OnchainTransactionConfirmed -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeTxid.allocationSize(value.`txid`) + + FfiConverterTypeBlockHash.allocationSize(value.`blockHash`) + + FfiConverterUInt.allocationSize(value.`blockHeight`) + + FfiConverterULong.allocationSize(value.`confirmationTime`) + + FfiConverterTypeTransactionDetails.allocationSize(value.`details`) + ) + } + is Event.OnchainTransactionReceived -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeTxid.allocationSize(value.`txid`) + + FfiConverterTypeTransactionDetails.allocationSize(value.`details`) + ) + } + is Event.OnchainTransactionReplaced -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeTxid.allocationSize(value.`txid`) + + FfiConverterSequenceTypeTxid.allocationSize(value.`conflicts`) + ) + } + is Event.OnchainTransactionReorged -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeTxid.allocationSize(value.`txid`) + ) + } + is Event.OnchainTransactionEvicted -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeTxid.allocationSize(value.`txid`) + ) + } + is Event.SyncProgress -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeSyncType.allocationSize(value.`syncType`) + + FfiConverterUByte.allocationSize(value.`progressPercent`) + + FfiConverterUInt.allocationSize(value.`currentBlockHeight`) + + FfiConverterUInt.allocationSize(value.`targetBlockHeight`) + ) + } + is Event.SyncCompleted -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeSyncType.allocationSize(value.`syncType`) + + FfiConverterUInt.allocationSize(value.`syncedBlockHeight`) + ) + } + is Event.BalanceChanged -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterULong.allocationSize(value.`oldSpendableOnchainBalanceSats`) + + FfiConverterULong.allocationSize(value.`newSpendableOnchainBalanceSats`) + + FfiConverterULong.allocationSize(value.`oldTotalOnchainBalanceSats`) + + FfiConverterULong.allocationSize(value.`newTotalOnchainBalanceSats`) + + FfiConverterULong.allocationSize(value.`oldTotalLightningBalanceSats`) + + FfiConverterULong.allocationSize(value.`newTotalLightningBalanceSats`) + ) + } + } + + override fun write(value: Event, buf: ByteBuffer) { + when(value) { + is Event.PaymentSuccessful -> { + buf.putInt(1) + FfiConverterOptionalTypePaymentId.write(value.`paymentId`, buf) + FfiConverterTypePaymentHash.write(value.`paymentHash`, buf) + FfiConverterOptionalTypePaymentPreimage.write(value.`paymentPreimage`, buf) + FfiConverterOptionalULong.write(value.`feePaidMsat`, buf) + Unit + } + is Event.PaymentFailed -> { + buf.putInt(2) + FfiConverterOptionalTypePaymentId.write(value.`paymentId`, buf) + FfiConverterOptionalTypePaymentHash.write(value.`paymentHash`, buf) + FfiConverterOptionalTypePaymentFailureReason.write(value.`reason`, buf) + Unit + } + is Event.PaymentReceived -> { + buf.putInt(3) + FfiConverterOptionalTypePaymentId.write(value.`paymentId`, buf) + FfiConverterTypePaymentHash.write(value.`paymentHash`, buf) + FfiConverterULong.write(value.`amountMsat`, buf) + FfiConverterSequenceTypeCustomTlvRecord.write(value.`customRecords`, buf) + Unit + } + is Event.PaymentClaimable -> { + buf.putInt(4) + FfiConverterTypePaymentId.write(value.`paymentId`, buf) + FfiConverterTypePaymentHash.write(value.`paymentHash`, buf) + FfiConverterULong.write(value.`claimableAmountMsat`, buf) + FfiConverterOptionalUInt.write(value.`claimDeadline`, buf) + FfiConverterSequenceTypeCustomTlvRecord.write(value.`customRecords`, buf) + Unit + } + is Event.PaymentForwarded -> { + buf.putInt(5) + FfiConverterTypeChannelId.write(value.`prevChannelId`, buf) + FfiConverterTypeChannelId.write(value.`nextChannelId`, buf) + FfiConverterOptionalTypeUserChannelId.write(value.`prevUserChannelId`, buf) + FfiConverterOptionalTypeUserChannelId.write(value.`nextUserChannelId`, buf) + FfiConverterOptionalTypePublicKey.write(value.`prevNodeId`, buf) + FfiConverterOptionalTypePublicKey.write(value.`nextNodeId`, buf) + FfiConverterOptionalULong.write(value.`totalFeeEarnedMsat`, buf) + FfiConverterOptionalULong.write(value.`skimmedFeeMsat`, buf) + FfiConverterBoolean.write(value.`claimFromOnchainTx`, buf) + FfiConverterOptionalULong.write(value.`outboundAmountForwardedMsat`, buf) + Unit + } + is Event.ProbeSuccessful -> { + buf.putInt(6) + FfiConverterTypePaymentId.write(value.`paymentId`, buf) + FfiConverterTypePaymentHash.write(value.`paymentHash`, buf) + FfiConverterOptionalULong.write(value.`routeFeeMsat`, buf) + Unit + } + is Event.ProbeFailed -> { + buf.putInt(7) + FfiConverterTypePaymentId.write(value.`paymentId`, buf) + FfiConverterTypePaymentHash.write(value.`paymentHash`, buf) + FfiConverterOptionalULong.write(value.`shortChannelId`, buf) + FfiConverterOptionalULong.write(value.`routeFeeMsat`, buf) + Unit + } + is Event.ChannelPending -> { + buf.putInt(8) + FfiConverterTypeChannelId.write(value.`channelId`, buf) + FfiConverterTypeUserChannelId.write(value.`userChannelId`, buf) + FfiConverterTypeChannelId.write(value.`formerTemporaryChannelId`, buf) + FfiConverterTypePublicKey.write(value.`counterpartyNodeId`, buf) + FfiConverterTypeOutPoint.write(value.`fundingTxo`, buf) + Unit + } + is Event.ChannelReady -> { + buf.putInt(9) + FfiConverterTypeChannelId.write(value.`channelId`, buf) + FfiConverterTypeUserChannelId.write(value.`userChannelId`, buf) + FfiConverterOptionalTypePublicKey.write(value.`counterpartyNodeId`, buf) + FfiConverterOptionalTypeOutPoint.write(value.`fundingTxo`, buf) + Unit + } + is Event.ChannelClosed -> { + buf.putInt(10) + FfiConverterTypeChannelId.write(value.`channelId`, buf) + FfiConverterTypeUserChannelId.write(value.`userChannelId`, buf) + FfiConverterOptionalTypePublicKey.write(value.`counterpartyNodeId`, buf) + FfiConverterOptionalTypeClosureReason.write(value.`reason`, buf) + Unit + } + is Event.SplicePending -> { + buf.putInt(11) + FfiConverterTypeChannelId.write(value.`channelId`, buf) + FfiConverterTypeUserChannelId.write(value.`userChannelId`, buf) + FfiConverterTypePublicKey.write(value.`counterpartyNodeId`, buf) + FfiConverterTypeOutPoint.write(value.`newFundingTxo`, buf) + Unit + } + is Event.SpliceFailed -> { + buf.putInt(12) + FfiConverterTypeChannelId.write(value.`channelId`, buf) + FfiConverterTypeUserChannelId.write(value.`userChannelId`, buf) + FfiConverterTypePublicKey.write(value.`counterpartyNodeId`, buf) + FfiConverterOptionalTypeOutPoint.write(value.`abandonedFundingTxo`, buf) + Unit + } + is Event.OnchainTransactionConfirmed -> { + buf.putInt(13) + FfiConverterTypeTxid.write(value.`txid`, buf) + FfiConverterTypeBlockHash.write(value.`blockHash`, buf) + FfiConverterUInt.write(value.`blockHeight`, buf) + FfiConverterULong.write(value.`confirmationTime`, buf) + FfiConverterTypeTransactionDetails.write(value.`details`, buf) + Unit + } + is Event.OnchainTransactionReceived -> { + buf.putInt(14) + FfiConverterTypeTxid.write(value.`txid`, buf) + FfiConverterTypeTransactionDetails.write(value.`details`, buf) + Unit + } + is Event.OnchainTransactionReplaced -> { + buf.putInt(15) + FfiConverterTypeTxid.write(value.`txid`, buf) + FfiConverterSequenceTypeTxid.write(value.`conflicts`, buf) + Unit + } + is Event.OnchainTransactionReorged -> { + buf.putInt(16) + FfiConverterTypeTxid.write(value.`txid`, buf) + Unit + } + is Event.OnchainTransactionEvicted -> { + buf.putInt(17) + FfiConverterTypeTxid.write(value.`txid`, buf) + Unit + } + is Event.SyncProgress -> { + buf.putInt(18) + FfiConverterTypeSyncType.write(value.`syncType`, buf) + FfiConverterUByte.write(value.`progressPercent`, buf) + FfiConverterUInt.write(value.`currentBlockHeight`, buf) + FfiConverterUInt.write(value.`targetBlockHeight`, buf) + Unit + } + is Event.SyncCompleted -> { + buf.putInt(19) + FfiConverterTypeSyncType.write(value.`syncType`, buf) + FfiConverterUInt.write(value.`syncedBlockHeight`, buf) + Unit + } + is Event.BalanceChanged -> { + buf.putInt(20) + FfiConverterULong.write(value.`oldSpendableOnchainBalanceSats`, buf) + FfiConverterULong.write(value.`newSpendableOnchainBalanceSats`, buf) + FfiConverterULong.write(value.`oldTotalOnchainBalanceSats`, buf) + FfiConverterULong.write(value.`newTotalOnchainBalanceSats`, buf) + FfiConverterULong.write(value.`oldTotalLightningBalanceSats`, buf) + FfiConverterULong.write(value.`newTotalLightningBalanceSats`, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + +object FfiConverterTypeKeychainKind: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + KeychainKind.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: KeychainKind) = 4UL + + override fun write(value: KeychainKind, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + +object FfiConverterTypeLSPS1PaymentState: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + Lsps1PaymentState.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: Lsps1PaymentState) = 4UL + + override fun write(value: Lsps1PaymentState, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + +object FfiConverterTypeLightningBalance : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): LightningBalance { + return when(buf.getInt()) { + 1 -> LightningBalance.ClaimableOnChannelClose( + FfiConverterTypeChannelId.read(buf), + FfiConverterTypePublicKey.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + ) + 2 -> LightningBalance.ClaimableAwaitingConfirmations( + FfiConverterTypeChannelId.read(buf), + FfiConverterTypePublicKey.read(buf), + FfiConverterULong.read(buf), + FfiConverterUInt.read(buf), + FfiConverterTypeBalanceSource.read(buf), + ) + 3 -> LightningBalance.ContentiousClaimable( + FfiConverterTypeChannelId.read(buf), + FfiConverterTypePublicKey.read(buf), + FfiConverterULong.read(buf), + FfiConverterUInt.read(buf), + FfiConverterTypePaymentHash.read(buf), + FfiConverterTypePaymentPreimage.read(buf), + ) + 4 -> LightningBalance.MaybeTimeoutClaimableHtlc( + FfiConverterTypeChannelId.read(buf), + FfiConverterTypePublicKey.read(buf), + FfiConverterULong.read(buf), + FfiConverterUInt.read(buf), + FfiConverterTypePaymentHash.read(buf), + FfiConverterBoolean.read(buf), + ) + 5 -> LightningBalance.MaybePreimageClaimableHtlc( + FfiConverterTypeChannelId.read(buf), + FfiConverterTypePublicKey.read(buf), + FfiConverterULong.read(buf), + FfiConverterUInt.read(buf), + FfiConverterTypePaymentHash.read(buf), + ) + 6 -> LightningBalance.CounterpartyRevokedOutputClaimable( + FfiConverterTypeChannelId.read(buf), + FfiConverterTypePublicKey.read(buf), + FfiConverterULong.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: LightningBalance) = when(value) { + is LightningBalance.ClaimableOnChannelClose -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterTypePublicKey.allocationSize(value.`counterpartyNodeId`) + + FfiConverterULong.allocationSize(value.`amountSatoshis`) + + FfiConverterULong.allocationSize(value.`transactionFeeSatoshis`) + + FfiConverterULong.allocationSize(value.`outboundPaymentHtlcRoundedMsat`) + + FfiConverterULong.allocationSize(value.`outboundForwardedHtlcRoundedMsat`) + + FfiConverterULong.allocationSize(value.`inboundClaimingHtlcRoundedMsat`) + + FfiConverterULong.allocationSize(value.`inboundHtlcRoundedMsat`) + ) + } + is LightningBalance.ClaimableAwaitingConfirmations -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterTypePublicKey.allocationSize(value.`counterpartyNodeId`) + + FfiConverterULong.allocationSize(value.`amountSatoshis`) + + FfiConverterUInt.allocationSize(value.`confirmationHeight`) + + FfiConverterTypeBalanceSource.allocationSize(value.`source`) + ) + } + is LightningBalance.ContentiousClaimable -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterTypePublicKey.allocationSize(value.`counterpartyNodeId`) + + FfiConverterULong.allocationSize(value.`amountSatoshis`) + + FfiConverterUInt.allocationSize(value.`timeoutHeight`) + + FfiConverterTypePaymentHash.allocationSize(value.`paymentHash`) + + FfiConverterTypePaymentPreimage.allocationSize(value.`paymentPreimage`) + ) + } + is LightningBalance.MaybeTimeoutClaimableHtlc -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterTypePublicKey.allocationSize(value.`counterpartyNodeId`) + + FfiConverterULong.allocationSize(value.`amountSatoshis`) + + FfiConverterUInt.allocationSize(value.`claimableHeight`) + + FfiConverterTypePaymentHash.allocationSize(value.`paymentHash`) + + FfiConverterBoolean.allocationSize(value.`outboundPayment`) + ) + } + is LightningBalance.MaybePreimageClaimableHtlc -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterTypePublicKey.allocationSize(value.`counterpartyNodeId`) + + FfiConverterULong.allocationSize(value.`amountSatoshis`) + + FfiConverterUInt.allocationSize(value.`expiryHeight`) + + FfiConverterTypePaymentHash.allocationSize(value.`paymentHash`) + ) + } + is LightningBalance.CounterpartyRevokedOutputClaimable -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterTypePublicKey.allocationSize(value.`counterpartyNodeId`) + + FfiConverterULong.allocationSize(value.`amountSatoshis`) + ) + } + } + + override fun write(value: LightningBalance, buf: ByteBuffer) { + when(value) { + is LightningBalance.ClaimableOnChannelClose -> { + buf.putInt(1) + FfiConverterTypeChannelId.write(value.`channelId`, buf) + FfiConverterTypePublicKey.write(value.`counterpartyNodeId`, buf) + FfiConverterULong.write(value.`amountSatoshis`, buf) + FfiConverterULong.write(value.`transactionFeeSatoshis`, buf) + FfiConverterULong.write(value.`outboundPaymentHtlcRoundedMsat`, buf) + FfiConverterULong.write(value.`outboundForwardedHtlcRoundedMsat`, buf) + FfiConverterULong.write(value.`inboundClaimingHtlcRoundedMsat`, buf) + FfiConverterULong.write(value.`inboundHtlcRoundedMsat`, buf) + Unit + } + is LightningBalance.ClaimableAwaitingConfirmations -> { + buf.putInt(2) + FfiConverterTypeChannelId.write(value.`channelId`, buf) + FfiConverterTypePublicKey.write(value.`counterpartyNodeId`, buf) + FfiConverterULong.write(value.`amountSatoshis`, buf) + FfiConverterUInt.write(value.`confirmationHeight`, buf) + FfiConverterTypeBalanceSource.write(value.`source`, buf) + Unit + } + is LightningBalance.ContentiousClaimable -> { + buf.putInt(3) + FfiConverterTypeChannelId.write(value.`channelId`, buf) + FfiConverterTypePublicKey.write(value.`counterpartyNodeId`, buf) + FfiConverterULong.write(value.`amountSatoshis`, buf) + FfiConverterUInt.write(value.`timeoutHeight`, buf) + FfiConverterTypePaymentHash.write(value.`paymentHash`, buf) + FfiConverterTypePaymentPreimage.write(value.`paymentPreimage`, buf) + Unit + } + is LightningBalance.MaybeTimeoutClaimableHtlc -> { + buf.putInt(4) + FfiConverterTypeChannelId.write(value.`channelId`, buf) + FfiConverterTypePublicKey.write(value.`counterpartyNodeId`, buf) + FfiConverterULong.write(value.`amountSatoshis`, buf) + FfiConverterUInt.write(value.`claimableHeight`, buf) + FfiConverterTypePaymentHash.write(value.`paymentHash`, buf) + FfiConverterBoolean.write(value.`outboundPayment`, buf) + Unit + } + is LightningBalance.MaybePreimageClaimableHtlc -> { + buf.putInt(5) + FfiConverterTypeChannelId.write(value.`channelId`, buf) + FfiConverterTypePublicKey.write(value.`counterpartyNodeId`, buf) + FfiConverterULong.write(value.`amountSatoshis`, buf) + FfiConverterUInt.write(value.`expiryHeight`, buf) + FfiConverterTypePaymentHash.write(value.`paymentHash`, buf) + Unit + } + is LightningBalance.CounterpartyRevokedOutputClaimable -> { + buf.putInt(6) + FfiConverterTypeChannelId.write(value.`channelId`, buf) + FfiConverterTypePublicKey.write(value.`counterpartyNodeId`, buf) + FfiConverterULong.write(value.`amountSatoshis`, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + +object FfiConverterTypeLogLevel: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + LogLevel.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: LogLevel) = 4UL + + override fun write(value: LogLevel, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + +object FfiConverterTypeMaxDustHTLCExposure : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): MaxDustHtlcExposure { + return when(buf.getInt()) { + 1 -> MaxDustHtlcExposure.FixedLimit( + FfiConverterULong.read(buf), + ) + 2 -> MaxDustHtlcExposure.FeeRateMultiplier( + FfiConverterULong.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: MaxDustHtlcExposure) = when(value) { + is MaxDustHtlcExposure.FixedLimit -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterULong.allocationSize(value.`limitMsat`) + ) + } + is MaxDustHtlcExposure.FeeRateMultiplier -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterULong.allocationSize(value.`multiplier`) + ) + } + } + + override fun write(value: MaxDustHtlcExposure, buf: ByteBuffer) { + when(value) { + is MaxDustHtlcExposure.FixedLimit -> { + buf.putInt(1) + FfiConverterULong.write(value.`limitMsat`, buf) + Unit + } + is MaxDustHtlcExposure.FeeRateMultiplier -> { + buf.putInt(2) + FfiConverterULong.write(value.`multiplier`, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + +object FfiConverterTypeNetwork: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + Network.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: Network) = 4UL + + override fun write(value: Network, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + +object NodeExceptionErrorHandler : UniffiRustCallStatusErrorHandler { + override fun lift(errorBuf: RustBufferByValue): NodeException = FfiConverterTypeNodeError.lift(errorBuf) +} + +object FfiConverterTypeNodeError : FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): NodeException { + return when (buf.getInt()) { + 1 -> NodeException.AlreadyRunning(FfiConverterString.read(buf)) + 2 -> NodeException.NotRunning(FfiConverterString.read(buf)) + 3 -> NodeException.OnchainTxCreationFailed(FfiConverterString.read(buf)) + 4 -> NodeException.ConnectionFailed(FfiConverterString.read(buf)) + 5 -> NodeException.InvoiceCreationFailed(FfiConverterString.read(buf)) + 6 -> NodeException.InvoiceRequestCreationFailed(FfiConverterString.read(buf)) + 7 -> NodeException.OfferCreationFailed(FfiConverterString.read(buf)) + 8 -> NodeException.RefundCreationFailed(FfiConverterString.read(buf)) + 9 -> NodeException.PaymentSendingFailed(FfiConverterString.read(buf)) + 10 -> NodeException.InvalidCustomTlvs(FfiConverterString.read(buf)) + 11 -> NodeException.ProbeSendingFailed(FfiConverterString.read(buf)) + 12 -> NodeException.RouteNotFound(FfiConverterString.read(buf)) + 13 -> NodeException.ChannelCreationFailed(FfiConverterString.read(buf)) + 14 -> NodeException.ChannelClosingFailed(FfiConverterString.read(buf)) + 15 -> NodeException.ChannelSplicingFailed(FfiConverterString.read(buf)) + 16 -> NodeException.ChannelConfigUpdateFailed(FfiConverterString.read(buf)) + 17 -> NodeException.PersistenceFailed(FfiConverterString.read(buf)) + 18 -> NodeException.FeerateEstimationUpdateFailed(FfiConverterString.read(buf)) + 19 -> NodeException.FeerateEstimationUpdateTimeout(FfiConverterString.read(buf)) + 20 -> NodeException.WalletOperationFailed(FfiConverterString.read(buf)) + 21 -> NodeException.WalletOperationTimeout(FfiConverterString.read(buf)) + 22 -> NodeException.OnchainTxSigningFailed(FfiConverterString.read(buf)) + 23 -> NodeException.TxSyncFailed(FfiConverterString.read(buf)) + 24 -> NodeException.TxSyncTimeout(FfiConverterString.read(buf)) + 25 -> NodeException.GossipUpdateFailed(FfiConverterString.read(buf)) + 26 -> NodeException.GossipUpdateTimeout(FfiConverterString.read(buf)) + 27 -> NodeException.LiquidityRequestFailed(FfiConverterString.read(buf)) + 28 -> NodeException.UriParameterParsingFailed(FfiConverterString.read(buf)) + 29 -> NodeException.InvalidAddress(FfiConverterString.read(buf)) + 30 -> NodeException.InvalidSocketAddress(FfiConverterString.read(buf)) + 31 -> NodeException.InvalidPublicKey(FfiConverterString.read(buf)) + 32 -> NodeException.InvalidSecretKey(FfiConverterString.read(buf)) + 33 -> NodeException.InvalidOfferId(FfiConverterString.read(buf)) + 34 -> NodeException.InvalidNodeId(FfiConverterString.read(buf)) + 35 -> NodeException.InvalidPaymentId(FfiConverterString.read(buf)) + 36 -> NodeException.InvalidPaymentHash(FfiConverterString.read(buf)) + 37 -> NodeException.InvalidPaymentPreimage(FfiConverterString.read(buf)) + 38 -> NodeException.InvalidPaymentSecret(FfiConverterString.read(buf)) + 39 -> NodeException.InvalidAmount(FfiConverterString.read(buf)) + 40 -> NodeException.InvalidInvoice(FfiConverterString.read(buf)) + 41 -> NodeException.InvalidOffer(FfiConverterString.read(buf)) + 42 -> NodeException.InvalidRefund(FfiConverterString.read(buf)) + 43 -> NodeException.InvalidChannelId(FfiConverterString.read(buf)) + 44 -> NodeException.InvalidNetwork(FfiConverterString.read(buf)) + 45 -> NodeException.InvalidUri(FfiConverterString.read(buf)) + 46 -> NodeException.InvalidQuantity(FfiConverterString.read(buf)) + 47 -> NodeException.InvalidNodeAlias(FfiConverterString.read(buf)) + 48 -> NodeException.InvalidDateTime(FfiConverterString.read(buf)) + 49 -> NodeException.InvalidFeeRate(FfiConverterString.read(buf)) + 50 -> NodeException.DuplicatePayment(FfiConverterString.read(buf)) + 51 -> NodeException.UnsupportedCurrency(FfiConverterString.read(buf)) + 52 -> NodeException.InsufficientFunds(FfiConverterString.read(buf)) + 53 -> NodeException.LiquiditySourceUnavailable(FfiConverterString.read(buf)) + 54 -> NodeException.LiquidityFeeTooHigh(FfiConverterString.read(buf)) + 55 -> NodeException.InvalidBlindedPaths(FfiConverterString.read(buf)) + 56 -> NodeException.AsyncPaymentServicesDisabled(FfiConverterString.read(buf)) + 57 -> NodeException.CannotRbfFundingTransaction(FfiConverterString.read(buf)) + 58 -> NodeException.TransactionNotFound(FfiConverterString.read(buf)) + 59 -> NodeException.TransactionAlreadyConfirmed(FfiConverterString.read(buf)) + 60 -> NodeException.NoSpendableOutputs(FfiConverterString.read(buf)) + 61 -> NodeException.CoinSelectionFailed(FfiConverterString.read(buf)) + 62 -> NodeException.InvalidMnemonic(FfiConverterString.read(buf)) + 63 -> NodeException.BackgroundSyncNotEnabled(FfiConverterString.read(buf)) + 64 -> NodeException.AddressTypeAlreadyMonitored(FfiConverterString.read(buf)) + 65 -> NodeException.AddressTypeIsPrimary(FfiConverterString.read(buf)) + 66 -> NodeException.AddressTypeNotMonitored(FfiConverterString.read(buf)) + 67 -> NodeException.OnchainWalletAccountNotRegistered(FfiConverterString.read(buf)) + 68 -> NodeException.InvalidSeedBytes(FfiConverterString.read(buf)) + else -> throw RuntimeException("invalid error enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: NodeException): ULong { + return 4UL + } + + override fun write(value: NodeException, buf: ByteBuffer) { + when (value) { + is NodeException.AlreadyRunning -> { + buf.putInt(1) + Unit + } + is NodeException.NotRunning -> { + buf.putInt(2) + Unit + } + is NodeException.OnchainTxCreationFailed -> { + buf.putInt(3) + Unit + } + is NodeException.ConnectionFailed -> { + buf.putInt(4) + Unit + } + is NodeException.InvoiceCreationFailed -> { + buf.putInt(5) + Unit + } + is NodeException.InvoiceRequestCreationFailed -> { + buf.putInt(6) + Unit + } + is NodeException.OfferCreationFailed -> { + buf.putInt(7) + Unit + } + is NodeException.RefundCreationFailed -> { + buf.putInt(8) + Unit + } + is NodeException.PaymentSendingFailed -> { + buf.putInt(9) + Unit + } + is NodeException.InvalidCustomTlvs -> { + buf.putInt(10) + Unit + } + is NodeException.ProbeSendingFailed -> { + buf.putInt(11) + Unit + } + is NodeException.RouteNotFound -> { + buf.putInt(12) + Unit + } + is NodeException.ChannelCreationFailed -> { + buf.putInt(13) + Unit + } + is NodeException.ChannelClosingFailed -> { + buf.putInt(14) + Unit + } + is NodeException.ChannelSplicingFailed -> { + buf.putInt(15) + Unit + } + is NodeException.ChannelConfigUpdateFailed -> { + buf.putInt(16) + Unit + } + is NodeException.PersistenceFailed -> { + buf.putInt(17) + Unit + } + is NodeException.FeerateEstimationUpdateFailed -> { + buf.putInt(18) + Unit + } + is NodeException.FeerateEstimationUpdateTimeout -> { + buf.putInt(19) + Unit + } + is NodeException.WalletOperationFailed -> { + buf.putInt(20) + Unit + } + is NodeException.WalletOperationTimeout -> { + buf.putInt(21) + Unit + } + is NodeException.OnchainTxSigningFailed -> { + buf.putInt(22) + Unit + } + is NodeException.TxSyncFailed -> { + buf.putInt(23) + Unit + } + is NodeException.TxSyncTimeout -> { + buf.putInt(24) + Unit + } + is NodeException.GossipUpdateFailed -> { + buf.putInt(25) + Unit + } + is NodeException.GossipUpdateTimeout -> { + buf.putInt(26) + Unit + } + is NodeException.LiquidityRequestFailed -> { + buf.putInt(27) + Unit + } + is NodeException.UriParameterParsingFailed -> { + buf.putInt(28) + Unit + } + is NodeException.InvalidAddress -> { + buf.putInt(29) + Unit + } + is NodeException.InvalidSocketAddress -> { + buf.putInt(30) + Unit + } + is NodeException.InvalidPublicKey -> { + buf.putInt(31) + Unit + } + is NodeException.InvalidSecretKey -> { + buf.putInt(32) + Unit + } + is NodeException.InvalidOfferId -> { + buf.putInt(33) + Unit + } + is NodeException.InvalidNodeId -> { + buf.putInt(34) + Unit + } + is NodeException.InvalidPaymentId -> { + buf.putInt(35) + Unit + } + is NodeException.InvalidPaymentHash -> { + buf.putInt(36) + Unit + } + is NodeException.InvalidPaymentPreimage -> { + buf.putInt(37) + Unit + } + is NodeException.InvalidPaymentSecret -> { + buf.putInt(38) + Unit + } + is NodeException.InvalidAmount -> { + buf.putInt(39) + Unit + } + is NodeException.InvalidInvoice -> { + buf.putInt(40) + Unit + } + is NodeException.InvalidOffer -> { + buf.putInt(41) + Unit + } + is NodeException.InvalidRefund -> { + buf.putInt(42) + Unit + } + is NodeException.InvalidChannelId -> { + buf.putInt(43) + Unit + } + is NodeException.InvalidNetwork -> { + buf.putInt(44) + Unit + } + is NodeException.InvalidUri -> { + buf.putInt(45) + Unit + } + is NodeException.InvalidQuantity -> { + buf.putInt(46) + Unit + } + is NodeException.InvalidNodeAlias -> { + buf.putInt(47) + Unit + } + is NodeException.InvalidDateTime -> { + buf.putInt(48) + Unit + } + is NodeException.InvalidFeeRate -> { + buf.putInt(49) + Unit + } + is NodeException.DuplicatePayment -> { + buf.putInt(50) + Unit + } + is NodeException.UnsupportedCurrency -> { + buf.putInt(51) + Unit + } + is NodeException.InsufficientFunds -> { + buf.putInt(52) + Unit + } + is NodeException.LiquiditySourceUnavailable -> { + buf.putInt(53) + Unit + } + is NodeException.LiquidityFeeTooHigh -> { + buf.putInt(54) + Unit + } + is NodeException.InvalidBlindedPaths -> { + buf.putInt(55) + Unit + } + is NodeException.AsyncPaymentServicesDisabled -> { + buf.putInt(56) + Unit + } + is NodeException.CannotRbfFundingTransaction -> { + buf.putInt(57) + Unit + } + is NodeException.TransactionNotFound -> { + buf.putInt(58) + Unit + } + is NodeException.TransactionAlreadyConfirmed -> { + buf.putInt(59) + Unit + } + is NodeException.NoSpendableOutputs -> { + buf.putInt(60) + Unit + } + is NodeException.CoinSelectionFailed -> { + buf.putInt(61) + Unit + } + is NodeException.InvalidMnemonic -> { + buf.putInt(62) + Unit + } + is NodeException.BackgroundSyncNotEnabled -> { + buf.putInt(63) + Unit + } + is NodeException.AddressTypeAlreadyMonitored -> { + buf.putInt(64) + Unit + } + is NodeException.AddressTypeIsPrimary -> { + buf.putInt(65) + Unit + } + is NodeException.AddressTypeNotMonitored -> { + buf.putInt(66) + Unit + } + is NodeException.OnchainWalletAccountNotRegistered -> { + buf.putInt(67) + Unit + } + is NodeException.InvalidSeedBytes -> { + buf.putInt(68) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + +object FfiConverterTypeOfferAmount : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): OfferAmount { + return when(buf.getInt()) { + 1 -> OfferAmount.Bitcoin( + FfiConverterULong.read(buf), + ) + 2 -> OfferAmount.Currency( + FfiConverterString.read(buf), + FfiConverterULong.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: OfferAmount) = when(value) { + is OfferAmount.Bitcoin -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterULong.allocationSize(value.`amountMsats`) + ) + } + is OfferAmount.Currency -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterString.allocationSize(value.`iso4217Code`) + + FfiConverterULong.allocationSize(value.`amount`) + ) + } + } + + override fun write(value: OfferAmount, buf: ByteBuffer) { + when(value) { + is OfferAmount.Bitcoin -> { + buf.putInt(1) + FfiConverterULong.write(value.`amountMsats`, buf) + Unit + } + is OfferAmount.Currency -> { + buf.putInt(2) + FfiConverterString.write(value.`iso4217Code`, buf) + FfiConverterULong.write(value.`amount`, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + +object FfiConverterTypePaymentDirection: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + PaymentDirection.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: PaymentDirection) = 4UL + + override fun write(value: PaymentDirection, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + +object FfiConverterTypePaymentFailureReason: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + PaymentFailureReason.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: PaymentFailureReason) = 4UL + + override fun write(value: PaymentFailureReason, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + +object FfiConverterTypePaymentKind : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): PaymentKind { + return when(buf.getInt()) { + 1 -> PaymentKind.Onchain( + FfiConverterTypeTxid.read(buf), + FfiConverterTypeConfirmationStatus.read(buf), + ) + 2 -> PaymentKind.Bolt11( + FfiConverterTypePaymentHash.read(buf), + FfiConverterOptionalTypePaymentPreimage.read(buf), + FfiConverterOptionalTypePaymentSecret.read(buf), + FfiConverterOptionalString.read(buf), + FfiConverterOptionalString.read(buf), + ) + 3 -> PaymentKind.Bolt11Jit( + FfiConverterTypePaymentHash.read(buf), + FfiConverterOptionalTypePaymentPreimage.read(buf), + FfiConverterOptionalTypePaymentSecret.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterTypeLSPFeeLimits.read(buf), + FfiConverterOptionalString.read(buf), + FfiConverterOptionalString.read(buf), + ) + 4 -> PaymentKind.Bolt12Offer( + FfiConverterOptionalTypePaymentHash.read(buf), + FfiConverterOptionalTypePaymentPreimage.read(buf), + FfiConverterOptionalTypePaymentSecret.read(buf), + FfiConverterTypeOfferId.read(buf), + FfiConverterOptionalTypeUntrustedString.read(buf), + FfiConverterOptionalULong.read(buf), + ) + 5 -> PaymentKind.Bolt12Refund( + FfiConverterOptionalTypePaymentHash.read(buf), + FfiConverterOptionalTypePaymentPreimage.read(buf), + FfiConverterOptionalTypePaymentSecret.read(buf), + FfiConverterOptionalTypeUntrustedString.read(buf), + FfiConverterOptionalULong.read(buf), + ) + 6 -> PaymentKind.Spontaneous( + FfiConverterTypePaymentHash.read(buf), + FfiConverterOptionalTypePaymentPreimage.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: PaymentKind) = when(value) { + is PaymentKind.Onchain -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeTxid.allocationSize(value.`txid`) + + FfiConverterTypeConfirmationStatus.allocationSize(value.`status`) + ) + } + is PaymentKind.Bolt11 -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypePaymentHash.allocationSize(value.`hash`) + + FfiConverterOptionalTypePaymentPreimage.allocationSize(value.`preimage`) + + FfiConverterOptionalTypePaymentSecret.allocationSize(value.`secret`) + + FfiConverterOptionalString.allocationSize(value.`description`) + + FfiConverterOptionalString.allocationSize(value.`bolt11`) + ) + } + is PaymentKind.Bolt11Jit -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypePaymentHash.allocationSize(value.`hash`) + + FfiConverterOptionalTypePaymentPreimage.allocationSize(value.`preimage`) + + FfiConverterOptionalTypePaymentSecret.allocationSize(value.`secret`) + + FfiConverterOptionalULong.allocationSize(value.`counterpartySkimmedFeeMsat`) + + FfiConverterTypeLSPFeeLimits.allocationSize(value.`lspFeeLimits`) + + FfiConverterOptionalString.allocationSize(value.`description`) + + FfiConverterOptionalString.allocationSize(value.`bolt11`) + ) + } + is PaymentKind.Bolt12Offer -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterOptionalTypePaymentHash.allocationSize(value.`hash`) + + FfiConverterOptionalTypePaymentPreimage.allocationSize(value.`preimage`) + + FfiConverterOptionalTypePaymentSecret.allocationSize(value.`secret`) + + FfiConverterTypeOfferId.allocationSize(value.`offerId`) + + FfiConverterOptionalTypeUntrustedString.allocationSize(value.`payerNote`) + + FfiConverterOptionalULong.allocationSize(value.`quantity`) + ) + } + is PaymentKind.Bolt12Refund -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterOptionalTypePaymentHash.allocationSize(value.`hash`) + + FfiConverterOptionalTypePaymentPreimage.allocationSize(value.`preimage`) + + FfiConverterOptionalTypePaymentSecret.allocationSize(value.`secret`) + + FfiConverterOptionalTypeUntrustedString.allocationSize(value.`payerNote`) + + FfiConverterOptionalULong.allocationSize(value.`quantity`) + ) + } + is PaymentKind.Spontaneous -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypePaymentHash.allocationSize(value.`hash`) + + FfiConverterOptionalTypePaymentPreimage.allocationSize(value.`preimage`) + ) + } + } + + override fun write(value: PaymentKind, buf: ByteBuffer) { + when(value) { + is PaymentKind.Onchain -> { + buf.putInt(1) + FfiConverterTypeTxid.write(value.`txid`, buf) + FfiConverterTypeConfirmationStatus.write(value.`status`, buf) + Unit + } + is PaymentKind.Bolt11 -> { + buf.putInt(2) + FfiConverterTypePaymentHash.write(value.`hash`, buf) + FfiConverterOptionalTypePaymentPreimage.write(value.`preimage`, buf) + FfiConverterOptionalTypePaymentSecret.write(value.`secret`, buf) + FfiConverterOptionalString.write(value.`description`, buf) + FfiConverterOptionalString.write(value.`bolt11`, buf) + Unit + } + is PaymentKind.Bolt11Jit -> { + buf.putInt(3) + FfiConverterTypePaymentHash.write(value.`hash`, buf) + FfiConverterOptionalTypePaymentPreimage.write(value.`preimage`, buf) + FfiConverterOptionalTypePaymentSecret.write(value.`secret`, buf) + FfiConverterOptionalULong.write(value.`counterpartySkimmedFeeMsat`, buf) + FfiConverterTypeLSPFeeLimits.write(value.`lspFeeLimits`, buf) + FfiConverterOptionalString.write(value.`description`, buf) + FfiConverterOptionalString.write(value.`bolt11`, buf) + Unit + } + is PaymentKind.Bolt12Offer -> { + buf.putInt(4) + FfiConverterOptionalTypePaymentHash.write(value.`hash`, buf) + FfiConverterOptionalTypePaymentPreimage.write(value.`preimage`, buf) + FfiConverterOptionalTypePaymentSecret.write(value.`secret`, buf) + FfiConverterTypeOfferId.write(value.`offerId`, buf) + FfiConverterOptionalTypeUntrustedString.write(value.`payerNote`, buf) + FfiConverterOptionalULong.write(value.`quantity`, buf) + Unit + } + is PaymentKind.Bolt12Refund -> { + buf.putInt(5) + FfiConverterOptionalTypePaymentHash.write(value.`hash`, buf) + FfiConverterOptionalTypePaymentPreimage.write(value.`preimage`, buf) + FfiConverterOptionalTypePaymentSecret.write(value.`secret`, buf) + FfiConverterOptionalTypeUntrustedString.write(value.`payerNote`, buf) + FfiConverterOptionalULong.write(value.`quantity`, buf) + Unit + } + is PaymentKind.Spontaneous -> { + buf.putInt(6) + FfiConverterTypePaymentHash.write(value.`hash`, buf) + FfiConverterOptionalTypePaymentPreimage.write(value.`preimage`, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + +object FfiConverterTypePaymentStatus: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + PaymentStatus.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: PaymentStatus) = 4UL + + override fun write(value: PaymentStatus, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + +object FfiConverterTypePendingSweepBalance : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): PendingSweepBalance { + return when(buf.getInt()) { + 1 -> PendingSweepBalance.PendingBroadcast( + FfiConverterOptionalTypeChannelId.read(buf), + FfiConverterULong.read(buf), + ) + 2 -> PendingSweepBalance.BroadcastAwaitingConfirmation( + FfiConverterOptionalTypeChannelId.read(buf), + FfiConverterUInt.read(buf), + FfiConverterTypeTxid.read(buf), + FfiConverterULong.read(buf), + ) + 3 -> PendingSweepBalance.AwaitingThresholdConfirmations( + FfiConverterOptionalTypeChannelId.read(buf), + FfiConverterTypeTxid.read(buf), + FfiConverterTypeBlockHash.read(buf), + FfiConverterUInt.read(buf), + FfiConverterULong.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: PendingSweepBalance) = when(value) { + is PendingSweepBalance.PendingBroadcast -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterOptionalTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterULong.allocationSize(value.`amountSatoshis`) + ) + } + is PendingSweepBalance.BroadcastAwaitingConfirmation -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterOptionalTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterUInt.allocationSize(value.`latestBroadcastHeight`) + + FfiConverterTypeTxid.allocationSize(value.`latestSpendingTxid`) + + FfiConverterULong.allocationSize(value.`amountSatoshis`) + ) + } + is PendingSweepBalance.AwaitingThresholdConfirmations -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterOptionalTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterTypeTxid.allocationSize(value.`latestSpendingTxid`) + + FfiConverterTypeBlockHash.allocationSize(value.`confirmationHash`) + + FfiConverterUInt.allocationSize(value.`confirmationHeight`) + + FfiConverterULong.allocationSize(value.`amountSatoshis`) + ) + } + } + + override fun write(value: PendingSweepBalance, buf: ByteBuffer) { + when(value) { + is PendingSweepBalance.PendingBroadcast -> { + buf.putInt(1) + FfiConverterOptionalTypeChannelId.write(value.`channelId`, buf) + FfiConverterULong.write(value.`amountSatoshis`, buf) + Unit + } + is PendingSweepBalance.BroadcastAwaitingConfirmation -> { + buf.putInt(2) + FfiConverterOptionalTypeChannelId.write(value.`channelId`, buf) + FfiConverterUInt.write(value.`latestBroadcastHeight`, buf) + FfiConverterTypeTxid.write(value.`latestSpendingTxid`, buf) + FfiConverterULong.write(value.`amountSatoshis`, buf) + Unit + } + is PendingSweepBalance.AwaitingThresholdConfirmations -> { + buf.putInt(3) + FfiConverterOptionalTypeChannelId.write(value.`channelId`, buf) + FfiConverterTypeTxid.write(value.`latestSpendingTxid`, buf) + FfiConverterTypeBlockHash.write(value.`confirmationHash`, buf) + FfiConverterUInt.write(value.`confirmationHeight`, buf) + FfiConverterULong.write(value.`amountSatoshis`, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + +object FfiConverterTypeQrPaymentResult : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): QrPaymentResult { + return when(buf.getInt()) { + 1 -> QrPaymentResult.Onchain( + FfiConverterTypeTxid.read(buf), + ) + 2 -> QrPaymentResult.Bolt11( + FfiConverterTypePaymentId.read(buf), + ) + 3 -> QrPaymentResult.Bolt12( + FfiConverterTypePaymentId.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: QrPaymentResult) = when(value) { + is QrPaymentResult.Onchain -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeTxid.allocationSize(value.`txid`) + ) + } + is QrPaymentResult.Bolt11 -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypePaymentId.allocationSize(value.`paymentId`) + ) + } + is QrPaymentResult.Bolt12 -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypePaymentId.allocationSize(value.`paymentId`) + ) + } + } + + override fun write(value: QrPaymentResult, buf: ByteBuffer) { + when(value) { + is QrPaymentResult.Onchain -> { + buf.putInt(1) + FfiConverterTypeTxid.write(value.`txid`, buf) + Unit + } + is QrPaymentResult.Bolt11 -> { + buf.putInt(2) + FfiConverterTypePaymentId.write(value.`paymentId`, buf) + Unit + } + is QrPaymentResult.Bolt12 -> { + buf.putInt(3) + FfiConverterTypePaymentId.write(value.`paymentId`, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + +object FfiConverterTypeSyncType: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + SyncType.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: SyncType) = 4UL + + override fun write(value: SyncType, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + +object VssHeaderProviderExceptionErrorHandler : UniffiRustCallStatusErrorHandler { + override fun lift(errorBuf: RustBufferByValue): VssHeaderProviderException = FfiConverterTypeVssHeaderProviderError.lift(errorBuf) +} + +object FfiConverterTypeVssHeaderProviderError : FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): VssHeaderProviderException { + return when (buf.getInt()) { + 1 -> VssHeaderProviderException.InvalidData(FfiConverterString.read(buf)) + 2 -> VssHeaderProviderException.RequestException(FfiConverterString.read(buf)) + 3 -> VssHeaderProviderException.AuthorizationException(FfiConverterString.read(buf)) + 4 -> VssHeaderProviderException.InternalException(FfiConverterString.read(buf)) + else -> throw RuntimeException("invalid error enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: VssHeaderProviderException): ULong { + return 4UL + } + + override fun write(value: VssHeaderProviderException, buf: ByteBuffer) { + when (value) { + is VssHeaderProviderException.InvalidData -> { + buf.putInt(1) + Unit + } + is VssHeaderProviderException.RequestException -> { + buf.putInt(2) + Unit + } + is VssHeaderProviderException.AuthorizationException -> { + buf.putInt(3) + Unit + } + is VssHeaderProviderException.InternalException -> { + buf.putInt(4) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + +object FfiConverterTypeWordCount: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + WordCount.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: WordCount) = 4UL + + override fun write(value: WordCount, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + +object FfiConverterOptionalUShort: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): kotlin.UShort? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterUShort.read(buf) + } + + override fun allocationSize(value: kotlin.UShort?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterUShort.allocationSize(value) + } + } + + override fun write(value: kotlin.UShort?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterUShort.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalUInt: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): kotlin.UInt? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterUInt.read(buf) + } + + override fun allocationSize(value: kotlin.UInt?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterUInt.allocationSize(value) + } + } + + override fun write(value: kotlin.UInt?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterUInt.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalULong: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): kotlin.ULong? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterULong.read(buf) + } + + override fun allocationSize(value: kotlin.ULong?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterULong.allocationSize(value) + } + } + + override fun write(value: kotlin.ULong?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterULong.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalBoolean: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): kotlin.Boolean? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterBoolean.read(buf) + } + + override fun allocationSize(value: kotlin.Boolean?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterBoolean.allocationSize(value) + } + } + + override fun write(value: kotlin.Boolean?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterBoolean.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalString: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): kotlin.String? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterString.read(buf) + } + + override fun allocationSize(value: kotlin.String?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterString.allocationSize(value) + } + } + + override fun write(value: kotlin.String?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterString.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeFeeRate: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): FeeRate? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeFeeRate.read(buf) + } + + override fun allocationSize(value: FeeRate?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeFeeRate.allocationSize(value) + } + } + + override fun write(value: FeeRate?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeFeeRate.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeAnchorChannelsConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): AnchorChannelsConfig? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeAnchorChannelsConfig.read(buf) + } + + override fun allocationSize(value: AnchorChannelsConfig?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeAnchorChannelsConfig.allocationSize(value) + } + } + + override fun write(value: AnchorChannelsConfig?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeAnchorChannelsConfig.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeBackgroundSyncConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): BackgroundSyncConfig? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeBackgroundSyncConfig.read(buf) + } + + override fun allocationSize(value: BackgroundSyncConfig?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeBackgroundSyncConfig.allocationSize(value) + } + } + + override fun write(value: BackgroundSyncConfig?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeBackgroundSyncConfig.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeChannelConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ChannelConfig? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeChannelConfig.read(buf) + } + + override fun allocationSize(value: ChannelConfig?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeChannelConfig.allocationSize(value) + } + } + + override fun write(value: ChannelConfig?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeChannelConfig.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeChannelInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ChannelInfo? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeChannelInfo.read(buf) + } + + override fun allocationSize(value: ChannelInfo?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeChannelInfo.allocationSize(value) + } + } + + override fun write(value: ChannelInfo?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeChannelInfo.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeChannelUpdateInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ChannelUpdateInfo? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeChannelUpdateInfo.read(buf) + } + + override fun allocationSize(value: ChannelUpdateInfo?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeChannelUpdateInfo.allocationSize(value) + } + } + + override fun write(value: ChannelUpdateInfo?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeChannelUpdateInfo.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeElectrumSyncConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ElectrumSyncConfig? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeElectrumSyncConfig.read(buf) + } + + override fun allocationSize(value: ElectrumSyncConfig?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeElectrumSyncConfig.allocationSize(value) + } + } + + override fun write(value: ElectrumSyncConfig?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeElectrumSyncConfig.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeEsploraSyncConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): EsploraSyncConfig? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeEsploraSyncConfig.read(buf) + } + + override fun allocationSize(value: EsploraSyncConfig?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeEsploraSyncConfig.allocationSize(value) + } + } + + override fun write(value: EsploraSyncConfig?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeEsploraSyncConfig.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeLSPS1Bolt11PaymentInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Lsps1Bolt11PaymentInfo? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeLSPS1Bolt11PaymentInfo.read(buf) + } + + override fun allocationSize(value: Lsps1Bolt11PaymentInfo?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeLSPS1Bolt11PaymentInfo.allocationSize(value) + } + } + + override fun write(value: Lsps1Bolt11PaymentInfo?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeLSPS1Bolt11PaymentInfo.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeLSPS1ChannelInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Lsps1ChannelInfo? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeLSPS1ChannelInfo.read(buf) + } + + override fun allocationSize(value: Lsps1ChannelInfo?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeLSPS1ChannelInfo.allocationSize(value) + } + } + + override fun write(value: Lsps1ChannelInfo?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeLSPS1ChannelInfo.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeLSPS1OnchainPaymentInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Lsps1OnchainPaymentInfo? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeLSPS1OnchainPaymentInfo.read(buf) + } + + override fun allocationSize(value: Lsps1OnchainPaymentInfo?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeLSPS1OnchainPaymentInfo.allocationSize(value) + } + } + + override fun write(value: Lsps1OnchainPaymentInfo?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeLSPS1OnchainPaymentInfo.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeNodeAnnouncementInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): NodeAnnouncementInfo? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeNodeAnnouncementInfo.read(buf) + } + + override fun allocationSize(value: NodeAnnouncementInfo?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeNodeAnnouncementInfo.allocationSize(value) + } + } + + override fun write(value: NodeAnnouncementInfo?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeNodeAnnouncementInfo.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeNodeInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): NodeInfo? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeNodeInfo.read(buf) + } + + override fun allocationSize(value: NodeInfo?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeNodeInfo.allocationSize(value) + } + } + + override fun write(value: NodeInfo?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeNodeInfo.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeOutPoint: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): OutPoint? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeOutPoint.read(buf) + } + + override fun allocationSize(value: OutPoint?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeOutPoint.allocationSize(value) + } + } + + override fun write(value: OutPoint?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeOutPoint.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypePaymentDetails: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): PaymentDetails? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypePaymentDetails.read(buf) + } + + override fun allocationSize(value: PaymentDetails?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypePaymentDetails.allocationSize(value) + } + } + + override fun write(value: PaymentDetails?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypePaymentDetails.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeRouteParametersConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): RouteParametersConfig? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeRouteParametersConfig.read(buf) + } + + override fun allocationSize(value: RouteParametersConfig?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeRouteParametersConfig.allocationSize(value) + } + } + + override fun write(value: RouteParametersConfig?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeRouteParametersConfig.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeScoringDecayParameters: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ScoringDecayParameters? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeScoringDecayParameters.read(buf) + } + + override fun allocationSize(value: ScoringDecayParameters?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeScoringDecayParameters.allocationSize(value) + } + } + + override fun write(value: ScoringDecayParameters?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeScoringDecayParameters.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeScoringFeeParameters: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ScoringFeeParameters? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeScoringFeeParameters.read(buf) + } + + override fun allocationSize(value: ScoringFeeParameters?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeScoringFeeParameters.allocationSize(value) + } + } + + override fun write(value: ScoringFeeParameters?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeScoringFeeParameters.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeTransactionDetails: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): TransactionDetails? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeTransactionDetails.read(buf) + } + + override fun allocationSize(value: TransactionDetails?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeTransactionDetails.allocationSize(value) + } + } + + override fun write(value: TransactionDetails?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeTransactionDetails.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeAsyncPaymentsRole: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): AsyncPaymentsRole? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeAsyncPaymentsRole.read(buf) + } + + override fun allocationSize(value: AsyncPaymentsRole?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeAsyncPaymentsRole.allocationSize(value) + } + } + + override fun write(value: AsyncPaymentsRole?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeAsyncPaymentsRole.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeClosureReason: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ClosureReason? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeClosureReason.read(buf) + } + + override fun allocationSize(value: ClosureReason?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeClosureReason.allocationSize(value) + } + } + + override fun write(value: ClosureReason?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeClosureReason.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeEvent: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Event? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeEvent.read(buf) + } + + override fun allocationSize(value: Event?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeEvent.allocationSize(value) + } + } + + override fun write(value: Event?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeEvent.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeLogLevel: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): LogLevel? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeLogLevel.read(buf) + } + + override fun allocationSize(value: LogLevel?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeLogLevel.allocationSize(value) + } + } + + override fun write(value: LogLevel?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeLogLevel.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeNetwork: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Network? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeNetwork.read(buf) + } + + override fun allocationSize(value: Network?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeNetwork.allocationSize(value) + } + } + + override fun write(value: Network?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeNetwork.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeOfferAmount: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): OfferAmount? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeOfferAmount.read(buf) + } + + override fun allocationSize(value: OfferAmount?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeOfferAmount.allocationSize(value) + } + } + + override fun write(value: OfferAmount?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeOfferAmount.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypePaymentFailureReason: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): PaymentFailureReason? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypePaymentFailureReason.read(buf) + } + + override fun allocationSize(value: PaymentFailureReason?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypePaymentFailureReason.allocationSize(value) + } + } + + override fun write(value: PaymentFailureReason?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypePaymentFailureReason.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeWordCount: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): WordCount? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeWordCount.read(buf) + } + + override fun allocationSize(value: WordCount?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeWordCount.allocationSize(value) + } + } + + override fun write(value: WordCount?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeWordCount.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalSequenceUByte: FfiConverterRustBuffer?> { + override fun read(buf: ByteBuffer): List? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterSequenceUByte.read(buf) + } + + override fun allocationSize(value: List?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterSequenceUByte.allocationSize(value) + } + } + + override fun write(value: List?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterSequenceUByte.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalSequenceTypeSpendableUtxo: FfiConverterRustBuffer?> { + override fun read(buf: ByteBuffer): List? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterSequenceTypeSpendableUtxo.read(buf) + } + + override fun allocationSize(value: List?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterSequenceTypeSpendableUtxo.allocationSize(value) + } + } + + override fun write(value: List?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterSequenceTypeSpendableUtxo.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalSequenceSequenceUByte: FfiConverterRustBuffer>?> { + override fun read(buf: ByteBuffer): List>? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterSequenceSequenceUByte.read(buf) + } + + override fun allocationSize(value: List>?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterSequenceSequenceUByte.allocationSize(value) + } + } + + override fun write(value: List>?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterSequenceSequenceUByte.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalSequenceTypeSocketAddress: FfiConverterRustBuffer?> { + override fun read(buf: ByteBuffer): List? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterSequenceTypeSocketAddress.read(buf) + } + + override fun allocationSize(value: List?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterSequenceTypeSocketAddress.allocationSize(value) + } + } + + override fun write(value: List?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterSequenceTypeSocketAddress.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeAddress: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Address? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeAddress.read(buf) + } + + override fun allocationSize(value: Address?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeAddress.allocationSize(value) + } + } + + override fun write(value: Address?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeAddress.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeChannelId: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ChannelId? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeChannelId.read(buf) + } + + override fun allocationSize(value: ChannelId?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeChannelId.allocationSize(value) + } + } + + override fun write(value: ChannelId?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeChannelId.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeNodeAlias: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): NodeAlias? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeNodeAlias.read(buf) + } + + override fun allocationSize(value: NodeAlias?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeNodeAlias.allocationSize(value) + } + } + + override fun write(value: NodeAlias?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeNodeAlias.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypePaymentHash: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): PaymentHash? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypePaymentHash.read(buf) + } + + override fun allocationSize(value: PaymentHash?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypePaymentHash.allocationSize(value) + } + } + + override fun write(value: PaymentHash?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypePaymentHash.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypePaymentId: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): PaymentId? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypePaymentId.read(buf) + } + + override fun allocationSize(value: PaymentId?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypePaymentId.allocationSize(value) + } + } + + override fun write(value: PaymentId?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypePaymentId.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypePaymentPreimage: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): PaymentPreimage? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypePaymentPreimage.read(buf) + } + + override fun allocationSize(value: PaymentPreimage?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypePaymentPreimage.allocationSize(value) + } + } + + override fun write(value: PaymentPreimage?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypePaymentPreimage.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypePaymentSecret: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): PaymentSecret? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypePaymentSecret.read(buf) + } + + override fun allocationSize(value: PaymentSecret?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypePaymentSecret.allocationSize(value) + } + } + + override fun write(value: PaymentSecret?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypePaymentSecret.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypePublicKey: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): PublicKey? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypePublicKey.read(buf) + } + + override fun allocationSize(value: PublicKey?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypePublicKey.allocationSize(value) + } + } + + override fun write(value: PublicKey?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypePublicKey.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeUntrustedString: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): UntrustedString? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeUntrustedString.read(buf) + } + + override fun allocationSize(value: UntrustedString?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeUntrustedString.allocationSize(value) + } + } + + override fun write(value: UntrustedString?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeUntrustedString.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeUserChannelId: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): UserChannelId? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeUserChannelId.read(buf) + } + + override fun allocationSize(value: UserChannelId?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeUserChannelId.allocationSize(value) + } + } + + override fun write(value: UserChannelId?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeUserChannelId.write(value, buf) + } + } +} + + + + +object FfiConverterSequenceUByte: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterUByte.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterUByte.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterUByte.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceULong: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterULong.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterULong.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterULong.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceString: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterString.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterString.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterString.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeAddressInfo: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeAddressInfo.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeAddressInfo.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeAddressInfo.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeChannelDetails: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeChannelDetails.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeChannelDetails.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeChannelDetails.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeCustomTlvRecord: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeCustomTlvRecord.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeCustomTlvRecord.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeCustomTlvRecord.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeOnchainWalletAccount: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeOnchainWalletAccount.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeOnchainWalletAccount.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeOnchainWalletAccount.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeOnchainWalletAccountConfig: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeOnchainWalletAccountConfig.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeOnchainWalletAccountConfig.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeOnchainWalletAccountConfig.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypePaymentDetails: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypePaymentDetails.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypePaymentDetails.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypePaymentDetails.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypePeerDetails: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypePeerDetails.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypePeerDetails.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypePeerDetails.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeProbeHandle: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeProbeHandle.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeProbeHandle.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeProbeHandle.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeRouteHintHop: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeRouteHintHop.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeRouteHintHop.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeRouteHintHop.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeSpendableUtxo: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeSpendableUtxo.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeSpendableUtxo.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeSpendableUtxo.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeTxInput: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeTxInput.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeTxInput.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeTxInput.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeTxOutput: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeTxOutput.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeTxOutput.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeTxOutput.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeAddressType: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeAddressType.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeAddressType.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeAddressType.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeLightningBalance: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeLightningBalance.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeLightningBalance.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeLightningBalance.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeNetwork: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeNetwork.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeNetwork.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeNetwork.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypePendingSweepBalance: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypePendingSweepBalance.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypePendingSweepBalance.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypePendingSweepBalance.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceSequenceUByte: FfiConverterRustBuffer>> { + override fun read(buf: ByteBuffer): List> { + val len = buf.getInt() + return List>(len) { + FfiConverterSequenceUByte.read(buf) + } + } + + override fun allocationSize(value: List>): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterSequenceUByte.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List>, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterSequenceUByte.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceSequenceTypeRouteHintHop: FfiConverterRustBuffer>> { + override fun read(buf: ByteBuffer): List> { + val len = buf.getInt() + return List>(len) { + FfiConverterSequenceTypeRouteHintHop.read(buf) + } + } + + override fun allocationSize(value: List>): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterSequenceTypeRouteHintHop.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List>, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterSequenceTypeRouteHintHop.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeAddress: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List
{ + val len = buf.getInt() + return List
(len) { + FfiConverterTypeAddress.read(buf) + } + } + + override fun allocationSize(value: List
): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeAddress.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List
, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeAddress.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeNodeId: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeNodeId.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeNodeId.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeNodeId.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypePublicKey: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypePublicKey.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypePublicKey.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypePublicKey.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeSocketAddress: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeSocketAddress.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeSocketAddress.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeSocketAddress.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeTxid: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeTxid.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeTxid.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeTxid.write(it, buf) + } + } +} + + + +object FfiConverterMapStringString: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): Map { + val len = buf.getInt() + return buildMap(len) { + repeat(len) { + val k = FfiConverterString.read(buf) + val v = FfiConverterString.read(buf) + this[k] = v + } + } + } + + override fun allocationSize(value: Map): ULong { + val spaceForMapSize = 4UL + val spaceForChildren = value.entries.sumOf { (k, v) -> + FfiConverterString.allocationSize(k) + + FfiConverterString.allocationSize(v) + } + return spaceForMapSize + spaceForChildren + } + + override fun write(value: Map, buf: ByteBuffer) { + buf.putInt(value.size) + // The parens on `(k, v)` here ensure we're calling the right method, + // which is important for compatibility with older android devices. + // Ref https://blog.danlew.net/2017/03/16/kotlin-puzzler-whose-line-is-it-anyways/ + value.forEach { (k, v) -> + FfiConverterString.write(k, buf) + FfiConverterString.write(v, buf) + } + } +} + + + + +typealias FfiConverterTypeAddress = FfiConverterString + + + + +typealias FfiConverterTypeBlockHash = FfiConverterString + + + + +typealias FfiConverterTypeChannelId = FfiConverterString + + + + +typealias FfiConverterTypeLSPS1OrderId = FfiConverterString + + + + +typealias FfiConverterTypeLSPSDateTime = FfiConverterString + + + + +typealias FfiConverterTypeMnemonic = FfiConverterString + + + + +typealias FfiConverterTypeNodeAlias = FfiConverterString + + + + +typealias FfiConverterTypeNodeId = FfiConverterString + + + + +typealias FfiConverterTypeOfferId = FfiConverterString + + + + +typealias FfiConverterTypePaymentHash = FfiConverterString + + + + +typealias FfiConverterTypePaymentId = FfiConverterString + + + + +typealias FfiConverterTypePaymentPreimage = FfiConverterString + + + + +typealias FfiConverterTypePaymentSecret = FfiConverterString + + + + +typealias FfiConverterTypePublicKey = FfiConverterString + + + + +typealias FfiConverterTypeSocketAddress = FfiConverterString + + + + +typealias FfiConverterTypeTxid = FfiConverterString + + + + +typealias FfiConverterTypeUntrustedString = FfiConverterString + + + + +typealias FfiConverterTypeUserChannelId = FfiConverterString + + + + + + + + + + + + + +fun `batterySavingSyncIntervals`(): RuntimeSyncIntervals { + return FfiConverterTypeRuntimeSyncIntervals.lift(uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_func_battery_saving_sync_intervals( + uniffiRustCallStatus, + ) + }) +} + +fun `defaultConfig`(): Config { + return FfiConverterTypeConfig.lift(uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_func_default_config( + uniffiRustCallStatus, + ) + }) +} + +@Throws(NodeException::class) +fun `deriveNodeSecretFromMnemonic`(`mnemonic`: kotlin.String, `passphrase`: kotlin.String?): List { + return FfiConverterSequenceUByte.lift(uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_func_derive_node_secret_from_mnemonic( + FfiConverterString.lower(`mnemonic`), + FfiConverterOptionalString.lower(`passphrase`), + uniffiRustCallStatus, + ) + }) +} + +fun `generateEntropyMnemonic`(`wordCount`: WordCount?): Mnemonic { + return FfiConverterTypeMnemonic.lift(uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_func_generate_entropy_mnemonic( + FfiConverterOptionalTypeWordCount.lower(`wordCount`), + uniffiRustCallStatus, + ) + }) +} + + +// Async support + +internal const val UNIFFI_RUST_FUTURE_POLL_READY = 0.toByte() +internal const val UNIFFI_RUST_FUTURE_POLL_MAYBE_READY = 1.toByte() + +internal val uniffiContinuationHandleMap = UniffiHandleMap>() + +// FFI type for Rust future continuations +internal suspend fun uniffiRustCallAsync( + rustFuture: Long, + pollFunc: (Long, UniffiRustFutureContinuationCallback, Long) -> Unit, + completeFunc: (Long, UniffiRustCallStatus) -> F, + freeFunc: (Long) -> Unit, + cancelFunc: (Long) -> Unit, + liftFunc: (F) -> T, + errorHandler: UniffiRustCallStatusErrorHandler +): T { + return withContext(Dispatchers.IO) { + try { + do { + val pollResult = suspendCancellableCoroutine { continuation -> + val handle = uniffiContinuationHandleMap.insert(continuation) + continuation.invokeOnCancellation { + cancelFunc(rustFuture) + } + pollFunc( + rustFuture, + uniffiRustFutureContinuationCallbackCallback, + handle + ) + } + } while (pollResult != UNIFFI_RUST_FUTURE_POLL_READY); + + return@withContext liftFunc( + uniffiRustCallWithError(errorHandler) { status -> completeFunc(rustFuture, status) } + ) + } finally { + freeFunc(rustFuture) + } + } +} + +object uniffiRustFutureContinuationCallbackCallback: UniffiRustFutureContinuationCallback { + override fun callback(data: Long, pollResult: Byte) { + uniffiContinuationHandleMap.remove(data).resume(pollResult) + } +} diff --git a/bindings/kotlin/ldk-node-android/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.common.kt b/bindings/kotlin/ldk-node-android/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.common.kt new file mode 100644 index 0000000000..c51632c07a --- /dev/null +++ b/bindings/kotlin/ldk-node-android/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.common.kt @@ -0,0 +1,2575 @@ + + +@file:Suppress("RemoveRedundantBackticks") + +package org.lightningdevkit.ldknode + +// Common helper code. +// +// Ideally this would live in a separate .kt file where it can be unittested etc +// in isolation, and perhaps even published as a re-useable package. +// +// However, it's important that the details of how this helper code works (e.g. the +// way that different builtin types are passed across the FFI) exactly match what's +// expected by the Rust code on the other side of the interface. In practice right +// now that means coming from the exact some version of `uniffi` that was used to +// compile the Rust component. The easiest way to ensure this is to bundle the Kotlin +// helpers directly inline like we're doing here. + +class InternalException(message: String) : kotlin.Exception(message) + +// Public interface members begin here. + + +// Interface implemented by anything that can contain an object reference. +// +// Such types expose a `destroy()` method that must be called to cleanly +// dispose of the contained objects. Failure to call this method may result +// in memory leaks. +// +// The easiest way to ensure this method is called is to use the `.use` +// helper method to execute a block and destroy the object at the end. +@OptIn(ExperimentalStdlibApi::class) +interface Disposable : AutoCloseable { + fun destroy() + override fun close() = destroy() + companion object { + internal fun destroy(vararg args: Any?) { + for (arg in args) { + when (arg) { + is Disposable -> arg.destroy() + is Iterable<*> -> { + for (element in arg) { + if (element is Disposable) { + element.destroy() + } + } + } + is Map<*, *> -> { + for (element in arg.values) { + if (element is Disposable) { + element.destroy() + } + } + } + is Array<*> -> { + for (element in arg) { + if (element is Disposable) { + element.destroy() + } + } + } + } + } + } + } +} + +@OptIn(kotlin.contracts.ExperimentalContracts::class) +inline fun T.use(block: (T) -> R): R { + kotlin.contracts.contract { + callsInPlace(block, kotlin.contracts.InvocationKind.EXACTLY_ONCE) + } + return try { + block(this) + } finally { + try { + // N.B. our implementation is on the nullable type `Disposable?`. + this?.destroy() + } catch (e: Throwable) { + // swallow + } + } +} + +/** Used to instantiate an interface without an actual pointer, for fakes in tests, mostly. */ +object NoPointer + + + + + + + + + + + + + + + + + + + +interface Bolt11InvoiceInterface { + + fun `amountMilliSatoshis`(): kotlin.ULong? + + fun `currency`(): Currency + + fun `expiryTimeSeconds`(): kotlin.ULong + + fun `fallbackAddresses`(): List
+ + fun `invoiceDescription`(): Bolt11InvoiceDescription + + fun `isExpired`(): kotlin.Boolean + + fun `minFinalCltvExpiryDelta`(): kotlin.ULong + + fun `network`(): Network + + fun `paymentHash`(): PaymentHash + + fun `paymentSecret`(): PaymentSecret + + fun `recoverPayeePubKey`(): PublicKey + + fun `routeHints`(): List> + + fun `secondsSinceEpoch`(): kotlin.ULong + + fun `secondsUntilExpiry`(): kotlin.ULong + + fun `signableHash`(): List + + fun `wouldExpire`(`atTimeSeconds`: kotlin.ULong): kotlin.Boolean + + companion object +} + + + + +interface Bolt11PaymentInterface { + + @Throws(NodeException::class) + fun `claimForHash`(`paymentHash`: PaymentHash, `claimableAmountMsat`: kotlin.ULong, `preimage`: PaymentPreimage) + + @Throws(NodeException::class) + fun `estimateRoutingFees`(`invoice`: Bolt11Invoice): kotlin.ULong + + @Throws(NodeException::class) + fun `estimateRoutingFeesUsingAmount`(`invoice`: Bolt11Invoice, `amountMsat`: kotlin.ULong): kotlin.ULong + + @Throws(NodeException::class) + fun `failForHash`(`paymentHash`: PaymentHash) + + @Throws(NodeException::class) + fun `receive`(`amountMsat`: kotlin.ULong, `description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt): Bolt11Invoice + + @Throws(NodeException::class) + fun `receiveForHash`(`amountMsat`: kotlin.ULong, `description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt, `paymentHash`: PaymentHash): Bolt11Invoice + + @Throws(NodeException::class) + fun `receiveVariableAmount`(`description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt): Bolt11Invoice + + @Throws(NodeException::class) + fun `receiveVariableAmountForHash`(`description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt, `paymentHash`: PaymentHash): Bolt11Invoice + + @Throws(NodeException::class) + fun `receiveVariableAmountViaJitChannel`(`description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt, `maxProportionalLspFeeLimitPpmMsat`: kotlin.ULong?): Bolt11Invoice + + @Throws(NodeException::class) + fun `receiveVariableAmountViaJitChannelForHash`(`description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt, `maxProportionalLspFeeLimitPpmMsat`: kotlin.ULong?, `paymentHash`: PaymentHash): Bolt11Invoice + + @Throws(NodeException::class) + fun `receiveViaJitChannel`(`amountMsat`: kotlin.ULong, `description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt, `maxLspFeeLimitMsat`: kotlin.ULong?): Bolt11Invoice + + @Throws(NodeException::class) + fun `receiveViaJitChannelForHash`(`amountMsat`: kotlin.ULong, `description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt, `maxLspFeeLimitMsat`: kotlin.ULong?, `paymentHash`: PaymentHash): Bolt11Invoice + + @Throws(NodeException::class) + fun `send`(`invoice`: Bolt11Invoice, `routeParameters`: RouteParametersConfig?): PaymentId + + @Throws(NodeException::class) + fun `sendProbes`(`invoice`: Bolt11Invoice, `routeParameters`: RouteParametersConfig?): List + + @Throws(NodeException::class) + fun `sendProbesUsingAmount`(`invoice`: Bolt11Invoice, `amountMsat`: kotlin.ULong, `routeParameters`: RouteParametersConfig?): List + + @Throws(NodeException::class) + fun `sendUsingAmount`(`invoice`: Bolt11Invoice, `amountMsat`: kotlin.ULong, `routeParameters`: RouteParametersConfig?): PaymentId + + companion object +} + + + + +interface Bolt12InvoiceInterface { + + fun `absoluteExpirySeconds`(): kotlin.ULong? + + fun `amount`(): OfferAmount? + + fun `amountMsats`(): kotlin.ULong + + fun `chain`(): List + + fun `createdAt`(): kotlin.ULong + + fun `encode`(): List + + fun `fallbackAddresses`(): List
+ + fun `invoiceDescription`(): kotlin.String? + + fun `isExpired`(): kotlin.Boolean + + fun `issuer`(): kotlin.String? + + fun `issuerSigningPubkey`(): PublicKey? + + fun `metadata`(): List? + + fun `offerChains`(): List>? + + fun `payerNote`(): kotlin.String? + + fun `payerSigningPubkey`(): PublicKey + + fun `paymentHash`(): PaymentHash + + fun `quantity`(): kotlin.ULong? + + fun `relativeExpiry`(): kotlin.ULong + + fun `signableHash`(): List + + fun `signingPubkey`(): PublicKey + + companion object +} + + + + +interface Bolt12PaymentInterface { + + @Throws(NodeException::class) + fun `blindedPathsForAsyncRecipient`(`recipientId`: kotlin.ByteArray): kotlin.ByteArray + + @Throws(NodeException::class) + fun `initiateRefund`(`amountMsat`: kotlin.ULong, `expirySecs`: kotlin.UInt, `quantity`: kotlin.ULong?, `payerNote`: kotlin.String?, `routeParameters`: RouteParametersConfig?): Refund + + @Throws(NodeException::class) + fun `receive`(`amountMsat`: kotlin.ULong, `description`: kotlin.String, `expirySecs`: kotlin.UInt?, `quantity`: kotlin.ULong?): Offer + + @Throws(NodeException::class) + fun `receiveAsync`(): Offer + + @Throws(NodeException::class) + fun `receiveVariableAmount`(`description`: kotlin.String, `expirySecs`: kotlin.UInt?): Offer + + @Throws(NodeException::class) + fun `requestRefundPayment`(`refund`: Refund): Bolt12Invoice + + @Throws(NodeException::class) + fun `send`(`offer`: Offer, `quantity`: kotlin.ULong?, `payerNote`: kotlin.String?, `routeParameters`: RouteParametersConfig?): PaymentId + + @Throws(NodeException::class) + fun `sendUsingAmount`(`offer`: Offer, `amountMsat`: kotlin.ULong, `quantity`: kotlin.ULong?, `payerNote`: kotlin.String?, `routeParameters`: RouteParametersConfig?): PaymentId + + @Throws(NodeException::class) + fun `setPathsToStaticInvoiceServer`(`paths`: kotlin.ByteArray) + + companion object +} + + + + +interface BuilderInterface { + + @Throws(BuildException::class) + fun `build`(): Node + + @Throws(BuildException::class) + fun `buildWithFsStore`(): Node + + @Throws(BuildException::class) + fun `buildWithVssStore`(`vssUrl`: kotlin.String, `storeId`: kotlin.String, `lnurlAuthServerUrl`: kotlin.String, `fixedHeaders`: Map): Node + + @Throws(BuildException::class) + fun `buildWithVssStoreAndFixedHeaders`(`vssUrl`: kotlin.String, `storeId`: kotlin.String, `fixedHeaders`: Map): Node + + @Throws(BuildException::class) + fun `buildWithVssStoreAndHeaderProvider`(`vssUrl`: kotlin.String, `storeId`: kotlin.String, `headerProvider`: VssHeaderProvider): Node + + fun `setAddressType`(`addressType`: AddressType) + + fun `setAddressTypesToMonitor`(`addressTypesToMonitor`: List) + + @Throws(BuildException::class) + fun `setAnnouncementAddresses`(`announcementAddresses`: List) + + @Throws(BuildException::class) + fun `setAsyncPaymentsRole`(`role`: AsyncPaymentsRole?) + + fun `setChainSourceBitcoindRest`(`restHost`: kotlin.String, `restPort`: kotlin.UShort, `rpcHost`: kotlin.String, `rpcPort`: kotlin.UShort, `rpcUser`: kotlin.String, `rpcPassword`: kotlin.String) + + fun `setChainSourceBitcoindRpc`(`rpcHost`: kotlin.String, `rpcPort`: kotlin.UShort, `rpcUser`: kotlin.String, `rpcPassword`: kotlin.String) + + fun `setChainSourceElectrum`(`serverUrl`: kotlin.String, `config`: ElectrumSyncConfig?) + + fun `setChainSourceEsplora`(`serverUrl`: kotlin.String, `config`: EsploraSyncConfig?) + + fun `setChannelDataMigration`(`migration`: ChannelDataMigration) + + fun `setCustomLogger`(`logWriter`: LogWriter) + + fun `setEntropyBip39Mnemonic`(`mnemonic`: Mnemonic, `passphrase`: kotlin.String?) + + @Throws(BuildException::class) + fun `setEntropySeedBytes`(`seedBytes`: List) + + fun `setEntropySeedPath`(`seedPath`: kotlin.String) + + fun `setFilesystemLogger`(`logFilePath`: kotlin.String?, `maxLogLevel`: LogLevel?) + + fun `setGossipSourceP2p`() + + fun `setGossipSourceRgs`(`rgsServerUrl`: kotlin.String) + + fun `setLiquiditySourceLsps1`(`nodeId`: PublicKey, `address`: SocketAddress, `token`: kotlin.String?) + + fun `setLiquiditySourceLsps2`(`nodeId`: PublicKey, `address`: SocketAddress, `token`: kotlin.String?) + + @Throws(BuildException::class) + fun `setListeningAddresses`(`listeningAddresses`: List) + + fun `setLogFacadeLogger`() + + fun `setNetwork`(`network`: Network) + + @Throws(BuildException::class) + fun `setNodeAlias`(`nodeAlias`: kotlin.String) + + fun `setPathfindingScoresSource`(`url`: kotlin.String) + + fun `setScoringDecayParams`(`params`: ScoringDecayParameters) + + fun `setScoringFeeParams`(`params`: ScoringFeeParameters) + + fun `setStorageDirPath`(`storageDirPath`: kotlin.String) + + companion object +} + + + + +interface FeeRateInterface { + + fun `toSatPerKwu`(): kotlin.ULong + + fun `toSatPerVbCeil`(): kotlin.ULong + + fun `toSatPerVbFloor`(): kotlin.ULong + + companion object +} + + + + +interface Lsps1LiquidityInterface { + + @Throws(NodeException::class) + fun `checkOrderStatus`(`orderId`: Lsps1OrderId): Lsps1OrderStatus + + @Throws(NodeException::class) + fun `requestChannel`(`lspBalanceSat`: kotlin.ULong, `clientBalanceSat`: kotlin.ULong, `channelExpiryBlocks`: kotlin.UInt, `announceChannel`: kotlin.Boolean): Lsps1OrderStatus + + companion object +} + + + + +interface LogWriter { + + fun `log`(`record`: LogRecord) + + companion object +} + + + + +interface NetworkGraphInterface { + + fun `channel`(`shortChannelId`: kotlin.ULong): ChannelInfo? + + fun `listChannels`(): List + + fun `listNodes`(): List + + fun `node`(`nodeId`: NodeId): NodeInfo? + + companion object +} + + + + +interface NodeInterface { + + @Throws(NodeException::class) + fun `addAddressTypeToMonitor`(`addressType`: AddressType, `seedBytes`: List) + + @Throws(NodeException::class) + fun `addAddressTypeToMonitorWithMnemonic`(`addressType`: AddressType, `mnemonic`: Mnemonic, `passphrase`: kotlin.String?) + + @Throws(NodeException::class) + fun `addOnchainWalletAccount`(`addressType`: AddressType, `accountIndex`: kotlin.UInt, `xpub`: kotlin.String) + + fun `announcementAddresses`(): List? + + fun `bolt11Payment`(): Bolt11Payment + + fun `bolt12Payment`(): Bolt12Payment + + @Throws(NodeException::class) + fun `closeChannel`(`userChannelId`: UserChannelId, `counterpartyNodeId`: PublicKey) + + fun `config`(): Config + + @Throws(NodeException::class) + fun `connect`(`nodeId`: PublicKey, `address`: SocketAddress, `persist`: kotlin.Boolean) + + fun `currentSyncIntervals`(): RuntimeSyncIntervals + + @Throws(NodeException::class) + fun `disconnect`(`nodeId`: PublicKey) + + @Throws(NodeException::class) + fun `eventHandled`() + + @Throws(NodeException::class) + fun `exportOnchainWalletAccountXpub`(`addressType`: AddressType, `accountIndex`: kotlin.UInt): kotlin.String + + @Throws(NodeException::class) + fun `exportPathfindingScores`(): kotlin.ByteArray + + @Throws(NodeException::class) + fun `forceCloseChannel`(`userChannelId`: UserChannelId, `counterpartyNodeId`: PublicKey, `reason`: kotlin.String?) + + @Throws(NodeException::class) + fun `getAddressBalance`(`addressStr`: kotlin.String): kotlin.ULong + + @Throws(NodeException::class) + fun `getBalanceForAddressType`(`addressType`: AddressType): AddressTypeBalance + + @Throws(NodeException::class) + fun `getBalanceForOnchainWalletAccount`(`addressType`: AddressType, `accountIndex`: kotlin.UInt): AddressTypeBalance + + fun `getTransactionDetails`(`txid`: Txid): TransactionDetails? + + fun `listBalances`(): BalanceDetails + + fun `listChannels`(): List + + fun `listMonitoredAddressTypes`(): List + + fun `listOnchainWalletAccounts`(): List + + fun `listPayments`(): List + + fun `listPeers`(): List + + fun `listeningAddresses`(): List? + + fun `lsps1Liquidity`(): Lsps1Liquidity + + fun `networkGraph`(): NetworkGraph + + fun `nextEvent`(): Event? + + suspend fun `nextEventAsync`(): Event + + fun `nodeAlias`(): NodeAlias? + + fun `nodeId`(): PublicKey + + fun `onchainPayment`(): OnchainPayment + + @Throws(NodeException::class) + fun `openAnnouncedChannel`(`nodeId`: PublicKey, `address`: SocketAddress, `channelAmountSats`: kotlin.ULong, `pushToCounterpartyMsat`: kotlin.ULong?, `channelConfig`: ChannelConfig?): UserChannelId + + @Throws(NodeException::class) + fun `openChannel`(`nodeId`: PublicKey, `address`: SocketAddress, `channelAmountSats`: kotlin.ULong, `pushToCounterpartyMsat`: kotlin.ULong?, `channelConfig`: ChannelConfig?): UserChannelId + + fun `payment`(`paymentId`: PaymentId): PaymentDetails? + + @Throws(NodeException::class) + fun `removeAddressTypeFromMonitor`(`addressType`: AddressType) + + @Throws(NodeException::class) + fun `removeOnchainWalletAccount`(`addressType`: AddressType, `accountIndex`: kotlin.UInt) + + @Throws(NodeException::class) + fun `removePayment`(`paymentId`: PaymentId) + + @Throws(NodeException::class) + fun `setPrimaryAddressType`(`addressType`: AddressType, `seedBytes`: List) + + @Throws(NodeException::class) + fun `setPrimaryAddressTypeWithMnemonic`(`addressType`: AddressType, `mnemonic`: Mnemonic, `passphrase`: kotlin.String?) + + fun `signMessage`(`msg`: List): kotlin.String + + @Throws(NodeException::class) + fun `spliceIn`(`userChannelId`: UserChannelId, `counterpartyNodeId`: PublicKey, `spliceAmountSats`: kotlin.ULong) + + @Throws(NodeException::class) + fun `spliceOut`(`userChannelId`: UserChannelId, `counterpartyNodeId`: PublicKey, `address`: Address, `spliceAmountSats`: kotlin.ULong) + + fun `spontaneousPayment`(): SpontaneousPayment + + @Throws(NodeException::class) + fun `start`() + + fun `status`(): NodeStatus + + @Throws(NodeException::class) + fun `stop`() + + @Throws(NodeException::class) + fun `syncWallets`() + + fun `unifiedQrPayment`(): UnifiedQrPayment + + @Throws(NodeException::class) + fun `updateChannelConfig`(`userChannelId`: UserChannelId, `counterpartyNodeId`: PublicKey, `channelConfig`: ChannelConfig) + + @Throws(NodeException::class) + fun `updateSyncIntervals`(`intervals`: RuntimeSyncIntervals) + + fun `verifySignature`(`msg`: List, `sig`: kotlin.String, `pkey`: PublicKey): kotlin.Boolean + + fun `waitNextEvent`(): Event + + companion object +} + + + + +interface OfferInterface { + + fun `absoluteExpirySeconds`(): kotlin.ULong? + + fun `amount`(): OfferAmount? + + fun `chains`(): List + + fun `expectsQuantity`(): kotlin.Boolean + + fun `id`(): OfferId + + fun `isExpired`(): kotlin.Boolean + + fun `isValidQuantity`(`quantity`: kotlin.ULong): kotlin.Boolean + + fun `issuer`(): kotlin.String? + + fun `issuerSigningPubkey`(): PublicKey? + + fun `metadata`(): List? + + fun `offerDescription`(): kotlin.String? + + fun `supportsChain`(`chain`: Network): kotlin.Boolean + + companion object +} + + + + +interface OnchainPaymentInterface { + + @Throws(NodeException::class) + fun `accelerateByCpfp`(`txid`: Txid, `feeRate`: FeeRate?, `destinationAddress`: Address?): Txid + + @Throws(NodeException::class) + fun `addressInfoForAccountAtIndex`(`addressType`: AddressType, `accountIndex`: kotlin.UInt, `keychain`: KeychainKind, `index`: kotlin.UInt): AddressInfo + + @Throws(NodeException::class) + fun `addressInfoForTypeAtIndex`(`addressType`: AddressType, `keychain`: KeychainKind, `index`: kotlin.UInt): AddressInfo + + @Throws(NodeException::class) + fun `addressInfosForAccount`(`addressType`: AddressType, `accountIndex`: kotlin.UInt, `keychain`: KeychainKind, `startIndex`: kotlin.UInt, `count`: kotlin.UInt): List + + @Throws(NodeException::class) + fun `addressInfosForType`(`addressType`: AddressType, `keychain`: KeychainKind, `startIndex`: kotlin.UInt, `count`: kotlin.UInt): List + + @Throws(NodeException::class) + fun `bumpFeeByRbf`(`txid`: Txid, `feeRate`: FeeRate): Txid + + @Throws(NodeException::class) + fun `calculateCpfpFeeRate`(`parentTxid`: Txid, `urgent`: kotlin.Boolean): FeeRate + + @Throws(NodeException::class) + fun `calculateSendAllFee`(`address`: Address, `retainReserves`: kotlin.Boolean, `feeRate`: FeeRate?): kotlin.ULong + + @Throws(NodeException::class) + fun `calculateTotalFee`(`address`: Address, `amountSats`: kotlin.ULong, `feeRate`: FeeRate?, `utxosToSpend`: List?): kotlin.ULong + + @Throws(NodeException::class) + fun `listSpendableOutputs`(): List + + @Throws(NodeException::class) + fun `newAddress`(): Address + + @Throws(NodeException::class) + fun `newAddressForAccount`(`addressType`: AddressType, `accountIndex`: kotlin.UInt): Address + + @Throws(NodeException::class) + fun `newAddressForType`(`addressType`: AddressType): Address + + @Throws(NodeException::class) + fun `newAddressInfo`(): AddressInfo + + @Throws(NodeException::class) + fun `newAddressInfoForAccount`(`addressType`: AddressType, `accountIndex`: kotlin.UInt): AddressInfo + + @Throws(NodeException::class) + fun `newAddressInfoForType`(`addressType`: AddressType): AddressInfo + + @Throws(NodeException::class) + fun `revealReceiveAddressesTo`(`addressType`: AddressType, `index`: kotlin.UInt) + + @Throws(NodeException::class) + fun `revealReceiveAddressesToAccount`(`addressType`: AddressType, `accountIndex`: kotlin.UInt, `index`: kotlin.UInt) + + @Throws(NodeException::class) + fun `selectUtxosWithAlgorithm`(`targetAmountSats`: kotlin.ULong, `feeRate`: FeeRate?, `algorithm`: CoinSelectionAlgorithm, `utxos`: List?): List + + @Throws(NodeException::class) + fun `sendAllToAddress`(`address`: Address, `retainReserve`: kotlin.Boolean, `feeRate`: FeeRate?): Txid + + @Throws(NodeException::class) + fun `sendToAddress`(`address`: Address, `amountSats`: kotlin.ULong, `feeRate`: FeeRate?, `utxosToSpend`: List?): Txid + + companion object +} + + + + +interface RefundInterface { + + fun `absoluteExpirySeconds`(): kotlin.ULong? + + fun `amountMsats`(): kotlin.ULong + + fun `chain`(): Network? + + fun `isExpired`(): kotlin.Boolean + + fun `issuer`(): kotlin.String? + + fun `payerMetadata`(): List + + fun `payerNote`(): kotlin.String? + + fun `payerSigningPubkey`(): PublicKey + + fun `quantity`(): kotlin.ULong? + + fun `refundDescription`(): kotlin.String + + companion object +} + + + + +interface SpontaneousPaymentInterface { + + @Throws(NodeException::class) + fun `send`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey, `routeParameters`: RouteParametersConfig?): PaymentId + + @Throws(NodeException::class) + fun `sendProbes`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey): List + + @Throws(NodeException::class) + fun `sendWithCustomTlvs`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey, `routeParameters`: RouteParametersConfig?, `customTlvs`: List): PaymentId + + @Throws(NodeException::class) + fun `sendWithPreimage`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey, `preimage`: PaymentPreimage, `routeParameters`: RouteParametersConfig?): PaymentId + + @Throws(NodeException::class) + fun `sendWithPreimageAndCustomTlvs`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey, `customTlvs`: List, `preimage`: PaymentPreimage, `routeParameters`: RouteParametersConfig?): PaymentId + + companion object +} + + + + +interface UnifiedQrPaymentInterface { + + @Throws(NodeException::class) + fun `receive`(`amountSats`: kotlin.ULong, `message`: kotlin.String, `expirySec`: kotlin.UInt): kotlin.String + + @Throws(NodeException::class) + fun `send`(`uriStr`: kotlin.String, `routeParameters`: RouteParametersConfig?): QrPaymentResult + + companion object +} + + + + +interface VssHeaderProviderInterface { + + @Throws(VssHeaderProviderException::class, kotlin.coroutines.cancellation.CancellationException::class) + suspend fun `getHeaders`(`request`: List): Map + + companion object +} + + + + +@kotlinx.serialization.Serializable +data class AddressInfo ( + val `index`: kotlin.UInt, + val `address`: Address, + val `keychain`: KeychainKind +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class AddressTypeBalance ( + val `totalSats`: kotlin.ULong, + val `spendableSats`: kotlin.ULong +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class AnchorChannelsConfig ( + val `trustedPeersNoReserve`: List, + val `perChannelReserveSats`: kotlin.ULong +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class BackgroundSyncConfig ( + val `onchainWalletSyncIntervalSecs`: kotlin.ULong, + val `lightningWalletSyncIntervalSecs`: kotlin.ULong, + val `feeRateCacheUpdateIntervalSecs`: kotlin.ULong +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class BalanceDetails ( + val `totalOnchainBalanceSats`: kotlin.ULong, + val `spendableOnchainBalanceSats`: kotlin.ULong, + val `totalAnchorChannelsReserveSats`: kotlin.ULong, + val `totalLightningBalanceSats`: kotlin.ULong, + val `lightningBalances`: List, + val `pendingBalancesFromChannelClosures`: List +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class BestBlock ( + val `blockHash`: BlockHash, + val `height`: kotlin.UInt +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class ChannelConfig ( + val `forwardingFeeProportionalMillionths`: kotlin.UInt, + val `forwardingFeeBaseMsat`: kotlin.UInt, + val `cltvExpiryDelta`: kotlin.UShort, + val `maxDustHtlcExposure`: MaxDustHtlcExposure, + val `forceCloseAvoidanceMaxFeeSatoshis`: kotlin.ULong, + val `acceptUnderpayingHtlcs`: kotlin.Boolean +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class ChannelDataMigration ( + val `channelManager`: List?, + val `channelMonitors`: List> +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class ChannelDetails ( + val `channelId`: ChannelId, + val `counterpartyNodeId`: PublicKey, + val `fundingTxo`: OutPoint?, + val `shortChannelId`: kotlin.ULong?, + val `outboundScidAlias`: kotlin.ULong?, + val `inboundScidAlias`: kotlin.ULong?, + val `channelValueSats`: kotlin.ULong, + val `unspendablePunishmentReserve`: kotlin.ULong?, + val `userChannelId`: UserChannelId, + val `feerateSatPer1000Weight`: kotlin.UInt, + val `outboundCapacityMsat`: kotlin.ULong, + val `inboundCapacityMsat`: kotlin.ULong, + val `confirmationsRequired`: kotlin.UInt?, + val `confirmations`: kotlin.UInt?, + val `isOutbound`: kotlin.Boolean, + val `isChannelReady`: kotlin.Boolean, + val `isUsable`: kotlin.Boolean, + val `isAnnounced`: kotlin.Boolean, + val `cltvExpiryDelta`: kotlin.UShort?, + val `counterpartyUnspendablePunishmentReserve`: kotlin.ULong, + val `counterpartyOutboundHtlcMinimumMsat`: kotlin.ULong?, + val `counterpartyOutboundHtlcMaximumMsat`: kotlin.ULong?, + val `counterpartyForwardingInfoFeeBaseMsat`: kotlin.UInt?, + val `counterpartyForwardingInfoFeeProportionalMillionths`: kotlin.UInt?, + val `counterpartyForwardingInfoCltvExpiryDelta`: kotlin.UShort?, + val `nextOutboundHtlcLimitMsat`: kotlin.ULong, + val `nextOutboundHtlcMinimumMsat`: kotlin.ULong, + val `forceCloseSpendDelay`: kotlin.UShort?, + val `inboundHtlcMinimumMsat`: kotlin.ULong, + val `inboundHtlcMaximumMsat`: kotlin.ULong?, + val `config`: ChannelConfig, + val `claimableOnCloseSats`: kotlin.ULong? +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class ChannelInfo ( + val `nodeOne`: NodeId, + val `oneToTwo`: ChannelUpdateInfo?, + val `nodeTwo`: NodeId, + val `twoToOne`: ChannelUpdateInfo?, + val `capacitySats`: kotlin.ULong? +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class ChannelUpdateInfo ( + val `lastUpdate`: kotlin.UInt, + val `enabled`: kotlin.Boolean, + val `cltvExpiryDelta`: kotlin.UShort, + val `htlcMinimumMsat`: kotlin.ULong, + val `htlcMaximumMsat`: kotlin.ULong, + val `fees`: RoutingFees +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class Config ( + val `storageDirPath`: kotlin.String, + val `network`: Network, + val `listeningAddresses`: List?, + val `announcementAddresses`: List?, + val `nodeAlias`: NodeAlias?, + val `trustedPeers0conf`: List, + val `probingLiquidityLimitMultiplier`: kotlin.ULong, + val `anchorChannelsConfig`: AnchorChannelsConfig?, + val `routeParameters`: RouteParametersConfig?, + val `scoringFeeParams`: ScoringFeeParameters?, + val `scoringDecayParams`: ScoringDecayParameters?, + val `includeUntrustedPendingInSpendable`: kotlin.Boolean, + val `addressType`: AddressType, + val `addressTypesToMonitor`: List, + val `onchainWalletAccounts`: List +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class CustomTlvRecord ( + val `typeNum`: kotlin.ULong, + val `value`: List +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class ElectrumSyncConfig ( + val `backgroundSyncConfig`: BackgroundSyncConfig?, + val `connectionTimeoutSecs`: kotlin.ULong, + val `additionalWalletFullScanBatchSize`: kotlin.UInt, + val `additionalWalletFullScanStopGap`: kotlin.UInt +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class EsploraSyncConfig ( + val `backgroundSyncConfig`: BackgroundSyncConfig? +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class LspFeeLimits ( + val `maxTotalOpeningFeeMsat`: kotlin.ULong?, + val `maxProportionalOpeningFeePpmMsat`: kotlin.ULong? +) { + companion object +} + + + + +data class Lsps1Bolt11PaymentInfo ( + val `state`: Lsps1PaymentState, + val `expiresAt`: LspsDateTime, + val `feeTotalSat`: kotlin.ULong, + val `orderTotalSat`: kotlin.ULong, + val `invoice`: Bolt11Invoice +) : Disposable { + override fun destroy() { + Disposable.destroy( + this.`state`, + this.`expiresAt`, + this.`feeTotalSat`, + this.`orderTotalSat`, + this.`invoice`, + ) + } + companion object +} + + + +@kotlinx.serialization.Serializable +data class Lsps1ChannelInfo ( + val `fundedAt`: LspsDateTime, + val `fundingOutpoint`: OutPoint, + val `expiresAt`: LspsDateTime +) { + companion object +} + + + + +data class Lsps1OnchainPaymentInfo ( + val `state`: Lsps1PaymentState, + val `expiresAt`: LspsDateTime, + val `feeTotalSat`: kotlin.ULong, + val `orderTotalSat`: kotlin.ULong, + val `address`: Address, + val `minOnchainPaymentConfirmations`: kotlin.UShort?, + val `minFeeFor0conf`: FeeRate, + val `refundOnchainAddress`: Address? +) : Disposable { + override fun destroy() { + Disposable.destroy( + this.`state`, + this.`expiresAt`, + this.`feeTotalSat`, + this.`orderTotalSat`, + this.`address`, + this.`minOnchainPaymentConfirmations`, + this.`minFeeFor0conf`, + this.`refundOnchainAddress`, + ) + } + companion object +} + + + +@kotlinx.serialization.Serializable +data class Lsps1OrderParams ( + val `lspBalanceSat`: kotlin.ULong, + val `clientBalanceSat`: kotlin.ULong, + val `requiredChannelConfirmations`: kotlin.UShort, + val `fundingConfirmsWithinBlocks`: kotlin.UShort, + val `channelExpiryBlocks`: kotlin.UInt, + val `token`: kotlin.String?, + val `announceChannel`: kotlin.Boolean +) { + companion object +} + + + + +data class Lsps1OrderStatus ( + val `orderId`: Lsps1OrderId, + val `orderParams`: Lsps1OrderParams, + val `paymentOptions`: Lsps1PaymentInfo, + val `channelState`: Lsps1ChannelInfo? +) : Disposable { + override fun destroy() { + Disposable.destroy( + this.`orderId`, + this.`orderParams`, + this.`paymentOptions`, + this.`channelState`, + ) + } + companion object +} + + + + +data class Lsps1PaymentInfo ( + val `bolt11`: Lsps1Bolt11PaymentInfo?, + val `onchain`: Lsps1OnchainPaymentInfo? +) : Disposable { + override fun destroy() { + Disposable.destroy( + this.`bolt11`, + this.`onchain`, + ) + } + companion object +} + + + +@kotlinx.serialization.Serializable +data class Lsps2ServiceConfig ( + val `requireToken`: kotlin.String?, + val `advertiseService`: kotlin.Boolean, + val `channelOpeningFeePpm`: kotlin.UInt, + val `channelOverProvisioningPpm`: kotlin.UInt, + val `minChannelOpeningFeeMsat`: kotlin.ULong, + val `minChannelLifetime`: kotlin.UInt, + val `maxClientToSelfDelay`: kotlin.UInt, + val `minPaymentSizeMsat`: kotlin.ULong, + val `maxPaymentSizeMsat`: kotlin.ULong, + val `clientTrustsLsp`: kotlin.Boolean +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class LogRecord ( + val `level`: LogLevel, + val `args`: kotlin.String, + val `modulePath`: kotlin.String, + val `line`: kotlin.UInt +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class NodeAnnouncementInfo ( + val `lastUpdate`: kotlin.UInt, + val `alias`: kotlin.String, + val `addresses`: List +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class NodeInfo ( + val `channels`: List, + val `announcementInfo`: NodeAnnouncementInfo? +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class NodeStatus ( + val `isRunning`: kotlin.Boolean, + val `currentBestBlock`: BestBlock, + val `latestLightningWalletSyncTimestamp`: kotlin.ULong?, + val `latestOnchainWalletSyncTimestamp`: kotlin.ULong?, + val `latestFeeRateCacheUpdateTimestamp`: kotlin.ULong?, + val `latestRgsSnapshotTimestamp`: kotlin.ULong?, + val `latestPathfindingScoresSyncTimestamp`: kotlin.ULong?, + val `latestNodeAnnouncementBroadcastTimestamp`: kotlin.ULong?, + val `latestChannelMonitorArchivalHeight`: kotlin.UInt? +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class OnchainWalletAccount ( + val `addressType`: AddressType, + val `accountIndex`: kotlin.UInt +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class OnchainWalletAccountConfig ( + val `addressType`: AddressType, + val `accountIndex`: kotlin.UInt, + val `xpub`: kotlin.String +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class OutPoint ( + val `txid`: Txid, + val `vout`: kotlin.UInt +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class PaymentDetails ( + val `id`: PaymentId, + val `kind`: PaymentKind, + val `amountMsat`: kotlin.ULong?, + val `feePaidMsat`: kotlin.ULong?, + val `direction`: PaymentDirection, + val `status`: PaymentStatus, + val `latestUpdateTimestamp`: kotlin.ULong +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class PeerDetails ( + val `nodeId`: PublicKey, + val `address`: SocketAddress, + val `isPersisted`: kotlin.Boolean, + val `isConnected`: kotlin.Boolean +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class ProbeHandle ( + val `paymentHash`: PaymentHash, + val `paymentId`: PaymentId +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class RouteHintHop ( + val `srcNodeId`: PublicKey, + val `shortChannelId`: kotlin.ULong, + val `cltvExpiryDelta`: kotlin.UShort, + val `htlcMinimumMsat`: kotlin.ULong?, + val `htlcMaximumMsat`: kotlin.ULong?, + val `fees`: RoutingFees +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class RouteParametersConfig ( + val `maxTotalRoutingFeeMsat`: kotlin.ULong?, + val `maxTotalCltvExpiryDelta`: kotlin.UInt, + val `maxPathCount`: kotlin.UByte, + val `maxChannelSaturationPowerOfHalf`: kotlin.UByte +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class RoutingFees ( + val `baseMsat`: kotlin.UInt, + val `proportionalMillionths`: kotlin.UInt +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class RuntimeSyncIntervals ( + val `onchainWalletSyncIntervalSecs`: kotlin.ULong, + val `lightningWalletSyncIntervalSecs`: kotlin.ULong, + val `feeRateCacheUpdateIntervalSecs`: kotlin.ULong +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class ScoringDecayParameters ( + val `historicalNoUpdatesHalfLifeSecs`: kotlin.ULong, + val `liquidityOffsetHalfLifeSecs`: kotlin.ULong +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class ScoringFeeParameters ( + val `basePenaltyMsat`: kotlin.ULong, + val `basePenaltyAmountMultiplierMsat`: kotlin.ULong, + val `liquidityPenaltyMultiplierMsat`: kotlin.ULong, + val `liquidityPenaltyAmountMultiplierMsat`: kotlin.ULong, + val `historicalLiquidityPenaltyMultiplierMsat`: kotlin.ULong, + val `historicalLiquidityPenaltyAmountMultiplierMsat`: kotlin.ULong, + val `antiProbingPenaltyMsat`: kotlin.ULong, + val `consideredImpossiblePenaltyMsat`: kotlin.ULong, + val `linearSuccessProbability`: kotlin.Boolean, + val `probingDiversityPenaltyMsat`: kotlin.ULong +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class SpendableUtxo ( + val `outpoint`: OutPoint, + val `valueSats`: kotlin.ULong +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class TransactionDetails ( + val `amountSats`: kotlin.Long, + val `inputs`: List, + val `outputs`: List +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class TxInput ( + val `txid`: Txid, + val `vout`: kotlin.UInt, + val `scriptsig`: kotlin.String, + val `witness`: List, + val `sequence`: kotlin.UInt +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class TxOutput ( + val `scriptpubkey`: kotlin.String, + val `scriptpubkeyType`: kotlin.String?, + val `scriptpubkeyAddress`: kotlin.String?, + val `value`: kotlin.Long, + val `n`: kotlin.UInt +) { + companion object +} + + + + + +@kotlinx.serialization.Serializable +enum class AddressType { + + LEGACY, + NESTED_SEGWIT, + NATIVE_SEGWIT, + TAPROOT; + companion object +} + + + + + + + +@kotlinx.serialization.Serializable +enum class AsyncPaymentsRole { + + CLIENT, + SERVER; + companion object +} + + + + + + + +@kotlinx.serialization.Serializable +enum class BalanceSource { + + HOLDER_FORCE_CLOSED, + COUNTERPARTY_FORCE_CLOSED, + COOP_CLOSE, + HTLC; + companion object +} + + + + + + +@kotlinx.serialization.Serializable +sealed class Bolt11InvoiceDescription { + @kotlinx.serialization.Serializable + data class Hash( + val `hash`: kotlin.String, + ) : Bolt11InvoiceDescription() { + } + @kotlinx.serialization.Serializable + data class Direct( + val `description`: kotlin.String, + ) : Bolt11InvoiceDescription() { + } + +} + + + + + + + +sealed class BuildException(message: String): kotlin.Exception(message) { + + class InvalidSeedBytes(message: String) : BuildException(message) + + class InvalidSeedFile(message: String) : BuildException(message) + + class InvalidSystemTime(message: String) : BuildException(message) + + class InvalidChannelMonitor(message: String) : BuildException(message) + + class InvalidListeningAddresses(message: String) : BuildException(message) + + class InvalidAnnouncementAddresses(message: String) : BuildException(message) + + class InvalidNodeAlias(message: String) : BuildException(message) + + class RuntimeSetupFailed(message: String) : BuildException(message) + + class ReadFailed(message: String) : BuildException(message) + + class DangerousValue(message: String) : BuildException(message) + + class WriteFailed(message: String) : BuildException(message) + + class StoragePathAccessFailed(message: String) : BuildException(message) + + class KvStoreSetupFailed(message: String) : BuildException(message) + + class WalletSetupFailed(message: String) : BuildException(message) + + class LoggerSetupFailed(message: String) : BuildException(message) + + class NetworkMismatch(message: String) : BuildException(message) + + class AsyncPaymentsConfigMismatch(message: String) : BuildException(message) + +} + + + + +@kotlinx.serialization.Serializable +sealed class ClosureReason { + @kotlinx.serialization.Serializable + data class CounterpartyForceClosed( + val `peerMsg`: UntrustedString, + ) : ClosureReason() { + } + @kotlinx.serialization.Serializable + data class HolderForceClosed( + val `broadcastedLatestTxn`: kotlin.Boolean?, + val `message`: kotlin.String, + ) : ClosureReason() { + } + + @kotlinx.serialization.Serializable + data object LegacyCooperativeClosure : ClosureReason() + + + @kotlinx.serialization.Serializable + data object CounterpartyInitiatedCooperativeClosure : ClosureReason() + + + @kotlinx.serialization.Serializable + data object LocallyInitiatedCooperativeClosure : ClosureReason() + + + @kotlinx.serialization.Serializable + data object CommitmentTxConfirmed : ClosureReason() + + + @kotlinx.serialization.Serializable + data object FundingTimedOut : ClosureReason() + + @kotlinx.serialization.Serializable + data class ProcessingError( + val `err`: kotlin.String, + ) : ClosureReason() { + } + + @kotlinx.serialization.Serializable + data object DisconnectedPeer : ClosureReason() + + + @kotlinx.serialization.Serializable + data object OutdatedChannelManager : ClosureReason() + + + @kotlinx.serialization.Serializable + data object CounterpartyCoopClosedUnfundedChannel : ClosureReason() + + + @kotlinx.serialization.Serializable + data object LocallyCoopClosedUnfundedChannel : ClosureReason() + + + @kotlinx.serialization.Serializable + data object FundingBatchClosure : ClosureReason() + + @kotlinx.serialization.Serializable + data class HtlCsTimedOut( + val `paymentHash`: PaymentHash?, + ) : ClosureReason() { + } + @kotlinx.serialization.Serializable + data class PeerFeerateTooLow( + val `peerFeerateSatPerKw`: kotlin.UInt, + val `requiredFeerateSatPerKw`: kotlin.UInt, + ) : ClosureReason() { + } + +} + + + + + + + +@kotlinx.serialization.Serializable +enum class CoinSelectionAlgorithm { + + BRANCH_AND_BOUND, + LARGEST_FIRST, + OLDEST_FIRST, + SINGLE_RANDOM_DRAW; + companion object +} + + + + + + +@kotlinx.serialization.Serializable +sealed class ConfirmationStatus { + @kotlinx.serialization.Serializable + data class Confirmed( + val `blockHash`: BlockHash, + val `height`: kotlin.UInt, + val `timestamp`: kotlin.ULong, + ) : ConfirmationStatus() { + } + + @kotlinx.serialization.Serializable + data object Unconfirmed : ConfirmationStatus() + + +} + + + + + + + +@kotlinx.serialization.Serializable +enum class Currency { + + BITCOIN, + BITCOIN_TESTNET, + REGTEST, + SIMNET, + SIGNET; + companion object +} + + + + + + +@kotlinx.serialization.Serializable +sealed class Event { + @kotlinx.serialization.Serializable + data class PaymentSuccessful( + val `paymentId`: PaymentId?, + val `paymentHash`: PaymentHash, + val `paymentPreimage`: PaymentPreimage?, + val `feePaidMsat`: kotlin.ULong?, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class PaymentFailed( + val `paymentId`: PaymentId?, + val `paymentHash`: PaymentHash?, + val `reason`: PaymentFailureReason?, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class PaymentReceived( + val `paymentId`: PaymentId?, + val `paymentHash`: PaymentHash, + val `amountMsat`: kotlin.ULong, + val `customRecords`: List, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class PaymentClaimable( + val `paymentId`: PaymentId, + val `paymentHash`: PaymentHash, + val `claimableAmountMsat`: kotlin.ULong, + val `claimDeadline`: kotlin.UInt?, + val `customRecords`: List, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class PaymentForwarded( + val `prevChannelId`: ChannelId, + val `nextChannelId`: ChannelId, + val `prevUserChannelId`: UserChannelId?, + val `nextUserChannelId`: UserChannelId?, + val `prevNodeId`: PublicKey?, + val `nextNodeId`: PublicKey?, + val `totalFeeEarnedMsat`: kotlin.ULong?, + val `skimmedFeeMsat`: kotlin.ULong?, + val `claimFromOnchainTx`: kotlin.Boolean, + val `outboundAmountForwardedMsat`: kotlin.ULong?, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class ProbeSuccessful( + val `paymentId`: PaymentId, + val `paymentHash`: PaymentHash, + val `routeFeeMsat`: kotlin.ULong?, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class ProbeFailed( + val `paymentId`: PaymentId, + val `paymentHash`: PaymentHash, + val `shortChannelId`: kotlin.ULong?, + val `routeFeeMsat`: kotlin.ULong?, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class ChannelPending( + val `channelId`: ChannelId, + val `userChannelId`: UserChannelId, + val `formerTemporaryChannelId`: ChannelId, + val `counterpartyNodeId`: PublicKey, + val `fundingTxo`: OutPoint, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class ChannelReady( + val `channelId`: ChannelId, + val `userChannelId`: UserChannelId, + val `counterpartyNodeId`: PublicKey?, + val `fundingTxo`: OutPoint?, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class ChannelClosed( + val `channelId`: ChannelId, + val `userChannelId`: UserChannelId, + val `counterpartyNodeId`: PublicKey?, + val `reason`: ClosureReason?, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class SplicePending( + val `channelId`: ChannelId, + val `userChannelId`: UserChannelId, + val `counterpartyNodeId`: PublicKey, + val `newFundingTxo`: OutPoint, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class SpliceFailed( + val `channelId`: ChannelId, + val `userChannelId`: UserChannelId, + val `counterpartyNodeId`: PublicKey, + val `abandonedFundingTxo`: OutPoint?, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class OnchainTransactionConfirmed( + val `txid`: Txid, + val `blockHash`: BlockHash, + val `blockHeight`: kotlin.UInt, + val `confirmationTime`: kotlin.ULong, + val `details`: TransactionDetails, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class OnchainTransactionReceived( + val `txid`: Txid, + val `details`: TransactionDetails, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class OnchainTransactionReplaced( + val `txid`: Txid, + val `conflicts`: List, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class OnchainTransactionReorged( + val `txid`: Txid, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class OnchainTransactionEvicted( + val `txid`: Txid, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class SyncProgress( + val `syncType`: SyncType, + val `progressPercent`: kotlin.UByte, + val `currentBlockHeight`: kotlin.UInt, + val `targetBlockHeight`: kotlin.UInt, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class SyncCompleted( + val `syncType`: SyncType, + val `syncedBlockHeight`: kotlin.UInt, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class BalanceChanged( + val `oldSpendableOnchainBalanceSats`: kotlin.ULong, + val `newSpendableOnchainBalanceSats`: kotlin.ULong, + val `oldTotalOnchainBalanceSats`: kotlin.ULong, + val `newTotalOnchainBalanceSats`: kotlin.ULong, + val `oldTotalLightningBalanceSats`: kotlin.ULong, + val `newTotalLightningBalanceSats`: kotlin.ULong, + ) : Event() { + } + +} + + + + + + + +@kotlinx.serialization.Serializable +enum class KeychainKind { + + EXTERNAL, + INTERNAL; + companion object +} + + + + + + + +@kotlinx.serialization.Serializable +enum class Lsps1PaymentState { + + EXPECT_PAYMENT, + PAID, + REFUNDED; + companion object +} + + + + + + +@kotlinx.serialization.Serializable +sealed class LightningBalance { + @kotlinx.serialization.Serializable + data class ClaimableOnChannelClose( + val `channelId`: ChannelId, + val `counterpartyNodeId`: PublicKey, + val `amountSatoshis`: kotlin.ULong, + val `transactionFeeSatoshis`: kotlin.ULong, + val `outboundPaymentHtlcRoundedMsat`: kotlin.ULong, + val `outboundForwardedHtlcRoundedMsat`: kotlin.ULong, + val `inboundClaimingHtlcRoundedMsat`: kotlin.ULong, + val `inboundHtlcRoundedMsat`: kotlin.ULong, + ) : LightningBalance() { + } + @kotlinx.serialization.Serializable + data class ClaimableAwaitingConfirmations( + val `channelId`: ChannelId, + val `counterpartyNodeId`: PublicKey, + val `amountSatoshis`: kotlin.ULong, + val `confirmationHeight`: kotlin.UInt, + val `source`: BalanceSource, + ) : LightningBalance() { + } + @kotlinx.serialization.Serializable + data class ContentiousClaimable( + val `channelId`: ChannelId, + val `counterpartyNodeId`: PublicKey, + val `amountSatoshis`: kotlin.ULong, + val `timeoutHeight`: kotlin.UInt, + val `paymentHash`: PaymentHash, + val `paymentPreimage`: PaymentPreimage, + ) : LightningBalance() { + } + @kotlinx.serialization.Serializable + data class MaybeTimeoutClaimableHtlc( + val `channelId`: ChannelId, + val `counterpartyNodeId`: PublicKey, + val `amountSatoshis`: kotlin.ULong, + val `claimableHeight`: kotlin.UInt, + val `paymentHash`: PaymentHash, + val `outboundPayment`: kotlin.Boolean, + ) : LightningBalance() { + } + @kotlinx.serialization.Serializable + data class MaybePreimageClaimableHtlc( + val `channelId`: ChannelId, + val `counterpartyNodeId`: PublicKey, + val `amountSatoshis`: kotlin.ULong, + val `expiryHeight`: kotlin.UInt, + val `paymentHash`: PaymentHash, + ) : LightningBalance() { + } + @kotlinx.serialization.Serializable + data class CounterpartyRevokedOutputClaimable( + val `channelId`: ChannelId, + val `counterpartyNodeId`: PublicKey, + val `amountSatoshis`: kotlin.ULong, + ) : LightningBalance() { + } + +} + + + + + + + +@kotlinx.serialization.Serializable +enum class LogLevel { + + GOSSIP, + TRACE, + DEBUG, + INFO, + WARN, + ERROR; + companion object +} + + + + + + +@kotlinx.serialization.Serializable +sealed class MaxDustHtlcExposure { + @kotlinx.serialization.Serializable + data class FixedLimit( + val `limitMsat`: kotlin.ULong, + ) : MaxDustHtlcExposure() { + } + @kotlinx.serialization.Serializable + data class FeeRateMultiplier( + val `multiplier`: kotlin.ULong, + ) : MaxDustHtlcExposure() { + } + +} + + + + + + + +@kotlinx.serialization.Serializable +enum class Network { + + BITCOIN, + TESTNET, + SIGNET, + REGTEST; + companion object +} + + + + + + + +sealed class NodeException(message: String): kotlin.Exception(message) { + + class AlreadyRunning(message: String) : NodeException(message) + + class NotRunning(message: String) : NodeException(message) + + class OnchainTxCreationFailed(message: String) : NodeException(message) + + class ConnectionFailed(message: String) : NodeException(message) + + class InvoiceCreationFailed(message: String) : NodeException(message) + + class InvoiceRequestCreationFailed(message: String) : NodeException(message) + + class OfferCreationFailed(message: String) : NodeException(message) + + class RefundCreationFailed(message: String) : NodeException(message) + + class PaymentSendingFailed(message: String) : NodeException(message) + + class InvalidCustomTlvs(message: String) : NodeException(message) + + class ProbeSendingFailed(message: String) : NodeException(message) + + class RouteNotFound(message: String) : NodeException(message) + + class ChannelCreationFailed(message: String) : NodeException(message) + + class ChannelClosingFailed(message: String) : NodeException(message) + + class ChannelSplicingFailed(message: String) : NodeException(message) + + class ChannelConfigUpdateFailed(message: String) : NodeException(message) + + class PersistenceFailed(message: String) : NodeException(message) + + class FeerateEstimationUpdateFailed(message: String) : NodeException(message) + + class FeerateEstimationUpdateTimeout(message: String) : NodeException(message) + + class WalletOperationFailed(message: String) : NodeException(message) + + class WalletOperationTimeout(message: String) : NodeException(message) + + class OnchainTxSigningFailed(message: String) : NodeException(message) + + class TxSyncFailed(message: String) : NodeException(message) + + class TxSyncTimeout(message: String) : NodeException(message) + + class GossipUpdateFailed(message: String) : NodeException(message) + + class GossipUpdateTimeout(message: String) : NodeException(message) + + class LiquidityRequestFailed(message: String) : NodeException(message) + + class UriParameterParsingFailed(message: String) : NodeException(message) + + class InvalidAddress(message: String) : NodeException(message) + + class InvalidSocketAddress(message: String) : NodeException(message) + + class InvalidPublicKey(message: String) : NodeException(message) + + class InvalidSecretKey(message: String) : NodeException(message) + + class InvalidOfferId(message: String) : NodeException(message) + + class InvalidNodeId(message: String) : NodeException(message) + + class InvalidPaymentId(message: String) : NodeException(message) + + class InvalidPaymentHash(message: String) : NodeException(message) + + class InvalidPaymentPreimage(message: String) : NodeException(message) + + class InvalidPaymentSecret(message: String) : NodeException(message) + + class InvalidAmount(message: String) : NodeException(message) + + class InvalidInvoice(message: String) : NodeException(message) + + class InvalidOffer(message: String) : NodeException(message) + + class InvalidRefund(message: String) : NodeException(message) + + class InvalidChannelId(message: String) : NodeException(message) + + class InvalidNetwork(message: String) : NodeException(message) + + class InvalidUri(message: String) : NodeException(message) + + class InvalidQuantity(message: String) : NodeException(message) + + class InvalidNodeAlias(message: String) : NodeException(message) + + class InvalidDateTime(message: String) : NodeException(message) + + class InvalidFeeRate(message: String) : NodeException(message) + + class DuplicatePayment(message: String) : NodeException(message) + + class UnsupportedCurrency(message: String) : NodeException(message) + + class InsufficientFunds(message: String) : NodeException(message) + + class LiquiditySourceUnavailable(message: String) : NodeException(message) + + class LiquidityFeeTooHigh(message: String) : NodeException(message) + + class InvalidBlindedPaths(message: String) : NodeException(message) + + class AsyncPaymentServicesDisabled(message: String) : NodeException(message) + + class CannotRbfFundingTransaction(message: String) : NodeException(message) + + class TransactionNotFound(message: String) : NodeException(message) + + class TransactionAlreadyConfirmed(message: String) : NodeException(message) + + class NoSpendableOutputs(message: String) : NodeException(message) + + class CoinSelectionFailed(message: String) : NodeException(message) + + class InvalidMnemonic(message: String) : NodeException(message) + + class BackgroundSyncNotEnabled(message: String) : NodeException(message) + + class AddressTypeAlreadyMonitored(message: String) : NodeException(message) + + class AddressTypeIsPrimary(message: String) : NodeException(message) + + class AddressTypeNotMonitored(message: String) : NodeException(message) + + class OnchainWalletAccountNotRegistered(message: String) : NodeException(message) + + class InvalidSeedBytes(message: String) : NodeException(message) + +} + + + + +@kotlinx.serialization.Serializable +sealed class OfferAmount { + @kotlinx.serialization.Serializable + data class Bitcoin( + val `amountMsats`: kotlin.ULong, + ) : OfferAmount() { + } + @kotlinx.serialization.Serializable + data class Currency( + val `iso4217Code`: kotlin.String, + val `amount`: kotlin.ULong, + ) : OfferAmount() { + } + +} + + + + + + + +@kotlinx.serialization.Serializable +enum class PaymentDirection { + + INBOUND, + OUTBOUND; + companion object +} + + + + + + + +@kotlinx.serialization.Serializable +enum class PaymentFailureReason { + + RECIPIENT_REJECTED, + USER_ABANDONED, + RETRIES_EXHAUSTED, + PAYMENT_EXPIRED, + ROUTE_NOT_FOUND, + UNEXPECTED_ERROR, + UNKNOWN_REQUIRED_FEATURES, + INVOICE_REQUEST_EXPIRED, + INVOICE_REQUEST_REJECTED, + BLINDED_PATH_CREATION_FAILED; + companion object +} + + + + + + +@kotlinx.serialization.Serializable +sealed class PaymentKind { + @kotlinx.serialization.Serializable + data class Onchain( + val `txid`: Txid, + val `status`: ConfirmationStatus, + ) : PaymentKind() { + } + @kotlinx.serialization.Serializable + data class Bolt11( + val `hash`: PaymentHash, + val `preimage`: PaymentPreimage?, + val `secret`: PaymentSecret?, + val `description`: kotlin.String?, + val `bolt11`: kotlin.String?, + ) : PaymentKind() { + } + @kotlinx.serialization.Serializable + data class Bolt11Jit( + val `hash`: PaymentHash, + val `preimage`: PaymentPreimage?, + val `secret`: PaymentSecret?, + val `counterpartySkimmedFeeMsat`: kotlin.ULong?, + val `lspFeeLimits`: LspFeeLimits, + val `description`: kotlin.String?, + val `bolt11`: kotlin.String?, + ) : PaymentKind() { + } + @kotlinx.serialization.Serializable + data class Bolt12Offer( + val `hash`: PaymentHash?, + val `preimage`: PaymentPreimage?, + val `secret`: PaymentSecret?, + val `offerId`: OfferId, + val `payerNote`: UntrustedString?, + val `quantity`: kotlin.ULong?, + ) : PaymentKind() { + } + @kotlinx.serialization.Serializable + data class Bolt12Refund( + val `hash`: PaymentHash?, + val `preimage`: PaymentPreimage?, + val `secret`: PaymentSecret?, + val `payerNote`: UntrustedString?, + val `quantity`: kotlin.ULong?, + ) : PaymentKind() { + } + @kotlinx.serialization.Serializable + data class Spontaneous( + val `hash`: PaymentHash, + val `preimage`: PaymentPreimage?, + ) : PaymentKind() { + } + +} + + + + + + + +@kotlinx.serialization.Serializable +enum class PaymentStatus { + + PENDING, + SUCCEEDED, + FAILED; + companion object +} + + + + + + +@kotlinx.serialization.Serializable +sealed class PendingSweepBalance { + @kotlinx.serialization.Serializable + data class PendingBroadcast( + val `channelId`: ChannelId?, + val `amountSatoshis`: kotlin.ULong, + ) : PendingSweepBalance() { + } + @kotlinx.serialization.Serializable + data class BroadcastAwaitingConfirmation( + val `channelId`: ChannelId?, + val `latestBroadcastHeight`: kotlin.UInt, + val `latestSpendingTxid`: Txid, + val `amountSatoshis`: kotlin.ULong, + ) : PendingSweepBalance() { + } + @kotlinx.serialization.Serializable + data class AwaitingThresholdConfirmations( + val `channelId`: ChannelId?, + val `latestSpendingTxid`: Txid, + val `confirmationHash`: BlockHash, + val `confirmationHeight`: kotlin.UInt, + val `amountSatoshis`: kotlin.ULong, + ) : PendingSweepBalance() { + } + +} + + + + + + +@kotlinx.serialization.Serializable +sealed class QrPaymentResult { + @kotlinx.serialization.Serializable + data class Onchain( + val `txid`: Txid, + ) : QrPaymentResult() { + } + @kotlinx.serialization.Serializable + data class Bolt11( + val `paymentId`: PaymentId, + ) : QrPaymentResult() { + } + @kotlinx.serialization.Serializable + data class Bolt12( + val `paymentId`: PaymentId, + ) : QrPaymentResult() { + } + +} + + + + + + + +@kotlinx.serialization.Serializable +enum class SyncType { + + ONCHAIN_WALLET, + LIGHTNING_WALLET, + FEE_RATE_CACHE; + companion object +} + + + + + + + +sealed class VssHeaderProviderException(message: String): kotlin.Exception(message) { + + class InvalidData(message: String) : VssHeaderProviderException(message) + + class RequestException(message: String) : VssHeaderProviderException(message) + + class AuthorizationException(message: String) : VssHeaderProviderException(message) + + class InternalException(message: String) : VssHeaderProviderException(message) + +} + + + + + +@kotlinx.serialization.Serializable +enum class WordCount { + + WORDS12, + WORDS15, + WORDS18, + WORDS21, + WORDS24; + companion object +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias Address = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias BlockHash = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias ChannelId = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias Lsps1OrderId = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias LspsDateTime = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias Mnemonic = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias NodeAlias = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias NodeId = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias OfferId = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias PaymentHash = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias PaymentId = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias PaymentPreimage = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias PaymentSecret = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias PublicKey = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias SocketAddress = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias Txid = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias UntrustedString = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias UserChannelId = kotlin.String diff --git a/bindings/kotlin/ldk-node-jvm/.gitignore b/bindings/kotlin/ldk-node-jvm/.gitignore index 1b6985c009..f544d64f3f 100644 --- a/bindings/kotlin/ldk-node-jvm/.gitignore +++ b/bindings/kotlin/ldk-node-jvm/.gitignore @@ -3,3 +3,6 @@ # Ignore Gradle build output directory build + +# Ignore kotlin compilation outputs +.kotlin diff --git a/bindings/kotlin/ldk-node-jvm/build.gradle.kts b/bindings/kotlin/ldk-node-jvm/build.gradle.kts index faf316ef06..aa82ba6fbf 100644 --- a/bindings/kotlin/ldk-node-jvm/build.gradle.kts +++ b/bindings/kotlin/ldk-node-jvm/build.gradle.kts @@ -10,8 +10,4 @@ buildscript { plugins { } -// library version is defined in gradle.properties -val libraryVersion: String by project - -group = "org.lightningdevkit" -version = libraryVersion +// group and version are defined in gradle.properties diff --git a/bindings/kotlin/ldk-node-jvm/gradle.properties b/bindings/kotlin/ldk-node-jvm/gradle.properties index 913b5caeac..7dc36cbade 100644 --- a/bindings/kotlin/ldk-node-jvm/gradle.properties +++ b/bindings/kotlin/ldk-node-jvm/gradle.properties @@ -1,3 +1,4 @@ org.gradle.jvmargs=-Xmx1536m kotlin.code.style=official -libraryVersion=0.6.0 +group=com.synonym +version=0.7.0-rc.63 diff --git a/bindings/kotlin/ldk-node-jvm/gradle/wrapper/gradle-wrapper.properties b/bindings/kotlin/ldk-node-jvm/gradle/wrapper/gradle-wrapper.properties index f398c33c4b..42defcc94b 100644 --- a/bindings/kotlin/ldk-node-jvm/gradle/wrapper/gradle-wrapper.properties +++ b/bindings/kotlin/ldk-node-jvm/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/bindings/kotlin/ldk-node-jvm/lib/build.gradle.kts b/bindings/kotlin/ldk-node-jvm/lib/build.gradle.kts index 5c9e6c47cf..79f13475ef 100644 --- a/bindings/kotlin/ldk-node-jvm/lib/build.gradle.kts +++ b/bindings/kotlin/ldk-node-jvm/lib/build.gradle.kts @@ -5,12 +5,10 @@ import org.gradle.api.tasks.testing.logging.TestLogEvent.SKIPPED import org.gradle.api.tasks.testing.logging.TestLogEvent.STANDARD_ERROR import org.gradle.api.tasks.testing.logging.TestLogEvent.STANDARD_OUT -// library version is defined in gradle.properties -val libraryVersion: String by project - plugins { // Apply the org.jetbrains.kotlin.jvm Plugin to add support for Kotlin. - id("org.jetbrains.kotlin.jvm") version "1.7.10" + id("org.jetbrains.kotlin.jvm") version "2.2.0" + id("org.jetbrains.kotlin.plugin.serialization") version "2.2.0" // Apply the java-library plugin for API and implementation separation. id("java-library") @@ -19,6 +17,8 @@ plugins { id("org.jlleitschuh.gradle.ktlint") version "11.6.1" } +// group and version are read from gradle.properties automatically + repositories { // Use Maven Central for resolving dependencies. mavenCentral() @@ -46,7 +46,9 @@ dependencies { // Use the Kotlin JDK 8 standard library. implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0") + implementation("org.jetbrains.kotlinx:atomicfu:0.27.0") implementation("net.java.dev.jna:jna:5.12.0") } @@ -86,41 +88,41 @@ afterEvaluate { publishing { publications { create("maven") { - groupId = "org.lightningdevkit" + groupId = providers.gradleProperty("group").orNull ?: "com.synonym" artifactId = "ldk-node-jvm" - version = libraryVersion + version = providers.gradleProperty("version").orNull ?: "0.0.0" from(components["java"]) pom { name.set("ldk-node-jvm") - description.set( - "LDK Node, a ready-to-go Lightning node library built using LDK and BDK." - ) - url.set("https://lightningdevkit.org") + description.set("LDK Node JVM bindings (Synonym fork).") + url.set("https://github.com/synonymdev/ldk-node") licenses { - license { - name.set("APACHE 2.0") - url.set("https://github.com/lightningdevkit/ldk-node/blob/main/LICENSE-APACHE") - } license { name.set("MIT") - url.set("https://github.com/lightningdevkit/ldk-node/blob/main/LICENSE-MIT") + url.set("https://github.com/synonymdev/ldk-node/blob/main/LICENSE-MIT") } } developers { - developers { - developer { - id.set("tnull") - name.set("Elias Rohrer") - email.set("dev@tnull.de") - } + developer { + id.set("synonymdev") + name.set("Synonym") + email.set("noreply@synonym.to") } } - scm { - connection.set("scm:git:github.com/lightningdevkit/ldk-node.git") - developerConnection.set("scm:git:ssh://github.com/lightningdevkit/ldk-node.git") - url.set("https://github.com/lightningdevkit/ldk-node/tree/main") - } + } + } + } + repositories { + maven { + val repo = System.getenv("GITHUB_REPO") + ?: providers.gradleProperty("gpr.repo").orNull + ?: "synonymdev/ldk-node" + name = "GitHubPackages" + url = uri("https://maven.pkg.github.com/$repo") + credentials { + username = System.getenv("GITHUB_ACTOR") ?: providers.gradleProperty("gpr.user").orNull + password = System.getenv("GITHUB_TOKEN") ?: providers.gradleProperty("gpr.key").orNull } } } @@ -128,10 +130,8 @@ afterEvaluate { } signing { -// val signingKeyId: String? by project -// val signingKey: String? by project -// val signingPassword: String? by project -// useInMemoryPgpKeys(signingKeyId, signingKey, signingPassword) + // Only sign if signing key is available (not on JitPack) + setRequired { gradle.taskGraph.hasTask("publish") && project.hasProperty("signingKey") } sign(publishing.publications) } diff --git a/bindings/kotlin/ldk-node-jvm/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.common.kt b/bindings/kotlin/ldk-node-jvm/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.common.kt new file mode 100644 index 0000000000..c51632c07a --- /dev/null +++ b/bindings/kotlin/ldk-node-jvm/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.common.kt @@ -0,0 +1,2575 @@ + + +@file:Suppress("RemoveRedundantBackticks") + +package org.lightningdevkit.ldknode + +// Common helper code. +// +// Ideally this would live in a separate .kt file where it can be unittested etc +// in isolation, and perhaps even published as a re-useable package. +// +// However, it's important that the details of how this helper code works (e.g. the +// way that different builtin types are passed across the FFI) exactly match what's +// expected by the Rust code on the other side of the interface. In practice right +// now that means coming from the exact some version of `uniffi` that was used to +// compile the Rust component. The easiest way to ensure this is to bundle the Kotlin +// helpers directly inline like we're doing here. + +class InternalException(message: String) : kotlin.Exception(message) + +// Public interface members begin here. + + +// Interface implemented by anything that can contain an object reference. +// +// Such types expose a `destroy()` method that must be called to cleanly +// dispose of the contained objects. Failure to call this method may result +// in memory leaks. +// +// The easiest way to ensure this method is called is to use the `.use` +// helper method to execute a block and destroy the object at the end. +@OptIn(ExperimentalStdlibApi::class) +interface Disposable : AutoCloseable { + fun destroy() + override fun close() = destroy() + companion object { + internal fun destroy(vararg args: Any?) { + for (arg in args) { + when (arg) { + is Disposable -> arg.destroy() + is Iterable<*> -> { + for (element in arg) { + if (element is Disposable) { + element.destroy() + } + } + } + is Map<*, *> -> { + for (element in arg.values) { + if (element is Disposable) { + element.destroy() + } + } + } + is Array<*> -> { + for (element in arg) { + if (element is Disposable) { + element.destroy() + } + } + } + } + } + } + } +} + +@OptIn(kotlin.contracts.ExperimentalContracts::class) +inline fun T.use(block: (T) -> R): R { + kotlin.contracts.contract { + callsInPlace(block, kotlin.contracts.InvocationKind.EXACTLY_ONCE) + } + return try { + block(this) + } finally { + try { + // N.B. our implementation is on the nullable type `Disposable?`. + this?.destroy() + } catch (e: Throwable) { + // swallow + } + } +} + +/** Used to instantiate an interface without an actual pointer, for fakes in tests, mostly. */ +object NoPointer + + + + + + + + + + + + + + + + + + + +interface Bolt11InvoiceInterface { + + fun `amountMilliSatoshis`(): kotlin.ULong? + + fun `currency`(): Currency + + fun `expiryTimeSeconds`(): kotlin.ULong + + fun `fallbackAddresses`(): List
+ + fun `invoiceDescription`(): Bolt11InvoiceDescription + + fun `isExpired`(): kotlin.Boolean + + fun `minFinalCltvExpiryDelta`(): kotlin.ULong + + fun `network`(): Network + + fun `paymentHash`(): PaymentHash + + fun `paymentSecret`(): PaymentSecret + + fun `recoverPayeePubKey`(): PublicKey + + fun `routeHints`(): List> + + fun `secondsSinceEpoch`(): kotlin.ULong + + fun `secondsUntilExpiry`(): kotlin.ULong + + fun `signableHash`(): List + + fun `wouldExpire`(`atTimeSeconds`: kotlin.ULong): kotlin.Boolean + + companion object +} + + + + +interface Bolt11PaymentInterface { + + @Throws(NodeException::class) + fun `claimForHash`(`paymentHash`: PaymentHash, `claimableAmountMsat`: kotlin.ULong, `preimage`: PaymentPreimage) + + @Throws(NodeException::class) + fun `estimateRoutingFees`(`invoice`: Bolt11Invoice): kotlin.ULong + + @Throws(NodeException::class) + fun `estimateRoutingFeesUsingAmount`(`invoice`: Bolt11Invoice, `amountMsat`: kotlin.ULong): kotlin.ULong + + @Throws(NodeException::class) + fun `failForHash`(`paymentHash`: PaymentHash) + + @Throws(NodeException::class) + fun `receive`(`amountMsat`: kotlin.ULong, `description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt): Bolt11Invoice + + @Throws(NodeException::class) + fun `receiveForHash`(`amountMsat`: kotlin.ULong, `description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt, `paymentHash`: PaymentHash): Bolt11Invoice + + @Throws(NodeException::class) + fun `receiveVariableAmount`(`description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt): Bolt11Invoice + + @Throws(NodeException::class) + fun `receiveVariableAmountForHash`(`description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt, `paymentHash`: PaymentHash): Bolt11Invoice + + @Throws(NodeException::class) + fun `receiveVariableAmountViaJitChannel`(`description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt, `maxProportionalLspFeeLimitPpmMsat`: kotlin.ULong?): Bolt11Invoice + + @Throws(NodeException::class) + fun `receiveVariableAmountViaJitChannelForHash`(`description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt, `maxProportionalLspFeeLimitPpmMsat`: kotlin.ULong?, `paymentHash`: PaymentHash): Bolt11Invoice + + @Throws(NodeException::class) + fun `receiveViaJitChannel`(`amountMsat`: kotlin.ULong, `description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt, `maxLspFeeLimitMsat`: kotlin.ULong?): Bolt11Invoice + + @Throws(NodeException::class) + fun `receiveViaJitChannelForHash`(`amountMsat`: kotlin.ULong, `description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt, `maxLspFeeLimitMsat`: kotlin.ULong?, `paymentHash`: PaymentHash): Bolt11Invoice + + @Throws(NodeException::class) + fun `send`(`invoice`: Bolt11Invoice, `routeParameters`: RouteParametersConfig?): PaymentId + + @Throws(NodeException::class) + fun `sendProbes`(`invoice`: Bolt11Invoice, `routeParameters`: RouteParametersConfig?): List + + @Throws(NodeException::class) + fun `sendProbesUsingAmount`(`invoice`: Bolt11Invoice, `amountMsat`: kotlin.ULong, `routeParameters`: RouteParametersConfig?): List + + @Throws(NodeException::class) + fun `sendUsingAmount`(`invoice`: Bolt11Invoice, `amountMsat`: kotlin.ULong, `routeParameters`: RouteParametersConfig?): PaymentId + + companion object +} + + + + +interface Bolt12InvoiceInterface { + + fun `absoluteExpirySeconds`(): kotlin.ULong? + + fun `amount`(): OfferAmount? + + fun `amountMsats`(): kotlin.ULong + + fun `chain`(): List + + fun `createdAt`(): kotlin.ULong + + fun `encode`(): List + + fun `fallbackAddresses`(): List
+ + fun `invoiceDescription`(): kotlin.String? + + fun `isExpired`(): kotlin.Boolean + + fun `issuer`(): kotlin.String? + + fun `issuerSigningPubkey`(): PublicKey? + + fun `metadata`(): List? + + fun `offerChains`(): List>? + + fun `payerNote`(): kotlin.String? + + fun `payerSigningPubkey`(): PublicKey + + fun `paymentHash`(): PaymentHash + + fun `quantity`(): kotlin.ULong? + + fun `relativeExpiry`(): kotlin.ULong + + fun `signableHash`(): List + + fun `signingPubkey`(): PublicKey + + companion object +} + + + + +interface Bolt12PaymentInterface { + + @Throws(NodeException::class) + fun `blindedPathsForAsyncRecipient`(`recipientId`: kotlin.ByteArray): kotlin.ByteArray + + @Throws(NodeException::class) + fun `initiateRefund`(`amountMsat`: kotlin.ULong, `expirySecs`: kotlin.UInt, `quantity`: kotlin.ULong?, `payerNote`: kotlin.String?, `routeParameters`: RouteParametersConfig?): Refund + + @Throws(NodeException::class) + fun `receive`(`amountMsat`: kotlin.ULong, `description`: kotlin.String, `expirySecs`: kotlin.UInt?, `quantity`: kotlin.ULong?): Offer + + @Throws(NodeException::class) + fun `receiveAsync`(): Offer + + @Throws(NodeException::class) + fun `receiveVariableAmount`(`description`: kotlin.String, `expirySecs`: kotlin.UInt?): Offer + + @Throws(NodeException::class) + fun `requestRefundPayment`(`refund`: Refund): Bolt12Invoice + + @Throws(NodeException::class) + fun `send`(`offer`: Offer, `quantity`: kotlin.ULong?, `payerNote`: kotlin.String?, `routeParameters`: RouteParametersConfig?): PaymentId + + @Throws(NodeException::class) + fun `sendUsingAmount`(`offer`: Offer, `amountMsat`: kotlin.ULong, `quantity`: kotlin.ULong?, `payerNote`: kotlin.String?, `routeParameters`: RouteParametersConfig?): PaymentId + + @Throws(NodeException::class) + fun `setPathsToStaticInvoiceServer`(`paths`: kotlin.ByteArray) + + companion object +} + + + + +interface BuilderInterface { + + @Throws(BuildException::class) + fun `build`(): Node + + @Throws(BuildException::class) + fun `buildWithFsStore`(): Node + + @Throws(BuildException::class) + fun `buildWithVssStore`(`vssUrl`: kotlin.String, `storeId`: kotlin.String, `lnurlAuthServerUrl`: kotlin.String, `fixedHeaders`: Map): Node + + @Throws(BuildException::class) + fun `buildWithVssStoreAndFixedHeaders`(`vssUrl`: kotlin.String, `storeId`: kotlin.String, `fixedHeaders`: Map): Node + + @Throws(BuildException::class) + fun `buildWithVssStoreAndHeaderProvider`(`vssUrl`: kotlin.String, `storeId`: kotlin.String, `headerProvider`: VssHeaderProvider): Node + + fun `setAddressType`(`addressType`: AddressType) + + fun `setAddressTypesToMonitor`(`addressTypesToMonitor`: List) + + @Throws(BuildException::class) + fun `setAnnouncementAddresses`(`announcementAddresses`: List) + + @Throws(BuildException::class) + fun `setAsyncPaymentsRole`(`role`: AsyncPaymentsRole?) + + fun `setChainSourceBitcoindRest`(`restHost`: kotlin.String, `restPort`: kotlin.UShort, `rpcHost`: kotlin.String, `rpcPort`: kotlin.UShort, `rpcUser`: kotlin.String, `rpcPassword`: kotlin.String) + + fun `setChainSourceBitcoindRpc`(`rpcHost`: kotlin.String, `rpcPort`: kotlin.UShort, `rpcUser`: kotlin.String, `rpcPassword`: kotlin.String) + + fun `setChainSourceElectrum`(`serverUrl`: kotlin.String, `config`: ElectrumSyncConfig?) + + fun `setChainSourceEsplora`(`serverUrl`: kotlin.String, `config`: EsploraSyncConfig?) + + fun `setChannelDataMigration`(`migration`: ChannelDataMigration) + + fun `setCustomLogger`(`logWriter`: LogWriter) + + fun `setEntropyBip39Mnemonic`(`mnemonic`: Mnemonic, `passphrase`: kotlin.String?) + + @Throws(BuildException::class) + fun `setEntropySeedBytes`(`seedBytes`: List) + + fun `setEntropySeedPath`(`seedPath`: kotlin.String) + + fun `setFilesystemLogger`(`logFilePath`: kotlin.String?, `maxLogLevel`: LogLevel?) + + fun `setGossipSourceP2p`() + + fun `setGossipSourceRgs`(`rgsServerUrl`: kotlin.String) + + fun `setLiquiditySourceLsps1`(`nodeId`: PublicKey, `address`: SocketAddress, `token`: kotlin.String?) + + fun `setLiquiditySourceLsps2`(`nodeId`: PublicKey, `address`: SocketAddress, `token`: kotlin.String?) + + @Throws(BuildException::class) + fun `setListeningAddresses`(`listeningAddresses`: List) + + fun `setLogFacadeLogger`() + + fun `setNetwork`(`network`: Network) + + @Throws(BuildException::class) + fun `setNodeAlias`(`nodeAlias`: kotlin.String) + + fun `setPathfindingScoresSource`(`url`: kotlin.String) + + fun `setScoringDecayParams`(`params`: ScoringDecayParameters) + + fun `setScoringFeeParams`(`params`: ScoringFeeParameters) + + fun `setStorageDirPath`(`storageDirPath`: kotlin.String) + + companion object +} + + + + +interface FeeRateInterface { + + fun `toSatPerKwu`(): kotlin.ULong + + fun `toSatPerVbCeil`(): kotlin.ULong + + fun `toSatPerVbFloor`(): kotlin.ULong + + companion object +} + + + + +interface Lsps1LiquidityInterface { + + @Throws(NodeException::class) + fun `checkOrderStatus`(`orderId`: Lsps1OrderId): Lsps1OrderStatus + + @Throws(NodeException::class) + fun `requestChannel`(`lspBalanceSat`: kotlin.ULong, `clientBalanceSat`: kotlin.ULong, `channelExpiryBlocks`: kotlin.UInt, `announceChannel`: kotlin.Boolean): Lsps1OrderStatus + + companion object +} + + + + +interface LogWriter { + + fun `log`(`record`: LogRecord) + + companion object +} + + + + +interface NetworkGraphInterface { + + fun `channel`(`shortChannelId`: kotlin.ULong): ChannelInfo? + + fun `listChannels`(): List + + fun `listNodes`(): List + + fun `node`(`nodeId`: NodeId): NodeInfo? + + companion object +} + + + + +interface NodeInterface { + + @Throws(NodeException::class) + fun `addAddressTypeToMonitor`(`addressType`: AddressType, `seedBytes`: List) + + @Throws(NodeException::class) + fun `addAddressTypeToMonitorWithMnemonic`(`addressType`: AddressType, `mnemonic`: Mnemonic, `passphrase`: kotlin.String?) + + @Throws(NodeException::class) + fun `addOnchainWalletAccount`(`addressType`: AddressType, `accountIndex`: kotlin.UInt, `xpub`: kotlin.String) + + fun `announcementAddresses`(): List? + + fun `bolt11Payment`(): Bolt11Payment + + fun `bolt12Payment`(): Bolt12Payment + + @Throws(NodeException::class) + fun `closeChannel`(`userChannelId`: UserChannelId, `counterpartyNodeId`: PublicKey) + + fun `config`(): Config + + @Throws(NodeException::class) + fun `connect`(`nodeId`: PublicKey, `address`: SocketAddress, `persist`: kotlin.Boolean) + + fun `currentSyncIntervals`(): RuntimeSyncIntervals + + @Throws(NodeException::class) + fun `disconnect`(`nodeId`: PublicKey) + + @Throws(NodeException::class) + fun `eventHandled`() + + @Throws(NodeException::class) + fun `exportOnchainWalletAccountXpub`(`addressType`: AddressType, `accountIndex`: kotlin.UInt): kotlin.String + + @Throws(NodeException::class) + fun `exportPathfindingScores`(): kotlin.ByteArray + + @Throws(NodeException::class) + fun `forceCloseChannel`(`userChannelId`: UserChannelId, `counterpartyNodeId`: PublicKey, `reason`: kotlin.String?) + + @Throws(NodeException::class) + fun `getAddressBalance`(`addressStr`: kotlin.String): kotlin.ULong + + @Throws(NodeException::class) + fun `getBalanceForAddressType`(`addressType`: AddressType): AddressTypeBalance + + @Throws(NodeException::class) + fun `getBalanceForOnchainWalletAccount`(`addressType`: AddressType, `accountIndex`: kotlin.UInt): AddressTypeBalance + + fun `getTransactionDetails`(`txid`: Txid): TransactionDetails? + + fun `listBalances`(): BalanceDetails + + fun `listChannels`(): List + + fun `listMonitoredAddressTypes`(): List + + fun `listOnchainWalletAccounts`(): List + + fun `listPayments`(): List + + fun `listPeers`(): List + + fun `listeningAddresses`(): List? + + fun `lsps1Liquidity`(): Lsps1Liquidity + + fun `networkGraph`(): NetworkGraph + + fun `nextEvent`(): Event? + + suspend fun `nextEventAsync`(): Event + + fun `nodeAlias`(): NodeAlias? + + fun `nodeId`(): PublicKey + + fun `onchainPayment`(): OnchainPayment + + @Throws(NodeException::class) + fun `openAnnouncedChannel`(`nodeId`: PublicKey, `address`: SocketAddress, `channelAmountSats`: kotlin.ULong, `pushToCounterpartyMsat`: kotlin.ULong?, `channelConfig`: ChannelConfig?): UserChannelId + + @Throws(NodeException::class) + fun `openChannel`(`nodeId`: PublicKey, `address`: SocketAddress, `channelAmountSats`: kotlin.ULong, `pushToCounterpartyMsat`: kotlin.ULong?, `channelConfig`: ChannelConfig?): UserChannelId + + fun `payment`(`paymentId`: PaymentId): PaymentDetails? + + @Throws(NodeException::class) + fun `removeAddressTypeFromMonitor`(`addressType`: AddressType) + + @Throws(NodeException::class) + fun `removeOnchainWalletAccount`(`addressType`: AddressType, `accountIndex`: kotlin.UInt) + + @Throws(NodeException::class) + fun `removePayment`(`paymentId`: PaymentId) + + @Throws(NodeException::class) + fun `setPrimaryAddressType`(`addressType`: AddressType, `seedBytes`: List) + + @Throws(NodeException::class) + fun `setPrimaryAddressTypeWithMnemonic`(`addressType`: AddressType, `mnemonic`: Mnemonic, `passphrase`: kotlin.String?) + + fun `signMessage`(`msg`: List): kotlin.String + + @Throws(NodeException::class) + fun `spliceIn`(`userChannelId`: UserChannelId, `counterpartyNodeId`: PublicKey, `spliceAmountSats`: kotlin.ULong) + + @Throws(NodeException::class) + fun `spliceOut`(`userChannelId`: UserChannelId, `counterpartyNodeId`: PublicKey, `address`: Address, `spliceAmountSats`: kotlin.ULong) + + fun `spontaneousPayment`(): SpontaneousPayment + + @Throws(NodeException::class) + fun `start`() + + fun `status`(): NodeStatus + + @Throws(NodeException::class) + fun `stop`() + + @Throws(NodeException::class) + fun `syncWallets`() + + fun `unifiedQrPayment`(): UnifiedQrPayment + + @Throws(NodeException::class) + fun `updateChannelConfig`(`userChannelId`: UserChannelId, `counterpartyNodeId`: PublicKey, `channelConfig`: ChannelConfig) + + @Throws(NodeException::class) + fun `updateSyncIntervals`(`intervals`: RuntimeSyncIntervals) + + fun `verifySignature`(`msg`: List, `sig`: kotlin.String, `pkey`: PublicKey): kotlin.Boolean + + fun `waitNextEvent`(): Event + + companion object +} + + + + +interface OfferInterface { + + fun `absoluteExpirySeconds`(): kotlin.ULong? + + fun `amount`(): OfferAmount? + + fun `chains`(): List + + fun `expectsQuantity`(): kotlin.Boolean + + fun `id`(): OfferId + + fun `isExpired`(): kotlin.Boolean + + fun `isValidQuantity`(`quantity`: kotlin.ULong): kotlin.Boolean + + fun `issuer`(): kotlin.String? + + fun `issuerSigningPubkey`(): PublicKey? + + fun `metadata`(): List? + + fun `offerDescription`(): kotlin.String? + + fun `supportsChain`(`chain`: Network): kotlin.Boolean + + companion object +} + + + + +interface OnchainPaymentInterface { + + @Throws(NodeException::class) + fun `accelerateByCpfp`(`txid`: Txid, `feeRate`: FeeRate?, `destinationAddress`: Address?): Txid + + @Throws(NodeException::class) + fun `addressInfoForAccountAtIndex`(`addressType`: AddressType, `accountIndex`: kotlin.UInt, `keychain`: KeychainKind, `index`: kotlin.UInt): AddressInfo + + @Throws(NodeException::class) + fun `addressInfoForTypeAtIndex`(`addressType`: AddressType, `keychain`: KeychainKind, `index`: kotlin.UInt): AddressInfo + + @Throws(NodeException::class) + fun `addressInfosForAccount`(`addressType`: AddressType, `accountIndex`: kotlin.UInt, `keychain`: KeychainKind, `startIndex`: kotlin.UInt, `count`: kotlin.UInt): List + + @Throws(NodeException::class) + fun `addressInfosForType`(`addressType`: AddressType, `keychain`: KeychainKind, `startIndex`: kotlin.UInt, `count`: kotlin.UInt): List + + @Throws(NodeException::class) + fun `bumpFeeByRbf`(`txid`: Txid, `feeRate`: FeeRate): Txid + + @Throws(NodeException::class) + fun `calculateCpfpFeeRate`(`parentTxid`: Txid, `urgent`: kotlin.Boolean): FeeRate + + @Throws(NodeException::class) + fun `calculateSendAllFee`(`address`: Address, `retainReserves`: kotlin.Boolean, `feeRate`: FeeRate?): kotlin.ULong + + @Throws(NodeException::class) + fun `calculateTotalFee`(`address`: Address, `amountSats`: kotlin.ULong, `feeRate`: FeeRate?, `utxosToSpend`: List?): kotlin.ULong + + @Throws(NodeException::class) + fun `listSpendableOutputs`(): List + + @Throws(NodeException::class) + fun `newAddress`(): Address + + @Throws(NodeException::class) + fun `newAddressForAccount`(`addressType`: AddressType, `accountIndex`: kotlin.UInt): Address + + @Throws(NodeException::class) + fun `newAddressForType`(`addressType`: AddressType): Address + + @Throws(NodeException::class) + fun `newAddressInfo`(): AddressInfo + + @Throws(NodeException::class) + fun `newAddressInfoForAccount`(`addressType`: AddressType, `accountIndex`: kotlin.UInt): AddressInfo + + @Throws(NodeException::class) + fun `newAddressInfoForType`(`addressType`: AddressType): AddressInfo + + @Throws(NodeException::class) + fun `revealReceiveAddressesTo`(`addressType`: AddressType, `index`: kotlin.UInt) + + @Throws(NodeException::class) + fun `revealReceiveAddressesToAccount`(`addressType`: AddressType, `accountIndex`: kotlin.UInt, `index`: kotlin.UInt) + + @Throws(NodeException::class) + fun `selectUtxosWithAlgorithm`(`targetAmountSats`: kotlin.ULong, `feeRate`: FeeRate?, `algorithm`: CoinSelectionAlgorithm, `utxos`: List?): List + + @Throws(NodeException::class) + fun `sendAllToAddress`(`address`: Address, `retainReserve`: kotlin.Boolean, `feeRate`: FeeRate?): Txid + + @Throws(NodeException::class) + fun `sendToAddress`(`address`: Address, `amountSats`: kotlin.ULong, `feeRate`: FeeRate?, `utxosToSpend`: List?): Txid + + companion object +} + + + + +interface RefundInterface { + + fun `absoluteExpirySeconds`(): kotlin.ULong? + + fun `amountMsats`(): kotlin.ULong + + fun `chain`(): Network? + + fun `isExpired`(): kotlin.Boolean + + fun `issuer`(): kotlin.String? + + fun `payerMetadata`(): List + + fun `payerNote`(): kotlin.String? + + fun `payerSigningPubkey`(): PublicKey + + fun `quantity`(): kotlin.ULong? + + fun `refundDescription`(): kotlin.String + + companion object +} + + + + +interface SpontaneousPaymentInterface { + + @Throws(NodeException::class) + fun `send`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey, `routeParameters`: RouteParametersConfig?): PaymentId + + @Throws(NodeException::class) + fun `sendProbes`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey): List + + @Throws(NodeException::class) + fun `sendWithCustomTlvs`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey, `routeParameters`: RouteParametersConfig?, `customTlvs`: List): PaymentId + + @Throws(NodeException::class) + fun `sendWithPreimage`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey, `preimage`: PaymentPreimage, `routeParameters`: RouteParametersConfig?): PaymentId + + @Throws(NodeException::class) + fun `sendWithPreimageAndCustomTlvs`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey, `customTlvs`: List, `preimage`: PaymentPreimage, `routeParameters`: RouteParametersConfig?): PaymentId + + companion object +} + + + + +interface UnifiedQrPaymentInterface { + + @Throws(NodeException::class) + fun `receive`(`amountSats`: kotlin.ULong, `message`: kotlin.String, `expirySec`: kotlin.UInt): kotlin.String + + @Throws(NodeException::class) + fun `send`(`uriStr`: kotlin.String, `routeParameters`: RouteParametersConfig?): QrPaymentResult + + companion object +} + + + + +interface VssHeaderProviderInterface { + + @Throws(VssHeaderProviderException::class, kotlin.coroutines.cancellation.CancellationException::class) + suspend fun `getHeaders`(`request`: List): Map + + companion object +} + + + + +@kotlinx.serialization.Serializable +data class AddressInfo ( + val `index`: kotlin.UInt, + val `address`: Address, + val `keychain`: KeychainKind +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class AddressTypeBalance ( + val `totalSats`: kotlin.ULong, + val `spendableSats`: kotlin.ULong +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class AnchorChannelsConfig ( + val `trustedPeersNoReserve`: List, + val `perChannelReserveSats`: kotlin.ULong +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class BackgroundSyncConfig ( + val `onchainWalletSyncIntervalSecs`: kotlin.ULong, + val `lightningWalletSyncIntervalSecs`: kotlin.ULong, + val `feeRateCacheUpdateIntervalSecs`: kotlin.ULong +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class BalanceDetails ( + val `totalOnchainBalanceSats`: kotlin.ULong, + val `spendableOnchainBalanceSats`: kotlin.ULong, + val `totalAnchorChannelsReserveSats`: kotlin.ULong, + val `totalLightningBalanceSats`: kotlin.ULong, + val `lightningBalances`: List, + val `pendingBalancesFromChannelClosures`: List +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class BestBlock ( + val `blockHash`: BlockHash, + val `height`: kotlin.UInt +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class ChannelConfig ( + val `forwardingFeeProportionalMillionths`: kotlin.UInt, + val `forwardingFeeBaseMsat`: kotlin.UInt, + val `cltvExpiryDelta`: kotlin.UShort, + val `maxDustHtlcExposure`: MaxDustHtlcExposure, + val `forceCloseAvoidanceMaxFeeSatoshis`: kotlin.ULong, + val `acceptUnderpayingHtlcs`: kotlin.Boolean +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class ChannelDataMigration ( + val `channelManager`: List?, + val `channelMonitors`: List> +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class ChannelDetails ( + val `channelId`: ChannelId, + val `counterpartyNodeId`: PublicKey, + val `fundingTxo`: OutPoint?, + val `shortChannelId`: kotlin.ULong?, + val `outboundScidAlias`: kotlin.ULong?, + val `inboundScidAlias`: kotlin.ULong?, + val `channelValueSats`: kotlin.ULong, + val `unspendablePunishmentReserve`: kotlin.ULong?, + val `userChannelId`: UserChannelId, + val `feerateSatPer1000Weight`: kotlin.UInt, + val `outboundCapacityMsat`: kotlin.ULong, + val `inboundCapacityMsat`: kotlin.ULong, + val `confirmationsRequired`: kotlin.UInt?, + val `confirmations`: kotlin.UInt?, + val `isOutbound`: kotlin.Boolean, + val `isChannelReady`: kotlin.Boolean, + val `isUsable`: kotlin.Boolean, + val `isAnnounced`: kotlin.Boolean, + val `cltvExpiryDelta`: kotlin.UShort?, + val `counterpartyUnspendablePunishmentReserve`: kotlin.ULong, + val `counterpartyOutboundHtlcMinimumMsat`: kotlin.ULong?, + val `counterpartyOutboundHtlcMaximumMsat`: kotlin.ULong?, + val `counterpartyForwardingInfoFeeBaseMsat`: kotlin.UInt?, + val `counterpartyForwardingInfoFeeProportionalMillionths`: kotlin.UInt?, + val `counterpartyForwardingInfoCltvExpiryDelta`: kotlin.UShort?, + val `nextOutboundHtlcLimitMsat`: kotlin.ULong, + val `nextOutboundHtlcMinimumMsat`: kotlin.ULong, + val `forceCloseSpendDelay`: kotlin.UShort?, + val `inboundHtlcMinimumMsat`: kotlin.ULong, + val `inboundHtlcMaximumMsat`: kotlin.ULong?, + val `config`: ChannelConfig, + val `claimableOnCloseSats`: kotlin.ULong? +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class ChannelInfo ( + val `nodeOne`: NodeId, + val `oneToTwo`: ChannelUpdateInfo?, + val `nodeTwo`: NodeId, + val `twoToOne`: ChannelUpdateInfo?, + val `capacitySats`: kotlin.ULong? +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class ChannelUpdateInfo ( + val `lastUpdate`: kotlin.UInt, + val `enabled`: kotlin.Boolean, + val `cltvExpiryDelta`: kotlin.UShort, + val `htlcMinimumMsat`: kotlin.ULong, + val `htlcMaximumMsat`: kotlin.ULong, + val `fees`: RoutingFees +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class Config ( + val `storageDirPath`: kotlin.String, + val `network`: Network, + val `listeningAddresses`: List?, + val `announcementAddresses`: List?, + val `nodeAlias`: NodeAlias?, + val `trustedPeers0conf`: List, + val `probingLiquidityLimitMultiplier`: kotlin.ULong, + val `anchorChannelsConfig`: AnchorChannelsConfig?, + val `routeParameters`: RouteParametersConfig?, + val `scoringFeeParams`: ScoringFeeParameters?, + val `scoringDecayParams`: ScoringDecayParameters?, + val `includeUntrustedPendingInSpendable`: kotlin.Boolean, + val `addressType`: AddressType, + val `addressTypesToMonitor`: List, + val `onchainWalletAccounts`: List +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class CustomTlvRecord ( + val `typeNum`: kotlin.ULong, + val `value`: List +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class ElectrumSyncConfig ( + val `backgroundSyncConfig`: BackgroundSyncConfig?, + val `connectionTimeoutSecs`: kotlin.ULong, + val `additionalWalletFullScanBatchSize`: kotlin.UInt, + val `additionalWalletFullScanStopGap`: kotlin.UInt +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class EsploraSyncConfig ( + val `backgroundSyncConfig`: BackgroundSyncConfig? +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class LspFeeLimits ( + val `maxTotalOpeningFeeMsat`: kotlin.ULong?, + val `maxProportionalOpeningFeePpmMsat`: kotlin.ULong? +) { + companion object +} + + + + +data class Lsps1Bolt11PaymentInfo ( + val `state`: Lsps1PaymentState, + val `expiresAt`: LspsDateTime, + val `feeTotalSat`: kotlin.ULong, + val `orderTotalSat`: kotlin.ULong, + val `invoice`: Bolt11Invoice +) : Disposable { + override fun destroy() { + Disposable.destroy( + this.`state`, + this.`expiresAt`, + this.`feeTotalSat`, + this.`orderTotalSat`, + this.`invoice`, + ) + } + companion object +} + + + +@kotlinx.serialization.Serializable +data class Lsps1ChannelInfo ( + val `fundedAt`: LspsDateTime, + val `fundingOutpoint`: OutPoint, + val `expiresAt`: LspsDateTime +) { + companion object +} + + + + +data class Lsps1OnchainPaymentInfo ( + val `state`: Lsps1PaymentState, + val `expiresAt`: LspsDateTime, + val `feeTotalSat`: kotlin.ULong, + val `orderTotalSat`: kotlin.ULong, + val `address`: Address, + val `minOnchainPaymentConfirmations`: kotlin.UShort?, + val `minFeeFor0conf`: FeeRate, + val `refundOnchainAddress`: Address? +) : Disposable { + override fun destroy() { + Disposable.destroy( + this.`state`, + this.`expiresAt`, + this.`feeTotalSat`, + this.`orderTotalSat`, + this.`address`, + this.`minOnchainPaymentConfirmations`, + this.`minFeeFor0conf`, + this.`refundOnchainAddress`, + ) + } + companion object +} + + + +@kotlinx.serialization.Serializable +data class Lsps1OrderParams ( + val `lspBalanceSat`: kotlin.ULong, + val `clientBalanceSat`: kotlin.ULong, + val `requiredChannelConfirmations`: kotlin.UShort, + val `fundingConfirmsWithinBlocks`: kotlin.UShort, + val `channelExpiryBlocks`: kotlin.UInt, + val `token`: kotlin.String?, + val `announceChannel`: kotlin.Boolean +) { + companion object +} + + + + +data class Lsps1OrderStatus ( + val `orderId`: Lsps1OrderId, + val `orderParams`: Lsps1OrderParams, + val `paymentOptions`: Lsps1PaymentInfo, + val `channelState`: Lsps1ChannelInfo? +) : Disposable { + override fun destroy() { + Disposable.destroy( + this.`orderId`, + this.`orderParams`, + this.`paymentOptions`, + this.`channelState`, + ) + } + companion object +} + + + + +data class Lsps1PaymentInfo ( + val `bolt11`: Lsps1Bolt11PaymentInfo?, + val `onchain`: Lsps1OnchainPaymentInfo? +) : Disposable { + override fun destroy() { + Disposable.destroy( + this.`bolt11`, + this.`onchain`, + ) + } + companion object +} + + + +@kotlinx.serialization.Serializable +data class Lsps2ServiceConfig ( + val `requireToken`: kotlin.String?, + val `advertiseService`: kotlin.Boolean, + val `channelOpeningFeePpm`: kotlin.UInt, + val `channelOverProvisioningPpm`: kotlin.UInt, + val `minChannelOpeningFeeMsat`: kotlin.ULong, + val `minChannelLifetime`: kotlin.UInt, + val `maxClientToSelfDelay`: kotlin.UInt, + val `minPaymentSizeMsat`: kotlin.ULong, + val `maxPaymentSizeMsat`: kotlin.ULong, + val `clientTrustsLsp`: kotlin.Boolean +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class LogRecord ( + val `level`: LogLevel, + val `args`: kotlin.String, + val `modulePath`: kotlin.String, + val `line`: kotlin.UInt +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class NodeAnnouncementInfo ( + val `lastUpdate`: kotlin.UInt, + val `alias`: kotlin.String, + val `addresses`: List +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class NodeInfo ( + val `channels`: List, + val `announcementInfo`: NodeAnnouncementInfo? +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class NodeStatus ( + val `isRunning`: kotlin.Boolean, + val `currentBestBlock`: BestBlock, + val `latestLightningWalletSyncTimestamp`: kotlin.ULong?, + val `latestOnchainWalletSyncTimestamp`: kotlin.ULong?, + val `latestFeeRateCacheUpdateTimestamp`: kotlin.ULong?, + val `latestRgsSnapshotTimestamp`: kotlin.ULong?, + val `latestPathfindingScoresSyncTimestamp`: kotlin.ULong?, + val `latestNodeAnnouncementBroadcastTimestamp`: kotlin.ULong?, + val `latestChannelMonitorArchivalHeight`: kotlin.UInt? +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class OnchainWalletAccount ( + val `addressType`: AddressType, + val `accountIndex`: kotlin.UInt +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class OnchainWalletAccountConfig ( + val `addressType`: AddressType, + val `accountIndex`: kotlin.UInt, + val `xpub`: kotlin.String +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class OutPoint ( + val `txid`: Txid, + val `vout`: kotlin.UInt +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class PaymentDetails ( + val `id`: PaymentId, + val `kind`: PaymentKind, + val `amountMsat`: kotlin.ULong?, + val `feePaidMsat`: kotlin.ULong?, + val `direction`: PaymentDirection, + val `status`: PaymentStatus, + val `latestUpdateTimestamp`: kotlin.ULong +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class PeerDetails ( + val `nodeId`: PublicKey, + val `address`: SocketAddress, + val `isPersisted`: kotlin.Boolean, + val `isConnected`: kotlin.Boolean +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class ProbeHandle ( + val `paymentHash`: PaymentHash, + val `paymentId`: PaymentId +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class RouteHintHop ( + val `srcNodeId`: PublicKey, + val `shortChannelId`: kotlin.ULong, + val `cltvExpiryDelta`: kotlin.UShort, + val `htlcMinimumMsat`: kotlin.ULong?, + val `htlcMaximumMsat`: kotlin.ULong?, + val `fees`: RoutingFees +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class RouteParametersConfig ( + val `maxTotalRoutingFeeMsat`: kotlin.ULong?, + val `maxTotalCltvExpiryDelta`: kotlin.UInt, + val `maxPathCount`: kotlin.UByte, + val `maxChannelSaturationPowerOfHalf`: kotlin.UByte +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class RoutingFees ( + val `baseMsat`: kotlin.UInt, + val `proportionalMillionths`: kotlin.UInt +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class RuntimeSyncIntervals ( + val `onchainWalletSyncIntervalSecs`: kotlin.ULong, + val `lightningWalletSyncIntervalSecs`: kotlin.ULong, + val `feeRateCacheUpdateIntervalSecs`: kotlin.ULong +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class ScoringDecayParameters ( + val `historicalNoUpdatesHalfLifeSecs`: kotlin.ULong, + val `liquidityOffsetHalfLifeSecs`: kotlin.ULong +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class ScoringFeeParameters ( + val `basePenaltyMsat`: kotlin.ULong, + val `basePenaltyAmountMultiplierMsat`: kotlin.ULong, + val `liquidityPenaltyMultiplierMsat`: kotlin.ULong, + val `liquidityPenaltyAmountMultiplierMsat`: kotlin.ULong, + val `historicalLiquidityPenaltyMultiplierMsat`: kotlin.ULong, + val `historicalLiquidityPenaltyAmountMultiplierMsat`: kotlin.ULong, + val `antiProbingPenaltyMsat`: kotlin.ULong, + val `consideredImpossiblePenaltyMsat`: kotlin.ULong, + val `linearSuccessProbability`: kotlin.Boolean, + val `probingDiversityPenaltyMsat`: kotlin.ULong +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class SpendableUtxo ( + val `outpoint`: OutPoint, + val `valueSats`: kotlin.ULong +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class TransactionDetails ( + val `amountSats`: kotlin.Long, + val `inputs`: List, + val `outputs`: List +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class TxInput ( + val `txid`: Txid, + val `vout`: kotlin.UInt, + val `scriptsig`: kotlin.String, + val `witness`: List, + val `sequence`: kotlin.UInt +) { + companion object +} + + + +@kotlinx.serialization.Serializable +data class TxOutput ( + val `scriptpubkey`: kotlin.String, + val `scriptpubkeyType`: kotlin.String?, + val `scriptpubkeyAddress`: kotlin.String?, + val `value`: kotlin.Long, + val `n`: kotlin.UInt +) { + companion object +} + + + + + +@kotlinx.serialization.Serializable +enum class AddressType { + + LEGACY, + NESTED_SEGWIT, + NATIVE_SEGWIT, + TAPROOT; + companion object +} + + + + + + + +@kotlinx.serialization.Serializable +enum class AsyncPaymentsRole { + + CLIENT, + SERVER; + companion object +} + + + + + + + +@kotlinx.serialization.Serializable +enum class BalanceSource { + + HOLDER_FORCE_CLOSED, + COUNTERPARTY_FORCE_CLOSED, + COOP_CLOSE, + HTLC; + companion object +} + + + + + + +@kotlinx.serialization.Serializable +sealed class Bolt11InvoiceDescription { + @kotlinx.serialization.Serializable + data class Hash( + val `hash`: kotlin.String, + ) : Bolt11InvoiceDescription() { + } + @kotlinx.serialization.Serializable + data class Direct( + val `description`: kotlin.String, + ) : Bolt11InvoiceDescription() { + } + +} + + + + + + + +sealed class BuildException(message: String): kotlin.Exception(message) { + + class InvalidSeedBytes(message: String) : BuildException(message) + + class InvalidSeedFile(message: String) : BuildException(message) + + class InvalidSystemTime(message: String) : BuildException(message) + + class InvalidChannelMonitor(message: String) : BuildException(message) + + class InvalidListeningAddresses(message: String) : BuildException(message) + + class InvalidAnnouncementAddresses(message: String) : BuildException(message) + + class InvalidNodeAlias(message: String) : BuildException(message) + + class RuntimeSetupFailed(message: String) : BuildException(message) + + class ReadFailed(message: String) : BuildException(message) + + class DangerousValue(message: String) : BuildException(message) + + class WriteFailed(message: String) : BuildException(message) + + class StoragePathAccessFailed(message: String) : BuildException(message) + + class KvStoreSetupFailed(message: String) : BuildException(message) + + class WalletSetupFailed(message: String) : BuildException(message) + + class LoggerSetupFailed(message: String) : BuildException(message) + + class NetworkMismatch(message: String) : BuildException(message) + + class AsyncPaymentsConfigMismatch(message: String) : BuildException(message) + +} + + + + +@kotlinx.serialization.Serializable +sealed class ClosureReason { + @kotlinx.serialization.Serializable + data class CounterpartyForceClosed( + val `peerMsg`: UntrustedString, + ) : ClosureReason() { + } + @kotlinx.serialization.Serializable + data class HolderForceClosed( + val `broadcastedLatestTxn`: kotlin.Boolean?, + val `message`: kotlin.String, + ) : ClosureReason() { + } + + @kotlinx.serialization.Serializable + data object LegacyCooperativeClosure : ClosureReason() + + + @kotlinx.serialization.Serializable + data object CounterpartyInitiatedCooperativeClosure : ClosureReason() + + + @kotlinx.serialization.Serializable + data object LocallyInitiatedCooperativeClosure : ClosureReason() + + + @kotlinx.serialization.Serializable + data object CommitmentTxConfirmed : ClosureReason() + + + @kotlinx.serialization.Serializable + data object FundingTimedOut : ClosureReason() + + @kotlinx.serialization.Serializable + data class ProcessingError( + val `err`: kotlin.String, + ) : ClosureReason() { + } + + @kotlinx.serialization.Serializable + data object DisconnectedPeer : ClosureReason() + + + @kotlinx.serialization.Serializable + data object OutdatedChannelManager : ClosureReason() + + + @kotlinx.serialization.Serializable + data object CounterpartyCoopClosedUnfundedChannel : ClosureReason() + + + @kotlinx.serialization.Serializable + data object LocallyCoopClosedUnfundedChannel : ClosureReason() + + + @kotlinx.serialization.Serializable + data object FundingBatchClosure : ClosureReason() + + @kotlinx.serialization.Serializable + data class HtlCsTimedOut( + val `paymentHash`: PaymentHash?, + ) : ClosureReason() { + } + @kotlinx.serialization.Serializable + data class PeerFeerateTooLow( + val `peerFeerateSatPerKw`: kotlin.UInt, + val `requiredFeerateSatPerKw`: kotlin.UInt, + ) : ClosureReason() { + } + +} + + + + + + + +@kotlinx.serialization.Serializable +enum class CoinSelectionAlgorithm { + + BRANCH_AND_BOUND, + LARGEST_FIRST, + OLDEST_FIRST, + SINGLE_RANDOM_DRAW; + companion object +} + + + + + + +@kotlinx.serialization.Serializable +sealed class ConfirmationStatus { + @kotlinx.serialization.Serializable + data class Confirmed( + val `blockHash`: BlockHash, + val `height`: kotlin.UInt, + val `timestamp`: kotlin.ULong, + ) : ConfirmationStatus() { + } + + @kotlinx.serialization.Serializable + data object Unconfirmed : ConfirmationStatus() + + +} + + + + + + + +@kotlinx.serialization.Serializable +enum class Currency { + + BITCOIN, + BITCOIN_TESTNET, + REGTEST, + SIMNET, + SIGNET; + companion object +} + + + + + + +@kotlinx.serialization.Serializable +sealed class Event { + @kotlinx.serialization.Serializable + data class PaymentSuccessful( + val `paymentId`: PaymentId?, + val `paymentHash`: PaymentHash, + val `paymentPreimage`: PaymentPreimage?, + val `feePaidMsat`: kotlin.ULong?, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class PaymentFailed( + val `paymentId`: PaymentId?, + val `paymentHash`: PaymentHash?, + val `reason`: PaymentFailureReason?, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class PaymentReceived( + val `paymentId`: PaymentId?, + val `paymentHash`: PaymentHash, + val `amountMsat`: kotlin.ULong, + val `customRecords`: List, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class PaymentClaimable( + val `paymentId`: PaymentId, + val `paymentHash`: PaymentHash, + val `claimableAmountMsat`: kotlin.ULong, + val `claimDeadline`: kotlin.UInt?, + val `customRecords`: List, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class PaymentForwarded( + val `prevChannelId`: ChannelId, + val `nextChannelId`: ChannelId, + val `prevUserChannelId`: UserChannelId?, + val `nextUserChannelId`: UserChannelId?, + val `prevNodeId`: PublicKey?, + val `nextNodeId`: PublicKey?, + val `totalFeeEarnedMsat`: kotlin.ULong?, + val `skimmedFeeMsat`: kotlin.ULong?, + val `claimFromOnchainTx`: kotlin.Boolean, + val `outboundAmountForwardedMsat`: kotlin.ULong?, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class ProbeSuccessful( + val `paymentId`: PaymentId, + val `paymentHash`: PaymentHash, + val `routeFeeMsat`: kotlin.ULong?, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class ProbeFailed( + val `paymentId`: PaymentId, + val `paymentHash`: PaymentHash, + val `shortChannelId`: kotlin.ULong?, + val `routeFeeMsat`: kotlin.ULong?, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class ChannelPending( + val `channelId`: ChannelId, + val `userChannelId`: UserChannelId, + val `formerTemporaryChannelId`: ChannelId, + val `counterpartyNodeId`: PublicKey, + val `fundingTxo`: OutPoint, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class ChannelReady( + val `channelId`: ChannelId, + val `userChannelId`: UserChannelId, + val `counterpartyNodeId`: PublicKey?, + val `fundingTxo`: OutPoint?, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class ChannelClosed( + val `channelId`: ChannelId, + val `userChannelId`: UserChannelId, + val `counterpartyNodeId`: PublicKey?, + val `reason`: ClosureReason?, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class SplicePending( + val `channelId`: ChannelId, + val `userChannelId`: UserChannelId, + val `counterpartyNodeId`: PublicKey, + val `newFundingTxo`: OutPoint, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class SpliceFailed( + val `channelId`: ChannelId, + val `userChannelId`: UserChannelId, + val `counterpartyNodeId`: PublicKey, + val `abandonedFundingTxo`: OutPoint?, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class OnchainTransactionConfirmed( + val `txid`: Txid, + val `blockHash`: BlockHash, + val `blockHeight`: kotlin.UInt, + val `confirmationTime`: kotlin.ULong, + val `details`: TransactionDetails, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class OnchainTransactionReceived( + val `txid`: Txid, + val `details`: TransactionDetails, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class OnchainTransactionReplaced( + val `txid`: Txid, + val `conflicts`: List, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class OnchainTransactionReorged( + val `txid`: Txid, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class OnchainTransactionEvicted( + val `txid`: Txid, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class SyncProgress( + val `syncType`: SyncType, + val `progressPercent`: kotlin.UByte, + val `currentBlockHeight`: kotlin.UInt, + val `targetBlockHeight`: kotlin.UInt, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class SyncCompleted( + val `syncType`: SyncType, + val `syncedBlockHeight`: kotlin.UInt, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class BalanceChanged( + val `oldSpendableOnchainBalanceSats`: kotlin.ULong, + val `newSpendableOnchainBalanceSats`: kotlin.ULong, + val `oldTotalOnchainBalanceSats`: kotlin.ULong, + val `newTotalOnchainBalanceSats`: kotlin.ULong, + val `oldTotalLightningBalanceSats`: kotlin.ULong, + val `newTotalLightningBalanceSats`: kotlin.ULong, + ) : Event() { + } + +} + + + + + + + +@kotlinx.serialization.Serializable +enum class KeychainKind { + + EXTERNAL, + INTERNAL; + companion object +} + + + + + + + +@kotlinx.serialization.Serializable +enum class Lsps1PaymentState { + + EXPECT_PAYMENT, + PAID, + REFUNDED; + companion object +} + + + + + + +@kotlinx.serialization.Serializable +sealed class LightningBalance { + @kotlinx.serialization.Serializable + data class ClaimableOnChannelClose( + val `channelId`: ChannelId, + val `counterpartyNodeId`: PublicKey, + val `amountSatoshis`: kotlin.ULong, + val `transactionFeeSatoshis`: kotlin.ULong, + val `outboundPaymentHtlcRoundedMsat`: kotlin.ULong, + val `outboundForwardedHtlcRoundedMsat`: kotlin.ULong, + val `inboundClaimingHtlcRoundedMsat`: kotlin.ULong, + val `inboundHtlcRoundedMsat`: kotlin.ULong, + ) : LightningBalance() { + } + @kotlinx.serialization.Serializable + data class ClaimableAwaitingConfirmations( + val `channelId`: ChannelId, + val `counterpartyNodeId`: PublicKey, + val `amountSatoshis`: kotlin.ULong, + val `confirmationHeight`: kotlin.UInt, + val `source`: BalanceSource, + ) : LightningBalance() { + } + @kotlinx.serialization.Serializable + data class ContentiousClaimable( + val `channelId`: ChannelId, + val `counterpartyNodeId`: PublicKey, + val `amountSatoshis`: kotlin.ULong, + val `timeoutHeight`: kotlin.UInt, + val `paymentHash`: PaymentHash, + val `paymentPreimage`: PaymentPreimage, + ) : LightningBalance() { + } + @kotlinx.serialization.Serializable + data class MaybeTimeoutClaimableHtlc( + val `channelId`: ChannelId, + val `counterpartyNodeId`: PublicKey, + val `amountSatoshis`: kotlin.ULong, + val `claimableHeight`: kotlin.UInt, + val `paymentHash`: PaymentHash, + val `outboundPayment`: kotlin.Boolean, + ) : LightningBalance() { + } + @kotlinx.serialization.Serializable + data class MaybePreimageClaimableHtlc( + val `channelId`: ChannelId, + val `counterpartyNodeId`: PublicKey, + val `amountSatoshis`: kotlin.ULong, + val `expiryHeight`: kotlin.UInt, + val `paymentHash`: PaymentHash, + ) : LightningBalance() { + } + @kotlinx.serialization.Serializable + data class CounterpartyRevokedOutputClaimable( + val `channelId`: ChannelId, + val `counterpartyNodeId`: PublicKey, + val `amountSatoshis`: kotlin.ULong, + ) : LightningBalance() { + } + +} + + + + + + + +@kotlinx.serialization.Serializable +enum class LogLevel { + + GOSSIP, + TRACE, + DEBUG, + INFO, + WARN, + ERROR; + companion object +} + + + + + + +@kotlinx.serialization.Serializable +sealed class MaxDustHtlcExposure { + @kotlinx.serialization.Serializable + data class FixedLimit( + val `limitMsat`: kotlin.ULong, + ) : MaxDustHtlcExposure() { + } + @kotlinx.serialization.Serializable + data class FeeRateMultiplier( + val `multiplier`: kotlin.ULong, + ) : MaxDustHtlcExposure() { + } + +} + + + + + + + +@kotlinx.serialization.Serializable +enum class Network { + + BITCOIN, + TESTNET, + SIGNET, + REGTEST; + companion object +} + + + + + + + +sealed class NodeException(message: String): kotlin.Exception(message) { + + class AlreadyRunning(message: String) : NodeException(message) + + class NotRunning(message: String) : NodeException(message) + + class OnchainTxCreationFailed(message: String) : NodeException(message) + + class ConnectionFailed(message: String) : NodeException(message) + + class InvoiceCreationFailed(message: String) : NodeException(message) + + class InvoiceRequestCreationFailed(message: String) : NodeException(message) + + class OfferCreationFailed(message: String) : NodeException(message) + + class RefundCreationFailed(message: String) : NodeException(message) + + class PaymentSendingFailed(message: String) : NodeException(message) + + class InvalidCustomTlvs(message: String) : NodeException(message) + + class ProbeSendingFailed(message: String) : NodeException(message) + + class RouteNotFound(message: String) : NodeException(message) + + class ChannelCreationFailed(message: String) : NodeException(message) + + class ChannelClosingFailed(message: String) : NodeException(message) + + class ChannelSplicingFailed(message: String) : NodeException(message) + + class ChannelConfigUpdateFailed(message: String) : NodeException(message) + + class PersistenceFailed(message: String) : NodeException(message) + + class FeerateEstimationUpdateFailed(message: String) : NodeException(message) + + class FeerateEstimationUpdateTimeout(message: String) : NodeException(message) + + class WalletOperationFailed(message: String) : NodeException(message) + + class WalletOperationTimeout(message: String) : NodeException(message) + + class OnchainTxSigningFailed(message: String) : NodeException(message) + + class TxSyncFailed(message: String) : NodeException(message) + + class TxSyncTimeout(message: String) : NodeException(message) + + class GossipUpdateFailed(message: String) : NodeException(message) + + class GossipUpdateTimeout(message: String) : NodeException(message) + + class LiquidityRequestFailed(message: String) : NodeException(message) + + class UriParameterParsingFailed(message: String) : NodeException(message) + + class InvalidAddress(message: String) : NodeException(message) + + class InvalidSocketAddress(message: String) : NodeException(message) + + class InvalidPublicKey(message: String) : NodeException(message) + + class InvalidSecretKey(message: String) : NodeException(message) + + class InvalidOfferId(message: String) : NodeException(message) + + class InvalidNodeId(message: String) : NodeException(message) + + class InvalidPaymentId(message: String) : NodeException(message) + + class InvalidPaymentHash(message: String) : NodeException(message) + + class InvalidPaymentPreimage(message: String) : NodeException(message) + + class InvalidPaymentSecret(message: String) : NodeException(message) + + class InvalidAmount(message: String) : NodeException(message) + + class InvalidInvoice(message: String) : NodeException(message) + + class InvalidOffer(message: String) : NodeException(message) + + class InvalidRefund(message: String) : NodeException(message) + + class InvalidChannelId(message: String) : NodeException(message) + + class InvalidNetwork(message: String) : NodeException(message) + + class InvalidUri(message: String) : NodeException(message) + + class InvalidQuantity(message: String) : NodeException(message) + + class InvalidNodeAlias(message: String) : NodeException(message) + + class InvalidDateTime(message: String) : NodeException(message) + + class InvalidFeeRate(message: String) : NodeException(message) + + class DuplicatePayment(message: String) : NodeException(message) + + class UnsupportedCurrency(message: String) : NodeException(message) + + class InsufficientFunds(message: String) : NodeException(message) + + class LiquiditySourceUnavailable(message: String) : NodeException(message) + + class LiquidityFeeTooHigh(message: String) : NodeException(message) + + class InvalidBlindedPaths(message: String) : NodeException(message) + + class AsyncPaymentServicesDisabled(message: String) : NodeException(message) + + class CannotRbfFundingTransaction(message: String) : NodeException(message) + + class TransactionNotFound(message: String) : NodeException(message) + + class TransactionAlreadyConfirmed(message: String) : NodeException(message) + + class NoSpendableOutputs(message: String) : NodeException(message) + + class CoinSelectionFailed(message: String) : NodeException(message) + + class InvalidMnemonic(message: String) : NodeException(message) + + class BackgroundSyncNotEnabled(message: String) : NodeException(message) + + class AddressTypeAlreadyMonitored(message: String) : NodeException(message) + + class AddressTypeIsPrimary(message: String) : NodeException(message) + + class AddressTypeNotMonitored(message: String) : NodeException(message) + + class OnchainWalletAccountNotRegistered(message: String) : NodeException(message) + + class InvalidSeedBytes(message: String) : NodeException(message) + +} + + + + +@kotlinx.serialization.Serializable +sealed class OfferAmount { + @kotlinx.serialization.Serializable + data class Bitcoin( + val `amountMsats`: kotlin.ULong, + ) : OfferAmount() { + } + @kotlinx.serialization.Serializable + data class Currency( + val `iso4217Code`: kotlin.String, + val `amount`: kotlin.ULong, + ) : OfferAmount() { + } + +} + + + + + + + +@kotlinx.serialization.Serializable +enum class PaymentDirection { + + INBOUND, + OUTBOUND; + companion object +} + + + + + + + +@kotlinx.serialization.Serializable +enum class PaymentFailureReason { + + RECIPIENT_REJECTED, + USER_ABANDONED, + RETRIES_EXHAUSTED, + PAYMENT_EXPIRED, + ROUTE_NOT_FOUND, + UNEXPECTED_ERROR, + UNKNOWN_REQUIRED_FEATURES, + INVOICE_REQUEST_EXPIRED, + INVOICE_REQUEST_REJECTED, + BLINDED_PATH_CREATION_FAILED; + companion object +} + + + + + + +@kotlinx.serialization.Serializable +sealed class PaymentKind { + @kotlinx.serialization.Serializable + data class Onchain( + val `txid`: Txid, + val `status`: ConfirmationStatus, + ) : PaymentKind() { + } + @kotlinx.serialization.Serializable + data class Bolt11( + val `hash`: PaymentHash, + val `preimage`: PaymentPreimage?, + val `secret`: PaymentSecret?, + val `description`: kotlin.String?, + val `bolt11`: kotlin.String?, + ) : PaymentKind() { + } + @kotlinx.serialization.Serializable + data class Bolt11Jit( + val `hash`: PaymentHash, + val `preimage`: PaymentPreimage?, + val `secret`: PaymentSecret?, + val `counterpartySkimmedFeeMsat`: kotlin.ULong?, + val `lspFeeLimits`: LspFeeLimits, + val `description`: kotlin.String?, + val `bolt11`: kotlin.String?, + ) : PaymentKind() { + } + @kotlinx.serialization.Serializable + data class Bolt12Offer( + val `hash`: PaymentHash?, + val `preimage`: PaymentPreimage?, + val `secret`: PaymentSecret?, + val `offerId`: OfferId, + val `payerNote`: UntrustedString?, + val `quantity`: kotlin.ULong?, + ) : PaymentKind() { + } + @kotlinx.serialization.Serializable + data class Bolt12Refund( + val `hash`: PaymentHash?, + val `preimage`: PaymentPreimage?, + val `secret`: PaymentSecret?, + val `payerNote`: UntrustedString?, + val `quantity`: kotlin.ULong?, + ) : PaymentKind() { + } + @kotlinx.serialization.Serializable + data class Spontaneous( + val `hash`: PaymentHash, + val `preimage`: PaymentPreimage?, + ) : PaymentKind() { + } + +} + + + + + + + +@kotlinx.serialization.Serializable +enum class PaymentStatus { + + PENDING, + SUCCEEDED, + FAILED; + companion object +} + + + + + + +@kotlinx.serialization.Serializable +sealed class PendingSweepBalance { + @kotlinx.serialization.Serializable + data class PendingBroadcast( + val `channelId`: ChannelId?, + val `amountSatoshis`: kotlin.ULong, + ) : PendingSweepBalance() { + } + @kotlinx.serialization.Serializable + data class BroadcastAwaitingConfirmation( + val `channelId`: ChannelId?, + val `latestBroadcastHeight`: kotlin.UInt, + val `latestSpendingTxid`: Txid, + val `amountSatoshis`: kotlin.ULong, + ) : PendingSweepBalance() { + } + @kotlinx.serialization.Serializable + data class AwaitingThresholdConfirmations( + val `channelId`: ChannelId?, + val `latestSpendingTxid`: Txid, + val `confirmationHash`: BlockHash, + val `confirmationHeight`: kotlin.UInt, + val `amountSatoshis`: kotlin.ULong, + ) : PendingSweepBalance() { + } + +} + + + + + + +@kotlinx.serialization.Serializable +sealed class QrPaymentResult { + @kotlinx.serialization.Serializable + data class Onchain( + val `txid`: Txid, + ) : QrPaymentResult() { + } + @kotlinx.serialization.Serializable + data class Bolt11( + val `paymentId`: PaymentId, + ) : QrPaymentResult() { + } + @kotlinx.serialization.Serializable + data class Bolt12( + val `paymentId`: PaymentId, + ) : QrPaymentResult() { + } + +} + + + + + + + +@kotlinx.serialization.Serializable +enum class SyncType { + + ONCHAIN_WALLET, + LIGHTNING_WALLET, + FEE_RATE_CACHE; + companion object +} + + + + + + + +sealed class VssHeaderProviderException(message: String): kotlin.Exception(message) { + + class InvalidData(message: String) : VssHeaderProviderException(message) + + class RequestException(message: String) : VssHeaderProviderException(message) + + class AuthorizationException(message: String) : VssHeaderProviderException(message) + + class InternalException(message: String) : VssHeaderProviderException(message) + +} + + + + + +@kotlinx.serialization.Serializable +enum class WordCount { + + WORDS12, + WORDS15, + WORDS18, + WORDS21, + WORDS24; + companion object +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias Address = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias BlockHash = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias ChannelId = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias Lsps1OrderId = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias LspsDateTime = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias Mnemonic = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias NodeAlias = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias NodeId = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias OfferId = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias PaymentHash = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias PaymentId = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias PaymentPreimage = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias PaymentSecret = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias PublicKey = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias SocketAddress = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias Txid = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias UntrustedString = kotlin.String + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +typealias UserChannelId = kotlin.String diff --git a/bindings/kotlin/ldk-node-jvm/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.jvm.kt b/bindings/kotlin/ldk-node-jvm/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.jvm.kt new file mode 100644 index 0000000000..945f76a53c --- /dev/null +++ b/bindings/kotlin/ldk-node-jvm/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.jvm.kt @@ -0,0 +1,15196 @@ + + +@file:Suppress("RemoveRedundantBackticks") + +package org.lightningdevkit.ldknode + +// Common helper code. +// +// Ideally this would live in a separate .kt file where it can be unittested etc +// in isolation, and perhaps even published as a re-useable package. +// +// However, it's important that the details of how this helper code works (e.g. the +// way that different builtin types are passed across the FFI) exactly match what's +// expected by the Rust code on the other side of the interface. In practice right +// now that means coming from the exact some version of `uniffi` that was used to +// compile the Rust component. The easiest way to ensure this is to bundle the Kotlin +// helpers directly inline like we're doing here. + +import com.sun.jna.Library +import com.sun.jna.Native +import com.sun.jna.Structure +import kotlin.coroutines.resume +import kotlinx.coroutines.CancellableContinuation +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import kotlinx.coroutines.suspendCancellableCoroutine +import kotlinx.coroutines.withContext + + +internal typealias Pointer = com.sun.jna.Pointer +internal val NullPointer: Pointer? = com.sun.jna.Pointer.NULL +internal fun Pointer.toLong(): Long = Pointer.nativeValue(this) +internal fun kotlin.Long.toPointer() = com.sun.jna.Pointer(this) + + +@kotlin.jvm.JvmInline +value class ByteBuffer(private val inner: java.nio.ByteBuffer) { + init { + inner.order(java.nio.ByteOrder.BIG_ENDIAN) + } + + fun internal() = inner + + fun limit() = inner.limit() + + fun position() = inner.position() + + fun hasRemaining() = inner.hasRemaining() + + fun get() = inner.get() + + fun get(bytesToRead: Int): ByteArray = ByteArray(bytesToRead).apply(inner::get) + + fun getShort() = inner.getShort() + + fun getInt() = inner.getInt() + + fun getLong() = inner.getLong() + + fun getFloat() = inner.getFloat() + + fun getDouble() = inner.getDouble() + + + + fun put(value: Byte) { + inner.put(value) + } + + fun put(src: ByteArray) { + inner.put(src) + } + + fun putShort(value: Short) { + inner.putShort(value) + } + + fun putInt(value: Int) { + inner.putInt(value) + } + + fun putLong(value: Long) { + inner.putLong(value) + } + + fun putFloat(value: Float) { + inner.putFloat(value) + } + + fun putDouble(value: Double) { + inner.putDouble(value) + } + + + fun writeUtf8(value: String) { + Charsets.UTF_8.newEncoder().run { + onMalformedInput(java.nio.charset.CodingErrorAction.REPLACE) + encode(java.nio.CharBuffer.wrap(value), inner, false) + } + } +} +fun RustBuffer.setValue(array: RustBufferByValue) { + this.data = array.data + this.len = array.len + this.capacity = array.capacity +} + +internal object RustBufferHelper { + fun allocValue(size: ULong = 0UL): RustBufferByValue = uniffiRustCall { status -> + // Note: need to convert the size to a `Long` value to make this work with JVM. + UniffiLib.INSTANCE.ffi_ldk_node_rustbuffer_alloc(size.toLong(), status) + }.also { + if(it.data == null) { + throw RuntimeException("RustBuffer.alloc() returned null data pointer (size=${size})") + } + } + + fun free(buf: RustBufferByValue) = uniffiRustCall { status -> + UniffiLib.INSTANCE.ffi_ldk_node_rustbuffer_free(buf, status) + } +} + +@Structure.FieldOrder("capacity", "len", "data") +open class RustBufferStruct( + // Note: `capacity` and `len` are actually `ULong` values, but JVM only supports signed values. + // When dealing with these fields, make sure to call `toULong()`. + @JvmField internal var capacity: Long, + @JvmField internal var len: Long, + @JvmField internal var data: Pointer?, +) : Structure() { + constructor(): this(0.toLong(), 0.toLong(), null) + + class ByValue( + capacity: Long, + len: Long, + data: Pointer?, + ): RustBuffer(capacity, len, data), Structure.ByValue { + constructor(): this(0.toLong(), 0.toLong(), null) + } + + /** + * The equivalent of the `*mut RustBuffer` type. + * Required for callbacks taking in an out pointer. + * + * Size is the sum of all values in the struct. + */ + class ByReference( + capacity: Long, + len: Long, + data: Pointer?, + ): RustBuffer(capacity, len, data), Structure.ByReference { + constructor(): this(0.toLong(), 0.toLong(), null) + } +} + +typealias RustBuffer = RustBufferStruct +typealias RustBufferByValue = RustBufferStruct.ByValue + +internal fun RustBuffer.asByteBuffer(): ByteBuffer? { + require(this.len <= Int.MAX_VALUE) { + val length = this.len + "cannot handle RustBuffer longer than Int.MAX_VALUE bytes: length is $length" + } + return ByteBuffer(data?.getByteBuffer(0L, this.len) ?: return null) +} + +internal fun RustBufferByValue.asByteBuffer(): ByteBuffer? { + require(this.len <= Int.MAX_VALUE) { + val length = this.len + "cannot handle RustBuffer longer than Int.MAX_VALUE bytes: length is $length" + } + return ByteBuffer(data?.getByteBuffer(0L, this.len) ?: return null) +} + +internal class RustBufferByReference : com.sun.jna.ptr.ByReference(16) +internal fun RustBufferByReference.setValue(value: RustBufferByValue) { + // NOTE: The offsets are as they are in the C-like struct. + val pointer = getPointer() + pointer.setLong(0, value.capacity) + pointer.setLong(8, value.len) + pointer.setPointer(16, value.data) +} +internal fun RustBufferByReference.getValue(): RustBufferByValue { + val pointer = getPointer() + val value = RustBufferByValue() + value.writeField("capacity", pointer.getLong(0)) + value.writeField("len", pointer.getLong(8)) + value.writeField("data", pointer.getLong(16)) + return value +} + + + +// This is a helper for safely passing byte references into the rust code. +// It's not actually used at the moment, because there aren't many things that you +// can take a direct pointer to in the JVM, and if we're going to copy something +// then we might as well copy it into a `RustBuffer`. But it's here for API +// completeness. + +@Structure.FieldOrder("len", "data") +internal open class ForeignBytesStruct : Structure() { + @JvmField internal var len: Int = 0 + @JvmField internal var data: Pointer? = null + + internal class ByValue : ForeignBytes(), Structure.ByValue +} +internal typealias ForeignBytes = ForeignBytesStruct +internal typealias ForeignBytesByValue = ForeignBytesStruct.ByValue + +interface FfiConverter { + // Convert an FFI type to a Kotlin type + fun lift(value: FfiType): KotlinType + + // Convert an Kotlin type to an FFI type + fun lower(value: KotlinType): FfiType + + // Read a Kotlin type from a `ByteBuffer` + fun read(buf: ByteBuffer): KotlinType + + // Calculate bytes to allocate when creating a `RustBuffer` + // + // This must return at least as many bytes as the write() function will + // write. It can return more bytes than needed, for example when writing + // Strings we can't know the exact bytes needed until we the UTF-8 + // encoding, so we pessimistically allocate the largest size possible (3 + // bytes per codepoint). Allocating extra bytes is not really a big deal + // because the `RustBuffer` is short-lived. + fun allocationSize(value: KotlinType): ULong + + // Write a Kotlin type to a `ByteBuffer` + fun write(value: KotlinType, buf: ByteBuffer) + + // Lower a value into a `RustBuffer` + // + // This method lowers a value into a `RustBuffer` rather than the normal + // FfiType. It's used by the callback interface code. Callback interface + // returns are always serialized into a `RustBuffer` regardless of their + // normal FFI type. + fun lowerIntoRustBuffer(value: KotlinType): RustBufferByValue { + val rbuf = RustBufferHelper.allocValue(allocationSize(value)) + val bbuf = rbuf.asByteBuffer()!! + write(value, bbuf) + return RustBufferByValue( + capacity = rbuf.capacity, + len = bbuf.position().toLong(), + data = rbuf.data, + ) + } + + // Lift a value from a `RustBuffer`. + // + // This here mostly because of the symmetry with `lowerIntoRustBuffer()`. + // It's currently only used by the `FfiConverterRustBuffer` class below. + fun liftFromRustBuffer(rbuf: RustBufferByValue): KotlinType { + val byteBuf = rbuf.asByteBuffer()!! + try { + val item = read(byteBuf) + if (byteBuf.hasRemaining()) { + throw RuntimeException("junk remaining in buffer after lifting, something is very wrong!!") + } + return item + } finally { + RustBufferHelper.free(rbuf) + } + } +} + +// FfiConverter that uses `RustBuffer` as the FfiType +interface FfiConverterRustBuffer: FfiConverter { + override fun lift(value: RustBufferByValue) = liftFromRustBuffer(value) + override fun lower(value: KotlinType) = lowerIntoRustBuffer(value) +} + +internal const val UNIFFI_CALL_SUCCESS = 0.toByte() +internal const val UNIFFI_CALL_ERROR = 1.toByte() +internal const val UNIFFI_CALL_UNEXPECTED_ERROR = 2.toByte() + +// Default Implementations +internal fun UniffiRustCallStatus.isSuccess(): Boolean + = code == UNIFFI_CALL_SUCCESS + +internal fun UniffiRustCallStatus.isError(): Boolean + = code == UNIFFI_CALL_ERROR + +internal fun UniffiRustCallStatus.isPanic(): Boolean + = code == UNIFFI_CALL_UNEXPECTED_ERROR + +internal fun UniffiRustCallStatusByValue.isSuccess(): Boolean + = code == UNIFFI_CALL_SUCCESS + +internal fun UniffiRustCallStatusByValue.isError(): Boolean + = code == UNIFFI_CALL_ERROR + +internal fun UniffiRustCallStatusByValue.isPanic(): Boolean + = code == UNIFFI_CALL_UNEXPECTED_ERROR + +// Each top-level error class has a companion object that can lift the error from the call status's rust buffer +interface UniffiRustCallStatusErrorHandler { + fun lift(errorBuf: RustBufferByValue): E; +} + +// Helpers for calling Rust +// In practice we usually need to be synchronized to call this safely, so it doesn't +// synchronize itself + +// Call a rust function that returns a Result<>. Pass in the Error class companion that corresponds to the Err +internal inline fun uniffiRustCallWithError(errorHandler: UniffiRustCallStatusErrorHandler, crossinline callback: (UniffiRustCallStatus) -> U): U { + return UniffiRustCallStatusHelper.withReference() { status -> + val returnValue = callback(status) + uniffiCheckCallStatus(errorHandler, status) + returnValue + } +} + +// Check `status` and throw an error if the call wasn't successful +internal fun uniffiCheckCallStatus(errorHandler: UniffiRustCallStatusErrorHandler, status: UniffiRustCallStatus) { + if (status.isSuccess()) { + return + } else if (status.isError()) { + throw errorHandler.lift(status.errorBuf) + } else if (status.isPanic()) { + // when the rust code sees a panic, it tries to construct a rustbuffer + // with the message. but if that code panics, then it just sends back + // an empty buffer. + if (status.errorBuf.len > 0) { + throw InternalException(FfiConverterString.lift(status.errorBuf)) + } else { + throw InternalException("Rust panic") + } + } else { + throw InternalException("Unknown rust call status: $status.code") + } +} + +// UniffiRustCallStatusErrorHandler implementation for times when we don't expect a CALL_ERROR +object UniffiNullRustCallStatusErrorHandler: UniffiRustCallStatusErrorHandler { + override fun lift(errorBuf: RustBufferByValue): InternalException { + RustBufferHelper.free(errorBuf) + return InternalException("Unexpected CALL_ERROR") + } +} + +// Call a rust function that returns a plain value +internal inline fun uniffiRustCall(crossinline callback: (UniffiRustCallStatus) -> U): U { + return uniffiRustCallWithError(UniffiNullRustCallStatusErrorHandler, callback) +} + +internal inline fun uniffiTraitInterfaceCall( + callStatus: UniffiRustCallStatus, + makeCall: () -> T, + writeReturn: (T) -> Unit, +) { + try { + writeReturn(makeCall()) + } catch(e: kotlin.Exception) { + callStatus.code = UNIFFI_CALL_UNEXPECTED_ERROR + callStatus.errorBuf = FfiConverterString.lower(e.toString()) + } +} + +internal inline fun uniffiTraitInterfaceCallWithError( + callStatus: UniffiRustCallStatus, + makeCall: () -> T, + writeReturn: (T) -> Unit, + lowerError: (E) -> RustBufferByValue +) { + try { + writeReturn(makeCall()) + } catch(e: kotlin.Exception) { + if (e is E) { + callStatus.code = UNIFFI_CALL_ERROR + callStatus.errorBuf = lowerError(e) + } else { + callStatus.code = UNIFFI_CALL_UNEXPECTED_ERROR + callStatus.errorBuf = FfiConverterString.lower(e.toString()) + } + } +} + +@Structure.FieldOrder("code", "errorBuf") +internal open class UniffiRustCallStatusStruct( + @JvmField internal var code: Byte, + @JvmField internal var errorBuf: RustBufferByValue, +) : Structure() { + constructor(): this(0.toByte(), RustBufferByValue()) + + internal class ByValue( + code: Byte, + errorBuf: RustBufferByValue, + ): UniffiRustCallStatusStruct(code, errorBuf), Structure.ByValue { + constructor(): this(0.toByte(), RustBufferByValue()) + } + internal class ByReference( + code: Byte, + errorBuf: RustBufferByValue, + ): UniffiRustCallStatusStruct(code, errorBuf), Structure.ByReference { + constructor(): this(0.toByte(), RustBufferByValue()) + } +} + +internal typealias UniffiRustCallStatus = UniffiRustCallStatusStruct.ByReference +internal typealias UniffiRustCallStatusByValue = UniffiRustCallStatusStruct.ByValue + +internal object UniffiRustCallStatusHelper { + fun allocValue() = UniffiRustCallStatusByValue() + fun withReference(block: (UniffiRustCallStatus) -> U): U { + val status = UniffiRustCallStatus() + return block(status) + } +} + +internal class UniffiHandleMap { + private val map = java.util.concurrent.ConcurrentHashMap() + private val counter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + val size: Int + get() = map.size + + // Insert a new object into the handle map and get a handle for it + fun insert(obj: T): Long { + val handle = counter.getAndAdd(1) + map[handle] = obj + return handle + } + + // Get an object from the handle map + fun get(handle: Long): T { + return map[handle] ?: throw InternalException("UniffiHandleMap.get: Invalid handle") + } + + // Remove an entry from the handlemap and get the Kotlin object back + fun remove(handle: Long): T { + return map.remove(handle) ?: throw InternalException("UniffiHandleMap.remove: Invalid handle") + } +} + +typealias ByteByReference = com.sun.jna.ptr.ByteByReference + +typealias DoubleByReference = com.sun.jna.ptr.DoubleByReference + +typealias FloatByReference = com.sun.jna.ptr.FloatByReference + +typealias IntByReference = com.sun.jna.ptr.IntByReference + +typealias LongByReference = com.sun.jna.ptr.LongByReference + +typealias PointerByReference = com.sun.jna.ptr.PointerByReference + +typealias ShortByReference = com.sun.jna.ptr.ShortByReference + +// Contains loading, initialization code, +// and the FFI Function declarations in a com.sun.jna.Library. + +// Define FFI callback types +internal interface UniffiRustFutureContinuationCallback: com.sun.jna.Callback { + fun callback(`data`: Long,`pollResult`: Byte,) +} +internal interface UniffiForeignFutureFree: com.sun.jna.Callback { + fun callback(`handle`: Long,) +} +internal interface UniffiCallbackInterfaceFree: com.sun.jna.Callback { + fun callback(`handle`: Long,) +} +@Structure.FieldOrder("handle", "free") +internal open class UniffiForeignFutureStruct( + @JvmField internal var `handle`: Long, + @JvmField internal var `free`: UniffiForeignFutureFree?, +) : com.sun.jna.Structure() { + constructor(): this( + + `handle` = 0.toLong(), + + `free` = null, + + ) + + internal class UniffiByValue( + `handle`: Long, + `free`: UniffiForeignFutureFree?, + ): UniffiForeignFuture(`handle`,`free`,), Structure.ByValue +} + +internal typealias UniffiForeignFuture = UniffiForeignFutureStruct + +internal fun UniffiForeignFuture.uniffiSetValue(other: UniffiForeignFuture) { + `handle` = other.`handle` + `free` = other.`free` +} +internal fun UniffiForeignFuture.uniffiSetValue(other: UniffiForeignFutureUniffiByValue) { + `handle` = other.`handle` + `free` = other.`free` +} + +internal typealias UniffiForeignFutureUniffiByValue = UniffiForeignFutureStruct.UniffiByValue +@Structure.FieldOrder("returnValue", "callStatus") +internal open class UniffiForeignFutureStructU8Struct( + @JvmField internal var `returnValue`: Byte, + @JvmField internal var `callStatus`: UniffiRustCallStatusByValue, +) : com.sun.jna.Structure() { + constructor(): this( + + `returnValue` = 0.toByte(), + + `callStatus` = UniffiRustCallStatusHelper.allocValue(), + + ) + + internal class UniffiByValue( + `returnValue`: Byte, + `callStatus`: UniffiRustCallStatusByValue, + ): UniffiForeignFutureStructU8(`returnValue`,`callStatus`,), Structure.ByValue +} + +internal typealias UniffiForeignFutureStructU8 = UniffiForeignFutureStructU8Struct + +internal fun UniffiForeignFutureStructU8.uniffiSetValue(other: UniffiForeignFutureStructU8) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} +internal fun UniffiForeignFutureStructU8.uniffiSetValue(other: UniffiForeignFutureStructU8UniffiByValue) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} + +internal typealias UniffiForeignFutureStructU8UniffiByValue = UniffiForeignFutureStructU8Struct.UniffiByValue +internal interface UniffiForeignFutureCompleteU8: com.sun.jna.Callback { + fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructU8UniffiByValue,) +} +@Structure.FieldOrder("returnValue", "callStatus") +internal open class UniffiForeignFutureStructI8Struct( + @JvmField internal var `returnValue`: Byte, + @JvmField internal var `callStatus`: UniffiRustCallStatusByValue, +) : com.sun.jna.Structure() { + constructor(): this( + + `returnValue` = 0.toByte(), + + `callStatus` = UniffiRustCallStatusHelper.allocValue(), + + ) + + internal class UniffiByValue( + `returnValue`: Byte, + `callStatus`: UniffiRustCallStatusByValue, + ): UniffiForeignFutureStructI8(`returnValue`,`callStatus`,), Structure.ByValue +} + +internal typealias UniffiForeignFutureStructI8 = UniffiForeignFutureStructI8Struct + +internal fun UniffiForeignFutureStructI8.uniffiSetValue(other: UniffiForeignFutureStructI8) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} +internal fun UniffiForeignFutureStructI8.uniffiSetValue(other: UniffiForeignFutureStructI8UniffiByValue) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} + +internal typealias UniffiForeignFutureStructI8UniffiByValue = UniffiForeignFutureStructI8Struct.UniffiByValue +internal interface UniffiForeignFutureCompleteI8: com.sun.jna.Callback { + fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructI8UniffiByValue,) +} +@Structure.FieldOrder("returnValue", "callStatus") +internal open class UniffiForeignFutureStructU16Struct( + @JvmField internal var `returnValue`: Short, + @JvmField internal var `callStatus`: UniffiRustCallStatusByValue, +) : com.sun.jna.Structure() { + constructor(): this( + + `returnValue` = 0.toShort(), + + `callStatus` = UniffiRustCallStatusHelper.allocValue(), + + ) + + internal class UniffiByValue( + `returnValue`: Short, + `callStatus`: UniffiRustCallStatusByValue, + ): UniffiForeignFutureStructU16(`returnValue`,`callStatus`,), Structure.ByValue +} + +internal typealias UniffiForeignFutureStructU16 = UniffiForeignFutureStructU16Struct + +internal fun UniffiForeignFutureStructU16.uniffiSetValue(other: UniffiForeignFutureStructU16) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} +internal fun UniffiForeignFutureStructU16.uniffiSetValue(other: UniffiForeignFutureStructU16UniffiByValue) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} + +internal typealias UniffiForeignFutureStructU16UniffiByValue = UniffiForeignFutureStructU16Struct.UniffiByValue +internal interface UniffiForeignFutureCompleteU16: com.sun.jna.Callback { + fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructU16UniffiByValue,) +} +@Structure.FieldOrder("returnValue", "callStatus") +internal open class UniffiForeignFutureStructI16Struct( + @JvmField internal var `returnValue`: Short, + @JvmField internal var `callStatus`: UniffiRustCallStatusByValue, +) : com.sun.jna.Structure() { + constructor(): this( + + `returnValue` = 0.toShort(), + + `callStatus` = UniffiRustCallStatusHelper.allocValue(), + + ) + + internal class UniffiByValue( + `returnValue`: Short, + `callStatus`: UniffiRustCallStatusByValue, + ): UniffiForeignFutureStructI16(`returnValue`,`callStatus`,), Structure.ByValue +} + +internal typealias UniffiForeignFutureStructI16 = UniffiForeignFutureStructI16Struct + +internal fun UniffiForeignFutureStructI16.uniffiSetValue(other: UniffiForeignFutureStructI16) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} +internal fun UniffiForeignFutureStructI16.uniffiSetValue(other: UniffiForeignFutureStructI16UniffiByValue) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} + +internal typealias UniffiForeignFutureStructI16UniffiByValue = UniffiForeignFutureStructI16Struct.UniffiByValue +internal interface UniffiForeignFutureCompleteI16: com.sun.jna.Callback { + fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructI16UniffiByValue,) +} +@Structure.FieldOrder("returnValue", "callStatus") +internal open class UniffiForeignFutureStructU32Struct( + @JvmField internal var `returnValue`: Int, + @JvmField internal var `callStatus`: UniffiRustCallStatusByValue, +) : com.sun.jna.Structure() { + constructor(): this( + + `returnValue` = 0, + + `callStatus` = UniffiRustCallStatusHelper.allocValue(), + + ) + + internal class UniffiByValue( + `returnValue`: Int, + `callStatus`: UniffiRustCallStatusByValue, + ): UniffiForeignFutureStructU32(`returnValue`,`callStatus`,), Structure.ByValue +} + +internal typealias UniffiForeignFutureStructU32 = UniffiForeignFutureStructU32Struct + +internal fun UniffiForeignFutureStructU32.uniffiSetValue(other: UniffiForeignFutureStructU32) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} +internal fun UniffiForeignFutureStructU32.uniffiSetValue(other: UniffiForeignFutureStructU32UniffiByValue) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} + +internal typealias UniffiForeignFutureStructU32UniffiByValue = UniffiForeignFutureStructU32Struct.UniffiByValue +internal interface UniffiForeignFutureCompleteU32: com.sun.jna.Callback { + fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructU32UniffiByValue,) +} +@Structure.FieldOrder("returnValue", "callStatus") +internal open class UniffiForeignFutureStructI32Struct( + @JvmField internal var `returnValue`: Int, + @JvmField internal var `callStatus`: UniffiRustCallStatusByValue, +) : com.sun.jna.Structure() { + constructor(): this( + + `returnValue` = 0, + + `callStatus` = UniffiRustCallStatusHelper.allocValue(), + + ) + + internal class UniffiByValue( + `returnValue`: Int, + `callStatus`: UniffiRustCallStatusByValue, + ): UniffiForeignFutureStructI32(`returnValue`,`callStatus`,), Structure.ByValue +} + +internal typealias UniffiForeignFutureStructI32 = UniffiForeignFutureStructI32Struct + +internal fun UniffiForeignFutureStructI32.uniffiSetValue(other: UniffiForeignFutureStructI32) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} +internal fun UniffiForeignFutureStructI32.uniffiSetValue(other: UniffiForeignFutureStructI32UniffiByValue) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} + +internal typealias UniffiForeignFutureStructI32UniffiByValue = UniffiForeignFutureStructI32Struct.UniffiByValue +internal interface UniffiForeignFutureCompleteI32: com.sun.jna.Callback { + fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructI32UniffiByValue,) +} +@Structure.FieldOrder("returnValue", "callStatus") +internal open class UniffiForeignFutureStructU64Struct( + @JvmField internal var `returnValue`: Long, + @JvmField internal var `callStatus`: UniffiRustCallStatusByValue, +) : com.sun.jna.Structure() { + constructor(): this( + + `returnValue` = 0.toLong(), + + `callStatus` = UniffiRustCallStatusHelper.allocValue(), + + ) + + internal class UniffiByValue( + `returnValue`: Long, + `callStatus`: UniffiRustCallStatusByValue, + ): UniffiForeignFutureStructU64(`returnValue`,`callStatus`,), Structure.ByValue +} + +internal typealias UniffiForeignFutureStructU64 = UniffiForeignFutureStructU64Struct + +internal fun UniffiForeignFutureStructU64.uniffiSetValue(other: UniffiForeignFutureStructU64) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} +internal fun UniffiForeignFutureStructU64.uniffiSetValue(other: UniffiForeignFutureStructU64UniffiByValue) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} + +internal typealias UniffiForeignFutureStructU64UniffiByValue = UniffiForeignFutureStructU64Struct.UniffiByValue +internal interface UniffiForeignFutureCompleteU64: com.sun.jna.Callback { + fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructU64UniffiByValue,) +} +@Structure.FieldOrder("returnValue", "callStatus") +internal open class UniffiForeignFutureStructI64Struct( + @JvmField internal var `returnValue`: Long, + @JvmField internal var `callStatus`: UniffiRustCallStatusByValue, +) : com.sun.jna.Structure() { + constructor(): this( + + `returnValue` = 0.toLong(), + + `callStatus` = UniffiRustCallStatusHelper.allocValue(), + + ) + + internal class UniffiByValue( + `returnValue`: Long, + `callStatus`: UniffiRustCallStatusByValue, + ): UniffiForeignFutureStructI64(`returnValue`,`callStatus`,), Structure.ByValue +} + +internal typealias UniffiForeignFutureStructI64 = UniffiForeignFutureStructI64Struct + +internal fun UniffiForeignFutureStructI64.uniffiSetValue(other: UniffiForeignFutureStructI64) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} +internal fun UniffiForeignFutureStructI64.uniffiSetValue(other: UniffiForeignFutureStructI64UniffiByValue) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} + +internal typealias UniffiForeignFutureStructI64UniffiByValue = UniffiForeignFutureStructI64Struct.UniffiByValue +internal interface UniffiForeignFutureCompleteI64: com.sun.jna.Callback { + fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructI64UniffiByValue,) +} +@Structure.FieldOrder("returnValue", "callStatus") +internal open class UniffiForeignFutureStructF32Struct( + @JvmField internal var `returnValue`: Float, + @JvmField internal var `callStatus`: UniffiRustCallStatusByValue, +) : com.sun.jna.Structure() { + constructor(): this( + + `returnValue` = 0.0f, + + `callStatus` = UniffiRustCallStatusHelper.allocValue(), + + ) + + internal class UniffiByValue( + `returnValue`: Float, + `callStatus`: UniffiRustCallStatusByValue, + ): UniffiForeignFutureStructF32(`returnValue`,`callStatus`,), Structure.ByValue +} + +internal typealias UniffiForeignFutureStructF32 = UniffiForeignFutureStructF32Struct + +internal fun UniffiForeignFutureStructF32.uniffiSetValue(other: UniffiForeignFutureStructF32) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} +internal fun UniffiForeignFutureStructF32.uniffiSetValue(other: UniffiForeignFutureStructF32UniffiByValue) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} + +internal typealias UniffiForeignFutureStructF32UniffiByValue = UniffiForeignFutureStructF32Struct.UniffiByValue +internal interface UniffiForeignFutureCompleteF32: com.sun.jna.Callback { + fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructF32UniffiByValue,) +} +@Structure.FieldOrder("returnValue", "callStatus") +internal open class UniffiForeignFutureStructF64Struct( + @JvmField internal var `returnValue`: Double, + @JvmField internal var `callStatus`: UniffiRustCallStatusByValue, +) : com.sun.jna.Structure() { + constructor(): this( + + `returnValue` = 0.0, + + `callStatus` = UniffiRustCallStatusHelper.allocValue(), + + ) + + internal class UniffiByValue( + `returnValue`: Double, + `callStatus`: UniffiRustCallStatusByValue, + ): UniffiForeignFutureStructF64(`returnValue`,`callStatus`,), Structure.ByValue +} + +internal typealias UniffiForeignFutureStructF64 = UniffiForeignFutureStructF64Struct + +internal fun UniffiForeignFutureStructF64.uniffiSetValue(other: UniffiForeignFutureStructF64) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} +internal fun UniffiForeignFutureStructF64.uniffiSetValue(other: UniffiForeignFutureStructF64UniffiByValue) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} + +internal typealias UniffiForeignFutureStructF64UniffiByValue = UniffiForeignFutureStructF64Struct.UniffiByValue +internal interface UniffiForeignFutureCompleteF64: com.sun.jna.Callback { + fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructF64UniffiByValue,) +} +@Structure.FieldOrder("returnValue", "callStatus") +internal open class UniffiForeignFutureStructPointerStruct( + @JvmField internal var `returnValue`: Pointer?, + @JvmField internal var `callStatus`: UniffiRustCallStatusByValue, +) : com.sun.jna.Structure() { + constructor(): this( + + `returnValue` = NullPointer, + + `callStatus` = UniffiRustCallStatusHelper.allocValue(), + + ) + + internal class UniffiByValue( + `returnValue`: Pointer?, + `callStatus`: UniffiRustCallStatusByValue, + ): UniffiForeignFutureStructPointer(`returnValue`,`callStatus`,), Structure.ByValue +} + +internal typealias UniffiForeignFutureStructPointer = UniffiForeignFutureStructPointerStruct + +internal fun UniffiForeignFutureStructPointer.uniffiSetValue(other: UniffiForeignFutureStructPointer) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} +internal fun UniffiForeignFutureStructPointer.uniffiSetValue(other: UniffiForeignFutureStructPointerUniffiByValue) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} + +internal typealias UniffiForeignFutureStructPointerUniffiByValue = UniffiForeignFutureStructPointerStruct.UniffiByValue +internal interface UniffiForeignFutureCompletePointer: com.sun.jna.Callback { + fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructPointerUniffiByValue,) +} +@Structure.FieldOrder("returnValue", "callStatus") +internal open class UniffiForeignFutureStructRustBufferStruct( + @JvmField internal var `returnValue`: RustBufferByValue, + @JvmField internal var `callStatus`: UniffiRustCallStatusByValue, +) : com.sun.jna.Structure() { + constructor(): this( + + `returnValue` = RustBufferHelper.allocValue(), + + `callStatus` = UniffiRustCallStatusHelper.allocValue(), + + ) + + internal class UniffiByValue( + `returnValue`: RustBufferByValue, + `callStatus`: UniffiRustCallStatusByValue, + ): UniffiForeignFutureStructRustBuffer(`returnValue`,`callStatus`,), Structure.ByValue +} + +internal typealias UniffiForeignFutureStructRustBuffer = UniffiForeignFutureStructRustBufferStruct + +internal fun UniffiForeignFutureStructRustBuffer.uniffiSetValue(other: UniffiForeignFutureStructRustBuffer) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} +internal fun UniffiForeignFutureStructRustBuffer.uniffiSetValue(other: UniffiForeignFutureStructRustBufferUniffiByValue) { + `returnValue` = other.`returnValue` + `callStatus` = other.`callStatus` +} + +internal typealias UniffiForeignFutureStructRustBufferUniffiByValue = UniffiForeignFutureStructRustBufferStruct.UniffiByValue +internal interface UniffiForeignFutureCompleteRustBuffer: com.sun.jna.Callback { + fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructRustBufferUniffiByValue,) +} +@Structure.FieldOrder("callStatus") +internal open class UniffiForeignFutureStructVoidStruct( + @JvmField internal var `callStatus`: UniffiRustCallStatusByValue, +) : com.sun.jna.Structure() { + constructor(): this( + + `callStatus` = UniffiRustCallStatusHelper.allocValue(), + + ) + + internal class UniffiByValue( + `callStatus`: UniffiRustCallStatusByValue, + ): UniffiForeignFutureStructVoid(`callStatus`,), Structure.ByValue +} + +internal typealias UniffiForeignFutureStructVoid = UniffiForeignFutureStructVoidStruct + +internal fun UniffiForeignFutureStructVoid.uniffiSetValue(other: UniffiForeignFutureStructVoid) { + `callStatus` = other.`callStatus` +} +internal fun UniffiForeignFutureStructVoid.uniffiSetValue(other: UniffiForeignFutureStructVoidUniffiByValue) { + `callStatus` = other.`callStatus` +} + +internal typealias UniffiForeignFutureStructVoidUniffiByValue = UniffiForeignFutureStructVoidStruct.UniffiByValue +internal interface UniffiForeignFutureCompleteVoid: com.sun.jna.Callback { + fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructVoidUniffiByValue,) +} +internal interface UniffiCallbackInterfaceLogWriterMethod0: com.sun.jna.Callback { + fun callback(`uniffiHandle`: Long,`record`: RustBufferByValue,`uniffiOutReturn`: Pointer,uniffiCallStatus: UniffiRustCallStatus,) +} +internal interface UniffiCallbackInterfaceVssHeaderProviderMethod0: com.sun.jna.Callback { + fun callback(`uniffiHandle`: Long,`request`: RustBufferByValue,`uniffiFutureCallback`: UniffiForeignFutureCompleteRustBuffer,`uniffiCallbackData`: Long,`uniffiOutReturn`: UniffiForeignFuture,) +} +@Structure.FieldOrder("log", "uniffiFree") +internal open class UniffiVTableCallbackInterfaceLogWriterStruct( + @JvmField internal var `log`: UniffiCallbackInterfaceLogWriterMethod0?, + @JvmField internal var `uniffiFree`: UniffiCallbackInterfaceFree?, +) : com.sun.jna.Structure() { + constructor(): this( + + `log` = null, + + `uniffiFree` = null, + + ) + + internal class UniffiByValue( + `log`: UniffiCallbackInterfaceLogWriterMethod0?, + `uniffiFree`: UniffiCallbackInterfaceFree?, + ): UniffiVTableCallbackInterfaceLogWriter(`log`,`uniffiFree`,), Structure.ByValue +} + +internal typealias UniffiVTableCallbackInterfaceLogWriter = UniffiVTableCallbackInterfaceLogWriterStruct + +internal fun UniffiVTableCallbackInterfaceLogWriter.uniffiSetValue(other: UniffiVTableCallbackInterfaceLogWriter) { + `log` = other.`log` + `uniffiFree` = other.`uniffiFree` +} +internal fun UniffiVTableCallbackInterfaceLogWriter.uniffiSetValue(other: UniffiVTableCallbackInterfaceLogWriterUniffiByValue) { + `log` = other.`log` + `uniffiFree` = other.`uniffiFree` +} + +internal typealias UniffiVTableCallbackInterfaceLogWriterUniffiByValue = UniffiVTableCallbackInterfaceLogWriterStruct.UniffiByValue +@Structure.FieldOrder("getHeaders", "uniffiFree") +internal open class UniffiVTableCallbackInterfaceVssHeaderProviderStruct( + @JvmField internal var `getHeaders`: UniffiCallbackInterfaceVssHeaderProviderMethod0?, + @JvmField internal var `uniffiFree`: UniffiCallbackInterfaceFree?, +) : com.sun.jna.Structure() { + constructor(): this( + + `getHeaders` = null, + + `uniffiFree` = null, + + ) + + internal class UniffiByValue( + `getHeaders`: UniffiCallbackInterfaceVssHeaderProviderMethod0?, + `uniffiFree`: UniffiCallbackInterfaceFree?, + ): UniffiVTableCallbackInterfaceVssHeaderProvider(`getHeaders`,`uniffiFree`,), Structure.ByValue +} + +internal typealias UniffiVTableCallbackInterfaceVssHeaderProvider = UniffiVTableCallbackInterfaceVssHeaderProviderStruct + +internal fun UniffiVTableCallbackInterfaceVssHeaderProvider.uniffiSetValue(other: UniffiVTableCallbackInterfaceVssHeaderProvider) { + `getHeaders` = other.`getHeaders` + `uniffiFree` = other.`uniffiFree` +} +internal fun UniffiVTableCallbackInterfaceVssHeaderProvider.uniffiSetValue(other: UniffiVTableCallbackInterfaceVssHeaderProviderUniffiByValue) { + `getHeaders` = other.`getHeaders` + `uniffiFree` = other.`uniffiFree` +} + +internal typealias UniffiVTableCallbackInterfaceVssHeaderProviderUniffiByValue = UniffiVTableCallbackInterfaceVssHeaderProviderStruct.UniffiByValue + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +@Synchronized +private fun findLibraryName(componentName: String): String { + val libOverride = System.getProperty("uniffi.component.$componentName.libraryOverride") + if (libOverride != null) { + return libOverride + } + return "ldk_node" +} + +private inline fun loadIndirect( + componentName: String +): Lib { + return Native.load(findLibraryName(componentName), Lib::class.java) +} + +// A JNA Library to expose the extern-C FFI definitions. +// This is an implementation detail which will be called internally by the public API. + +internal interface UniffiLib : Library { + companion object { + internal val INSTANCE: UniffiLib by lazy { + loadIndirect(componentName = "ldk_node") + .also { lib: UniffiLib -> + uniffiCheckContractApiVersion(lib) + uniffiCheckApiChecksums(lib) + uniffiCallbackInterfaceLogWriter.register(lib) + } + } + + // The Cleaner for the whole library + internal val CLEANER: UniffiCleaner by lazy { + UniffiCleaner.create() + } + } + + fun uniffi_ldk_node_fn_clone_bolt11invoice( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_bolt11invoice( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_constructor_bolt11invoice_from_str( + `invoiceStr`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt11invoice_amount_milli_satoshis( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11invoice_currency( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11invoice_expiry_time_seconds( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_bolt11invoice_fallback_addresses( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11invoice_invoice_description( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11invoice_is_expired( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_method_bolt11invoice_min_final_cltv_expiry_delta( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_bolt11invoice_network( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11invoice_payment_hash( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11invoice_payment_secret( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11invoice_recover_payee_pub_key( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11invoice_route_hints( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11invoice_seconds_since_epoch( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_bolt11invoice_seconds_until_expiry( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_bolt11invoice_signable_hash( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11invoice_would_expire( + `ptr`: Pointer?, + `atTimeSeconds`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_debug( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_display( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_eq_eq( + `ptr`: Pointer?, + `other`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_eq_ne( + `ptr`: Pointer?, + `other`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_clone_bolt11payment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_bolt11payment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_bolt11payment_claim_for_hash( + `ptr`: Pointer?, + `paymentHash`: RustBufferByValue, + `claimableAmountMsat`: Long, + `preimage`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_bolt11payment_estimate_routing_fees( + `ptr`: Pointer?, + `invoice`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_bolt11payment_estimate_routing_fees_using_amount( + `ptr`: Pointer?, + `invoice`: Pointer?, + `amountMsat`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_bolt11payment_fail_for_hash( + `ptr`: Pointer?, + `paymentHash`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_bolt11payment_receive( + `ptr`: Pointer?, + `amountMsat`: Long, + `description`: RustBufferByValue, + `expirySecs`: Int, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt11payment_receive_for_hash( + `ptr`: Pointer?, + `amountMsat`: Long, + `description`: RustBufferByValue, + `expirySecs`: Int, + `paymentHash`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount( + `ptr`: Pointer?, + `description`: RustBufferByValue, + `expirySecs`: Int, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount_for_hash( + `ptr`: Pointer?, + `description`: RustBufferByValue, + `expirySecs`: Int, + `paymentHash`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount_via_jit_channel( + `ptr`: Pointer?, + `description`: RustBufferByValue, + `expirySecs`: Int, + `maxProportionalLspFeeLimitPpmMsat`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount_via_jit_channel_for_hash( + `ptr`: Pointer?, + `description`: RustBufferByValue, + `expirySecs`: Int, + `maxProportionalLspFeeLimitPpmMsat`: RustBufferByValue, + `paymentHash`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt11payment_receive_via_jit_channel( + `ptr`: Pointer?, + `amountMsat`: Long, + `description`: RustBufferByValue, + `expirySecs`: Int, + `maxLspFeeLimitMsat`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt11payment_receive_via_jit_channel_for_hash( + `ptr`: Pointer?, + `amountMsat`: Long, + `description`: RustBufferByValue, + `expirySecs`: Int, + `maxLspFeeLimitMsat`: RustBufferByValue, + `paymentHash`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt11payment_send( + `ptr`: Pointer?, + `invoice`: Pointer?, + `routeParameters`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11payment_send_probes( + `ptr`: Pointer?, + `invoice`: Pointer?, + `routeParameters`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11payment_send_probes_using_amount( + `ptr`: Pointer?, + `invoice`: Pointer?, + `amountMsat`: Long, + `routeParameters`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt11payment_send_using_amount( + `ptr`: Pointer?, + `invoice`: Pointer?, + `amountMsat`: Long, + `routeParameters`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_clone_bolt12invoice( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_bolt12invoice( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_constructor_bolt12invoice_from_str( + `invoiceStr`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt12invoice_absolute_expiry_seconds( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_amount( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_amount_msats( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_bolt12invoice_chain( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_created_at( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_bolt12invoice_encode( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_fallback_addresses( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_invoice_description( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_is_expired( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_method_bolt12invoice_issuer( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_issuer_signing_pubkey( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_metadata( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_offer_chains( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_payer_note( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_payer_signing_pubkey( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_payment_hash( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_quantity( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_relative_expiry( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_bolt12invoice_signable_hash( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12invoice_signing_pubkey( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_clone_bolt12payment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_bolt12payment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_bolt12payment_blinded_paths_for_async_recipient( + `ptr`: Pointer?, + `recipientId`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12payment_initiate_refund( + `ptr`: Pointer?, + `amountMsat`: Long, + `expirySecs`: Int, + `quantity`: RustBufferByValue, + `payerNote`: RustBufferByValue, + `routeParameters`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt12payment_receive( + `ptr`: Pointer?, + `amountMsat`: Long, + `description`: RustBufferByValue, + `expirySecs`: RustBufferByValue, + `quantity`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt12payment_receive_async( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt12payment_receive_variable_amount( + `ptr`: Pointer?, + `description`: RustBufferByValue, + `expirySecs`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt12payment_request_refund_payment( + `ptr`: Pointer?, + `refund`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_bolt12payment_send( + `ptr`: Pointer?, + `offer`: Pointer?, + `quantity`: RustBufferByValue, + `payerNote`: RustBufferByValue, + `routeParameters`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12payment_send_using_amount( + `ptr`: Pointer?, + `offer`: Pointer?, + `amountMsat`: Long, + `quantity`: RustBufferByValue, + `payerNote`: RustBufferByValue, + `routeParameters`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_bolt12payment_set_paths_to_static_invoice_server( + `ptr`: Pointer?, + `paths`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_clone_builder( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_builder( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_constructor_builder_from_config( + `config`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_constructor_builder_new( + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_builder_build( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_builder_build_with_fs_store( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_builder_build_with_vss_store( + `ptr`: Pointer?, + `vssUrl`: RustBufferByValue, + `storeId`: RustBufferByValue, + `lnurlAuthServerUrl`: RustBufferByValue, + `fixedHeaders`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_builder_build_with_vss_store_and_fixed_headers( + `ptr`: Pointer?, + `vssUrl`: RustBufferByValue, + `storeId`: RustBufferByValue, + `fixedHeaders`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_builder_build_with_vss_store_and_header_provider( + `ptr`: Pointer?, + `vssUrl`: RustBufferByValue, + `storeId`: RustBufferByValue, + `headerProvider`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_builder_set_address_type( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_address_types_to_monitor( + `ptr`: Pointer?, + `addressTypesToMonitor`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_announcement_addresses( + `ptr`: Pointer?, + `announcementAddresses`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_async_payments_role( + `ptr`: Pointer?, + `role`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_chain_source_bitcoind_rest( + `ptr`: Pointer?, + `restHost`: RustBufferByValue, + `restPort`: Short, + `rpcHost`: RustBufferByValue, + `rpcPort`: Short, + `rpcUser`: RustBufferByValue, + `rpcPassword`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_chain_source_bitcoind_rpc( + `ptr`: Pointer?, + `rpcHost`: RustBufferByValue, + `rpcPort`: Short, + `rpcUser`: RustBufferByValue, + `rpcPassword`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_chain_source_electrum( + `ptr`: Pointer?, + `serverUrl`: RustBufferByValue, + `config`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_chain_source_esplora( + `ptr`: Pointer?, + `serverUrl`: RustBufferByValue, + `config`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_channel_data_migration( + `ptr`: Pointer?, + `migration`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_custom_logger( + `ptr`: Pointer?, + `logWriter`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_entropy_bip39_mnemonic( + `ptr`: Pointer?, + `mnemonic`: RustBufferByValue, + `passphrase`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_entropy_seed_bytes( + `ptr`: Pointer?, + `seedBytes`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_entropy_seed_path( + `ptr`: Pointer?, + `seedPath`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_filesystem_logger( + `ptr`: Pointer?, + `logFilePath`: RustBufferByValue, + `maxLogLevel`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_gossip_source_p2p( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_gossip_source_rgs( + `ptr`: Pointer?, + `rgsServerUrl`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_liquidity_source_lsps1( + `ptr`: Pointer?, + `nodeId`: RustBufferByValue, + `address`: RustBufferByValue, + `token`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_liquidity_source_lsps2( + `ptr`: Pointer?, + `nodeId`: RustBufferByValue, + `address`: RustBufferByValue, + `token`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_listening_addresses( + `ptr`: Pointer?, + `listeningAddresses`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_log_facade_logger( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_network( + `ptr`: Pointer?, + `network`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_node_alias( + `ptr`: Pointer?, + `nodeAlias`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_pathfinding_scores_source( + `ptr`: Pointer?, + `url`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_scoring_decay_params( + `ptr`: Pointer?, + `params`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_scoring_fee_params( + `ptr`: Pointer?, + `params`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_builder_set_storage_dir_path( + `ptr`: Pointer?, + `storageDirPath`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_clone_feerate( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_feerate( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_constructor_feerate_from_sat_per_kwu( + `satKwu`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_constructor_feerate_from_sat_per_vb_unchecked( + `satVb`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_feerate_to_sat_per_kwu( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_feerate_to_sat_per_vb_ceil( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_feerate_to_sat_per_vb_floor( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_clone_lsps1liquidity( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_lsps1liquidity( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_lsps1liquidity_check_order_status( + `ptr`: Pointer?, + `orderId`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_lsps1liquidity_request_channel( + `ptr`: Pointer?, + `lspBalanceSat`: Long, + `clientBalanceSat`: Long, + `channelExpiryBlocks`: Int, + `announceChannel`: Byte, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_clone_logwriter( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_logwriter( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_init_callback_vtable_logwriter( + `vtable`: UniffiVTableCallbackInterfaceLogWriter, + ): Unit + fun uniffi_ldk_node_fn_method_logwriter_log( + `ptr`: Pointer?, + `record`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_clone_networkgraph( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_networkgraph( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_networkgraph_channel( + `ptr`: Pointer?, + `shortChannelId`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_networkgraph_list_channels( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_networkgraph_list_nodes( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_networkgraph_node( + `ptr`: Pointer?, + `nodeId`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_clone_node( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_node( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_add_address_type_to_monitor( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `seedBytes`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_add_address_type_to_monitor_with_mnemonic( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `mnemonic`: RustBufferByValue, + `passphrase`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_add_onchain_wallet_account( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `accountIndex`: Int, + `xpub`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_announcement_addresses( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_bolt11_payment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_node_bolt12_payment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_node_close_channel( + `ptr`: Pointer?, + `userChannelId`: RustBufferByValue, + `counterpartyNodeId`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_config( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_connect( + `ptr`: Pointer?, + `nodeId`: RustBufferByValue, + `address`: RustBufferByValue, + `persist`: Byte, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_current_sync_intervals( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_disconnect( + `ptr`: Pointer?, + `nodeId`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_event_handled( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_export_onchain_wallet_account_xpub( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `accountIndex`: Int, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_export_pathfinding_scores( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_force_close_channel( + `ptr`: Pointer?, + `userChannelId`: RustBufferByValue, + `counterpartyNodeId`: RustBufferByValue, + `reason`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_get_address_balance( + `ptr`: Pointer?, + `addressStr`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_node_get_balance_for_address_type( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_get_balance_for_onchain_wallet_account( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `accountIndex`: Int, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_get_transaction_details( + `ptr`: Pointer?, + `txid`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_list_balances( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_list_channels( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_list_monitored_address_types( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_list_onchain_wallet_accounts( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_list_payments( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_list_peers( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_listening_addresses( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_lsps1_liquidity( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_node_network_graph( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_node_next_event( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_next_event_async( + `ptr`: Pointer?, + ): Long + fun uniffi_ldk_node_fn_method_node_node_alias( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_node_id( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_onchain_payment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_node_open_announced_channel( + `ptr`: Pointer?, + `nodeId`: RustBufferByValue, + `address`: RustBufferByValue, + `channelAmountSats`: Long, + `pushToCounterpartyMsat`: RustBufferByValue, + `channelConfig`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_open_channel( + `ptr`: Pointer?, + `nodeId`: RustBufferByValue, + `address`: RustBufferByValue, + `channelAmountSats`: Long, + `pushToCounterpartyMsat`: RustBufferByValue, + `channelConfig`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_payment( + `ptr`: Pointer?, + `paymentId`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_remove_address_type_from_monitor( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_remove_onchain_wallet_account( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `accountIndex`: Int, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_remove_payment( + `ptr`: Pointer?, + `paymentId`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_set_primary_address_type( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `seedBytes`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_set_primary_address_type_with_mnemonic( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `mnemonic`: RustBufferByValue, + `passphrase`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_sign_message( + `ptr`: Pointer?, + `msg`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_splice_in( + `ptr`: Pointer?, + `userChannelId`: RustBufferByValue, + `counterpartyNodeId`: RustBufferByValue, + `spliceAmountSats`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_splice_out( + `ptr`: Pointer?, + `userChannelId`: RustBufferByValue, + `counterpartyNodeId`: RustBufferByValue, + `address`: RustBufferByValue, + `spliceAmountSats`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_spontaneous_payment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_node_start( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_status( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_node_stop( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_sync_wallets( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_unified_qr_payment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_node_update_channel_config( + `ptr`: Pointer?, + `userChannelId`: RustBufferByValue, + `counterpartyNodeId`: RustBufferByValue, + `channelConfig`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_update_sync_intervals( + `ptr`: Pointer?, + `intervals`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_node_verify_signature( + `ptr`: Pointer?, + `msg`: RustBufferByValue, + `sig`: RustBufferByValue, + `pkey`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_method_node_wait_next_event( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_clone_offer( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_offer( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_constructor_offer_from_str( + `offerStr`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_offer_absolute_expiry_seconds( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_offer_amount( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_offer_chains( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_offer_expects_quantity( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_method_offer_id( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_offer_is_expired( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_method_offer_is_valid_quantity( + `ptr`: Pointer?, + `quantity`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_method_offer_issuer( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_offer_issuer_signing_pubkey( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_offer_metadata( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_offer_offer_description( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_offer_supports_chain( + `ptr`: Pointer?, + `chain`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_method_offer_uniffi_trait_debug( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_offer_uniffi_trait_display( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_offer_uniffi_trait_eq_eq( + `ptr`: Pointer?, + `other`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_method_offer_uniffi_trait_eq_ne( + `ptr`: Pointer?, + `other`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_clone_onchainpayment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_onchainpayment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_onchainpayment_accelerate_by_cpfp( + `ptr`: Pointer?, + `txid`: RustBufferByValue, + `feeRate`: RustBufferByValue, + `destinationAddress`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_address_info_for_account_at_index( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `accountIndex`: Int, + `keychain`: RustBufferByValue, + `index`: Int, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_address_info_for_type_at_index( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `keychain`: RustBufferByValue, + `index`: Int, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_address_infos_for_account( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `accountIndex`: Int, + `keychain`: RustBufferByValue, + `startIndex`: Int, + `count`: Int, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_address_infos_for_type( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `keychain`: RustBufferByValue, + `startIndex`: Int, + `count`: Int, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_bump_fee_by_rbf( + `ptr`: Pointer?, + `txid`: RustBufferByValue, + `feeRate`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_calculate_cpfp_fee_rate( + `ptr`: Pointer?, + `parentTxid`: RustBufferByValue, + `urgent`: Byte, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_onchainpayment_calculate_send_all_fee( + `ptr`: Pointer?, + `address`: RustBufferByValue, + `retainReserves`: Byte, + `feeRate`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_onchainpayment_calculate_total_fee( + `ptr`: Pointer?, + `address`: RustBufferByValue, + `amountSats`: Long, + `feeRate`: RustBufferByValue, + `utxosToSpend`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_onchainpayment_list_spendable_outputs( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_new_address( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_new_address_for_account( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `accountIndex`: Int, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_new_address_for_type( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_new_address_info( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_new_address_info_for_account( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `accountIndex`: Int, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_new_address_info_for_type( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_reveal_receive_addresses_to( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `index`: Int, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_onchainpayment_reveal_receive_addresses_to_account( + `ptr`: Pointer?, + `addressType`: RustBufferByValue, + `accountIndex`: Int, + `index`: Int, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_onchainpayment_select_utxos_with_algorithm( + `ptr`: Pointer?, + `targetAmountSats`: Long, + `feeRate`: RustBufferByValue, + `algorithm`: RustBufferByValue, + `utxos`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_send_all_to_address( + `ptr`: Pointer?, + `address`: RustBufferByValue, + `retainReserve`: Byte, + `feeRate`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_onchainpayment_send_to_address( + `ptr`: Pointer?, + `address`: RustBufferByValue, + `amountSats`: Long, + `feeRate`: RustBufferByValue, + `utxosToSpend`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_clone_refund( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_refund( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_constructor_refund_from_str( + `refundStr`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_method_refund_absolute_expiry_seconds( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_refund_amount_msats( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun uniffi_ldk_node_fn_method_refund_chain( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_refund_is_expired( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_method_refund_issuer( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_refund_payer_metadata( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_refund_payer_note( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_refund_payer_signing_pubkey( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_refund_quantity( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_refund_refund_description( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_refund_uniffi_trait_debug( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_refund_uniffi_trait_display( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_refund_uniffi_trait_eq_eq( + `ptr`: Pointer?, + `other`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_method_refund_uniffi_trait_eq_ne( + `ptr`: Pointer?, + `other`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun uniffi_ldk_node_fn_clone_spontaneouspayment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_spontaneouspayment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_spontaneouspayment_send( + `ptr`: Pointer?, + `amountMsat`: Long, + `nodeId`: RustBufferByValue, + `routeParameters`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_spontaneouspayment_send_probes( + `ptr`: Pointer?, + `amountMsat`: Long, + `nodeId`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_spontaneouspayment_send_with_custom_tlvs( + `ptr`: Pointer?, + `amountMsat`: Long, + `nodeId`: RustBufferByValue, + `routeParameters`: RustBufferByValue, + `customTlvs`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_spontaneouspayment_send_with_preimage( + `ptr`: Pointer?, + `amountMsat`: Long, + `nodeId`: RustBufferByValue, + `preimage`: RustBufferByValue, + `routeParameters`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_spontaneouspayment_send_with_preimage_and_custom_tlvs( + `ptr`: Pointer?, + `amountMsat`: Long, + `nodeId`: RustBufferByValue, + `customTlvs`: RustBufferByValue, + `preimage`: RustBufferByValue, + `routeParameters`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_clone_unifiedqrpayment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_unifiedqrpayment( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_unifiedqrpayment_receive( + `ptr`: Pointer?, + `amountSats`: Long, + `message`: RustBufferByValue, + `expirySec`: Int, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_method_unifiedqrpayment_send( + `ptr`: Pointer?, + `uriStr`: RustBufferByValue, + `routeParameters`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_clone_vssheaderprovider( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun uniffi_ldk_node_fn_free_vssheaderprovider( + `ptr`: Pointer?, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_fn_method_vssheaderprovider_get_headers( + `ptr`: Pointer?, + `request`: RustBufferByValue, + ): Long + fun uniffi_ldk_node_fn_func_battery_saving_sync_intervals( + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_func_default_config( + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_func_derive_node_secret_from_mnemonic( + `mnemonic`: RustBufferByValue, + `passphrase`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun uniffi_ldk_node_fn_func_generate_entropy_mnemonic( + `wordCount`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun ffi_ldk_node_rustbuffer_alloc( + `size`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun ffi_ldk_node_rustbuffer_from_bytes( + `bytes`: ForeignBytesByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun ffi_ldk_node_rustbuffer_free( + `buf`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun ffi_ldk_node_rustbuffer_reserve( + `buf`: RustBufferByValue, + `additional`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun ffi_ldk_node_rust_future_poll_u8( + `handle`: Long, + `callback`: UniffiRustFutureContinuationCallback, + `callbackData`: Long, + ): Unit + fun ffi_ldk_node_rust_future_cancel_u8( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_free_u8( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_complete_u8( + `handle`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun ffi_ldk_node_rust_future_poll_i8( + `handle`: Long, + `callback`: UniffiRustFutureContinuationCallback, + `callbackData`: Long, + ): Unit + fun ffi_ldk_node_rust_future_cancel_i8( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_free_i8( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_complete_i8( + `handle`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Byte + fun ffi_ldk_node_rust_future_poll_u16( + `handle`: Long, + `callback`: UniffiRustFutureContinuationCallback, + `callbackData`: Long, + ): Unit + fun ffi_ldk_node_rust_future_cancel_u16( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_free_u16( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_complete_u16( + `handle`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Short + fun ffi_ldk_node_rust_future_poll_i16( + `handle`: Long, + `callback`: UniffiRustFutureContinuationCallback, + `callbackData`: Long, + ): Unit + fun ffi_ldk_node_rust_future_cancel_i16( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_free_i16( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_complete_i16( + `handle`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Short + fun ffi_ldk_node_rust_future_poll_u32( + `handle`: Long, + `callback`: UniffiRustFutureContinuationCallback, + `callbackData`: Long, + ): Unit + fun ffi_ldk_node_rust_future_cancel_u32( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_free_u32( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_complete_u32( + `handle`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Int + fun ffi_ldk_node_rust_future_poll_i32( + `handle`: Long, + `callback`: UniffiRustFutureContinuationCallback, + `callbackData`: Long, + ): Unit + fun ffi_ldk_node_rust_future_cancel_i32( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_free_i32( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_complete_i32( + `handle`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Int + fun ffi_ldk_node_rust_future_poll_u64( + `handle`: Long, + `callback`: UniffiRustFutureContinuationCallback, + `callbackData`: Long, + ): Unit + fun ffi_ldk_node_rust_future_cancel_u64( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_free_u64( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_complete_u64( + `handle`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun ffi_ldk_node_rust_future_poll_i64( + `handle`: Long, + `callback`: UniffiRustFutureContinuationCallback, + `callbackData`: Long, + ): Unit + fun ffi_ldk_node_rust_future_cancel_i64( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_free_i64( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_complete_i64( + `handle`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Long + fun ffi_ldk_node_rust_future_poll_f32( + `handle`: Long, + `callback`: UniffiRustFutureContinuationCallback, + `callbackData`: Long, + ): Unit + fun ffi_ldk_node_rust_future_cancel_f32( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_free_f32( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_complete_f32( + `handle`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Float + fun ffi_ldk_node_rust_future_poll_f64( + `handle`: Long, + `callback`: UniffiRustFutureContinuationCallback, + `callbackData`: Long, + ): Unit + fun ffi_ldk_node_rust_future_cancel_f64( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_free_f64( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_complete_f64( + `handle`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Double + fun ffi_ldk_node_rust_future_poll_pointer( + `handle`: Long, + `callback`: UniffiRustFutureContinuationCallback, + `callbackData`: Long, + ): Unit + fun ffi_ldk_node_rust_future_cancel_pointer( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_free_pointer( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_complete_pointer( + `handle`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Pointer? + fun ffi_ldk_node_rust_future_poll_rust_buffer( + `handle`: Long, + `callback`: UniffiRustFutureContinuationCallback, + `callbackData`: Long, + ): Unit + fun ffi_ldk_node_rust_future_cancel_rust_buffer( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_free_rust_buffer( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_complete_rust_buffer( + `handle`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + fun ffi_ldk_node_rust_future_poll_void( + `handle`: Long, + `callback`: UniffiRustFutureContinuationCallback, + `callbackData`: Long, + ): Unit + fun ffi_ldk_node_rust_future_cancel_void( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_free_void( + `handle`: Long, + ): Unit + fun ffi_ldk_node_rust_future_complete_void( + `handle`: Long, + uniffiCallStatus: UniffiRustCallStatus, + ): Unit + fun uniffi_ldk_node_checksum_func_battery_saving_sync_intervals( + ): Short + fun uniffi_ldk_node_checksum_func_default_config( + ): Short + fun uniffi_ldk_node_checksum_func_derive_node_secret_from_mnemonic( + ): Short + fun uniffi_ldk_node_checksum_func_generate_entropy_mnemonic( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_amount_milli_satoshis( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_currency( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_expiry_time_seconds( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_fallback_addresses( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_invoice_description( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_is_expired( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_min_final_cltv_expiry_delta( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_network( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_payment_hash( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_payment_secret( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_recover_payee_pub_key( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_route_hints( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_seconds_since_epoch( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_seconds_until_expiry( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_signable_hash( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11invoice_would_expire( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_claim_for_hash( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_estimate_routing_fees( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_estimate_routing_fees_using_amount( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_fail_for_hash( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_receive( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_receive_for_hash( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount_for_hash( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount_via_jit_channel( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount_via_jit_channel_for_hash( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_receive_via_jit_channel( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_receive_via_jit_channel_for_hash( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_send( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_send_probes( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_send_probes_using_amount( + ): Short + fun uniffi_ldk_node_checksum_method_bolt11payment_send_using_amount( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_absolute_expiry_seconds( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_amount( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_amount_msats( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_chain( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_created_at( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_encode( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_fallback_addresses( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_invoice_description( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_is_expired( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_issuer( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_issuer_signing_pubkey( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_metadata( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_offer_chains( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_payer_note( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_payer_signing_pubkey( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_payment_hash( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_quantity( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_relative_expiry( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_signable_hash( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12invoice_signing_pubkey( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12payment_blinded_paths_for_async_recipient( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12payment_initiate_refund( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12payment_receive( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12payment_receive_async( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12payment_receive_variable_amount( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12payment_request_refund_payment( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12payment_send( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12payment_send_using_amount( + ): Short + fun uniffi_ldk_node_checksum_method_bolt12payment_set_paths_to_static_invoice_server( + ): Short + fun uniffi_ldk_node_checksum_method_builder_build( + ): Short + fun uniffi_ldk_node_checksum_method_builder_build_with_fs_store( + ): Short + fun uniffi_ldk_node_checksum_method_builder_build_with_vss_store( + ): Short + fun uniffi_ldk_node_checksum_method_builder_build_with_vss_store_and_fixed_headers( + ): Short + fun uniffi_ldk_node_checksum_method_builder_build_with_vss_store_and_header_provider( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_address_type( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_address_types_to_monitor( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_announcement_addresses( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_async_payments_role( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_chain_source_bitcoind_rest( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_chain_source_bitcoind_rpc( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_chain_source_electrum( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_chain_source_esplora( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_channel_data_migration( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_custom_logger( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_entropy_bip39_mnemonic( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_entropy_seed_bytes( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_entropy_seed_path( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_filesystem_logger( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_gossip_source_p2p( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_gossip_source_rgs( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_liquidity_source_lsps1( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_liquidity_source_lsps2( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_listening_addresses( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_log_facade_logger( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_network( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_node_alias( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_pathfinding_scores_source( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_scoring_decay_params( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_scoring_fee_params( + ): Short + fun uniffi_ldk_node_checksum_method_builder_set_storage_dir_path( + ): Short + fun uniffi_ldk_node_checksum_method_feerate_to_sat_per_kwu( + ): Short + fun uniffi_ldk_node_checksum_method_feerate_to_sat_per_vb_ceil( + ): Short + fun uniffi_ldk_node_checksum_method_feerate_to_sat_per_vb_floor( + ): Short + fun uniffi_ldk_node_checksum_method_lsps1liquidity_check_order_status( + ): Short + fun uniffi_ldk_node_checksum_method_lsps1liquidity_request_channel( + ): Short + fun uniffi_ldk_node_checksum_method_logwriter_log( + ): Short + fun uniffi_ldk_node_checksum_method_networkgraph_channel( + ): Short + fun uniffi_ldk_node_checksum_method_networkgraph_list_channels( + ): Short + fun uniffi_ldk_node_checksum_method_networkgraph_list_nodes( + ): Short + fun uniffi_ldk_node_checksum_method_networkgraph_node( + ): Short + fun uniffi_ldk_node_checksum_method_node_add_address_type_to_monitor( + ): Short + fun uniffi_ldk_node_checksum_method_node_add_address_type_to_monitor_with_mnemonic( + ): Short + fun uniffi_ldk_node_checksum_method_node_add_onchain_wallet_account( + ): Short + fun uniffi_ldk_node_checksum_method_node_announcement_addresses( + ): Short + fun uniffi_ldk_node_checksum_method_node_bolt11_payment( + ): Short + fun uniffi_ldk_node_checksum_method_node_bolt12_payment( + ): Short + fun uniffi_ldk_node_checksum_method_node_close_channel( + ): Short + fun uniffi_ldk_node_checksum_method_node_config( + ): Short + fun uniffi_ldk_node_checksum_method_node_connect( + ): Short + fun uniffi_ldk_node_checksum_method_node_current_sync_intervals( + ): Short + fun uniffi_ldk_node_checksum_method_node_disconnect( + ): Short + fun uniffi_ldk_node_checksum_method_node_event_handled( + ): Short + fun uniffi_ldk_node_checksum_method_node_export_onchain_wallet_account_xpub( + ): Short + fun uniffi_ldk_node_checksum_method_node_export_pathfinding_scores( + ): Short + fun uniffi_ldk_node_checksum_method_node_force_close_channel( + ): Short + fun uniffi_ldk_node_checksum_method_node_get_address_balance( + ): Short + fun uniffi_ldk_node_checksum_method_node_get_balance_for_address_type( + ): Short + fun uniffi_ldk_node_checksum_method_node_get_balance_for_onchain_wallet_account( + ): Short + fun uniffi_ldk_node_checksum_method_node_get_transaction_details( + ): Short + fun uniffi_ldk_node_checksum_method_node_list_balances( + ): Short + fun uniffi_ldk_node_checksum_method_node_list_channels( + ): Short + fun uniffi_ldk_node_checksum_method_node_list_monitored_address_types( + ): Short + fun uniffi_ldk_node_checksum_method_node_list_onchain_wallet_accounts( + ): Short + fun uniffi_ldk_node_checksum_method_node_list_payments( + ): Short + fun uniffi_ldk_node_checksum_method_node_list_peers( + ): Short + fun uniffi_ldk_node_checksum_method_node_listening_addresses( + ): Short + fun uniffi_ldk_node_checksum_method_node_lsps1_liquidity( + ): Short + fun uniffi_ldk_node_checksum_method_node_network_graph( + ): Short + fun uniffi_ldk_node_checksum_method_node_next_event( + ): Short + fun uniffi_ldk_node_checksum_method_node_next_event_async( + ): Short + fun uniffi_ldk_node_checksum_method_node_node_alias( + ): Short + fun uniffi_ldk_node_checksum_method_node_node_id( + ): Short + fun uniffi_ldk_node_checksum_method_node_onchain_payment( + ): Short + fun uniffi_ldk_node_checksum_method_node_open_announced_channel( + ): Short + fun uniffi_ldk_node_checksum_method_node_open_channel( + ): Short + fun uniffi_ldk_node_checksum_method_node_payment( + ): Short + fun uniffi_ldk_node_checksum_method_node_remove_address_type_from_monitor( + ): Short + fun uniffi_ldk_node_checksum_method_node_remove_onchain_wallet_account( + ): Short + fun uniffi_ldk_node_checksum_method_node_remove_payment( + ): Short + fun uniffi_ldk_node_checksum_method_node_set_primary_address_type( + ): Short + fun uniffi_ldk_node_checksum_method_node_set_primary_address_type_with_mnemonic( + ): Short + fun uniffi_ldk_node_checksum_method_node_sign_message( + ): Short + fun uniffi_ldk_node_checksum_method_node_splice_in( + ): Short + fun uniffi_ldk_node_checksum_method_node_splice_out( + ): Short + fun uniffi_ldk_node_checksum_method_node_spontaneous_payment( + ): Short + fun uniffi_ldk_node_checksum_method_node_start( + ): Short + fun uniffi_ldk_node_checksum_method_node_status( + ): Short + fun uniffi_ldk_node_checksum_method_node_stop( + ): Short + fun uniffi_ldk_node_checksum_method_node_sync_wallets( + ): Short + fun uniffi_ldk_node_checksum_method_node_unified_qr_payment( + ): Short + fun uniffi_ldk_node_checksum_method_node_update_channel_config( + ): Short + fun uniffi_ldk_node_checksum_method_node_update_sync_intervals( + ): Short + fun uniffi_ldk_node_checksum_method_node_verify_signature( + ): Short + fun uniffi_ldk_node_checksum_method_node_wait_next_event( + ): Short + fun uniffi_ldk_node_checksum_method_offer_absolute_expiry_seconds( + ): Short + fun uniffi_ldk_node_checksum_method_offer_amount( + ): Short + fun uniffi_ldk_node_checksum_method_offer_chains( + ): Short + fun uniffi_ldk_node_checksum_method_offer_expects_quantity( + ): Short + fun uniffi_ldk_node_checksum_method_offer_id( + ): Short + fun uniffi_ldk_node_checksum_method_offer_is_expired( + ): Short + fun uniffi_ldk_node_checksum_method_offer_is_valid_quantity( + ): Short + fun uniffi_ldk_node_checksum_method_offer_issuer( + ): Short + fun uniffi_ldk_node_checksum_method_offer_issuer_signing_pubkey( + ): Short + fun uniffi_ldk_node_checksum_method_offer_metadata( + ): Short + fun uniffi_ldk_node_checksum_method_offer_offer_description( + ): Short + fun uniffi_ldk_node_checksum_method_offer_supports_chain( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_accelerate_by_cpfp( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_address_info_for_account_at_index( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_address_info_for_type_at_index( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_address_infos_for_account( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_address_infos_for_type( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_bump_fee_by_rbf( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_calculate_cpfp_fee_rate( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_calculate_send_all_fee( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_calculate_total_fee( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_list_spendable_outputs( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_new_address( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_new_address_for_account( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_new_address_for_type( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_new_address_info( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_new_address_info_for_account( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_new_address_info_for_type( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_reveal_receive_addresses_to( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_reveal_receive_addresses_to_account( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_select_utxos_with_algorithm( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_send_all_to_address( + ): Short + fun uniffi_ldk_node_checksum_method_onchainpayment_send_to_address( + ): Short + fun uniffi_ldk_node_checksum_method_refund_absolute_expiry_seconds( + ): Short + fun uniffi_ldk_node_checksum_method_refund_amount_msats( + ): Short + fun uniffi_ldk_node_checksum_method_refund_chain( + ): Short + fun uniffi_ldk_node_checksum_method_refund_is_expired( + ): Short + fun uniffi_ldk_node_checksum_method_refund_issuer( + ): Short + fun uniffi_ldk_node_checksum_method_refund_payer_metadata( + ): Short + fun uniffi_ldk_node_checksum_method_refund_payer_note( + ): Short + fun uniffi_ldk_node_checksum_method_refund_payer_signing_pubkey( + ): Short + fun uniffi_ldk_node_checksum_method_refund_quantity( + ): Short + fun uniffi_ldk_node_checksum_method_refund_refund_description( + ): Short + fun uniffi_ldk_node_checksum_method_spontaneouspayment_send( + ): Short + fun uniffi_ldk_node_checksum_method_spontaneouspayment_send_probes( + ): Short + fun uniffi_ldk_node_checksum_method_spontaneouspayment_send_with_custom_tlvs( + ): Short + fun uniffi_ldk_node_checksum_method_spontaneouspayment_send_with_preimage( + ): Short + fun uniffi_ldk_node_checksum_method_spontaneouspayment_send_with_preimage_and_custom_tlvs( + ): Short + fun uniffi_ldk_node_checksum_method_unifiedqrpayment_receive( + ): Short + fun uniffi_ldk_node_checksum_method_unifiedqrpayment_send( + ): Short + fun uniffi_ldk_node_checksum_method_vssheaderprovider_get_headers( + ): Short + fun uniffi_ldk_node_checksum_constructor_bolt11invoice_from_str( + ): Short + fun uniffi_ldk_node_checksum_constructor_bolt12invoice_from_str( + ): Short + fun uniffi_ldk_node_checksum_constructor_builder_from_config( + ): Short + fun uniffi_ldk_node_checksum_constructor_builder_new( + ): Short + fun uniffi_ldk_node_checksum_constructor_feerate_from_sat_per_kwu( + ): Short + fun uniffi_ldk_node_checksum_constructor_feerate_from_sat_per_vb_unchecked( + ): Short + fun uniffi_ldk_node_checksum_constructor_offer_from_str( + ): Short + fun uniffi_ldk_node_checksum_constructor_refund_from_str( + ): Short + fun ffi_ldk_node_uniffi_contract_version( + ): Int + +} + +private fun uniffiCheckContractApiVersion(lib: UniffiLib) { + // Get the bindings contract version from our ComponentInterface + val bindings_contract_version = 26 + // Get the scaffolding contract version by calling the into the dylib + val scaffolding_contract_version = lib.ffi_ldk_node_uniffi_contract_version() + if (bindings_contract_version != scaffolding_contract_version) { + throw RuntimeException("UniFFI contract version mismatch: try cleaning and rebuilding your project") + } +} + + +private fun uniffiCheckApiChecksums(lib: UniffiLib) { + if (lib.uniffi_ldk_node_checksum_func_battery_saving_sync_intervals() != 25473.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_func_default_config() != 55381.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_func_derive_node_secret_from_mnemonic() != 15067.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_func_generate_entropy_mnemonic() != 48014.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_amount_milli_satoshis() != 50823.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_currency() != 32179.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_expiry_time_seconds() != 23625.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_fallback_addresses() != 55276.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_invoice_description() != 395.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_is_expired() != 15932.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_min_final_cltv_expiry_delta() != 8855.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_network() != 10420.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_payment_hash() != 42571.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_payment_secret() != 26081.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_recover_payee_pub_key() != 18874.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_route_hints() != 63051.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_seconds_since_epoch() != 53979.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_seconds_until_expiry() != 64193.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_signable_hash() != 30910.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11invoice_would_expire() != 30331.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_claim_for_hash() != 52848.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_estimate_routing_fees() != 5123.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_estimate_routing_fees_using_amount() != 46411.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_fail_for_hash() != 24516.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_receive() != 6073.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_receive_for_hash() != 27050.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount() != 4893.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount_for_hash() != 1402.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount_via_jit_channel() != 24506.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount_via_jit_channel_for_hash() != 38025.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_receive_via_jit_channel() != 16532.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_receive_via_jit_channel_for_hash() != 1143.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_send() != 12953.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_send_probes() != 16067.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_send_probes_using_amount() != 37281.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_send_using_amount() != 42793.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_absolute_expiry_seconds() != 28589.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_amount() != 5213.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_amount_msats() != 9297.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_chain() != 3308.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_created_at() != 56866.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_encode() != 13200.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_fallback_addresses() != 7925.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_invoice_description() != 1713.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_is_expired() != 39560.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_issuer() != 65270.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_issuer_signing_pubkey() != 55411.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_metadata() != 37374.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_offer_chains() != 39622.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_payer_note() != 28018.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_payer_signing_pubkey() != 12798.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_payment_hash() != 63778.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_quantity() != 43105.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_relative_expiry() != 14024.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_signable_hash() != 39303.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12invoice_signing_pubkey() != 35202.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12payment_blinded_paths_for_async_recipient() != 14695.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12payment_initiate_refund() != 15019.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12payment_receive() != 59252.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12payment_receive_async() != 23867.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12payment_receive_variable_amount() != 35484.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12payment_request_refund_payment() != 43248.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12payment_send() != 27679.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12payment_send_using_amount() != 33255.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_bolt12payment_set_paths_to_static_invoice_server() != 20921.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_build() != 785.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_build_with_fs_store() != 61304.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_build_with_vss_store() != 2871.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_build_with_vss_store_and_fixed_headers() != 24910.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_build_with_vss_store_and_header_provider() != 9090.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_address_type() != 647.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_address_types_to_monitor() != 23561.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_announcement_addresses() != 39271.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_async_payments_role() != 16463.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_chain_source_bitcoind_rest() != 37382.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_chain_source_bitcoind_rpc() != 2111.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_chain_source_electrum() != 55552.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_chain_source_esplora() != 1781.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_channel_data_migration() != 58453.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_custom_logger() != 51232.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_entropy_bip39_mnemonic() != 827.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_entropy_seed_bytes() != 44799.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_entropy_seed_path() != 64056.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_filesystem_logger() != 10249.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_gossip_source_p2p() != 9279.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_gossip_source_rgs() != 64312.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_liquidity_source_lsps1() != 51527.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_liquidity_source_lsps2() != 14430.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_listening_addresses() != 14051.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_log_facade_logger() != 58410.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_network() != 27539.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_node_alias() != 18342.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_pathfinding_scores_source() != 63501.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_scoring_decay_params() != 19869.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_scoring_fee_params() != 11588.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_builder_set_storage_dir_path() != 59019.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_feerate_to_sat_per_kwu() != 58911.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_feerate_to_sat_per_vb_ceil() != 58575.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_feerate_to_sat_per_vb_floor() != 59617.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_lsps1liquidity_check_order_status() != 57147.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_lsps1liquidity_request_channel() != 18153.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_logwriter_log() != 3299.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_networkgraph_channel() != 38070.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_networkgraph_list_channels() != 4693.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_networkgraph_list_nodes() != 36715.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_networkgraph_node() != 48925.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_add_address_type_to_monitor() != 14706.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_add_address_type_to_monitor_with_mnemonic() != 4517.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_add_onchain_wallet_account() != 37245.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_announcement_addresses() != 61426.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_bolt11_payment() != 41402.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_bolt12_payment() != 49254.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_close_channel() != 62479.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_config() != 7511.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_connect() != 34120.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_current_sync_intervals() != 51918.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_disconnect() != 43538.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_event_handled() != 38712.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_export_onchain_wallet_account_xpub() != 5977.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_export_pathfinding_scores() != 62331.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_force_close_channel() != 48831.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_get_address_balance() != 45284.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_get_balance_for_address_type() != 34906.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_get_balance_for_onchain_wallet_account() != 18159.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_get_transaction_details() != 65000.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_list_balances() != 57528.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_list_channels() != 7954.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_list_monitored_address_types() != 25084.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_list_onchain_wallet_accounts() != 4403.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_list_payments() != 35002.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_list_peers() != 14889.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_listening_addresses() != 2665.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_lsps1_liquidity() != 38201.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_network_graph() != 2695.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_next_event() != 7682.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_next_event_async() != 25426.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_node_alias() != 29526.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_node_id() != 51489.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_onchain_payment() != 6092.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_open_announced_channel() != 36623.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_open_channel() != 40283.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_payment() != 60296.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_remove_address_type_from_monitor() != 37081.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_remove_onchain_wallet_account() != 21186.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_remove_payment() != 47952.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_set_primary_address_type() != 11005.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_set_primary_address_type_with_mnemonic() != 50783.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_sign_message() != 49319.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_splice_in() != 46431.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_splice_out() != 22115.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_spontaneous_payment() != 37403.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_start() != 58480.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_status() != 55952.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_stop() != 42188.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_sync_wallets() != 32474.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_unified_qr_payment() != 9837.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_update_channel_config() != 37852.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_update_sync_intervals() != 42322.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_verify_signature() != 20486.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_node_wait_next_event() != 55101.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_offer_absolute_expiry_seconds() != 22836.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_offer_amount() != 59890.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_offer_chains() != 59522.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_offer_expects_quantity() != 58457.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_offer_id() != 8391.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_offer_is_expired() != 22651.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_offer_is_valid_quantity() != 58469.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_offer_issuer() != 41632.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_offer_issuer_signing_pubkey() != 38162.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_offer_metadata() != 18979.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_offer_offer_description() != 11122.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_offer_supports_chain() != 2135.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_accelerate_by_cpfp() != 31954.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_address_info_for_account_at_index() != 63246.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_address_info_for_type_at_index() != 42692.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_address_infos_for_account() != 39321.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_address_infos_for_type() != 3701.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_bump_fee_by_rbf() != 53877.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_calculate_cpfp_fee_rate() != 32879.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_calculate_send_all_fee() != 16052.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_calculate_total_fee() != 57218.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_list_spendable_outputs() != 19144.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_new_address() != 37251.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_new_address_for_account() != 9932.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_new_address_for_type() != 9083.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_new_address_info() != 9889.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_new_address_info_for_account() != 30767.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_new_address_info_for_type() != 62171.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_reveal_receive_addresses_to() != 44189.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_reveal_receive_addresses_to_account() != 53588.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_select_utxos_with_algorithm() != 14084.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_send_all_to_address() != 37748.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_onchainpayment_send_to_address() != 28826.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_refund_absolute_expiry_seconds() != 43722.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_refund_amount_msats() != 26467.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_refund_chain() != 36565.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_refund_is_expired() != 10232.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_refund_issuer() != 40306.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_refund_payer_metadata() != 23501.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_refund_payer_note() != 47799.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_refund_payer_signing_pubkey() != 40880.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_refund_quantity() != 15192.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_refund_refund_description() != 39295.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_spontaneouspayment_send() != 27905.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_spontaneouspayment_send_probes() != 44206.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_spontaneouspayment_send_with_custom_tlvs() != 17876.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_spontaneouspayment_send_with_preimage() != 30854.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_spontaneouspayment_send_with_preimage_and_custom_tlvs() != 12104.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_unifiedqrpayment_receive() != 913.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_unifiedqrpayment_send() != 28285.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_method_vssheaderprovider_get_headers() != 7788.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_constructor_bolt11invoice_from_str() != 349.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_constructor_bolt12invoice_from_str() != 22276.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_constructor_builder_from_config() != 994.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_constructor_builder_new() != 40499.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_constructor_feerate_from_sat_per_kwu() != 50548.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_constructor_feerate_from_sat_per_vb_unchecked() != 41808.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_constructor_offer_from_str() != 37070.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_ldk_node_checksum_constructor_refund_from_str() != 64884.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } +} + +// Public interface members begin here. + + + +object FfiConverterUByte: FfiConverter { + override fun lift(value: Byte): UByte { + return value.toUByte() + } + + override fun read(buf: ByteBuffer): UByte { + return lift(buf.get()) + } + + override fun lower(value: UByte): Byte { + return value.toByte() + } + + override fun allocationSize(value: UByte) = 1UL + + override fun write(value: UByte, buf: ByteBuffer) { + buf.put(value.toByte()) + } +} + + +object FfiConverterUShort: FfiConverter { + override fun lift(value: Short): UShort { + return value.toUShort() + } + + override fun read(buf: ByteBuffer): UShort { + return lift(buf.getShort()) + } + + override fun lower(value: UShort): Short { + return value.toShort() + } + + override fun allocationSize(value: UShort) = 2UL + + override fun write(value: UShort, buf: ByteBuffer) { + buf.putShort(value.toShort()) + } +} + + +object FfiConverterUInt: FfiConverter { + override fun lift(value: Int): UInt { + return value.toUInt() + } + + override fun read(buf: ByteBuffer): UInt { + return lift(buf.getInt()) + } + + override fun lower(value: UInt): Int { + return value.toInt() + } + + override fun allocationSize(value: UInt) = 4UL + + override fun write(value: UInt, buf: ByteBuffer) { + buf.putInt(value.toInt()) + } +} + + +object FfiConverterULong: FfiConverter { + override fun lift(value: Long): ULong { + return value.toULong() + } + + override fun read(buf: ByteBuffer): ULong { + return lift(buf.getLong()) + } + + override fun lower(value: ULong): Long { + return value.toLong() + } + + override fun allocationSize(value: ULong) = 8UL + + override fun write(value: ULong, buf: ByteBuffer) { + buf.putLong(value.toLong()) + } +} + + +object FfiConverterLong: FfiConverter { + override fun lift(value: Long): Long { + return value + } + + override fun read(buf: ByteBuffer): Long { + return buf.getLong() + } + + override fun lower(value: Long): Long { + return value + } + + override fun allocationSize(value: Long) = 8UL + + override fun write(value: Long, buf: ByteBuffer) { + buf.putLong(value) + } +} + + +object FfiConverterBoolean: FfiConverter { + override fun lift(value: Byte): Boolean { + return value.toInt() != 0 + } + + override fun read(buf: ByteBuffer): Boolean { + return lift(buf.get()) + } + + override fun lower(value: Boolean): Byte { + return if (value) 1.toByte() else 0.toByte() + } + + override fun allocationSize(value: Boolean) = 1UL + + override fun write(value: Boolean, buf: ByteBuffer) { + buf.put(lower(value)) + } +} + + +fun String.utf8Size(): Int = this.toByteArray(Charsets.UTF_8).size + +object FfiConverterString: FfiConverter { + // Note: we don't inherit from FfiConverterRustBuffer, because we use a + // special encoding when lowering/lifting. We can use `RustBuffer.len` to + // store our length and avoid writing it out to the buffer. + override fun lift(value: RustBufferByValue): String { + try { + require(value.len <= Int.MAX_VALUE) { + val length = value.len + "cannot handle RustBuffer longer than Int.MAX_VALUE bytes: length is $length" + } + val byteArr = value.asByteBuffer()!!.get(value.len.toInt()) + return byteArr.decodeToString() + } finally { + RustBufferHelper.free(value) + } + } + + override fun read(buf: ByteBuffer): String { + val len = buf.getInt() + val byteArr = buf.get(len) + return byteArr.decodeToString() + } + + override fun lower(value: String): RustBufferByValue { + return RustBufferHelper.allocValue(value.utf8Size().toULong()).apply { + asByteBuffer()!!.writeUtf8(value) + } + } + + // We aren't sure exactly how many bytes our string will be once it's UTF-8 + // encoded. Allocate 3 bytes per UTF-16 code unit which will always be + // enough. + override fun allocationSize(value: String): ULong { + val sizeForLength = 4UL + val sizeForString = value.length.toULong() * 3UL + return sizeForLength + sizeForString + } + + override fun write(value: String, buf: ByteBuffer) { + buf.putInt(value.utf8Size().toInt()) + buf.writeUtf8(value) + } +} + + +object FfiConverterByteArray: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ByteArray { + val len = buf.getInt() + val byteArr = buf.get(len) + return byteArr + } + override fun allocationSize(value: ByteArray): ULong { + return 4UL + value.size.toULong() + } + override fun write(value: ByteArray, buf: ByteBuffer) { + buf.putInt(value.size) + buf.put(value) + } +} + + + +open class Bolt11Invoice: Disposable, Bolt11InvoiceInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_bolt11invoice(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_bolt11invoice(pointer!!, status) + }!! + } + + + override fun `amountMilliSatoshis`(): kotlin.ULong? { + return FfiConverterOptionalULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_amount_milli_satoshis( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `currency`(): Currency { + return FfiConverterTypeCurrency.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_currency( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `expiryTimeSeconds`(): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_expiry_time_seconds( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `fallbackAddresses`(): List
{ + return FfiConverterSequenceTypeAddress.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_fallback_addresses( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `invoiceDescription`(): Bolt11InvoiceDescription { + return FfiConverterTypeBolt11InvoiceDescription.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_invoice_description( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `isExpired`(): kotlin.Boolean { + return FfiConverterBoolean.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_is_expired( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `minFinalCltvExpiryDelta`(): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_min_final_cltv_expiry_delta( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `network`(): Network { + return FfiConverterTypeNetwork.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_network( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `paymentHash`(): PaymentHash { + return FfiConverterTypePaymentHash.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_payment_hash( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `paymentSecret`(): PaymentSecret { + return FfiConverterTypePaymentSecret.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_payment_secret( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `recoverPayeePubKey`(): PublicKey { + return FfiConverterTypePublicKey.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_recover_payee_pub_key( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `routeHints`(): List> { + return FfiConverterSequenceSequenceTypeRouteHintHop.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_route_hints( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `secondsSinceEpoch`(): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_seconds_since_epoch( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `secondsUntilExpiry`(): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_seconds_until_expiry( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `signableHash`(): List { + return FfiConverterSequenceUByte.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_signable_hash( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `wouldExpire`(`atTimeSeconds`: kotlin.ULong): kotlin.Boolean { + return FfiConverterBoolean.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_would_expire( + it, + FfiConverterULong.lower(`atTimeSeconds`), + uniffiRustCallStatus, + ) + } + }) + } + + + + + override fun toString(): String { + return FfiConverterString.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_display( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is Bolt11Invoice) return false + return FfiConverterBoolean.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_eq_eq( + it, + FfiConverterTypeBolt11Invoice.lower(`other`), + uniffiRustCallStatus, + ) + } + }) + } + + + + companion object { + + @Throws(NodeException::class) + fun `fromStr`(`invoiceStr`: kotlin.String): Bolt11Invoice { + return FfiConverterTypeBolt11Invoice.lift(uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_constructor_bolt11invoice_from_str( + FfiConverterString.lower(`invoiceStr`), + uniffiRustCallStatus, + ) + }!!) + } + + + } + +} + + + + + +object FfiConverterTypeBolt11Invoice: FfiConverter { + + override fun lower(value: Bolt11Invoice): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): Bolt11Invoice { + return Bolt11Invoice(value) + } + + override fun read(buf: ByteBuffer): Bolt11Invoice { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: Bolt11Invoice) = 8UL + + override fun write(value: Bolt11Invoice, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} +// The cleaner interface for Object finalization code to run. +// This is the entry point to any implementation that we're using. +// +// The cleaner registers disposables and returns cleanables, so now we are +// defining a `UniffiCleaner` with a `UniffiClenaer.Cleanable` to abstract the +// different implementations available at compile time. +interface UniffiCleaner { + interface Cleanable { + fun clean() + } + + fun register(resource: Any, disposable: Disposable): UniffiCleaner.Cleanable + + companion object +} +// The fallback Jna cleaner, which is available for both Android, and the JVM. +private class UniffiJnaCleaner : UniffiCleaner { + private val cleaner = com.sun.jna.internal.Cleaner.getCleaner() + + override fun register(resource: Any, disposable: Disposable): UniffiCleaner.Cleanable = + UniffiJnaCleanable(cleaner.register(resource, UniffiCleanerAction(disposable))) +} + +private class UniffiJnaCleanable( + private val cleanable: com.sun.jna.internal.Cleaner.Cleanable, +) : UniffiCleaner.Cleanable { + override fun clean() = cleanable.clean() +} + +private class UniffiCleanerAction(private val disposable: Disposable): Runnable { + override fun run() { + disposable.destroy() + } +} + +private class JavaLangRefCleaner : UniffiCleaner { + private val cleaner: java.lang.ref.Cleaner = java.lang.ref.Cleaner.create() + + override fun register(resource: Any, disposable: Disposable): UniffiCleaner.Cleanable = + JavaLangRefCleanable(cleaner.register(resource, UniffiCleanerAction(disposable))) +} + +private class JavaLangRefCleanable( + val cleanable: java.lang.ref.Cleaner.Cleanable +) : UniffiCleaner.Cleanable { + override fun clean() = cleanable.clean() +} + +private fun UniffiCleaner.Companion.create(): UniffiCleaner = + try { + JavaLangRefCleaner() + } catch (e: ClassNotFoundException) { + UniffiJnaCleaner() + } + + + +open class Bolt11Payment: Disposable, Bolt11PaymentInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_bolt11payment(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_bolt11payment(pointer!!, status) + }!! + } + + + @Throws(NodeException::class) + override fun `claimForHash`(`paymentHash`: PaymentHash, `claimableAmountMsat`: kotlin.ULong, `preimage`: PaymentPreimage) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_claim_for_hash( + it, + FfiConverterTypePaymentHash.lower(`paymentHash`), + FfiConverterULong.lower(`claimableAmountMsat`), + FfiConverterTypePaymentPreimage.lower(`preimage`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `estimateRoutingFees`(`invoice`: Bolt11Invoice): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_estimate_routing_fees( + it, + FfiConverterTypeBolt11Invoice.lower(`invoice`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `estimateRoutingFeesUsingAmount`(`invoice`: Bolt11Invoice, `amountMsat`: kotlin.ULong): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_estimate_routing_fees_using_amount( + it, + FfiConverterTypeBolt11Invoice.lower(`invoice`), + FfiConverterULong.lower(`amountMsat`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `failForHash`(`paymentHash`: PaymentHash) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_fail_for_hash( + it, + FfiConverterTypePaymentHash.lower(`paymentHash`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `receive`(`amountMsat`: kotlin.ULong, `description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt): Bolt11Invoice { + return FfiConverterTypeBolt11Invoice.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_receive( + it, + FfiConverterULong.lower(`amountMsat`), + FfiConverterTypeBolt11InvoiceDescription.lower(`description`), + FfiConverterUInt.lower(`expirySecs`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `receiveForHash`(`amountMsat`: kotlin.ULong, `description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt, `paymentHash`: PaymentHash): Bolt11Invoice { + return FfiConverterTypeBolt11Invoice.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_receive_for_hash( + it, + FfiConverterULong.lower(`amountMsat`), + FfiConverterTypeBolt11InvoiceDescription.lower(`description`), + FfiConverterUInt.lower(`expirySecs`), + FfiConverterTypePaymentHash.lower(`paymentHash`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `receiveVariableAmount`(`description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt): Bolt11Invoice { + return FfiConverterTypeBolt11Invoice.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount( + it, + FfiConverterTypeBolt11InvoiceDescription.lower(`description`), + FfiConverterUInt.lower(`expirySecs`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `receiveVariableAmountForHash`(`description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt, `paymentHash`: PaymentHash): Bolt11Invoice { + return FfiConverterTypeBolt11Invoice.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount_for_hash( + it, + FfiConverterTypeBolt11InvoiceDescription.lower(`description`), + FfiConverterUInt.lower(`expirySecs`), + FfiConverterTypePaymentHash.lower(`paymentHash`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `receiveVariableAmountViaJitChannel`(`description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt, `maxProportionalLspFeeLimitPpmMsat`: kotlin.ULong?): Bolt11Invoice { + return FfiConverterTypeBolt11Invoice.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount_via_jit_channel( + it, + FfiConverterTypeBolt11InvoiceDescription.lower(`description`), + FfiConverterUInt.lower(`expirySecs`), + FfiConverterOptionalULong.lower(`maxProportionalLspFeeLimitPpmMsat`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `receiveVariableAmountViaJitChannelForHash`(`description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt, `maxProportionalLspFeeLimitPpmMsat`: kotlin.ULong?, `paymentHash`: PaymentHash): Bolt11Invoice { + return FfiConverterTypeBolt11Invoice.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount_via_jit_channel_for_hash( + it, + FfiConverterTypeBolt11InvoiceDescription.lower(`description`), + FfiConverterUInt.lower(`expirySecs`), + FfiConverterOptionalULong.lower(`maxProportionalLspFeeLimitPpmMsat`), + FfiConverterTypePaymentHash.lower(`paymentHash`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `receiveViaJitChannel`(`amountMsat`: kotlin.ULong, `description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt, `maxLspFeeLimitMsat`: kotlin.ULong?): Bolt11Invoice { + return FfiConverterTypeBolt11Invoice.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_receive_via_jit_channel( + it, + FfiConverterULong.lower(`amountMsat`), + FfiConverterTypeBolt11InvoiceDescription.lower(`description`), + FfiConverterUInt.lower(`expirySecs`), + FfiConverterOptionalULong.lower(`maxLspFeeLimitMsat`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `receiveViaJitChannelForHash`(`amountMsat`: kotlin.ULong, `description`: Bolt11InvoiceDescription, `expirySecs`: kotlin.UInt, `maxLspFeeLimitMsat`: kotlin.ULong?, `paymentHash`: PaymentHash): Bolt11Invoice { + return FfiConverterTypeBolt11Invoice.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_receive_via_jit_channel_for_hash( + it, + FfiConverterULong.lower(`amountMsat`), + FfiConverterTypeBolt11InvoiceDescription.lower(`description`), + FfiConverterUInt.lower(`expirySecs`), + FfiConverterOptionalULong.lower(`maxLspFeeLimitMsat`), + FfiConverterTypePaymentHash.lower(`paymentHash`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `send`(`invoice`: Bolt11Invoice, `routeParameters`: RouteParametersConfig?): PaymentId { + return FfiConverterTypePaymentId.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_send( + it, + FfiConverterTypeBolt11Invoice.lower(`invoice`), + FfiConverterOptionalTypeRouteParametersConfig.lower(`routeParameters`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `sendProbes`(`invoice`: Bolt11Invoice, `routeParameters`: RouteParametersConfig?): List { + return FfiConverterSequenceTypeProbeHandle.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_send_probes( + it, + FfiConverterTypeBolt11Invoice.lower(`invoice`), + FfiConverterOptionalTypeRouteParametersConfig.lower(`routeParameters`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `sendProbesUsingAmount`(`invoice`: Bolt11Invoice, `amountMsat`: kotlin.ULong, `routeParameters`: RouteParametersConfig?): List { + return FfiConverterSequenceTypeProbeHandle.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_send_probes_using_amount( + it, + FfiConverterTypeBolt11Invoice.lower(`invoice`), + FfiConverterULong.lower(`amountMsat`), + FfiConverterOptionalTypeRouteParametersConfig.lower(`routeParameters`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `sendUsingAmount`(`invoice`: Bolt11Invoice, `amountMsat`: kotlin.ULong, `routeParameters`: RouteParametersConfig?): PaymentId { + return FfiConverterTypePaymentId.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_send_using_amount( + it, + FfiConverterTypeBolt11Invoice.lower(`invoice`), + FfiConverterULong.lower(`amountMsat`), + FfiConverterOptionalTypeRouteParametersConfig.lower(`routeParameters`), + uniffiRustCallStatus, + ) + } + }) + } + + + + + + + + companion object + +} + + + + + +object FfiConverterTypeBolt11Payment: FfiConverter { + + override fun lower(value: Bolt11Payment): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): Bolt11Payment { + return Bolt11Payment(value) + } + + override fun read(buf: ByteBuffer): Bolt11Payment { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: Bolt11Payment) = 8UL + + override fun write(value: Bolt11Payment, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + + + +open class Bolt12Invoice: Disposable, Bolt12InvoiceInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_bolt12invoice(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_bolt12invoice(pointer!!, status) + }!! + } + + + override fun `absoluteExpirySeconds`(): kotlin.ULong? { + return FfiConverterOptionalULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_absolute_expiry_seconds( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `amount`(): OfferAmount? { + return FfiConverterOptionalTypeOfferAmount.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_amount( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `amountMsats`(): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_amount_msats( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `chain`(): List { + return FfiConverterSequenceUByte.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_chain( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `createdAt`(): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_created_at( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `encode`(): List { + return FfiConverterSequenceUByte.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_encode( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `fallbackAddresses`(): List
{ + return FfiConverterSequenceTypeAddress.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_fallback_addresses( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `invoiceDescription`(): kotlin.String? { + return FfiConverterOptionalString.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_invoice_description( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `isExpired`(): kotlin.Boolean { + return FfiConverterBoolean.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_is_expired( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `issuer`(): kotlin.String? { + return FfiConverterOptionalString.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_issuer( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `issuerSigningPubkey`(): PublicKey? { + return FfiConverterOptionalTypePublicKey.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_issuer_signing_pubkey( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `metadata`(): List? { + return FfiConverterOptionalSequenceUByte.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_metadata( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `offerChains`(): List>? { + return FfiConverterOptionalSequenceSequenceUByte.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_offer_chains( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `payerNote`(): kotlin.String? { + return FfiConverterOptionalString.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_payer_note( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `payerSigningPubkey`(): PublicKey { + return FfiConverterTypePublicKey.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_payer_signing_pubkey( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `paymentHash`(): PaymentHash { + return FfiConverterTypePaymentHash.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_payment_hash( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `quantity`(): kotlin.ULong? { + return FfiConverterOptionalULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_quantity( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `relativeExpiry`(): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_relative_expiry( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `signableHash`(): List { + return FfiConverterSequenceUByte.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_signable_hash( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `signingPubkey`(): PublicKey { + return FfiConverterTypePublicKey.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12invoice_signing_pubkey( + it, + uniffiRustCallStatus, + ) + } + }) + } + + + + + + + companion object { + + @Throws(NodeException::class) + fun `fromStr`(`invoiceStr`: kotlin.String): Bolt12Invoice { + return FfiConverterTypeBolt12Invoice.lift(uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_constructor_bolt12invoice_from_str( + FfiConverterString.lower(`invoiceStr`), + uniffiRustCallStatus, + ) + }!!) + } + + + } + +} + + + + + +object FfiConverterTypeBolt12Invoice: FfiConverter { + + override fun lower(value: Bolt12Invoice): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): Bolt12Invoice { + return Bolt12Invoice(value) + } + + override fun read(buf: ByteBuffer): Bolt12Invoice { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: Bolt12Invoice) = 8UL + + override fun write(value: Bolt12Invoice, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + + + +open class Bolt12Payment: Disposable, Bolt12PaymentInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_bolt12payment(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_bolt12payment(pointer!!, status) + }!! + } + + + @Throws(NodeException::class) + override fun `blindedPathsForAsyncRecipient`(`recipientId`: kotlin.ByteArray): kotlin.ByteArray { + return FfiConverterByteArray.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12payment_blinded_paths_for_async_recipient( + it, + FfiConverterByteArray.lower(`recipientId`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `initiateRefund`(`amountMsat`: kotlin.ULong, `expirySecs`: kotlin.UInt, `quantity`: kotlin.ULong?, `payerNote`: kotlin.String?, `routeParameters`: RouteParametersConfig?): Refund { + return FfiConverterTypeRefund.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12payment_initiate_refund( + it, + FfiConverterULong.lower(`amountMsat`), + FfiConverterUInt.lower(`expirySecs`), + FfiConverterOptionalULong.lower(`quantity`), + FfiConverterOptionalString.lower(`payerNote`), + FfiConverterOptionalTypeRouteParametersConfig.lower(`routeParameters`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `receive`(`amountMsat`: kotlin.ULong, `description`: kotlin.String, `expirySecs`: kotlin.UInt?, `quantity`: kotlin.ULong?): Offer { + return FfiConverterTypeOffer.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12payment_receive( + it, + FfiConverterULong.lower(`amountMsat`), + FfiConverterString.lower(`description`), + FfiConverterOptionalUInt.lower(`expirySecs`), + FfiConverterOptionalULong.lower(`quantity`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `receiveAsync`(): Offer { + return FfiConverterTypeOffer.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12payment_receive_async( + it, + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `receiveVariableAmount`(`description`: kotlin.String, `expirySecs`: kotlin.UInt?): Offer { + return FfiConverterTypeOffer.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12payment_receive_variable_amount( + it, + FfiConverterString.lower(`description`), + FfiConverterOptionalUInt.lower(`expirySecs`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `requestRefundPayment`(`refund`: Refund): Bolt12Invoice { + return FfiConverterTypeBolt12Invoice.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12payment_request_refund_payment( + it, + FfiConverterTypeRefund.lower(`refund`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `send`(`offer`: Offer, `quantity`: kotlin.ULong?, `payerNote`: kotlin.String?, `routeParameters`: RouteParametersConfig?): PaymentId { + return FfiConverterTypePaymentId.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12payment_send( + it, + FfiConverterTypeOffer.lower(`offer`), + FfiConverterOptionalULong.lower(`quantity`), + FfiConverterOptionalString.lower(`payerNote`), + FfiConverterOptionalTypeRouteParametersConfig.lower(`routeParameters`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `sendUsingAmount`(`offer`: Offer, `amountMsat`: kotlin.ULong, `quantity`: kotlin.ULong?, `payerNote`: kotlin.String?, `routeParameters`: RouteParametersConfig?): PaymentId { + return FfiConverterTypePaymentId.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12payment_send_using_amount( + it, + FfiConverterTypeOffer.lower(`offer`), + FfiConverterULong.lower(`amountMsat`), + FfiConverterOptionalULong.lower(`quantity`), + FfiConverterOptionalString.lower(`payerNote`), + FfiConverterOptionalTypeRouteParametersConfig.lower(`routeParameters`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `setPathsToStaticInvoiceServer`(`paths`: kotlin.ByteArray) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt12payment_set_paths_to_static_invoice_server( + it, + FfiConverterByteArray.lower(`paths`), + uniffiRustCallStatus, + ) + } + } + } + + + + + + + + companion object + +} + + + + + +object FfiConverterTypeBolt12Payment: FfiConverter { + + override fun lower(value: Bolt12Payment): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): Bolt12Payment { + return Bolt12Payment(value) + } + + override fun read(buf: ByteBuffer): Bolt12Payment { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: Bolt12Payment) = 8UL + + override fun write(value: Bolt12Payment, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + + + +open class Builder: Disposable, BuilderInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + constructor() : this( + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_constructor_builder_new( + uniffiRustCallStatus, + ) + }!! + ) + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_builder(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_builder(pointer!!, status) + }!! + } + + + @Throws(BuildException::class) + override fun `build`(): Node { + return FfiConverterTypeNode.lift(callWithPointer { + uniffiRustCallWithError(BuildExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_build( + it, + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(BuildException::class) + override fun `buildWithFsStore`(): Node { + return FfiConverterTypeNode.lift(callWithPointer { + uniffiRustCallWithError(BuildExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_build_with_fs_store( + it, + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(BuildException::class) + override fun `buildWithVssStore`(`vssUrl`: kotlin.String, `storeId`: kotlin.String, `lnurlAuthServerUrl`: kotlin.String, `fixedHeaders`: Map): Node { + return FfiConverterTypeNode.lift(callWithPointer { + uniffiRustCallWithError(BuildExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_build_with_vss_store( + it, + FfiConverterString.lower(`vssUrl`), + FfiConverterString.lower(`storeId`), + FfiConverterString.lower(`lnurlAuthServerUrl`), + FfiConverterMapStringString.lower(`fixedHeaders`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(BuildException::class) + override fun `buildWithVssStoreAndFixedHeaders`(`vssUrl`: kotlin.String, `storeId`: kotlin.String, `fixedHeaders`: Map): Node { + return FfiConverterTypeNode.lift(callWithPointer { + uniffiRustCallWithError(BuildExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_build_with_vss_store_and_fixed_headers( + it, + FfiConverterString.lower(`vssUrl`), + FfiConverterString.lower(`storeId`), + FfiConverterMapStringString.lower(`fixedHeaders`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(BuildException::class) + override fun `buildWithVssStoreAndHeaderProvider`(`vssUrl`: kotlin.String, `storeId`: kotlin.String, `headerProvider`: VssHeaderProvider): Node { + return FfiConverterTypeNode.lift(callWithPointer { + uniffiRustCallWithError(BuildExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_build_with_vss_store_and_header_provider( + it, + FfiConverterString.lower(`vssUrl`), + FfiConverterString.lower(`storeId`), + FfiConverterTypeVssHeaderProvider.lower(`headerProvider`), + uniffiRustCallStatus, + ) + }!! + }) + } + + override fun `setAddressType`(`addressType`: AddressType) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_address_type( + it, + FfiConverterTypeAddressType.lower(`addressType`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setAddressTypesToMonitor`(`addressTypesToMonitor`: List) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_address_types_to_monitor( + it, + FfiConverterSequenceTypeAddressType.lower(`addressTypesToMonitor`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(BuildException::class) + override fun `setAnnouncementAddresses`(`announcementAddresses`: List) { + callWithPointer { + uniffiRustCallWithError(BuildExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_announcement_addresses( + it, + FfiConverterSequenceTypeSocketAddress.lower(`announcementAddresses`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(BuildException::class) + override fun `setAsyncPaymentsRole`(`role`: AsyncPaymentsRole?) { + callWithPointer { + uniffiRustCallWithError(BuildExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_async_payments_role( + it, + FfiConverterOptionalTypeAsyncPaymentsRole.lower(`role`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setChainSourceBitcoindRest`(`restHost`: kotlin.String, `restPort`: kotlin.UShort, `rpcHost`: kotlin.String, `rpcPort`: kotlin.UShort, `rpcUser`: kotlin.String, `rpcPassword`: kotlin.String) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_chain_source_bitcoind_rest( + it, + FfiConverterString.lower(`restHost`), + FfiConverterUShort.lower(`restPort`), + FfiConverterString.lower(`rpcHost`), + FfiConverterUShort.lower(`rpcPort`), + FfiConverterString.lower(`rpcUser`), + FfiConverterString.lower(`rpcPassword`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setChainSourceBitcoindRpc`(`rpcHost`: kotlin.String, `rpcPort`: kotlin.UShort, `rpcUser`: kotlin.String, `rpcPassword`: kotlin.String) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_chain_source_bitcoind_rpc( + it, + FfiConverterString.lower(`rpcHost`), + FfiConverterUShort.lower(`rpcPort`), + FfiConverterString.lower(`rpcUser`), + FfiConverterString.lower(`rpcPassword`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setChainSourceElectrum`(`serverUrl`: kotlin.String, `config`: ElectrumSyncConfig?) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_chain_source_electrum( + it, + FfiConverterString.lower(`serverUrl`), + FfiConverterOptionalTypeElectrumSyncConfig.lower(`config`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setChainSourceEsplora`(`serverUrl`: kotlin.String, `config`: EsploraSyncConfig?) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_chain_source_esplora( + it, + FfiConverterString.lower(`serverUrl`), + FfiConverterOptionalTypeEsploraSyncConfig.lower(`config`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setChannelDataMigration`(`migration`: ChannelDataMigration) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_channel_data_migration( + it, + FfiConverterTypeChannelDataMigration.lower(`migration`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setCustomLogger`(`logWriter`: LogWriter) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_custom_logger( + it, + FfiConverterTypeLogWriter.lower(`logWriter`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setEntropyBip39Mnemonic`(`mnemonic`: Mnemonic, `passphrase`: kotlin.String?) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_entropy_bip39_mnemonic( + it, + FfiConverterTypeMnemonic.lower(`mnemonic`), + FfiConverterOptionalString.lower(`passphrase`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(BuildException::class) + override fun `setEntropySeedBytes`(`seedBytes`: List) { + callWithPointer { + uniffiRustCallWithError(BuildExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_entropy_seed_bytes( + it, + FfiConverterSequenceUByte.lower(`seedBytes`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setEntropySeedPath`(`seedPath`: kotlin.String) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_entropy_seed_path( + it, + FfiConverterString.lower(`seedPath`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setFilesystemLogger`(`logFilePath`: kotlin.String?, `maxLogLevel`: LogLevel?) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_filesystem_logger( + it, + FfiConverterOptionalString.lower(`logFilePath`), + FfiConverterOptionalTypeLogLevel.lower(`maxLogLevel`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setGossipSourceP2p`() { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_gossip_source_p2p( + it, + uniffiRustCallStatus, + ) + } + } + } + + override fun `setGossipSourceRgs`(`rgsServerUrl`: kotlin.String) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_gossip_source_rgs( + it, + FfiConverterString.lower(`rgsServerUrl`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setLiquiditySourceLsps1`(`nodeId`: PublicKey, `address`: SocketAddress, `token`: kotlin.String?) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_liquidity_source_lsps1( + it, + FfiConverterTypePublicKey.lower(`nodeId`), + FfiConverterTypeSocketAddress.lower(`address`), + FfiConverterOptionalString.lower(`token`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setLiquiditySourceLsps2`(`nodeId`: PublicKey, `address`: SocketAddress, `token`: kotlin.String?) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_liquidity_source_lsps2( + it, + FfiConverterTypePublicKey.lower(`nodeId`), + FfiConverterTypeSocketAddress.lower(`address`), + FfiConverterOptionalString.lower(`token`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(BuildException::class) + override fun `setListeningAddresses`(`listeningAddresses`: List) { + callWithPointer { + uniffiRustCallWithError(BuildExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_listening_addresses( + it, + FfiConverterSequenceTypeSocketAddress.lower(`listeningAddresses`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setLogFacadeLogger`() { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_log_facade_logger( + it, + uniffiRustCallStatus, + ) + } + } + } + + override fun `setNetwork`(`network`: Network) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_network( + it, + FfiConverterTypeNetwork.lower(`network`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(BuildException::class) + override fun `setNodeAlias`(`nodeAlias`: kotlin.String) { + callWithPointer { + uniffiRustCallWithError(BuildExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_node_alias( + it, + FfiConverterString.lower(`nodeAlias`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setPathfindingScoresSource`(`url`: kotlin.String) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_pathfinding_scores_source( + it, + FfiConverterString.lower(`url`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setScoringDecayParams`(`params`: ScoringDecayParameters) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_scoring_decay_params( + it, + FfiConverterTypeScoringDecayParameters.lower(`params`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setScoringFeeParams`(`params`: ScoringFeeParameters) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_scoring_fee_params( + it, + FfiConverterTypeScoringFeeParameters.lower(`params`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `setStorageDirPath`(`storageDirPath`: kotlin.String) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_builder_set_storage_dir_path( + it, + FfiConverterString.lower(`storageDirPath`), + uniffiRustCallStatus, + ) + } + } + } + + + + + + + companion object { + + fun `fromConfig`(`config`: Config): Builder { + return FfiConverterTypeBuilder.lift(uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_constructor_builder_from_config( + FfiConverterTypeConfig.lower(`config`), + uniffiRustCallStatus, + ) + }!!) + } + + + } + +} + + + + + +object FfiConverterTypeBuilder: FfiConverter { + + override fun lower(value: Builder): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): Builder { + return Builder(value) + } + + override fun read(buf: ByteBuffer): Builder { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: Builder) = 8UL + + override fun write(value: Builder, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + + + +open class FeeRate: Disposable, FeeRateInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_feerate(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_feerate(pointer!!, status) + }!! + } + + + override fun `toSatPerKwu`(): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_feerate_to_sat_per_kwu( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `toSatPerVbCeil`(): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_feerate_to_sat_per_vb_ceil( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `toSatPerVbFloor`(): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_feerate_to_sat_per_vb_floor( + it, + uniffiRustCallStatus, + ) + } + }) + } + + + + + + + companion object { + + fun `fromSatPerKwu`(`satKwu`: kotlin.ULong): FeeRate { + return FfiConverterTypeFeeRate.lift(uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_constructor_feerate_from_sat_per_kwu( + FfiConverterULong.lower(`satKwu`), + uniffiRustCallStatus, + ) + }!!) + } + + + fun `fromSatPerVbUnchecked`(`satVb`: kotlin.ULong): FeeRate { + return FfiConverterTypeFeeRate.lift(uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_constructor_feerate_from_sat_per_vb_unchecked( + FfiConverterULong.lower(`satVb`), + uniffiRustCallStatus, + ) + }!!) + } + + + } + +} + + + + + +object FfiConverterTypeFeeRate: FfiConverter { + + override fun lower(value: FeeRate): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): FeeRate { + return FeeRate(value) + } + + override fun read(buf: ByteBuffer): FeeRate { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: FeeRate) = 8UL + + override fun write(value: FeeRate, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + + + +open class Lsps1Liquidity: Disposable, Lsps1LiquidityInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_lsps1liquidity(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_lsps1liquidity(pointer!!, status) + }!! + } + + + @Throws(NodeException::class) + override fun `checkOrderStatus`(`orderId`: Lsps1OrderId): Lsps1OrderStatus { + return FfiConverterTypeLSPS1OrderStatus.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_lsps1liquidity_check_order_status( + it, + FfiConverterTypeLSPS1OrderId.lower(`orderId`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `requestChannel`(`lspBalanceSat`: kotlin.ULong, `clientBalanceSat`: kotlin.ULong, `channelExpiryBlocks`: kotlin.UInt, `announceChannel`: kotlin.Boolean): Lsps1OrderStatus { + return FfiConverterTypeLSPS1OrderStatus.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_lsps1liquidity_request_channel( + it, + FfiConverterULong.lower(`lspBalanceSat`), + FfiConverterULong.lower(`clientBalanceSat`), + FfiConverterUInt.lower(`channelExpiryBlocks`), + FfiConverterBoolean.lower(`announceChannel`), + uniffiRustCallStatus, + ) + } + }) + } + + + + + + + + companion object + +} + + + + + +object FfiConverterTypeLSPS1Liquidity: FfiConverter { + + override fun lower(value: Lsps1Liquidity): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): Lsps1Liquidity { + return Lsps1Liquidity(value) + } + + override fun read(buf: ByteBuffer): Lsps1Liquidity { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: Lsps1Liquidity) = 8UL + + override fun write(value: Lsps1Liquidity, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + + + +open class LogWriterImpl: Disposable, LogWriter { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_logwriter(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_logwriter(pointer!!, status) + }!! + } + + + override fun `log`(`record`: LogRecord) { + callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_logwriter_log( + it, + FfiConverterTypeLogRecord.lower(`record`), + uniffiRustCallStatus, + ) + } + } + } + + + + + + + + companion object + +} + + + + + +object FfiConverterTypeLogWriter: FfiConverter { + internal val handleMap = UniffiHandleMap() + + override fun lower(value: LogWriter): Pointer { + return handleMap.insert(value).toPointer() + } + + override fun lift(value: Pointer): LogWriter { + return LogWriterImpl(value) + } + + override fun read(buf: ByteBuffer): LogWriter { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: LogWriter) = 8UL + + override fun write(value: LogWriter, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + +internal const val IDX_CALLBACK_FREE = 0 +// Callback return codes +internal const val UNIFFI_CALLBACK_SUCCESS = 0 +internal const val UNIFFI_CALLBACK_ERROR = 1 +internal const val UNIFFI_CALLBACK_UNEXPECTED_ERROR = 2 + +abstract class FfiConverterCallbackInterface: FfiConverter { + internal val handleMap = UniffiHandleMap() + + internal fun drop(handle: Long) { + handleMap.remove(handle) + } + + override fun lift(value: Long): CallbackInterface { + return handleMap.get(value) + } + + override fun read(buf: ByteBuffer) = lift(buf.getLong()) + + override fun lower(value: CallbackInterface) = handleMap.insert(value) + + override fun allocationSize(value: CallbackInterface) = 8UL + + override fun write(value: CallbackInterface, buf: ByteBuffer) { + buf.putLong(lower(value)) + } +} + +// Put the implementation in an object so we don't pollute the top-level namespace +internal object uniffiCallbackInterfaceLogWriter { + internal object `log`: UniffiCallbackInterfaceLogWriterMethod0 { + override fun callback ( + `uniffiHandle`: Long, + `record`: RustBufferByValue, + `uniffiOutReturn`: Pointer, + uniffiCallStatus: UniffiRustCallStatus, + ) { + val uniffiObj = FfiConverterTypeLogWriter.handleMap.get(uniffiHandle) + val makeCall = { -> + uniffiObj.`log`( + FfiConverterTypeLogRecord.lift(`record`), + ) + } + val writeReturn = { _: Unit -> + @Suppress("UNUSED_EXPRESSION") + uniffiOutReturn + Unit + } + uniffiTraitInterfaceCall(uniffiCallStatus, makeCall, writeReturn) + } + } + internal object uniffiFree: UniffiCallbackInterfaceFree { + override fun callback(handle: Long) { + FfiConverterTypeLogWriter.handleMap.remove(handle) + } + } + + internal val vtable = UniffiVTableCallbackInterfaceLogWriter( + `log`, + uniffiFree, + ) + + internal fun register(lib: UniffiLib) { + lib.uniffi_ldk_node_fn_init_callback_vtable_logwriter(vtable) + } +} + + + +open class NetworkGraph: Disposable, NetworkGraphInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_networkgraph(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_networkgraph(pointer!!, status) + }!! + } + + + override fun `channel`(`shortChannelId`: kotlin.ULong): ChannelInfo? { + return FfiConverterOptionalTypeChannelInfo.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_networkgraph_channel( + it, + FfiConverterULong.lower(`shortChannelId`), + uniffiRustCallStatus, + ) + } + }) + } + + override fun `listChannels`(): List { + return FfiConverterSequenceULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_networkgraph_list_channels( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `listNodes`(): List { + return FfiConverterSequenceTypeNodeId.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_networkgraph_list_nodes( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `node`(`nodeId`: NodeId): NodeInfo? { + return FfiConverterOptionalTypeNodeInfo.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_networkgraph_node( + it, + FfiConverterTypeNodeId.lower(`nodeId`), + uniffiRustCallStatus, + ) + } + }) + } + + + + + + + + companion object + +} + + + + + +object FfiConverterTypeNetworkGraph: FfiConverter { + + override fun lower(value: NetworkGraph): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): NetworkGraph { + return NetworkGraph(value) + } + + override fun read(buf: ByteBuffer): NetworkGraph { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: NetworkGraph) = 8UL + + override fun write(value: NetworkGraph, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + + + +open class Node: Disposable, NodeInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_node(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_node(pointer!!, status) + }!! + } + + + @Throws(NodeException::class) + override fun `addAddressTypeToMonitor`(`addressType`: AddressType, `seedBytes`: List) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_add_address_type_to_monitor( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterSequenceUByte.lower(`seedBytes`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `addAddressTypeToMonitorWithMnemonic`(`addressType`: AddressType, `mnemonic`: Mnemonic, `passphrase`: kotlin.String?) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_add_address_type_to_monitor_with_mnemonic( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterTypeMnemonic.lower(`mnemonic`), + FfiConverterOptionalString.lower(`passphrase`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `addOnchainWalletAccount`(`addressType`: AddressType, `accountIndex`: kotlin.UInt, `xpub`: kotlin.String) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_add_onchain_wallet_account( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterUInt.lower(`accountIndex`), + FfiConverterString.lower(`xpub`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `announcementAddresses`(): List? { + return FfiConverterOptionalSequenceTypeSocketAddress.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_announcement_addresses( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `bolt11Payment`(): Bolt11Payment { + return FfiConverterTypeBolt11Payment.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_bolt11_payment( + it, + uniffiRustCallStatus, + ) + }!! + }) + } + + override fun `bolt12Payment`(): Bolt12Payment { + return FfiConverterTypeBolt12Payment.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_bolt12_payment( + it, + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `closeChannel`(`userChannelId`: UserChannelId, `counterpartyNodeId`: PublicKey) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_close_channel( + it, + FfiConverterTypeUserChannelId.lower(`userChannelId`), + FfiConverterTypePublicKey.lower(`counterpartyNodeId`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `config`(): Config { + return FfiConverterTypeConfig.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_config( + it, + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `connect`(`nodeId`: PublicKey, `address`: SocketAddress, `persist`: kotlin.Boolean) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_connect( + it, + FfiConverterTypePublicKey.lower(`nodeId`), + FfiConverterTypeSocketAddress.lower(`address`), + FfiConverterBoolean.lower(`persist`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `currentSyncIntervals`(): RuntimeSyncIntervals { + return FfiConverterTypeRuntimeSyncIntervals.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_current_sync_intervals( + it, + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `disconnect`(`nodeId`: PublicKey) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_disconnect( + it, + FfiConverterTypePublicKey.lower(`nodeId`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `eventHandled`() { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_event_handled( + it, + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `exportOnchainWalletAccountXpub`(`addressType`: AddressType, `accountIndex`: kotlin.UInt): kotlin.String { + return FfiConverterString.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_export_onchain_wallet_account_xpub( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterUInt.lower(`accountIndex`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `exportPathfindingScores`(): kotlin.ByteArray { + return FfiConverterByteArray.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_export_pathfinding_scores( + it, + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `forceCloseChannel`(`userChannelId`: UserChannelId, `counterpartyNodeId`: PublicKey, `reason`: kotlin.String?) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_force_close_channel( + it, + FfiConverterTypeUserChannelId.lower(`userChannelId`), + FfiConverterTypePublicKey.lower(`counterpartyNodeId`), + FfiConverterOptionalString.lower(`reason`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `getAddressBalance`(`addressStr`: kotlin.String): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_get_address_balance( + it, + FfiConverterString.lower(`addressStr`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `getBalanceForAddressType`(`addressType`: AddressType): AddressTypeBalance { + return FfiConverterTypeAddressTypeBalance.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_get_balance_for_address_type( + it, + FfiConverterTypeAddressType.lower(`addressType`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `getBalanceForOnchainWalletAccount`(`addressType`: AddressType, `accountIndex`: kotlin.UInt): AddressTypeBalance { + return FfiConverterTypeAddressTypeBalance.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_get_balance_for_onchain_wallet_account( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterUInt.lower(`accountIndex`), + uniffiRustCallStatus, + ) + } + }) + } + + override fun `getTransactionDetails`(`txid`: Txid): TransactionDetails? { + return FfiConverterOptionalTypeTransactionDetails.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_get_transaction_details( + it, + FfiConverterTypeTxid.lower(`txid`), + uniffiRustCallStatus, + ) + } + }) + } + + override fun `listBalances`(): BalanceDetails { + return FfiConverterTypeBalanceDetails.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_list_balances( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `listChannels`(): List { + return FfiConverterSequenceTypeChannelDetails.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_list_channels( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `listMonitoredAddressTypes`(): List { + return FfiConverterSequenceTypeAddressType.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_list_monitored_address_types( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `listOnchainWalletAccounts`(): List { + return FfiConverterSequenceTypeOnchainWalletAccount.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_list_onchain_wallet_accounts( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `listPayments`(): List { + return FfiConverterSequenceTypePaymentDetails.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_list_payments( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `listPeers`(): List { + return FfiConverterSequenceTypePeerDetails.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_list_peers( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `listeningAddresses`(): List? { + return FfiConverterOptionalSequenceTypeSocketAddress.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_listening_addresses( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `lsps1Liquidity`(): Lsps1Liquidity { + return FfiConverterTypeLSPS1Liquidity.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_lsps1_liquidity( + it, + uniffiRustCallStatus, + ) + }!! + }) + } + + override fun `networkGraph`(): NetworkGraph { + return FfiConverterTypeNetworkGraph.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_network_graph( + it, + uniffiRustCallStatus, + ) + }!! + }) + } + + override fun `nextEvent`(): Event? { + return FfiConverterOptionalTypeEvent.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_next_event( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override suspend fun `nextEventAsync`(): Event { + return uniffiRustCallAsync( + callWithPointer { thisPtr -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_next_event_async( + thisPtr, + ) + }, + { future, callback, continuation -> UniffiLib.INSTANCE.ffi_ldk_node_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.INSTANCE.ffi_ldk_node_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.INSTANCE.ffi_ldk_node_rust_future_free_rust_buffer(future) }, + { future -> UniffiLib.INSTANCE.ffi_ldk_node_rust_future_cancel_rust_buffer(future) }, + // lift function + { FfiConverterTypeEvent.lift(it) }, + // Error FFI converter + UniffiNullRustCallStatusErrorHandler, + ) + } + + override fun `nodeAlias`(): NodeAlias? { + return FfiConverterOptionalTypeNodeAlias.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_node_alias( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `nodeId`(): PublicKey { + return FfiConverterTypePublicKey.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_node_id( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `onchainPayment`(): OnchainPayment { + return FfiConverterTypeOnchainPayment.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_onchain_payment( + it, + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `openAnnouncedChannel`(`nodeId`: PublicKey, `address`: SocketAddress, `channelAmountSats`: kotlin.ULong, `pushToCounterpartyMsat`: kotlin.ULong?, `channelConfig`: ChannelConfig?): UserChannelId { + return FfiConverterTypeUserChannelId.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_open_announced_channel( + it, + FfiConverterTypePublicKey.lower(`nodeId`), + FfiConverterTypeSocketAddress.lower(`address`), + FfiConverterULong.lower(`channelAmountSats`), + FfiConverterOptionalULong.lower(`pushToCounterpartyMsat`), + FfiConverterOptionalTypeChannelConfig.lower(`channelConfig`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `openChannel`(`nodeId`: PublicKey, `address`: SocketAddress, `channelAmountSats`: kotlin.ULong, `pushToCounterpartyMsat`: kotlin.ULong?, `channelConfig`: ChannelConfig?): UserChannelId { + return FfiConverterTypeUserChannelId.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_open_channel( + it, + FfiConverterTypePublicKey.lower(`nodeId`), + FfiConverterTypeSocketAddress.lower(`address`), + FfiConverterULong.lower(`channelAmountSats`), + FfiConverterOptionalULong.lower(`pushToCounterpartyMsat`), + FfiConverterOptionalTypeChannelConfig.lower(`channelConfig`), + uniffiRustCallStatus, + ) + } + }) + } + + override fun `payment`(`paymentId`: PaymentId): PaymentDetails? { + return FfiConverterOptionalTypePaymentDetails.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_payment( + it, + FfiConverterTypePaymentId.lower(`paymentId`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `removeAddressTypeFromMonitor`(`addressType`: AddressType) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_remove_address_type_from_monitor( + it, + FfiConverterTypeAddressType.lower(`addressType`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `removeOnchainWalletAccount`(`addressType`: AddressType, `accountIndex`: kotlin.UInt) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_remove_onchain_wallet_account( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterUInt.lower(`accountIndex`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `removePayment`(`paymentId`: PaymentId) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_remove_payment( + it, + FfiConverterTypePaymentId.lower(`paymentId`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `setPrimaryAddressType`(`addressType`: AddressType, `seedBytes`: List) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_set_primary_address_type( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterSequenceUByte.lower(`seedBytes`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `setPrimaryAddressTypeWithMnemonic`(`addressType`: AddressType, `mnemonic`: Mnemonic, `passphrase`: kotlin.String?) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_set_primary_address_type_with_mnemonic( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterTypeMnemonic.lower(`mnemonic`), + FfiConverterOptionalString.lower(`passphrase`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `signMessage`(`msg`: List): kotlin.String { + return FfiConverterString.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_sign_message( + it, + FfiConverterSequenceUByte.lower(`msg`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `spliceIn`(`userChannelId`: UserChannelId, `counterpartyNodeId`: PublicKey, `spliceAmountSats`: kotlin.ULong) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_splice_in( + it, + FfiConverterTypeUserChannelId.lower(`userChannelId`), + FfiConverterTypePublicKey.lower(`counterpartyNodeId`), + FfiConverterULong.lower(`spliceAmountSats`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `spliceOut`(`userChannelId`: UserChannelId, `counterpartyNodeId`: PublicKey, `address`: Address, `spliceAmountSats`: kotlin.ULong) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_splice_out( + it, + FfiConverterTypeUserChannelId.lower(`userChannelId`), + FfiConverterTypePublicKey.lower(`counterpartyNodeId`), + FfiConverterTypeAddress.lower(`address`), + FfiConverterULong.lower(`spliceAmountSats`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `spontaneousPayment`(): SpontaneousPayment { + return FfiConverterTypeSpontaneousPayment.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_spontaneous_payment( + it, + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `start`() { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_start( + it, + uniffiRustCallStatus, + ) + } + } + } + + override fun `status`(): NodeStatus { + return FfiConverterTypeNodeStatus.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_status( + it, + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `stop`() { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_stop( + it, + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `syncWallets`() { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_sync_wallets( + it, + uniffiRustCallStatus, + ) + } + } + } + + override fun `unifiedQrPayment`(): UnifiedQrPayment { + return FfiConverterTypeUnifiedQrPayment.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_unified_qr_payment( + it, + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `updateChannelConfig`(`userChannelId`: UserChannelId, `counterpartyNodeId`: PublicKey, `channelConfig`: ChannelConfig) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_update_channel_config( + it, + FfiConverterTypeUserChannelId.lower(`userChannelId`), + FfiConverterTypePublicKey.lower(`counterpartyNodeId`), + FfiConverterTypeChannelConfig.lower(`channelConfig`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `updateSyncIntervals`(`intervals`: RuntimeSyncIntervals) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_update_sync_intervals( + it, + FfiConverterTypeRuntimeSyncIntervals.lower(`intervals`), + uniffiRustCallStatus, + ) + } + } + } + + override fun `verifySignature`(`msg`: List, `sig`: kotlin.String, `pkey`: PublicKey): kotlin.Boolean { + return FfiConverterBoolean.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_verify_signature( + it, + FfiConverterSequenceUByte.lower(`msg`), + FfiConverterString.lower(`sig`), + FfiConverterTypePublicKey.lower(`pkey`), + uniffiRustCallStatus, + ) + } + }) + } + + override fun `waitNextEvent`(): Event { + return FfiConverterTypeEvent.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_node_wait_next_event( + it, + uniffiRustCallStatus, + ) + } + }) + } + + + + + + + + companion object + +} + + + + + +object FfiConverterTypeNode: FfiConverter { + + override fun lower(value: Node): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): Node { + return Node(value) + } + + override fun read(buf: ByteBuffer): Node { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: Node) = 8UL + + override fun write(value: Node, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + + + +open class Offer: Disposable, OfferInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_offer(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_offer(pointer!!, status) + }!! + } + + + override fun `absoluteExpirySeconds`(): kotlin.ULong? { + return FfiConverterOptionalULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_offer_absolute_expiry_seconds( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `amount`(): OfferAmount? { + return FfiConverterOptionalTypeOfferAmount.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_offer_amount( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `chains`(): List { + return FfiConverterSequenceTypeNetwork.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_offer_chains( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `expectsQuantity`(): kotlin.Boolean { + return FfiConverterBoolean.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_offer_expects_quantity( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `id`(): OfferId { + return FfiConverterTypeOfferId.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_offer_id( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `isExpired`(): kotlin.Boolean { + return FfiConverterBoolean.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_offer_is_expired( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `isValidQuantity`(`quantity`: kotlin.ULong): kotlin.Boolean { + return FfiConverterBoolean.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_offer_is_valid_quantity( + it, + FfiConverterULong.lower(`quantity`), + uniffiRustCallStatus, + ) + } + }) + } + + override fun `issuer`(): kotlin.String? { + return FfiConverterOptionalString.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_offer_issuer( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `issuerSigningPubkey`(): PublicKey? { + return FfiConverterOptionalTypePublicKey.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_offer_issuer_signing_pubkey( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `metadata`(): List? { + return FfiConverterOptionalSequenceUByte.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_offer_metadata( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `offerDescription`(): kotlin.String? { + return FfiConverterOptionalString.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_offer_offer_description( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `supportsChain`(`chain`: Network): kotlin.Boolean { + return FfiConverterBoolean.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_offer_supports_chain( + it, + FfiConverterTypeNetwork.lower(`chain`), + uniffiRustCallStatus, + ) + } + }) + } + + + + + override fun toString(): String { + return FfiConverterString.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_offer_uniffi_trait_display( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is Offer) return false + return FfiConverterBoolean.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_offer_uniffi_trait_eq_eq( + it, + FfiConverterTypeOffer.lower(`other`), + uniffiRustCallStatus, + ) + } + }) + } + + + + companion object { + + @Throws(NodeException::class) + fun `fromStr`(`offerStr`: kotlin.String): Offer { + return FfiConverterTypeOffer.lift(uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_constructor_offer_from_str( + FfiConverterString.lower(`offerStr`), + uniffiRustCallStatus, + ) + }!!) + } + + + } + +} + + + + + +object FfiConverterTypeOffer: FfiConverter { + + override fun lower(value: Offer): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): Offer { + return Offer(value) + } + + override fun read(buf: ByteBuffer): Offer { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: Offer) = 8UL + + override fun write(value: Offer, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + + + +open class OnchainPayment: Disposable, OnchainPaymentInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_onchainpayment(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_onchainpayment(pointer!!, status) + }!! + } + + + @Throws(NodeException::class) + override fun `accelerateByCpfp`(`txid`: Txid, `feeRate`: FeeRate?, `destinationAddress`: Address?): Txid { + return FfiConverterTypeTxid.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_accelerate_by_cpfp( + it, + FfiConverterTypeTxid.lower(`txid`), + FfiConverterOptionalTypeFeeRate.lower(`feeRate`), + FfiConverterOptionalTypeAddress.lower(`destinationAddress`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `addressInfoForAccountAtIndex`(`addressType`: AddressType, `accountIndex`: kotlin.UInt, `keychain`: KeychainKind, `index`: kotlin.UInt): AddressInfo { + return FfiConverterTypeAddressInfo.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_address_info_for_account_at_index( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterUInt.lower(`accountIndex`), + FfiConverterTypeKeychainKind.lower(`keychain`), + FfiConverterUInt.lower(`index`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `addressInfoForTypeAtIndex`(`addressType`: AddressType, `keychain`: KeychainKind, `index`: kotlin.UInt): AddressInfo { + return FfiConverterTypeAddressInfo.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_address_info_for_type_at_index( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterTypeKeychainKind.lower(`keychain`), + FfiConverterUInt.lower(`index`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `addressInfosForAccount`(`addressType`: AddressType, `accountIndex`: kotlin.UInt, `keychain`: KeychainKind, `startIndex`: kotlin.UInt, `count`: kotlin.UInt): List { + return FfiConverterSequenceTypeAddressInfo.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_address_infos_for_account( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterUInt.lower(`accountIndex`), + FfiConverterTypeKeychainKind.lower(`keychain`), + FfiConverterUInt.lower(`startIndex`), + FfiConverterUInt.lower(`count`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `addressInfosForType`(`addressType`: AddressType, `keychain`: KeychainKind, `startIndex`: kotlin.UInt, `count`: kotlin.UInt): List { + return FfiConverterSequenceTypeAddressInfo.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_address_infos_for_type( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterTypeKeychainKind.lower(`keychain`), + FfiConverterUInt.lower(`startIndex`), + FfiConverterUInt.lower(`count`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `bumpFeeByRbf`(`txid`: Txid, `feeRate`: FeeRate): Txid { + return FfiConverterTypeTxid.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_bump_fee_by_rbf( + it, + FfiConverterTypeTxid.lower(`txid`), + FfiConverterTypeFeeRate.lower(`feeRate`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `calculateCpfpFeeRate`(`parentTxid`: Txid, `urgent`: kotlin.Boolean): FeeRate { + return FfiConverterTypeFeeRate.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_calculate_cpfp_fee_rate( + it, + FfiConverterTypeTxid.lower(`parentTxid`), + FfiConverterBoolean.lower(`urgent`), + uniffiRustCallStatus, + ) + }!! + }) + } + + @Throws(NodeException::class) + override fun `calculateSendAllFee`(`address`: Address, `retainReserves`: kotlin.Boolean, `feeRate`: FeeRate?): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_calculate_send_all_fee( + it, + FfiConverterTypeAddress.lower(`address`), + FfiConverterBoolean.lower(`retainReserves`), + FfiConverterOptionalTypeFeeRate.lower(`feeRate`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `calculateTotalFee`(`address`: Address, `amountSats`: kotlin.ULong, `feeRate`: FeeRate?, `utxosToSpend`: List?): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_calculate_total_fee( + it, + FfiConverterTypeAddress.lower(`address`), + FfiConverterULong.lower(`amountSats`), + FfiConverterOptionalTypeFeeRate.lower(`feeRate`), + FfiConverterOptionalSequenceTypeSpendableUtxo.lower(`utxosToSpend`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `listSpendableOutputs`(): List { + return FfiConverterSequenceTypeSpendableUtxo.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_list_spendable_outputs( + it, + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `newAddress`(): Address { + return FfiConverterTypeAddress.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_new_address( + it, + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `newAddressForAccount`(`addressType`: AddressType, `accountIndex`: kotlin.UInt): Address { + return FfiConverterTypeAddress.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_new_address_for_account( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterUInt.lower(`accountIndex`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `newAddressForType`(`addressType`: AddressType): Address { + return FfiConverterTypeAddress.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_new_address_for_type( + it, + FfiConverterTypeAddressType.lower(`addressType`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `newAddressInfo`(): AddressInfo { + return FfiConverterTypeAddressInfo.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_new_address_info( + it, + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `newAddressInfoForAccount`(`addressType`: AddressType, `accountIndex`: kotlin.UInt): AddressInfo { + return FfiConverterTypeAddressInfo.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_new_address_info_for_account( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterUInt.lower(`accountIndex`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `newAddressInfoForType`(`addressType`: AddressType): AddressInfo { + return FfiConverterTypeAddressInfo.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_new_address_info_for_type( + it, + FfiConverterTypeAddressType.lower(`addressType`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `revealReceiveAddressesTo`(`addressType`: AddressType, `index`: kotlin.UInt) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_reveal_receive_addresses_to( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterUInt.lower(`index`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `revealReceiveAddressesToAccount`(`addressType`: AddressType, `accountIndex`: kotlin.UInt, `index`: kotlin.UInt) { + callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_reveal_receive_addresses_to_account( + it, + FfiConverterTypeAddressType.lower(`addressType`), + FfiConverterUInt.lower(`accountIndex`), + FfiConverterUInt.lower(`index`), + uniffiRustCallStatus, + ) + } + } + } + + @Throws(NodeException::class) + override fun `selectUtxosWithAlgorithm`(`targetAmountSats`: kotlin.ULong, `feeRate`: FeeRate?, `algorithm`: CoinSelectionAlgorithm, `utxos`: List?): List { + return FfiConverterSequenceTypeSpendableUtxo.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_select_utxos_with_algorithm( + it, + FfiConverterULong.lower(`targetAmountSats`), + FfiConverterOptionalTypeFeeRate.lower(`feeRate`), + FfiConverterTypeCoinSelectionAlgorithm.lower(`algorithm`), + FfiConverterOptionalSequenceTypeSpendableUtxo.lower(`utxos`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `sendAllToAddress`(`address`: Address, `retainReserve`: kotlin.Boolean, `feeRate`: FeeRate?): Txid { + return FfiConverterTypeTxid.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_send_all_to_address( + it, + FfiConverterTypeAddress.lower(`address`), + FfiConverterBoolean.lower(`retainReserve`), + FfiConverterOptionalTypeFeeRate.lower(`feeRate`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `sendToAddress`(`address`: Address, `amountSats`: kotlin.ULong, `feeRate`: FeeRate?, `utxosToSpend`: List?): Txid { + return FfiConverterTypeTxid.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_send_to_address( + it, + FfiConverterTypeAddress.lower(`address`), + FfiConverterULong.lower(`amountSats`), + FfiConverterOptionalTypeFeeRate.lower(`feeRate`), + FfiConverterOptionalSequenceTypeSpendableUtxo.lower(`utxosToSpend`), + uniffiRustCallStatus, + ) + } + }) + } + + + + + + + + companion object + +} + + + + + +object FfiConverterTypeOnchainPayment: FfiConverter { + + override fun lower(value: OnchainPayment): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): OnchainPayment { + return OnchainPayment(value) + } + + override fun read(buf: ByteBuffer): OnchainPayment { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: OnchainPayment) = 8UL + + override fun write(value: OnchainPayment, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + + + +open class Refund: Disposable, RefundInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_refund(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_refund(pointer!!, status) + }!! + } + + + override fun `absoluteExpirySeconds`(): kotlin.ULong? { + return FfiConverterOptionalULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_refund_absolute_expiry_seconds( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `amountMsats`(): kotlin.ULong { + return FfiConverterULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_refund_amount_msats( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `chain`(): Network? { + return FfiConverterOptionalTypeNetwork.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_refund_chain( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `isExpired`(): kotlin.Boolean { + return FfiConverterBoolean.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_refund_is_expired( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `issuer`(): kotlin.String? { + return FfiConverterOptionalString.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_refund_issuer( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `payerMetadata`(): List { + return FfiConverterSequenceUByte.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_refund_payer_metadata( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `payerNote`(): kotlin.String? { + return FfiConverterOptionalString.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_refund_payer_note( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `payerSigningPubkey`(): PublicKey { + return FfiConverterTypePublicKey.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_refund_payer_signing_pubkey( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `quantity`(): kotlin.ULong? { + return FfiConverterOptionalULong.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_refund_quantity( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun `refundDescription`(): kotlin.String { + return FfiConverterString.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_refund_refund_description( + it, + uniffiRustCallStatus, + ) + } + }) + } + + + + + override fun toString(): String { + return FfiConverterString.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_refund_uniffi_trait_display( + it, + uniffiRustCallStatus, + ) + } + }) + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is Refund) return false + return FfiConverterBoolean.lift(callWithPointer { + uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_refund_uniffi_trait_eq_eq( + it, + FfiConverterTypeRefund.lower(`other`), + uniffiRustCallStatus, + ) + } + }) + } + + + + companion object { + + @Throws(NodeException::class) + fun `fromStr`(`refundStr`: kotlin.String): Refund { + return FfiConverterTypeRefund.lift(uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_constructor_refund_from_str( + FfiConverterString.lower(`refundStr`), + uniffiRustCallStatus, + ) + }!!) + } + + + } + +} + + + + + +object FfiConverterTypeRefund: FfiConverter { + + override fun lower(value: Refund): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): Refund { + return Refund(value) + } + + override fun read(buf: ByteBuffer): Refund { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: Refund) = 8UL + + override fun write(value: Refund, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + + + +open class SpontaneousPayment: Disposable, SpontaneousPaymentInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_spontaneouspayment(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_spontaneouspayment(pointer!!, status) + }!! + } + + + @Throws(NodeException::class) + override fun `send`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey, `routeParameters`: RouteParametersConfig?): PaymentId { + return FfiConverterTypePaymentId.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_spontaneouspayment_send( + it, + FfiConverterULong.lower(`amountMsat`), + FfiConverterTypePublicKey.lower(`nodeId`), + FfiConverterOptionalTypeRouteParametersConfig.lower(`routeParameters`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `sendProbes`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey): List { + return FfiConverterSequenceTypeProbeHandle.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_spontaneouspayment_send_probes( + it, + FfiConverterULong.lower(`amountMsat`), + FfiConverterTypePublicKey.lower(`nodeId`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `sendWithCustomTlvs`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey, `routeParameters`: RouteParametersConfig?, `customTlvs`: List): PaymentId { + return FfiConverterTypePaymentId.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_spontaneouspayment_send_with_custom_tlvs( + it, + FfiConverterULong.lower(`amountMsat`), + FfiConverterTypePublicKey.lower(`nodeId`), + FfiConverterOptionalTypeRouteParametersConfig.lower(`routeParameters`), + FfiConverterSequenceTypeCustomTlvRecord.lower(`customTlvs`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `sendWithPreimage`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey, `preimage`: PaymentPreimage, `routeParameters`: RouteParametersConfig?): PaymentId { + return FfiConverterTypePaymentId.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_spontaneouspayment_send_with_preimage( + it, + FfiConverterULong.lower(`amountMsat`), + FfiConverterTypePublicKey.lower(`nodeId`), + FfiConverterTypePaymentPreimage.lower(`preimage`), + FfiConverterOptionalTypeRouteParametersConfig.lower(`routeParameters`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `sendWithPreimageAndCustomTlvs`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey, `customTlvs`: List, `preimage`: PaymentPreimage, `routeParameters`: RouteParametersConfig?): PaymentId { + return FfiConverterTypePaymentId.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_spontaneouspayment_send_with_preimage_and_custom_tlvs( + it, + FfiConverterULong.lower(`amountMsat`), + FfiConverterTypePublicKey.lower(`nodeId`), + FfiConverterSequenceTypeCustomTlvRecord.lower(`customTlvs`), + FfiConverterTypePaymentPreimage.lower(`preimage`), + FfiConverterOptionalTypeRouteParametersConfig.lower(`routeParameters`), + uniffiRustCallStatus, + ) + } + }) + } + + + + + + + + companion object + +} + + + + + +object FfiConverterTypeSpontaneousPayment: FfiConverter { + + override fun lower(value: SpontaneousPayment): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): SpontaneousPayment { + return SpontaneousPayment(value) + } + + override fun read(buf: ByteBuffer): SpontaneousPayment { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: SpontaneousPayment) = 8UL + + override fun write(value: SpontaneousPayment, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + + + +open class UnifiedQrPayment: Disposable, UnifiedQrPaymentInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_unifiedqrpayment(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_unifiedqrpayment(pointer!!, status) + }!! + } + + + @Throws(NodeException::class) + override fun `receive`(`amountSats`: kotlin.ULong, `message`: kotlin.String, `expirySec`: kotlin.UInt): kotlin.String { + return FfiConverterString.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_unifiedqrpayment_receive( + it, + FfiConverterULong.lower(`amountSats`), + FfiConverterString.lower(`message`), + FfiConverterUInt.lower(`expirySec`), + uniffiRustCallStatus, + ) + } + }) + } + + @Throws(NodeException::class) + override fun `send`(`uriStr`: kotlin.String, `routeParameters`: RouteParametersConfig?): QrPaymentResult { + return FfiConverterTypeQrPaymentResult.lift(callWithPointer { + uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_unifiedqrpayment_send( + it, + FfiConverterString.lower(`uriStr`), + FfiConverterOptionalTypeRouteParametersConfig.lower(`routeParameters`), + uniffiRustCallStatus, + ) + } + }) + } + + + + + + + + companion object + +} + + + + + +object FfiConverterTypeUnifiedQrPayment: FfiConverter { + + override fun lower(value: UnifiedQrPayment): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): UnifiedQrPayment { + return UnifiedQrPayment(value) + } + + override fun read(buf: ByteBuffer): UnifiedQrPayment { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: UnifiedQrPayment) = 8UL + + override fun write(value: UnifiedQrPayment, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + + + +open class VssHeaderProvider: Disposable, VssHeaderProviderInterface { + + constructor(pointer: Pointer) { + this.pointer = pointer + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(pointer)) + } + + /** + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + constructor(noPointer: NoPointer) { + this.pointer = null + this.cleanable = UniffiLib.CLEANER.register(this, UniffiPointerDestroyer(null)) + } + + protected val pointer: Pointer? + protected val cleanable: UniffiCleaner.Cleanable + + private val wasDestroyed: kotlinx.atomicfu.AtomicBoolean = kotlinx.atomicfu.atomic(false) + private val callCounter: kotlinx.atomicfu.AtomicLong = kotlinx.atomicfu.atomic(1L) + + private val lock = kotlinx.atomicfu.locks.ReentrantLock() + + private fun synchronized(block: () -> T): T { + lock.lock() + try { + return block() + } finally { + lock.unlock() + } + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + override fun close() { + synchronized { this.destroy() } + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.value + if (c == 0L) { + throw IllegalStateException("${this::class::simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this::class::simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.uniffiClonePointer()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiPointerDestroyer(private val pointer: Pointer?) : Disposable { + override fun destroy() { + pointer?.let { ptr -> + uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_free_vssheaderprovider(ptr, status) + } + } + } + } + + fun uniffiClonePointer(): Pointer { + return uniffiRustCall { status -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_clone_vssheaderprovider(pointer!!, status) + }!! + } + + + @Throws(VssHeaderProviderException::class, kotlin.coroutines.cancellation.CancellationException::class) + override suspend fun `getHeaders`(`request`: List): Map { + return uniffiRustCallAsync( + callWithPointer { thisPtr -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_vssheaderprovider_get_headers( + thisPtr, + FfiConverterSequenceUByte.lower(`request`), + ) + }, + { future, callback, continuation -> UniffiLib.INSTANCE.ffi_ldk_node_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.INSTANCE.ffi_ldk_node_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.INSTANCE.ffi_ldk_node_rust_future_free_rust_buffer(future) }, + { future -> UniffiLib.INSTANCE.ffi_ldk_node_rust_future_cancel_rust_buffer(future) }, + // lift function + { FfiConverterMapStringString.lift(it) }, + // Error FFI converter + VssHeaderProviderExceptionErrorHandler, + ) + } + + + + + + + + companion object + +} + + + + + +object FfiConverterTypeVssHeaderProvider: FfiConverter { + + override fun lower(value: VssHeaderProvider): Pointer { + return value.uniffiClonePointer() + } + + override fun lift(value: Pointer): VssHeaderProvider { + return VssHeaderProvider(value) + } + + override fun read(buf: ByteBuffer): VssHeaderProvider { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(buf.getLong().toPointer()) + } + + override fun allocationSize(value: VssHeaderProvider) = 8UL + + override fun write(value: VssHeaderProvider, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(lower(value).toLong()) + } +} + + + + +object FfiConverterTypeAddressInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): AddressInfo { + return AddressInfo( + FfiConverterUInt.read(buf), + FfiConverterTypeAddress.read(buf), + FfiConverterTypeKeychainKind.read(buf), + ) + } + + override fun allocationSize(value: AddressInfo) = ( + FfiConverterUInt.allocationSize(value.`index`) + + FfiConverterTypeAddress.allocationSize(value.`address`) + + FfiConverterTypeKeychainKind.allocationSize(value.`keychain`) + ) + + override fun write(value: AddressInfo, buf: ByteBuffer) { + FfiConverterUInt.write(value.`index`, buf) + FfiConverterTypeAddress.write(value.`address`, buf) + FfiConverterTypeKeychainKind.write(value.`keychain`, buf) + } +} + + + + +object FfiConverterTypeAddressTypeBalance: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): AddressTypeBalance { + return AddressTypeBalance( + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + ) + } + + override fun allocationSize(value: AddressTypeBalance) = ( + FfiConverterULong.allocationSize(value.`totalSats`) + + FfiConverterULong.allocationSize(value.`spendableSats`) + ) + + override fun write(value: AddressTypeBalance, buf: ByteBuffer) { + FfiConverterULong.write(value.`totalSats`, buf) + FfiConverterULong.write(value.`spendableSats`, buf) + } +} + + + + +object FfiConverterTypeAnchorChannelsConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): AnchorChannelsConfig { + return AnchorChannelsConfig( + FfiConverterSequenceTypePublicKey.read(buf), + FfiConverterULong.read(buf), + ) + } + + override fun allocationSize(value: AnchorChannelsConfig) = ( + FfiConverterSequenceTypePublicKey.allocationSize(value.`trustedPeersNoReserve`) + + FfiConverterULong.allocationSize(value.`perChannelReserveSats`) + ) + + override fun write(value: AnchorChannelsConfig, buf: ByteBuffer) { + FfiConverterSequenceTypePublicKey.write(value.`trustedPeersNoReserve`, buf) + FfiConverterULong.write(value.`perChannelReserveSats`, buf) + } +} + + + + +object FfiConverterTypeBackgroundSyncConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): BackgroundSyncConfig { + return BackgroundSyncConfig( + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + ) + } + + override fun allocationSize(value: BackgroundSyncConfig) = ( + FfiConverterULong.allocationSize(value.`onchainWalletSyncIntervalSecs`) + + FfiConverterULong.allocationSize(value.`lightningWalletSyncIntervalSecs`) + + FfiConverterULong.allocationSize(value.`feeRateCacheUpdateIntervalSecs`) + ) + + override fun write(value: BackgroundSyncConfig, buf: ByteBuffer) { + FfiConverterULong.write(value.`onchainWalletSyncIntervalSecs`, buf) + FfiConverterULong.write(value.`lightningWalletSyncIntervalSecs`, buf) + FfiConverterULong.write(value.`feeRateCacheUpdateIntervalSecs`, buf) + } +} + + + + +object FfiConverterTypeBalanceDetails: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): BalanceDetails { + return BalanceDetails( + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterSequenceTypeLightningBalance.read(buf), + FfiConverterSequenceTypePendingSweepBalance.read(buf), + ) + } + + override fun allocationSize(value: BalanceDetails) = ( + FfiConverterULong.allocationSize(value.`totalOnchainBalanceSats`) + + FfiConverterULong.allocationSize(value.`spendableOnchainBalanceSats`) + + FfiConverterULong.allocationSize(value.`totalAnchorChannelsReserveSats`) + + FfiConverterULong.allocationSize(value.`totalLightningBalanceSats`) + + FfiConverterSequenceTypeLightningBalance.allocationSize(value.`lightningBalances`) + + FfiConverterSequenceTypePendingSweepBalance.allocationSize(value.`pendingBalancesFromChannelClosures`) + ) + + override fun write(value: BalanceDetails, buf: ByteBuffer) { + FfiConverterULong.write(value.`totalOnchainBalanceSats`, buf) + FfiConverterULong.write(value.`spendableOnchainBalanceSats`, buf) + FfiConverterULong.write(value.`totalAnchorChannelsReserveSats`, buf) + FfiConverterULong.write(value.`totalLightningBalanceSats`, buf) + FfiConverterSequenceTypeLightningBalance.write(value.`lightningBalances`, buf) + FfiConverterSequenceTypePendingSweepBalance.write(value.`pendingBalancesFromChannelClosures`, buf) + } +} + + + + +object FfiConverterTypeBestBlock: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): BestBlock { + return BestBlock( + FfiConverterTypeBlockHash.read(buf), + FfiConverterUInt.read(buf), + ) + } + + override fun allocationSize(value: BestBlock) = ( + FfiConverterTypeBlockHash.allocationSize(value.`blockHash`) + + FfiConverterUInt.allocationSize(value.`height`) + ) + + override fun write(value: BestBlock, buf: ByteBuffer) { + FfiConverterTypeBlockHash.write(value.`blockHash`, buf) + FfiConverterUInt.write(value.`height`, buf) + } +} + + + + +object FfiConverterTypeChannelConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ChannelConfig { + return ChannelConfig( + FfiConverterUInt.read(buf), + FfiConverterUInt.read(buf), + FfiConverterUShort.read(buf), + FfiConverterTypeMaxDustHTLCExposure.read(buf), + FfiConverterULong.read(buf), + FfiConverterBoolean.read(buf), + ) + } + + override fun allocationSize(value: ChannelConfig) = ( + FfiConverterUInt.allocationSize(value.`forwardingFeeProportionalMillionths`) + + FfiConverterUInt.allocationSize(value.`forwardingFeeBaseMsat`) + + FfiConverterUShort.allocationSize(value.`cltvExpiryDelta`) + + FfiConverterTypeMaxDustHTLCExposure.allocationSize(value.`maxDustHtlcExposure`) + + FfiConverterULong.allocationSize(value.`forceCloseAvoidanceMaxFeeSatoshis`) + + FfiConverterBoolean.allocationSize(value.`acceptUnderpayingHtlcs`) + ) + + override fun write(value: ChannelConfig, buf: ByteBuffer) { + FfiConverterUInt.write(value.`forwardingFeeProportionalMillionths`, buf) + FfiConverterUInt.write(value.`forwardingFeeBaseMsat`, buf) + FfiConverterUShort.write(value.`cltvExpiryDelta`, buf) + FfiConverterTypeMaxDustHTLCExposure.write(value.`maxDustHtlcExposure`, buf) + FfiConverterULong.write(value.`forceCloseAvoidanceMaxFeeSatoshis`, buf) + FfiConverterBoolean.write(value.`acceptUnderpayingHtlcs`, buf) + } +} + + + + +object FfiConverterTypeChannelDataMigration: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ChannelDataMigration { + return ChannelDataMigration( + FfiConverterOptionalSequenceUByte.read(buf), + FfiConverterSequenceSequenceUByte.read(buf), + ) + } + + override fun allocationSize(value: ChannelDataMigration) = ( + FfiConverterOptionalSequenceUByte.allocationSize(value.`channelManager`) + + FfiConverterSequenceSequenceUByte.allocationSize(value.`channelMonitors`) + ) + + override fun write(value: ChannelDataMigration, buf: ByteBuffer) { + FfiConverterOptionalSequenceUByte.write(value.`channelManager`, buf) + FfiConverterSequenceSequenceUByte.write(value.`channelMonitors`, buf) + } +} + + + + +object FfiConverterTypeChannelDetails: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ChannelDetails { + return ChannelDetails( + FfiConverterTypeChannelId.read(buf), + FfiConverterTypePublicKey.read(buf), + FfiConverterOptionalTypeOutPoint.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterTypeUserChannelId.read(buf), + FfiConverterUInt.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterOptionalUInt.read(buf), + FfiConverterOptionalUInt.read(buf), + FfiConverterBoolean.read(buf), + FfiConverterBoolean.read(buf), + FfiConverterBoolean.read(buf), + FfiConverterBoolean.read(buf), + FfiConverterOptionalUShort.read(buf), + FfiConverterULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalUInt.read(buf), + FfiConverterOptionalUInt.read(buf), + FfiConverterOptionalUShort.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterOptionalUShort.read(buf), + FfiConverterULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterTypeChannelConfig.read(buf), + FfiConverterOptionalULong.read(buf), + ) + } + + override fun allocationSize(value: ChannelDetails) = ( + FfiConverterTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterTypePublicKey.allocationSize(value.`counterpartyNodeId`) + + FfiConverterOptionalTypeOutPoint.allocationSize(value.`fundingTxo`) + + FfiConverterOptionalULong.allocationSize(value.`shortChannelId`) + + FfiConverterOptionalULong.allocationSize(value.`outboundScidAlias`) + + FfiConverterOptionalULong.allocationSize(value.`inboundScidAlias`) + + FfiConverterULong.allocationSize(value.`channelValueSats`) + + FfiConverterOptionalULong.allocationSize(value.`unspendablePunishmentReserve`) + + FfiConverterTypeUserChannelId.allocationSize(value.`userChannelId`) + + FfiConverterUInt.allocationSize(value.`feerateSatPer1000Weight`) + + FfiConverterULong.allocationSize(value.`outboundCapacityMsat`) + + FfiConverterULong.allocationSize(value.`inboundCapacityMsat`) + + FfiConverterOptionalUInt.allocationSize(value.`confirmationsRequired`) + + FfiConverterOptionalUInt.allocationSize(value.`confirmations`) + + FfiConverterBoolean.allocationSize(value.`isOutbound`) + + FfiConverterBoolean.allocationSize(value.`isChannelReady`) + + FfiConverterBoolean.allocationSize(value.`isUsable`) + + FfiConverterBoolean.allocationSize(value.`isAnnounced`) + + FfiConverterOptionalUShort.allocationSize(value.`cltvExpiryDelta`) + + FfiConverterULong.allocationSize(value.`counterpartyUnspendablePunishmentReserve`) + + FfiConverterOptionalULong.allocationSize(value.`counterpartyOutboundHtlcMinimumMsat`) + + FfiConverterOptionalULong.allocationSize(value.`counterpartyOutboundHtlcMaximumMsat`) + + FfiConverterOptionalUInt.allocationSize(value.`counterpartyForwardingInfoFeeBaseMsat`) + + FfiConverterOptionalUInt.allocationSize(value.`counterpartyForwardingInfoFeeProportionalMillionths`) + + FfiConverterOptionalUShort.allocationSize(value.`counterpartyForwardingInfoCltvExpiryDelta`) + + FfiConverterULong.allocationSize(value.`nextOutboundHtlcLimitMsat`) + + FfiConverterULong.allocationSize(value.`nextOutboundHtlcMinimumMsat`) + + FfiConverterOptionalUShort.allocationSize(value.`forceCloseSpendDelay`) + + FfiConverterULong.allocationSize(value.`inboundHtlcMinimumMsat`) + + FfiConverterOptionalULong.allocationSize(value.`inboundHtlcMaximumMsat`) + + FfiConverterTypeChannelConfig.allocationSize(value.`config`) + + FfiConverterOptionalULong.allocationSize(value.`claimableOnCloseSats`) + ) + + override fun write(value: ChannelDetails, buf: ByteBuffer) { + FfiConverterTypeChannelId.write(value.`channelId`, buf) + FfiConverterTypePublicKey.write(value.`counterpartyNodeId`, buf) + FfiConverterOptionalTypeOutPoint.write(value.`fundingTxo`, buf) + FfiConverterOptionalULong.write(value.`shortChannelId`, buf) + FfiConverterOptionalULong.write(value.`outboundScidAlias`, buf) + FfiConverterOptionalULong.write(value.`inboundScidAlias`, buf) + FfiConverterULong.write(value.`channelValueSats`, buf) + FfiConverterOptionalULong.write(value.`unspendablePunishmentReserve`, buf) + FfiConverterTypeUserChannelId.write(value.`userChannelId`, buf) + FfiConverterUInt.write(value.`feerateSatPer1000Weight`, buf) + FfiConverterULong.write(value.`outboundCapacityMsat`, buf) + FfiConverterULong.write(value.`inboundCapacityMsat`, buf) + FfiConverterOptionalUInt.write(value.`confirmationsRequired`, buf) + FfiConverterOptionalUInt.write(value.`confirmations`, buf) + FfiConverterBoolean.write(value.`isOutbound`, buf) + FfiConverterBoolean.write(value.`isChannelReady`, buf) + FfiConverterBoolean.write(value.`isUsable`, buf) + FfiConverterBoolean.write(value.`isAnnounced`, buf) + FfiConverterOptionalUShort.write(value.`cltvExpiryDelta`, buf) + FfiConverterULong.write(value.`counterpartyUnspendablePunishmentReserve`, buf) + FfiConverterOptionalULong.write(value.`counterpartyOutboundHtlcMinimumMsat`, buf) + FfiConverterOptionalULong.write(value.`counterpartyOutboundHtlcMaximumMsat`, buf) + FfiConverterOptionalUInt.write(value.`counterpartyForwardingInfoFeeBaseMsat`, buf) + FfiConverterOptionalUInt.write(value.`counterpartyForwardingInfoFeeProportionalMillionths`, buf) + FfiConverterOptionalUShort.write(value.`counterpartyForwardingInfoCltvExpiryDelta`, buf) + FfiConverterULong.write(value.`nextOutboundHtlcLimitMsat`, buf) + FfiConverterULong.write(value.`nextOutboundHtlcMinimumMsat`, buf) + FfiConverterOptionalUShort.write(value.`forceCloseSpendDelay`, buf) + FfiConverterULong.write(value.`inboundHtlcMinimumMsat`, buf) + FfiConverterOptionalULong.write(value.`inboundHtlcMaximumMsat`, buf) + FfiConverterTypeChannelConfig.write(value.`config`, buf) + FfiConverterOptionalULong.write(value.`claimableOnCloseSats`, buf) + } +} + + + + +object FfiConverterTypeChannelInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ChannelInfo { + return ChannelInfo( + FfiConverterTypeNodeId.read(buf), + FfiConverterOptionalTypeChannelUpdateInfo.read(buf), + FfiConverterTypeNodeId.read(buf), + FfiConverterOptionalTypeChannelUpdateInfo.read(buf), + FfiConverterOptionalULong.read(buf), + ) + } + + override fun allocationSize(value: ChannelInfo) = ( + FfiConverterTypeNodeId.allocationSize(value.`nodeOne`) + + FfiConverterOptionalTypeChannelUpdateInfo.allocationSize(value.`oneToTwo`) + + FfiConverterTypeNodeId.allocationSize(value.`nodeTwo`) + + FfiConverterOptionalTypeChannelUpdateInfo.allocationSize(value.`twoToOne`) + + FfiConverterOptionalULong.allocationSize(value.`capacitySats`) + ) + + override fun write(value: ChannelInfo, buf: ByteBuffer) { + FfiConverterTypeNodeId.write(value.`nodeOne`, buf) + FfiConverterOptionalTypeChannelUpdateInfo.write(value.`oneToTwo`, buf) + FfiConverterTypeNodeId.write(value.`nodeTwo`, buf) + FfiConverterOptionalTypeChannelUpdateInfo.write(value.`twoToOne`, buf) + FfiConverterOptionalULong.write(value.`capacitySats`, buf) + } +} + + + + +object FfiConverterTypeChannelUpdateInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ChannelUpdateInfo { + return ChannelUpdateInfo( + FfiConverterUInt.read(buf), + FfiConverterBoolean.read(buf), + FfiConverterUShort.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterTypeRoutingFees.read(buf), + ) + } + + override fun allocationSize(value: ChannelUpdateInfo) = ( + FfiConverterUInt.allocationSize(value.`lastUpdate`) + + FfiConverterBoolean.allocationSize(value.`enabled`) + + FfiConverterUShort.allocationSize(value.`cltvExpiryDelta`) + + FfiConverterULong.allocationSize(value.`htlcMinimumMsat`) + + FfiConverterULong.allocationSize(value.`htlcMaximumMsat`) + + FfiConverterTypeRoutingFees.allocationSize(value.`fees`) + ) + + override fun write(value: ChannelUpdateInfo, buf: ByteBuffer) { + FfiConverterUInt.write(value.`lastUpdate`, buf) + FfiConverterBoolean.write(value.`enabled`, buf) + FfiConverterUShort.write(value.`cltvExpiryDelta`, buf) + FfiConverterULong.write(value.`htlcMinimumMsat`, buf) + FfiConverterULong.write(value.`htlcMaximumMsat`, buf) + FfiConverterTypeRoutingFees.write(value.`fees`, buf) + } +} + + + + +object FfiConverterTypeConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Config { + return Config( + FfiConverterString.read(buf), + FfiConverterTypeNetwork.read(buf), + FfiConverterOptionalSequenceTypeSocketAddress.read(buf), + FfiConverterOptionalSequenceTypeSocketAddress.read(buf), + FfiConverterOptionalTypeNodeAlias.read(buf), + FfiConverterSequenceTypePublicKey.read(buf), + FfiConverterULong.read(buf), + FfiConverterOptionalTypeAnchorChannelsConfig.read(buf), + FfiConverterOptionalTypeRouteParametersConfig.read(buf), + FfiConverterOptionalTypeScoringFeeParameters.read(buf), + FfiConverterOptionalTypeScoringDecayParameters.read(buf), + FfiConverterBoolean.read(buf), + FfiConverterTypeAddressType.read(buf), + FfiConverterSequenceTypeAddressType.read(buf), + FfiConverterSequenceTypeOnchainWalletAccountConfig.read(buf), + ) + } + + override fun allocationSize(value: Config) = ( + FfiConverterString.allocationSize(value.`storageDirPath`) + + FfiConverterTypeNetwork.allocationSize(value.`network`) + + FfiConverterOptionalSequenceTypeSocketAddress.allocationSize(value.`listeningAddresses`) + + FfiConverterOptionalSequenceTypeSocketAddress.allocationSize(value.`announcementAddresses`) + + FfiConverterOptionalTypeNodeAlias.allocationSize(value.`nodeAlias`) + + FfiConverterSequenceTypePublicKey.allocationSize(value.`trustedPeers0conf`) + + FfiConverterULong.allocationSize(value.`probingLiquidityLimitMultiplier`) + + FfiConverterOptionalTypeAnchorChannelsConfig.allocationSize(value.`anchorChannelsConfig`) + + FfiConverterOptionalTypeRouteParametersConfig.allocationSize(value.`routeParameters`) + + FfiConverterOptionalTypeScoringFeeParameters.allocationSize(value.`scoringFeeParams`) + + FfiConverterOptionalTypeScoringDecayParameters.allocationSize(value.`scoringDecayParams`) + + FfiConverterBoolean.allocationSize(value.`includeUntrustedPendingInSpendable`) + + FfiConverterTypeAddressType.allocationSize(value.`addressType`) + + FfiConverterSequenceTypeAddressType.allocationSize(value.`addressTypesToMonitor`) + + FfiConverterSequenceTypeOnchainWalletAccountConfig.allocationSize(value.`onchainWalletAccounts`) + ) + + override fun write(value: Config, buf: ByteBuffer) { + FfiConverterString.write(value.`storageDirPath`, buf) + FfiConverterTypeNetwork.write(value.`network`, buf) + FfiConverterOptionalSequenceTypeSocketAddress.write(value.`listeningAddresses`, buf) + FfiConverterOptionalSequenceTypeSocketAddress.write(value.`announcementAddresses`, buf) + FfiConverterOptionalTypeNodeAlias.write(value.`nodeAlias`, buf) + FfiConverterSequenceTypePublicKey.write(value.`trustedPeers0conf`, buf) + FfiConverterULong.write(value.`probingLiquidityLimitMultiplier`, buf) + FfiConverterOptionalTypeAnchorChannelsConfig.write(value.`anchorChannelsConfig`, buf) + FfiConverterOptionalTypeRouteParametersConfig.write(value.`routeParameters`, buf) + FfiConverterOptionalTypeScoringFeeParameters.write(value.`scoringFeeParams`, buf) + FfiConverterOptionalTypeScoringDecayParameters.write(value.`scoringDecayParams`, buf) + FfiConverterBoolean.write(value.`includeUntrustedPendingInSpendable`, buf) + FfiConverterTypeAddressType.write(value.`addressType`, buf) + FfiConverterSequenceTypeAddressType.write(value.`addressTypesToMonitor`, buf) + FfiConverterSequenceTypeOnchainWalletAccountConfig.write(value.`onchainWalletAccounts`, buf) + } +} + + + + +object FfiConverterTypeCustomTlvRecord: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): CustomTlvRecord { + return CustomTlvRecord( + FfiConverterULong.read(buf), + FfiConverterSequenceUByte.read(buf), + ) + } + + override fun allocationSize(value: CustomTlvRecord) = ( + FfiConverterULong.allocationSize(value.`typeNum`) + + FfiConverterSequenceUByte.allocationSize(value.`value`) + ) + + override fun write(value: CustomTlvRecord, buf: ByteBuffer) { + FfiConverterULong.write(value.`typeNum`, buf) + FfiConverterSequenceUByte.write(value.`value`, buf) + } +} + + + + +object FfiConverterTypeElectrumSyncConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ElectrumSyncConfig { + return ElectrumSyncConfig( + FfiConverterOptionalTypeBackgroundSyncConfig.read(buf), + FfiConverterULong.read(buf), + FfiConverterUInt.read(buf), + FfiConverterUInt.read(buf), + ) + } + + override fun allocationSize(value: ElectrumSyncConfig) = ( + FfiConverterOptionalTypeBackgroundSyncConfig.allocationSize(value.`backgroundSyncConfig`) + + FfiConverterULong.allocationSize(value.`connectionTimeoutSecs`) + + FfiConverterUInt.allocationSize(value.`additionalWalletFullScanBatchSize`) + + FfiConverterUInt.allocationSize(value.`additionalWalletFullScanStopGap`) + ) + + override fun write(value: ElectrumSyncConfig, buf: ByteBuffer) { + FfiConverterOptionalTypeBackgroundSyncConfig.write(value.`backgroundSyncConfig`, buf) + FfiConverterULong.write(value.`connectionTimeoutSecs`, buf) + FfiConverterUInt.write(value.`additionalWalletFullScanBatchSize`, buf) + FfiConverterUInt.write(value.`additionalWalletFullScanStopGap`, buf) + } +} + + + + +object FfiConverterTypeEsploraSyncConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): EsploraSyncConfig { + return EsploraSyncConfig( + FfiConverterOptionalTypeBackgroundSyncConfig.read(buf), + ) + } + + override fun allocationSize(value: EsploraSyncConfig) = ( + FfiConverterOptionalTypeBackgroundSyncConfig.allocationSize(value.`backgroundSyncConfig`) + ) + + override fun write(value: EsploraSyncConfig, buf: ByteBuffer) { + FfiConverterOptionalTypeBackgroundSyncConfig.write(value.`backgroundSyncConfig`, buf) + } +} + + + + +object FfiConverterTypeLSPFeeLimits: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): LspFeeLimits { + return LspFeeLimits( + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalULong.read(buf), + ) + } + + override fun allocationSize(value: LspFeeLimits) = ( + FfiConverterOptionalULong.allocationSize(value.`maxTotalOpeningFeeMsat`) + + FfiConverterOptionalULong.allocationSize(value.`maxProportionalOpeningFeePpmMsat`) + ) + + override fun write(value: LspFeeLimits, buf: ByteBuffer) { + FfiConverterOptionalULong.write(value.`maxTotalOpeningFeeMsat`, buf) + FfiConverterOptionalULong.write(value.`maxProportionalOpeningFeePpmMsat`, buf) + } +} + + + + +object FfiConverterTypeLSPS1Bolt11PaymentInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Lsps1Bolt11PaymentInfo { + return Lsps1Bolt11PaymentInfo( + FfiConverterTypeLSPS1PaymentState.read(buf), + FfiConverterTypeLSPSDateTime.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterTypeBolt11Invoice.read(buf), + ) + } + + override fun allocationSize(value: Lsps1Bolt11PaymentInfo) = ( + FfiConverterTypeLSPS1PaymentState.allocationSize(value.`state`) + + FfiConverterTypeLSPSDateTime.allocationSize(value.`expiresAt`) + + FfiConverterULong.allocationSize(value.`feeTotalSat`) + + FfiConverterULong.allocationSize(value.`orderTotalSat`) + + FfiConverterTypeBolt11Invoice.allocationSize(value.`invoice`) + ) + + override fun write(value: Lsps1Bolt11PaymentInfo, buf: ByteBuffer) { + FfiConverterTypeLSPS1PaymentState.write(value.`state`, buf) + FfiConverterTypeLSPSDateTime.write(value.`expiresAt`, buf) + FfiConverterULong.write(value.`feeTotalSat`, buf) + FfiConverterULong.write(value.`orderTotalSat`, buf) + FfiConverterTypeBolt11Invoice.write(value.`invoice`, buf) + } +} + + + + +object FfiConverterTypeLSPS1ChannelInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Lsps1ChannelInfo { + return Lsps1ChannelInfo( + FfiConverterTypeLSPSDateTime.read(buf), + FfiConverterTypeOutPoint.read(buf), + FfiConverterTypeLSPSDateTime.read(buf), + ) + } + + override fun allocationSize(value: Lsps1ChannelInfo) = ( + FfiConverterTypeLSPSDateTime.allocationSize(value.`fundedAt`) + + FfiConverterTypeOutPoint.allocationSize(value.`fundingOutpoint`) + + FfiConverterTypeLSPSDateTime.allocationSize(value.`expiresAt`) + ) + + override fun write(value: Lsps1ChannelInfo, buf: ByteBuffer) { + FfiConverterTypeLSPSDateTime.write(value.`fundedAt`, buf) + FfiConverterTypeOutPoint.write(value.`fundingOutpoint`, buf) + FfiConverterTypeLSPSDateTime.write(value.`expiresAt`, buf) + } +} + + + + +object FfiConverterTypeLSPS1OnchainPaymentInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Lsps1OnchainPaymentInfo { + return Lsps1OnchainPaymentInfo( + FfiConverterTypeLSPS1PaymentState.read(buf), + FfiConverterTypeLSPSDateTime.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterTypeAddress.read(buf), + FfiConverterOptionalUShort.read(buf), + FfiConverterTypeFeeRate.read(buf), + FfiConverterOptionalTypeAddress.read(buf), + ) + } + + override fun allocationSize(value: Lsps1OnchainPaymentInfo) = ( + FfiConverterTypeLSPS1PaymentState.allocationSize(value.`state`) + + FfiConverterTypeLSPSDateTime.allocationSize(value.`expiresAt`) + + FfiConverterULong.allocationSize(value.`feeTotalSat`) + + FfiConverterULong.allocationSize(value.`orderTotalSat`) + + FfiConverterTypeAddress.allocationSize(value.`address`) + + FfiConverterOptionalUShort.allocationSize(value.`minOnchainPaymentConfirmations`) + + FfiConverterTypeFeeRate.allocationSize(value.`minFeeFor0conf`) + + FfiConverterOptionalTypeAddress.allocationSize(value.`refundOnchainAddress`) + ) + + override fun write(value: Lsps1OnchainPaymentInfo, buf: ByteBuffer) { + FfiConverterTypeLSPS1PaymentState.write(value.`state`, buf) + FfiConverterTypeLSPSDateTime.write(value.`expiresAt`, buf) + FfiConverterULong.write(value.`feeTotalSat`, buf) + FfiConverterULong.write(value.`orderTotalSat`, buf) + FfiConverterTypeAddress.write(value.`address`, buf) + FfiConverterOptionalUShort.write(value.`minOnchainPaymentConfirmations`, buf) + FfiConverterTypeFeeRate.write(value.`minFeeFor0conf`, buf) + FfiConverterOptionalTypeAddress.write(value.`refundOnchainAddress`, buf) + } +} + + + + +object FfiConverterTypeLSPS1OrderParams: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Lsps1OrderParams { + return Lsps1OrderParams( + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterUShort.read(buf), + FfiConverterUShort.read(buf), + FfiConverterUInt.read(buf), + FfiConverterOptionalString.read(buf), + FfiConverterBoolean.read(buf), + ) + } + + override fun allocationSize(value: Lsps1OrderParams) = ( + FfiConverterULong.allocationSize(value.`lspBalanceSat`) + + FfiConverterULong.allocationSize(value.`clientBalanceSat`) + + FfiConverterUShort.allocationSize(value.`requiredChannelConfirmations`) + + FfiConverterUShort.allocationSize(value.`fundingConfirmsWithinBlocks`) + + FfiConverterUInt.allocationSize(value.`channelExpiryBlocks`) + + FfiConverterOptionalString.allocationSize(value.`token`) + + FfiConverterBoolean.allocationSize(value.`announceChannel`) + ) + + override fun write(value: Lsps1OrderParams, buf: ByteBuffer) { + FfiConverterULong.write(value.`lspBalanceSat`, buf) + FfiConverterULong.write(value.`clientBalanceSat`, buf) + FfiConverterUShort.write(value.`requiredChannelConfirmations`, buf) + FfiConverterUShort.write(value.`fundingConfirmsWithinBlocks`, buf) + FfiConverterUInt.write(value.`channelExpiryBlocks`, buf) + FfiConverterOptionalString.write(value.`token`, buf) + FfiConverterBoolean.write(value.`announceChannel`, buf) + } +} + + + + +object FfiConverterTypeLSPS1OrderStatus: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Lsps1OrderStatus { + return Lsps1OrderStatus( + FfiConverterTypeLSPS1OrderId.read(buf), + FfiConverterTypeLSPS1OrderParams.read(buf), + FfiConverterTypeLSPS1PaymentInfo.read(buf), + FfiConverterOptionalTypeLSPS1ChannelInfo.read(buf), + ) + } + + override fun allocationSize(value: Lsps1OrderStatus) = ( + FfiConverterTypeLSPS1OrderId.allocationSize(value.`orderId`) + + FfiConverterTypeLSPS1OrderParams.allocationSize(value.`orderParams`) + + FfiConverterTypeLSPS1PaymentInfo.allocationSize(value.`paymentOptions`) + + FfiConverterOptionalTypeLSPS1ChannelInfo.allocationSize(value.`channelState`) + ) + + override fun write(value: Lsps1OrderStatus, buf: ByteBuffer) { + FfiConverterTypeLSPS1OrderId.write(value.`orderId`, buf) + FfiConverterTypeLSPS1OrderParams.write(value.`orderParams`, buf) + FfiConverterTypeLSPS1PaymentInfo.write(value.`paymentOptions`, buf) + FfiConverterOptionalTypeLSPS1ChannelInfo.write(value.`channelState`, buf) + } +} + + + + +object FfiConverterTypeLSPS1PaymentInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Lsps1PaymentInfo { + return Lsps1PaymentInfo( + FfiConverterOptionalTypeLSPS1Bolt11PaymentInfo.read(buf), + FfiConverterOptionalTypeLSPS1OnchainPaymentInfo.read(buf), + ) + } + + override fun allocationSize(value: Lsps1PaymentInfo) = ( + FfiConverterOptionalTypeLSPS1Bolt11PaymentInfo.allocationSize(value.`bolt11`) + + FfiConverterOptionalTypeLSPS1OnchainPaymentInfo.allocationSize(value.`onchain`) + ) + + override fun write(value: Lsps1PaymentInfo, buf: ByteBuffer) { + FfiConverterOptionalTypeLSPS1Bolt11PaymentInfo.write(value.`bolt11`, buf) + FfiConverterOptionalTypeLSPS1OnchainPaymentInfo.write(value.`onchain`, buf) + } +} + + + + +object FfiConverterTypeLSPS2ServiceConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Lsps2ServiceConfig { + return Lsps2ServiceConfig( + FfiConverterOptionalString.read(buf), + FfiConverterBoolean.read(buf), + FfiConverterUInt.read(buf), + FfiConverterUInt.read(buf), + FfiConverterULong.read(buf), + FfiConverterUInt.read(buf), + FfiConverterUInt.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterBoolean.read(buf), + ) + } + + override fun allocationSize(value: Lsps2ServiceConfig) = ( + FfiConverterOptionalString.allocationSize(value.`requireToken`) + + FfiConverterBoolean.allocationSize(value.`advertiseService`) + + FfiConverterUInt.allocationSize(value.`channelOpeningFeePpm`) + + FfiConverterUInt.allocationSize(value.`channelOverProvisioningPpm`) + + FfiConverterULong.allocationSize(value.`minChannelOpeningFeeMsat`) + + FfiConverterUInt.allocationSize(value.`minChannelLifetime`) + + FfiConverterUInt.allocationSize(value.`maxClientToSelfDelay`) + + FfiConverterULong.allocationSize(value.`minPaymentSizeMsat`) + + FfiConverterULong.allocationSize(value.`maxPaymentSizeMsat`) + + FfiConverterBoolean.allocationSize(value.`clientTrustsLsp`) + ) + + override fun write(value: Lsps2ServiceConfig, buf: ByteBuffer) { + FfiConverterOptionalString.write(value.`requireToken`, buf) + FfiConverterBoolean.write(value.`advertiseService`, buf) + FfiConverterUInt.write(value.`channelOpeningFeePpm`, buf) + FfiConverterUInt.write(value.`channelOverProvisioningPpm`, buf) + FfiConverterULong.write(value.`minChannelOpeningFeeMsat`, buf) + FfiConverterUInt.write(value.`minChannelLifetime`, buf) + FfiConverterUInt.write(value.`maxClientToSelfDelay`, buf) + FfiConverterULong.write(value.`minPaymentSizeMsat`, buf) + FfiConverterULong.write(value.`maxPaymentSizeMsat`, buf) + FfiConverterBoolean.write(value.`clientTrustsLsp`, buf) + } +} + + + + +object FfiConverterTypeLogRecord: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): LogRecord { + return LogRecord( + FfiConverterTypeLogLevel.read(buf), + FfiConverterString.read(buf), + FfiConverterString.read(buf), + FfiConverterUInt.read(buf), + ) + } + + override fun allocationSize(value: LogRecord) = ( + FfiConverterTypeLogLevel.allocationSize(value.`level`) + + FfiConverterString.allocationSize(value.`args`) + + FfiConverterString.allocationSize(value.`modulePath`) + + FfiConverterUInt.allocationSize(value.`line`) + ) + + override fun write(value: LogRecord, buf: ByteBuffer) { + FfiConverterTypeLogLevel.write(value.`level`, buf) + FfiConverterString.write(value.`args`, buf) + FfiConverterString.write(value.`modulePath`, buf) + FfiConverterUInt.write(value.`line`, buf) + } +} + + + + +object FfiConverterTypeNodeAnnouncementInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): NodeAnnouncementInfo { + return NodeAnnouncementInfo( + FfiConverterUInt.read(buf), + FfiConverterString.read(buf), + FfiConverterSequenceTypeSocketAddress.read(buf), + ) + } + + override fun allocationSize(value: NodeAnnouncementInfo) = ( + FfiConverterUInt.allocationSize(value.`lastUpdate`) + + FfiConverterString.allocationSize(value.`alias`) + + FfiConverterSequenceTypeSocketAddress.allocationSize(value.`addresses`) + ) + + override fun write(value: NodeAnnouncementInfo, buf: ByteBuffer) { + FfiConverterUInt.write(value.`lastUpdate`, buf) + FfiConverterString.write(value.`alias`, buf) + FfiConverterSequenceTypeSocketAddress.write(value.`addresses`, buf) + } +} + + + + +object FfiConverterTypeNodeInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): NodeInfo { + return NodeInfo( + FfiConverterSequenceULong.read(buf), + FfiConverterOptionalTypeNodeAnnouncementInfo.read(buf), + ) + } + + override fun allocationSize(value: NodeInfo) = ( + FfiConverterSequenceULong.allocationSize(value.`channels`) + + FfiConverterOptionalTypeNodeAnnouncementInfo.allocationSize(value.`announcementInfo`) + ) + + override fun write(value: NodeInfo, buf: ByteBuffer) { + FfiConverterSequenceULong.write(value.`channels`, buf) + FfiConverterOptionalTypeNodeAnnouncementInfo.write(value.`announcementInfo`, buf) + } +} + + + + +object FfiConverterTypeNodeStatus: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): NodeStatus { + return NodeStatus( + FfiConverterBoolean.read(buf), + FfiConverterTypeBestBlock.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalUInt.read(buf), + ) + } + + override fun allocationSize(value: NodeStatus) = ( + FfiConverterBoolean.allocationSize(value.`isRunning`) + + FfiConverterTypeBestBlock.allocationSize(value.`currentBestBlock`) + + FfiConverterOptionalULong.allocationSize(value.`latestLightningWalletSyncTimestamp`) + + FfiConverterOptionalULong.allocationSize(value.`latestOnchainWalletSyncTimestamp`) + + FfiConverterOptionalULong.allocationSize(value.`latestFeeRateCacheUpdateTimestamp`) + + FfiConverterOptionalULong.allocationSize(value.`latestRgsSnapshotTimestamp`) + + FfiConverterOptionalULong.allocationSize(value.`latestPathfindingScoresSyncTimestamp`) + + FfiConverterOptionalULong.allocationSize(value.`latestNodeAnnouncementBroadcastTimestamp`) + + FfiConverterOptionalUInt.allocationSize(value.`latestChannelMonitorArchivalHeight`) + ) + + override fun write(value: NodeStatus, buf: ByteBuffer) { + FfiConverterBoolean.write(value.`isRunning`, buf) + FfiConverterTypeBestBlock.write(value.`currentBestBlock`, buf) + FfiConverterOptionalULong.write(value.`latestLightningWalletSyncTimestamp`, buf) + FfiConverterOptionalULong.write(value.`latestOnchainWalletSyncTimestamp`, buf) + FfiConverterOptionalULong.write(value.`latestFeeRateCacheUpdateTimestamp`, buf) + FfiConverterOptionalULong.write(value.`latestRgsSnapshotTimestamp`, buf) + FfiConverterOptionalULong.write(value.`latestPathfindingScoresSyncTimestamp`, buf) + FfiConverterOptionalULong.write(value.`latestNodeAnnouncementBroadcastTimestamp`, buf) + FfiConverterOptionalUInt.write(value.`latestChannelMonitorArchivalHeight`, buf) + } +} + + + + +object FfiConverterTypeOnchainWalletAccount: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): OnchainWalletAccount { + return OnchainWalletAccount( + FfiConverterTypeAddressType.read(buf), + FfiConverterUInt.read(buf), + ) + } + + override fun allocationSize(value: OnchainWalletAccount) = ( + FfiConverterTypeAddressType.allocationSize(value.`addressType`) + + FfiConverterUInt.allocationSize(value.`accountIndex`) + ) + + override fun write(value: OnchainWalletAccount, buf: ByteBuffer) { + FfiConverterTypeAddressType.write(value.`addressType`, buf) + FfiConverterUInt.write(value.`accountIndex`, buf) + } +} + + + + +object FfiConverterTypeOnchainWalletAccountConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): OnchainWalletAccountConfig { + return OnchainWalletAccountConfig( + FfiConverterTypeAddressType.read(buf), + FfiConverterUInt.read(buf), + FfiConverterString.read(buf), + ) + } + + override fun allocationSize(value: OnchainWalletAccountConfig) = ( + FfiConverterTypeAddressType.allocationSize(value.`addressType`) + + FfiConverterUInt.allocationSize(value.`accountIndex`) + + FfiConverterString.allocationSize(value.`xpub`) + ) + + override fun write(value: OnchainWalletAccountConfig, buf: ByteBuffer) { + FfiConverterTypeAddressType.write(value.`addressType`, buf) + FfiConverterUInt.write(value.`accountIndex`, buf) + FfiConverterString.write(value.`xpub`, buf) + } +} + + + + +object FfiConverterTypeOutPoint: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): OutPoint { + return OutPoint( + FfiConverterTypeTxid.read(buf), + FfiConverterUInt.read(buf), + ) + } + + override fun allocationSize(value: OutPoint) = ( + FfiConverterTypeTxid.allocationSize(value.`txid`) + + FfiConverterUInt.allocationSize(value.`vout`) + ) + + override fun write(value: OutPoint, buf: ByteBuffer) { + FfiConverterTypeTxid.write(value.`txid`, buf) + FfiConverterUInt.write(value.`vout`, buf) + } +} + + + + +object FfiConverterTypePaymentDetails: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): PaymentDetails { + return PaymentDetails( + FfiConverterTypePaymentId.read(buf), + FfiConverterTypePaymentKind.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterTypePaymentDirection.read(buf), + FfiConverterTypePaymentStatus.read(buf), + FfiConverterULong.read(buf), + ) + } + + override fun allocationSize(value: PaymentDetails) = ( + FfiConverterTypePaymentId.allocationSize(value.`id`) + + FfiConverterTypePaymentKind.allocationSize(value.`kind`) + + FfiConverterOptionalULong.allocationSize(value.`amountMsat`) + + FfiConverterOptionalULong.allocationSize(value.`feePaidMsat`) + + FfiConverterTypePaymentDirection.allocationSize(value.`direction`) + + FfiConverterTypePaymentStatus.allocationSize(value.`status`) + + FfiConverterULong.allocationSize(value.`latestUpdateTimestamp`) + ) + + override fun write(value: PaymentDetails, buf: ByteBuffer) { + FfiConverterTypePaymentId.write(value.`id`, buf) + FfiConverterTypePaymentKind.write(value.`kind`, buf) + FfiConverterOptionalULong.write(value.`amountMsat`, buf) + FfiConverterOptionalULong.write(value.`feePaidMsat`, buf) + FfiConverterTypePaymentDirection.write(value.`direction`, buf) + FfiConverterTypePaymentStatus.write(value.`status`, buf) + FfiConverterULong.write(value.`latestUpdateTimestamp`, buf) + } +} + + + + +object FfiConverterTypePeerDetails: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): PeerDetails { + return PeerDetails( + FfiConverterTypePublicKey.read(buf), + FfiConverterTypeSocketAddress.read(buf), + FfiConverterBoolean.read(buf), + FfiConverterBoolean.read(buf), + ) + } + + override fun allocationSize(value: PeerDetails) = ( + FfiConverterTypePublicKey.allocationSize(value.`nodeId`) + + FfiConverterTypeSocketAddress.allocationSize(value.`address`) + + FfiConverterBoolean.allocationSize(value.`isPersisted`) + + FfiConverterBoolean.allocationSize(value.`isConnected`) + ) + + override fun write(value: PeerDetails, buf: ByteBuffer) { + FfiConverterTypePublicKey.write(value.`nodeId`, buf) + FfiConverterTypeSocketAddress.write(value.`address`, buf) + FfiConverterBoolean.write(value.`isPersisted`, buf) + FfiConverterBoolean.write(value.`isConnected`, buf) + } +} + + + + +object FfiConverterTypeProbeHandle: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ProbeHandle { + return ProbeHandle( + FfiConverterTypePaymentHash.read(buf), + FfiConverterTypePaymentId.read(buf), + ) + } + + override fun allocationSize(value: ProbeHandle) = ( + FfiConverterTypePaymentHash.allocationSize(value.`paymentHash`) + + FfiConverterTypePaymentId.allocationSize(value.`paymentId`) + ) + + override fun write(value: ProbeHandle, buf: ByteBuffer) { + FfiConverterTypePaymentHash.write(value.`paymentHash`, buf) + FfiConverterTypePaymentId.write(value.`paymentId`, buf) + } +} + + + + +object FfiConverterTypeRouteHintHop: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): RouteHintHop { + return RouteHintHop( + FfiConverterTypePublicKey.read(buf), + FfiConverterULong.read(buf), + FfiConverterUShort.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterTypeRoutingFees.read(buf), + ) + } + + override fun allocationSize(value: RouteHintHop) = ( + FfiConverterTypePublicKey.allocationSize(value.`srcNodeId`) + + FfiConverterULong.allocationSize(value.`shortChannelId`) + + FfiConverterUShort.allocationSize(value.`cltvExpiryDelta`) + + FfiConverterOptionalULong.allocationSize(value.`htlcMinimumMsat`) + + FfiConverterOptionalULong.allocationSize(value.`htlcMaximumMsat`) + + FfiConverterTypeRoutingFees.allocationSize(value.`fees`) + ) + + override fun write(value: RouteHintHop, buf: ByteBuffer) { + FfiConverterTypePublicKey.write(value.`srcNodeId`, buf) + FfiConverterULong.write(value.`shortChannelId`, buf) + FfiConverterUShort.write(value.`cltvExpiryDelta`, buf) + FfiConverterOptionalULong.write(value.`htlcMinimumMsat`, buf) + FfiConverterOptionalULong.write(value.`htlcMaximumMsat`, buf) + FfiConverterTypeRoutingFees.write(value.`fees`, buf) + } +} + + + + +object FfiConverterTypeRouteParametersConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): RouteParametersConfig { + return RouteParametersConfig( + FfiConverterOptionalULong.read(buf), + FfiConverterUInt.read(buf), + FfiConverterUByte.read(buf), + FfiConverterUByte.read(buf), + ) + } + + override fun allocationSize(value: RouteParametersConfig) = ( + FfiConverterOptionalULong.allocationSize(value.`maxTotalRoutingFeeMsat`) + + FfiConverterUInt.allocationSize(value.`maxTotalCltvExpiryDelta`) + + FfiConverterUByte.allocationSize(value.`maxPathCount`) + + FfiConverterUByte.allocationSize(value.`maxChannelSaturationPowerOfHalf`) + ) + + override fun write(value: RouteParametersConfig, buf: ByteBuffer) { + FfiConverterOptionalULong.write(value.`maxTotalRoutingFeeMsat`, buf) + FfiConverterUInt.write(value.`maxTotalCltvExpiryDelta`, buf) + FfiConverterUByte.write(value.`maxPathCount`, buf) + FfiConverterUByte.write(value.`maxChannelSaturationPowerOfHalf`, buf) + } +} + + + + +object FfiConverterTypeRoutingFees: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): RoutingFees { + return RoutingFees( + FfiConverterUInt.read(buf), + FfiConverterUInt.read(buf), + ) + } + + override fun allocationSize(value: RoutingFees) = ( + FfiConverterUInt.allocationSize(value.`baseMsat`) + + FfiConverterUInt.allocationSize(value.`proportionalMillionths`) + ) + + override fun write(value: RoutingFees, buf: ByteBuffer) { + FfiConverterUInt.write(value.`baseMsat`, buf) + FfiConverterUInt.write(value.`proportionalMillionths`, buf) + } +} + + + + +object FfiConverterTypeRuntimeSyncIntervals: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): RuntimeSyncIntervals { + return RuntimeSyncIntervals( + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + ) + } + + override fun allocationSize(value: RuntimeSyncIntervals) = ( + FfiConverterULong.allocationSize(value.`onchainWalletSyncIntervalSecs`) + + FfiConverterULong.allocationSize(value.`lightningWalletSyncIntervalSecs`) + + FfiConverterULong.allocationSize(value.`feeRateCacheUpdateIntervalSecs`) + ) + + override fun write(value: RuntimeSyncIntervals, buf: ByteBuffer) { + FfiConverterULong.write(value.`onchainWalletSyncIntervalSecs`, buf) + FfiConverterULong.write(value.`lightningWalletSyncIntervalSecs`, buf) + FfiConverterULong.write(value.`feeRateCacheUpdateIntervalSecs`, buf) + } +} + + + + +object FfiConverterTypeScoringDecayParameters: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ScoringDecayParameters { + return ScoringDecayParameters( + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + ) + } + + override fun allocationSize(value: ScoringDecayParameters) = ( + FfiConverterULong.allocationSize(value.`historicalNoUpdatesHalfLifeSecs`) + + FfiConverterULong.allocationSize(value.`liquidityOffsetHalfLifeSecs`) + ) + + override fun write(value: ScoringDecayParameters, buf: ByteBuffer) { + FfiConverterULong.write(value.`historicalNoUpdatesHalfLifeSecs`, buf) + FfiConverterULong.write(value.`liquidityOffsetHalfLifeSecs`, buf) + } +} + + + + +object FfiConverterTypeScoringFeeParameters: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ScoringFeeParameters { + return ScoringFeeParameters( + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterBoolean.read(buf), + FfiConverterULong.read(buf), + ) + } + + override fun allocationSize(value: ScoringFeeParameters) = ( + FfiConverterULong.allocationSize(value.`basePenaltyMsat`) + + FfiConverterULong.allocationSize(value.`basePenaltyAmountMultiplierMsat`) + + FfiConverterULong.allocationSize(value.`liquidityPenaltyMultiplierMsat`) + + FfiConverterULong.allocationSize(value.`liquidityPenaltyAmountMultiplierMsat`) + + FfiConverterULong.allocationSize(value.`historicalLiquidityPenaltyMultiplierMsat`) + + FfiConverterULong.allocationSize(value.`historicalLiquidityPenaltyAmountMultiplierMsat`) + + FfiConverterULong.allocationSize(value.`antiProbingPenaltyMsat`) + + FfiConverterULong.allocationSize(value.`consideredImpossiblePenaltyMsat`) + + FfiConverterBoolean.allocationSize(value.`linearSuccessProbability`) + + FfiConverterULong.allocationSize(value.`probingDiversityPenaltyMsat`) + ) + + override fun write(value: ScoringFeeParameters, buf: ByteBuffer) { + FfiConverterULong.write(value.`basePenaltyMsat`, buf) + FfiConverterULong.write(value.`basePenaltyAmountMultiplierMsat`, buf) + FfiConverterULong.write(value.`liquidityPenaltyMultiplierMsat`, buf) + FfiConverterULong.write(value.`liquidityPenaltyAmountMultiplierMsat`, buf) + FfiConverterULong.write(value.`historicalLiquidityPenaltyMultiplierMsat`, buf) + FfiConverterULong.write(value.`historicalLiquidityPenaltyAmountMultiplierMsat`, buf) + FfiConverterULong.write(value.`antiProbingPenaltyMsat`, buf) + FfiConverterULong.write(value.`consideredImpossiblePenaltyMsat`, buf) + FfiConverterBoolean.write(value.`linearSuccessProbability`, buf) + FfiConverterULong.write(value.`probingDiversityPenaltyMsat`, buf) + } +} + + + + +object FfiConverterTypeSpendableUtxo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): SpendableUtxo { + return SpendableUtxo( + FfiConverterTypeOutPoint.read(buf), + FfiConverterULong.read(buf), + ) + } + + override fun allocationSize(value: SpendableUtxo) = ( + FfiConverterTypeOutPoint.allocationSize(value.`outpoint`) + + FfiConverterULong.allocationSize(value.`valueSats`) + ) + + override fun write(value: SpendableUtxo, buf: ByteBuffer) { + FfiConverterTypeOutPoint.write(value.`outpoint`, buf) + FfiConverterULong.write(value.`valueSats`, buf) + } +} + + + + +object FfiConverterTypeTransactionDetails: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): TransactionDetails { + return TransactionDetails( + FfiConverterLong.read(buf), + FfiConverterSequenceTypeTxInput.read(buf), + FfiConverterSequenceTypeTxOutput.read(buf), + ) + } + + override fun allocationSize(value: TransactionDetails) = ( + FfiConverterLong.allocationSize(value.`amountSats`) + + FfiConverterSequenceTypeTxInput.allocationSize(value.`inputs`) + + FfiConverterSequenceTypeTxOutput.allocationSize(value.`outputs`) + ) + + override fun write(value: TransactionDetails, buf: ByteBuffer) { + FfiConverterLong.write(value.`amountSats`, buf) + FfiConverterSequenceTypeTxInput.write(value.`inputs`, buf) + FfiConverterSequenceTypeTxOutput.write(value.`outputs`, buf) + } +} + + + + +object FfiConverterTypeTxInput: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): TxInput { + return TxInput( + FfiConverterTypeTxid.read(buf), + FfiConverterUInt.read(buf), + FfiConverterString.read(buf), + FfiConverterSequenceString.read(buf), + FfiConverterUInt.read(buf), + ) + } + + override fun allocationSize(value: TxInput) = ( + FfiConverterTypeTxid.allocationSize(value.`txid`) + + FfiConverterUInt.allocationSize(value.`vout`) + + FfiConverterString.allocationSize(value.`scriptsig`) + + FfiConverterSequenceString.allocationSize(value.`witness`) + + FfiConverterUInt.allocationSize(value.`sequence`) + ) + + override fun write(value: TxInput, buf: ByteBuffer) { + FfiConverterTypeTxid.write(value.`txid`, buf) + FfiConverterUInt.write(value.`vout`, buf) + FfiConverterString.write(value.`scriptsig`, buf) + FfiConverterSequenceString.write(value.`witness`, buf) + FfiConverterUInt.write(value.`sequence`, buf) + } +} + + + + +object FfiConverterTypeTxOutput: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): TxOutput { + return TxOutput( + FfiConverterString.read(buf), + FfiConverterOptionalString.read(buf), + FfiConverterOptionalString.read(buf), + FfiConverterLong.read(buf), + FfiConverterUInt.read(buf), + ) + } + + override fun allocationSize(value: TxOutput) = ( + FfiConverterString.allocationSize(value.`scriptpubkey`) + + FfiConverterOptionalString.allocationSize(value.`scriptpubkeyType`) + + FfiConverterOptionalString.allocationSize(value.`scriptpubkeyAddress`) + + FfiConverterLong.allocationSize(value.`value`) + + FfiConverterUInt.allocationSize(value.`n`) + ) + + override fun write(value: TxOutput, buf: ByteBuffer) { + FfiConverterString.write(value.`scriptpubkey`, buf) + FfiConverterOptionalString.write(value.`scriptpubkeyType`, buf) + FfiConverterOptionalString.write(value.`scriptpubkeyAddress`, buf) + FfiConverterLong.write(value.`value`, buf) + FfiConverterUInt.write(value.`n`, buf) + } +} + + + + + +object FfiConverterTypeAddressType: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + AddressType.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: AddressType) = 4UL + + override fun write(value: AddressType, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + +object FfiConverterTypeAsyncPaymentsRole: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + AsyncPaymentsRole.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: AsyncPaymentsRole) = 4UL + + override fun write(value: AsyncPaymentsRole, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + +object FfiConverterTypeBalanceSource: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + BalanceSource.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: BalanceSource) = 4UL + + override fun write(value: BalanceSource, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + +object FfiConverterTypeBolt11InvoiceDescription : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): Bolt11InvoiceDescription { + return when(buf.getInt()) { + 1 -> Bolt11InvoiceDescription.Hash( + FfiConverterString.read(buf), + ) + 2 -> Bolt11InvoiceDescription.Direct( + FfiConverterString.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: Bolt11InvoiceDescription) = when(value) { + is Bolt11InvoiceDescription.Hash -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterString.allocationSize(value.`hash`) + ) + } + is Bolt11InvoiceDescription.Direct -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterString.allocationSize(value.`description`) + ) + } + } + + override fun write(value: Bolt11InvoiceDescription, buf: ByteBuffer) { + when(value) { + is Bolt11InvoiceDescription.Hash -> { + buf.putInt(1) + FfiConverterString.write(value.`hash`, buf) + Unit + } + is Bolt11InvoiceDescription.Direct -> { + buf.putInt(2) + FfiConverterString.write(value.`description`, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + +object BuildExceptionErrorHandler : UniffiRustCallStatusErrorHandler { + override fun lift(errorBuf: RustBufferByValue): BuildException = FfiConverterTypeBuildError.lift(errorBuf) +} + +object FfiConverterTypeBuildError : FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): BuildException { + return when (buf.getInt()) { + 1 -> BuildException.InvalidSeedBytes(FfiConverterString.read(buf)) + 2 -> BuildException.InvalidSeedFile(FfiConverterString.read(buf)) + 3 -> BuildException.InvalidSystemTime(FfiConverterString.read(buf)) + 4 -> BuildException.InvalidChannelMonitor(FfiConverterString.read(buf)) + 5 -> BuildException.InvalidListeningAddresses(FfiConverterString.read(buf)) + 6 -> BuildException.InvalidAnnouncementAddresses(FfiConverterString.read(buf)) + 7 -> BuildException.InvalidNodeAlias(FfiConverterString.read(buf)) + 8 -> BuildException.RuntimeSetupFailed(FfiConverterString.read(buf)) + 9 -> BuildException.ReadFailed(FfiConverterString.read(buf)) + 10 -> BuildException.DangerousValue(FfiConverterString.read(buf)) + 11 -> BuildException.WriteFailed(FfiConverterString.read(buf)) + 12 -> BuildException.StoragePathAccessFailed(FfiConverterString.read(buf)) + 13 -> BuildException.KvStoreSetupFailed(FfiConverterString.read(buf)) + 14 -> BuildException.WalletSetupFailed(FfiConverterString.read(buf)) + 15 -> BuildException.LoggerSetupFailed(FfiConverterString.read(buf)) + 16 -> BuildException.NetworkMismatch(FfiConverterString.read(buf)) + 17 -> BuildException.AsyncPaymentsConfigMismatch(FfiConverterString.read(buf)) + else -> throw RuntimeException("invalid error enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: BuildException): ULong { + return 4UL + } + + override fun write(value: BuildException, buf: ByteBuffer) { + when (value) { + is BuildException.InvalidSeedBytes -> { + buf.putInt(1) + Unit + } + is BuildException.InvalidSeedFile -> { + buf.putInt(2) + Unit + } + is BuildException.InvalidSystemTime -> { + buf.putInt(3) + Unit + } + is BuildException.InvalidChannelMonitor -> { + buf.putInt(4) + Unit + } + is BuildException.InvalidListeningAddresses -> { + buf.putInt(5) + Unit + } + is BuildException.InvalidAnnouncementAddresses -> { + buf.putInt(6) + Unit + } + is BuildException.InvalidNodeAlias -> { + buf.putInt(7) + Unit + } + is BuildException.RuntimeSetupFailed -> { + buf.putInt(8) + Unit + } + is BuildException.ReadFailed -> { + buf.putInt(9) + Unit + } + is BuildException.DangerousValue -> { + buf.putInt(10) + Unit + } + is BuildException.WriteFailed -> { + buf.putInt(11) + Unit + } + is BuildException.StoragePathAccessFailed -> { + buf.putInt(12) + Unit + } + is BuildException.KvStoreSetupFailed -> { + buf.putInt(13) + Unit + } + is BuildException.WalletSetupFailed -> { + buf.putInt(14) + Unit + } + is BuildException.LoggerSetupFailed -> { + buf.putInt(15) + Unit + } + is BuildException.NetworkMismatch -> { + buf.putInt(16) + Unit + } + is BuildException.AsyncPaymentsConfigMismatch -> { + buf.putInt(17) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + +object FfiConverterTypeClosureReason : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): ClosureReason { + return when(buf.getInt()) { + 1 -> ClosureReason.CounterpartyForceClosed( + FfiConverterTypeUntrustedString.read(buf), + ) + 2 -> ClosureReason.HolderForceClosed( + FfiConverterOptionalBoolean.read(buf), + FfiConverterString.read(buf), + ) + 3 -> ClosureReason.LegacyCooperativeClosure + 4 -> ClosureReason.CounterpartyInitiatedCooperativeClosure + 5 -> ClosureReason.LocallyInitiatedCooperativeClosure + 6 -> ClosureReason.CommitmentTxConfirmed + 7 -> ClosureReason.FundingTimedOut + 8 -> ClosureReason.ProcessingError( + FfiConverterString.read(buf), + ) + 9 -> ClosureReason.DisconnectedPeer + 10 -> ClosureReason.OutdatedChannelManager + 11 -> ClosureReason.CounterpartyCoopClosedUnfundedChannel + 12 -> ClosureReason.LocallyCoopClosedUnfundedChannel + 13 -> ClosureReason.FundingBatchClosure + 14 -> ClosureReason.HtlCsTimedOut( + FfiConverterOptionalTypePaymentHash.read(buf), + ) + 15 -> ClosureReason.PeerFeerateTooLow( + FfiConverterUInt.read(buf), + FfiConverterUInt.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: ClosureReason) = when(value) { + is ClosureReason.CounterpartyForceClosed -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeUntrustedString.allocationSize(value.`peerMsg`) + ) + } + is ClosureReason.HolderForceClosed -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterOptionalBoolean.allocationSize(value.`broadcastedLatestTxn`) + + FfiConverterString.allocationSize(value.`message`) + ) + } + is ClosureReason.LegacyCooperativeClosure -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is ClosureReason.CounterpartyInitiatedCooperativeClosure -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is ClosureReason.LocallyInitiatedCooperativeClosure -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is ClosureReason.CommitmentTxConfirmed -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is ClosureReason.FundingTimedOut -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is ClosureReason.ProcessingError -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterString.allocationSize(value.`err`) + ) + } + is ClosureReason.DisconnectedPeer -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is ClosureReason.OutdatedChannelManager -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is ClosureReason.CounterpartyCoopClosedUnfundedChannel -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is ClosureReason.LocallyCoopClosedUnfundedChannel -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is ClosureReason.FundingBatchClosure -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is ClosureReason.HtlCsTimedOut -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterOptionalTypePaymentHash.allocationSize(value.`paymentHash`) + ) + } + is ClosureReason.PeerFeerateTooLow -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterUInt.allocationSize(value.`peerFeerateSatPerKw`) + + FfiConverterUInt.allocationSize(value.`requiredFeerateSatPerKw`) + ) + } + } + + override fun write(value: ClosureReason, buf: ByteBuffer) { + when(value) { + is ClosureReason.CounterpartyForceClosed -> { + buf.putInt(1) + FfiConverterTypeUntrustedString.write(value.`peerMsg`, buf) + Unit + } + is ClosureReason.HolderForceClosed -> { + buf.putInt(2) + FfiConverterOptionalBoolean.write(value.`broadcastedLatestTxn`, buf) + FfiConverterString.write(value.`message`, buf) + Unit + } + is ClosureReason.LegacyCooperativeClosure -> { + buf.putInt(3) + Unit + } + is ClosureReason.CounterpartyInitiatedCooperativeClosure -> { + buf.putInt(4) + Unit + } + is ClosureReason.LocallyInitiatedCooperativeClosure -> { + buf.putInt(5) + Unit + } + is ClosureReason.CommitmentTxConfirmed -> { + buf.putInt(6) + Unit + } + is ClosureReason.FundingTimedOut -> { + buf.putInt(7) + Unit + } + is ClosureReason.ProcessingError -> { + buf.putInt(8) + FfiConverterString.write(value.`err`, buf) + Unit + } + is ClosureReason.DisconnectedPeer -> { + buf.putInt(9) + Unit + } + is ClosureReason.OutdatedChannelManager -> { + buf.putInt(10) + Unit + } + is ClosureReason.CounterpartyCoopClosedUnfundedChannel -> { + buf.putInt(11) + Unit + } + is ClosureReason.LocallyCoopClosedUnfundedChannel -> { + buf.putInt(12) + Unit + } + is ClosureReason.FundingBatchClosure -> { + buf.putInt(13) + Unit + } + is ClosureReason.HtlCsTimedOut -> { + buf.putInt(14) + FfiConverterOptionalTypePaymentHash.write(value.`paymentHash`, buf) + Unit + } + is ClosureReason.PeerFeerateTooLow -> { + buf.putInt(15) + FfiConverterUInt.write(value.`peerFeerateSatPerKw`, buf) + FfiConverterUInt.write(value.`requiredFeerateSatPerKw`, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + +object FfiConverterTypeCoinSelectionAlgorithm: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + CoinSelectionAlgorithm.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: CoinSelectionAlgorithm) = 4UL + + override fun write(value: CoinSelectionAlgorithm, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + +object FfiConverterTypeConfirmationStatus : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): ConfirmationStatus { + return when(buf.getInt()) { + 1 -> ConfirmationStatus.Confirmed( + FfiConverterTypeBlockHash.read(buf), + FfiConverterUInt.read(buf), + FfiConverterULong.read(buf), + ) + 2 -> ConfirmationStatus.Unconfirmed + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: ConfirmationStatus) = when(value) { + is ConfirmationStatus.Confirmed -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeBlockHash.allocationSize(value.`blockHash`) + + FfiConverterUInt.allocationSize(value.`height`) + + FfiConverterULong.allocationSize(value.`timestamp`) + ) + } + is ConfirmationStatus.Unconfirmed -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + } + + override fun write(value: ConfirmationStatus, buf: ByteBuffer) { + when(value) { + is ConfirmationStatus.Confirmed -> { + buf.putInt(1) + FfiConverterTypeBlockHash.write(value.`blockHash`, buf) + FfiConverterUInt.write(value.`height`, buf) + FfiConverterULong.write(value.`timestamp`, buf) + Unit + } + is ConfirmationStatus.Unconfirmed -> { + buf.putInt(2) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + +object FfiConverterTypeCurrency: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + Currency.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: Currency) = 4UL + + override fun write(value: Currency, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + +object FfiConverterTypeEvent : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): Event { + return when(buf.getInt()) { + 1 -> Event.PaymentSuccessful( + FfiConverterOptionalTypePaymentId.read(buf), + FfiConverterTypePaymentHash.read(buf), + FfiConverterOptionalTypePaymentPreimage.read(buf), + FfiConverterOptionalULong.read(buf), + ) + 2 -> Event.PaymentFailed( + FfiConverterOptionalTypePaymentId.read(buf), + FfiConverterOptionalTypePaymentHash.read(buf), + FfiConverterOptionalTypePaymentFailureReason.read(buf), + ) + 3 -> Event.PaymentReceived( + FfiConverterOptionalTypePaymentId.read(buf), + FfiConverterTypePaymentHash.read(buf), + FfiConverterULong.read(buf), + FfiConverterSequenceTypeCustomTlvRecord.read(buf), + ) + 4 -> Event.PaymentClaimable( + FfiConverterTypePaymentId.read(buf), + FfiConverterTypePaymentHash.read(buf), + FfiConverterULong.read(buf), + FfiConverterOptionalUInt.read(buf), + FfiConverterSequenceTypeCustomTlvRecord.read(buf), + ) + 5 -> Event.PaymentForwarded( + FfiConverterTypeChannelId.read(buf), + FfiConverterTypeChannelId.read(buf), + FfiConverterOptionalTypeUserChannelId.read(buf), + FfiConverterOptionalTypeUserChannelId.read(buf), + FfiConverterOptionalTypePublicKey.read(buf), + FfiConverterOptionalTypePublicKey.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterBoolean.read(buf), + FfiConverterOptionalULong.read(buf), + ) + 6 -> Event.ProbeSuccessful( + FfiConverterTypePaymentId.read(buf), + FfiConverterTypePaymentHash.read(buf), + FfiConverterOptionalULong.read(buf), + ) + 7 -> Event.ProbeFailed( + FfiConverterTypePaymentId.read(buf), + FfiConverterTypePaymentHash.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalULong.read(buf), + ) + 8 -> Event.ChannelPending( + FfiConverterTypeChannelId.read(buf), + FfiConverterTypeUserChannelId.read(buf), + FfiConverterTypeChannelId.read(buf), + FfiConverterTypePublicKey.read(buf), + FfiConverterTypeOutPoint.read(buf), + ) + 9 -> Event.ChannelReady( + FfiConverterTypeChannelId.read(buf), + FfiConverterTypeUserChannelId.read(buf), + FfiConverterOptionalTypePublicKey.read(buf), + FfiConverterOptionalTypeOutPoint.read(buf), + ) + 10 -> Event.ChannelClosed( + FfiConverterTypeChannelId.read(buf), + FfiConverterTypeUserChannelId.read(buf), + FfiConverterOptionalTypePublicKey.read(buf), + FfiConverterOptionalTypeClosureReason.read(buf), + ) + 11 -> Event.SplicePending( + FfiConverterTypeChannelId.read(buf), + FfiConverterTypeUserChannelId.read(buf), + FfiConverterTypePublicKey.read(buf), + FfiConverterTypeOutPoint.read(buf), + ) + 12 -> Event.SpliceFailed( + FfiConverterTypeChannelId.read(buf), + FfiConverterTypeUserChannelId.read(buf), + FfiConverterTypePublicKey.read(buf), + FfiConverterOptionalTypeOutPoint.read(buf), + ) + 13 -> Event.OnchainTransactionConfirmed( + FfiConverterTypeTxid.read(buf), + FfiConverterTypeBlockHash.read(buf), + FfiConverterUInt.read(buf), + FfiConverterULong.read(buf), + FfiConverterTypeTransactionDetails.read(buf), + ) + 14 -> Event.OnchainTransactionReceived( + FfiConverterTypeTxid.read(buf), + FfiConverterTypeTransactionDetails.read(buf), + ) + 15 -> Event.OnchainTransactionReplaced( + FfiConverterTypeTxid.read(buf), + FfiConverterSequenceTypeTxid.read(buf), + ) + 16 -> Event.OnchainTransactionReorged( + FfiConverterTypeTxid.read(buf), + ) + 17 -> Event.OnchainTransactionEvicted( + FfiConverterTypeTxid.read(buf), + ) + 18 -> Event.SyncProgress( + FfiConverterTypeSyncType.read(buf), + FfiConverterUByte.read(buf), + FfiConverterUInt.read(buf), + FfiConverterUInt.read(buf), + ) + 19 -> Event.SyncCompleted( + FfiConverterTypeSyncType.read(buf), + FfiConverterUInt.read(buf), + ) + 20 -> Event.BalanceChanged( + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: Event) = when(value) { + is Event.PaymentSuccessful -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterOptionalTypePaymentId.allocationSize(value.`paymentId`) + + FfiConverterTypePaymentHash.allocationSize(value.`paymentHash`) + + FfiConverterOptionalTypePaymentPreimage.allocationSize(value.`paymentPreimage`) + + FfiConverterOptionalULong.allocationSize(value.`feePaidMsat`) + ) + } + is Event.PaymentFailed -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterOptionalTypePaymentId.allocationSize(value.`paymentId`) + + FfiConverterOptionalTypePaymentHash.allocationSize(value.`paymentHash`) + + FfiConverterOptionalTypePaymentFailureReason.allocationSize(value.`reason`) + ) + } + is Event.PaymentReceived -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterOptionalTypePaymentId.allocationSize(value.`paymentId`) + + FfiConverterTypePaymentHash.allocationSize(value.`paymentHash`) + + FfiConverterULong.allocationSize(value.`amountMsat`) + + FfiConverterSequenceTypeCustomTlvRecord.allocationSize(value.`customRecords`) + ) + } + is Event.PaymentClaimable -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypePaymentId.allocationSize(value.`paymentId`) + + FfiConverterTypePaymentHash.allocationSize(value.`paymentHash`) + + FfiConverterULong.allocationSize(value.`claimableAmountMsat`) + + FfiConverterOptionalUInt.allocationSize(value.`claimDeadline`) + + FfiConverterSequenceTypeCustomTlvRecord.allocationSize(value.`customRecords`) + ) + } + is Event.PaymentForwarded -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeChannelId.allocationSize(value.`prevChannelId`) + + FfiConverterTypeChannelId.allocationSize(value.`nextChannelId`) + + FfiConverterOptionalTypeUserChannelId.allocationSize(value.`prevUserChannelId`) + + FfiConverterOptionalTypeUserChannelId.allocationSize(value.`nextUserChannelId`) + + FfiConverterOptionalTypePublicKey.allocationSize(value.`prevNodeId`) + + FfiConverterOptionalTypePublicKey.allocationSize(value.`nextNodeId`) + + FfiConverterOptionalULong.allocationSize(value.`totalFeeEarnedMsat`) + + FfiConverterOptionalULong.allocationSize(value.`skimmedFeeMsat`) + + FfiConverterBoolean.allocationSize(value.`claimFromOnchainTx`) + + FfiConverterOptionalULong.allocationSize(value.`outboundAmountForwardedMsat`) + ) + } + is Event.ProbeSuccessful -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypePaymentId.allocationSize(value.`paymentId`) + + FfiConverterTypePaymentHash.allocationSize(value.`paymentHash`) + + FfiConverterOptionalULong.allocationSize(value.`routeFeeMsat`) + ) + } + is Event.ProbeFailed -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypePaymentId.allocationSize(value.`paymentId`) + + FfiConverterTypePaymentHash.allocationSize(value.`paymentHash`) + + FfiConverterOptionalULong.allocationSize(value.`shortChannelId`) + + FfiConverterOptionalULong.allocationSize(value.`routeFeeMsat`) + ) + } + is Event.ChannelPending -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterTypeUserChannelId.allocationSize(value.`userChannelId`) + + FfiConverterTypeChannelId.allocationSize(value.`formerTemporaryChannelId`) + + FfiConverterTypePublicKey.allocationSize(value.`counterpartyNodeId`) + + FfiConverterTypeOutPoint.allocationSize(value.`fundingTxo`) + ) + } + is Event.ChannelReady -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterTypeUserChannelId.allocationSize(value.`userChannelId`) + + FfiConverterOptionalTypePublicKey.allocationSize(value.`counterpartyNodeId`) + + FfiConverterOptionalTypeOutPoint.allocationSize(value.`fundingTxo`) + ) + } + is Event.ChannelClosed -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterTypeUserChannelId.allocationSize(value.`userChannelId`) + + FfiConverterOptionalTypePublicKey.allocationSize(value.`counterpartyNodeId`) + + FfiConverterOptionalTypeClosureReason.allocationSize(value.`reason`) + ) + } + is Event.SplicePending -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterTypeUserChannelId.allocationSize(value.`userChannelId`) + + FfiConverterTypePublicKey.allocationSize(value.`counterpartyNodeId`) + + FfiConverterTypeOutPoint.allocationSize(value.`newFundingTxo`) + ) + } + is Event.SpliceFailed -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterTypeUserChannelId.allocationSize(value.`userChannelId`) + + FfiConverterTypePublicKey.allocationSize(value.`counterpartyNodeId`) + + FfiConverterOptionalTypeOutPoint.allocationSize(value.`abandonedFundingTxo`) + ) + } + is Event.OnchainTransactionConfirmed -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeTxid.allocationSize(value.`txid`) + + FfiConverterTypeBlockHash.allocationSize(value.`blockHash`) + + FfiConverterUInt.allocationSize(value.`blockHeight`) + + FfiConverterULong.allocationSize(value.`confirmationTime`) + + FfiConverterTypeTransactionDetails.allocationSize(value.`details`) + ) + } + is Event.OnchainTransactionReceived -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeTxid.allocationSize(value.`txid`) + + FfiConverterTypeTransactionDetails.allocationSize(value.`details`) + ) + } + is Event.OnchainTransactionReplaced -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeTxid.allocationSize(value.`txid`) + + FfiConverterSequenceTypeTxid.allocationSize(value.`conflicts`) + ) + } + is Event.OnchainTransactionReorged -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeTxid.allocationSize(value.`txid`) + ) + } + is Event.OnchainTransactionEvicted -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeTxid.allocationSize(value.`txid`) + ) + } + is Event.SyncProgress -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeSyncType.allocationSize(value.`syncType`) + + FfiConverterUByte.allocationSize(value.`progressPercent`) + + FfiConverterUInt.allocationSize(value.`currentBlockHeight`) + + FfiConverterUInt.allocationSize(value.`targetBlockHeight`) + ) + } + is Event.SyncCompleted -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeSyncType.allocationSize(value.`syncType`) + + FfiConverterUInt.allocationSize(value.`syncedBlockHeight`) + ) + } + is Event.BalanceChanged -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterULong.allocationSize(value.`oldSpendableOnchainBalanceSats`) + + FfiConverterULong.allocationSize(value.`newSpendableOnchainBalanceSats`) + + FfiConverterULong.allocationSize(value.`oldTotalOnchainBalanceSats`) + + FfiConverterULong.allocationSize(value.`newTotalOnchainBalanceSats`) + + FfiConverterULong.allocationSize(value.`oldTotalLightningBalanceSats`) + + FfiConverterULong.allocationSize(value.`newTotalLightningBalanceSats`) + ) + } + } + + override fun write(value: Event, buf: ByteBuffer) { + when(value) { + is Event.PaymentSuccessful -> { + buf.putInt(1) + FfiConverterOptionalTypePaymentId.write(value.`paymentId`, buf) + FfiConverterTypePaymentHash.write(value.`paymentHash`, buf) + FfiConverterOptionalTypePaymentPreimage.write(value.`paymentPreimage`, buf) + FfiConverterOptionalULong.write(value.`feePaidMsat`, buf) + Unit + } + is Event.PaymentFailed -> { + buf.putInt(2) + FfiConverterOptionalTypePaymentId.write(value.`paymentId`, buf) + FfiConverterOptionalTypePaymentHash.write(value.`paymentHash`, buf) + FfiConverterOptionalTypePaymentFailureReason.write(value.`reason`, buf) + Unit + } + is Event.PaymentReceived -> { + buf.putInt(3) + FfiConverterOptionalTypePaymentId.write(value.`paymentId`, buf) + FfiConverterTypePaymentHash.write(value.`paymentHash`, buf) + FfiConverterULong.write(value.`amountMsat`, buf) + FfiConverterSequenceTypeCustomTlvRecord.write(value.`customRecords`, buf) + Unit + } + is Event.PaymentClaimable -> { + buf.putInt(4) + FfiConverterTypePaymentId.write(value.`paymentId`, buf) + FfiConverterTypePaymentHash.write(value.`paymentHash`, buf) + FfiConverterULong.write(value.`claimableAmountMsat`, buf) + FfiConverterOptionalUInt.write(value.`claimDeadline`, buf) + FfiConverterSequenceTypeCustomTlvRecord.write(value.`customRecords`, buf) + Unit + } + is Event.PaymentForwarded -> { + buf.putInt(5) + FfiConverterTypeChannelId.write(value.`prevChannelId`, buf) + FfiConverterTypeChannelId.write(value.`nextChannelId`, buf) + FfiConverterOptionalTypeUserChannelId.write(value.`prevUserChannelId`, buf) + FfiConverterOptionalTypeUserChannelId.write(value.`nextUserChannelId`, buf) + FfiConverterOptionalTypePublicKey.write(value.`prevNodeId`, buf) + FfiConverterOptionalTypePublicKey.write(value.`nextNodeId`, buf) + FfiConverterOptionalULong.write(value.`totalFeeEarnedMsat`, buf) + FfiConverterOptionalULong.write(value.`skimmedFeeMsat`, buf) + FfiConverterBoolean.write(value.`claimFromOnchainTx`, buf) + FfiConverterOptionalULong.write(value.`outboundAmountForwardedMsat`, buf) + Unit + } + is Event.ProbeSuccessful -> { + buf.putInt(6) + FfiConverterTypePaymentId.write(value.`paymentId`, buf) + FfiConverterTypePaymentHash.write(value.`paymentHash`, buf) + FfiConverterOptionalULong.write(value.`routeFeeMsat`, buf) + Unit + } + is Event.ProbeFailed -> { + buf.putInt(7) + FfiConverterTypePaymentId.write(value.`paymentId`, buf) + FfiConverterTypePaymentHash.write(value.`paymentHash`, buf) + FfiConverterOptionalULong.write(value.`shortChannelId`, buf) + FfiConverterOptionalULong.write(value.`routeFeeMsat`, buf) + Unit + } + is Event.ChannelPending -> { + buf.putInt(8) + FfiConverterTypeChannelId.write(value.`channelId`, buf) + FfiConverterTypeUserChannelId.write(value.`userChannelId`, buf) + FfiConverterTypeChannelId.write(value.`formerTemporaryChannelId`, buf) + FfiConverterTypePublicKey.write(value.`counterpartyNodeId`, buf) + FfiConverterTypeOutPoint.write(value.`fundingTxo`, buf) + Unit + } + is Event.ChannelReady -> { + buf.putInt(9) + FfiConverterTypeChannelId.write(value.`channelId`, buf) + FfiConverterTypeUserChannelId.write(value.`userChannelId`, buf) + FfiConverterOptionalTypePublicKey.write(value.`counterpartyNodeId`, buf) + FfiConverterOptionalTypeOutPoint.write(value.`fundingTxo`, buf) + Unit + } + is Event.ChannelClosed -> { + buf.putInt(10) + FfiConverterTypeChannelId.write(value.`channelId`, buf) + FfiConverterTypeUserChannelId.write(value.`userChannelId`, buf) + FfiConverterOptionalTypePublicKey.write(value.`counterpartyNodeId`, buf) + FfiConverterOptionalTypeClosureReason.write(value.`reason`, buf) + Unit + } + is Event.SplicePending -> { + buf.putInt(11) + FfiConverterTypeChannelId.write(value.`channelId`, buf) + FfiConverterTypeUserChannelId.write(value.`userChannelId`, buf) + FfiConverterTypePublicKey.write(value.`counterpartyNodeId`, buf) + FfiConverterTypeOutPoint.write(value.`newFundingTxo`, buf) + Unit + } + is Event.SpliceFailed -> { + buf.putInt(12) + FfiConverterTypeChannelId.write(value.`channelId`, buf) + FfiConverterTypeUserChannelId.write(value.`userChannelId`, buf) + FfiConverterTypePublicKey.write(value.`counterpartyNodeId`, buf) + FfiConverterOptionalTypeOutPoint.write(value.`abandonedFundingTxo`, buf) + Unit + } + is Event.OnchainTransactionConfirmed -> { + buf.putInt(13) + FfiConverterTypeTxid.write(value.`txid`, buf) + FfiConverterTypeBlockHash.write(value.`blockHash`, buf) + FfiConverterUInt.write(value.`blockHeight`, buf) + FfiConverterULong.write(value.`confirmationTime`, buf) + FfiConverterTypeTransactionDetails.write(value.`details`, buf) + Unit + } + is Event.OnchainTransactionReceived -> { + buf.putInt(14) + FfiConverterTypeTxid.write(value.`txid`, buf) + FfiConverterTypeTransactionDetails.write(value.`details`, buf) + Unit + } + is Event.OnchainTransactionReplaced -> { + buf.putInt(15) + FfiConverterTypeTxid.write(value.`txid`, buf) + FfiConverterSequenceTypeTxid.write(value.`conflicts`, buf) + Unit + } + is Event.OnchainTransactionReorged -> { + buf.putInt(16) + FfiConverterTypeTxid.write(value.`txid`, buf) + Unit + } + is Event.OnchainTransactionEvicted -> { + buf.putInt(17) + FfiConverterTypeTxid.write(value.`txid`, buf) + Unit + } + is Event.SyncProgress -> { + buf.putInt(18) + FfiConverterTypeSyncType.write(value.`syncType`, buf) + FfiConverterUByte.write(value.`progressPercent`, buf) + FfiConverterUInt.write(value.`currentBlockHeight`, buf) + FfiConverterUInt.write(value.`targetBlockHeight`, buf) + Unit + } + is Event.SyncCompleted -> { + buf.putInt(19) + FfiConverterTypeSyncType.write(value.`syncType`, buf) + FfiConverterUInt.write(value.`syncedBlockHeight`, buf) + Unit + } + is Event.BalanceChanged -> { + buf.putInt(20) + FfiConverterULong.write(value.`oldSpendableOnchainBalanceSats`, buf) + FfiConverterULong.write(value.`newSpendableOnchainBalanceSats`, buf) + FfiConverterULong.write(value.`oldTotalOnchainBalanceSats`, buf) + FfiConverterULong.write(value.`newTotalOnchainBalanceSats`, buf) + FfiConverterULong.write(value.`oldTotalLightningBalanceSats`, buf) + FfiConverterULong.write(value.`newTotalLightningBalanceSats`, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + +object FfiConverterTypeKeychainKind: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + KeychainKind.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: KeychainKind) = 4UL + + override fun write(value: KeychainKind, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + +object FfiConverterTypeLSPS1PaymentState: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + Lsps1PaymentState.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: Lsps1PaymentState) = 4UL + + override fun write(value: Lsps1PaymentState, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + +object FfiConverterTypeLightningBalance : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): LightningBalance { + return when(buf.getInt()) { + 1 -> LightningBalance.ClaimableOnChannelClose( + FfiConverterTypeChannelId.read(buf), + FfiConverterTypePublicKey.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + ) + 2 -> LightningBalance.ClaimableAwaitingConfirmations( + FfiConverterTypeChannelId.read(buf), + FfiConverterTypePublicKey.read(buf), + FfiConverterULong.read(buf), + FfiConverterUInt.read(buf), + FfiConverterTypeBalanceSource.read(buf), + ) + 3 -> LightningBalance.ContentiousClaimable( + FfiConverterTypeChannelId.read(buf), + FfiConverterTypePublicKey.read(buf), + FfiConverterULong.read(buf), + FfiConverterUInt.read(buf), + FfiConverterTypePaymentHash.read(buf), + FfiConverterTypePaymentPreimage.read(buf), + ) + 4 -> LightningBalance.MaybeTimeoutClaimableHtlc( + FfiConverterTypeChannelId.read(buf), + FfiConverterTypePublicKey.read(buf), + FfiConverterULong.read(buf), + FfiConverterUInt.read(buf), + FfiConverterTypePaymentHash.read(buf), + FfiConverterBoolean.read(buf), + ) + 5 -> LightningBalance.MaybePreimageClaimableHtlc( + FfiConverterTypeChannelId.read(buf), + FfiConverterTypePublicKey.read(buf), + FfiConverterULong.read(buf), + FfiConverterUInt.read(buf), + FfiConverterTypePaymentHash.read(buf), + ) + 6 -> LightningBalance.CounterpartyRevokedOutputClaimable( + FfiConverterTypeChannelId.read(buf), + FfiConverterTypePublicKey.read(buf), + FfiConverterULong.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: LightningBalance) = when(value) { + is LightningBalance.ClaimableOnChannelClose -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterTypePublicKey.allocationSize(value.`counterpartyNodeId`) + + FfiConverterULong.allocationSize(value.`amountSatoshis`) + + FfiConverterULong.allocationSize(value.`transactionFeeSatoshis`) + + FfiConverterULong.allocationSize(value.`outboundPaymentHtlcRoundedMsat`) + + FfiConverterULong.allocationSize(value.`outboundForwardedHtlcRoundedMsat`) + + FfiConverterULong.allocationSize(value.`inboundClaimingHtlcRoundedMsat`) + + FfiConverterULong.allocationSize(value.`inboundHtlcRoundedMsat`) + ) + } + is LightningBalance.ClaimableAwaitingConfirmations -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterTypePublicKey.allocationSize(value.`counterpartyNodeId`) + + FfiConverterULong.allocationSize(value.`amountSatoshis`) + + FfiConverterUInt.allocationSize(value.`confirmationHeight`) + + FfiConverterTypeBalanceSource.allocationSize(value.`source`) + ) + } + is LightningBalance.ContentiousClaimable -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterTypePublicKey.allocationSize(value.`counterpartyNodeId`) + + FfiConverterULong.allocationSize(value.`amountSatoshis`) + + FfiConverterUInt.allocationSize(value.`timeoutHeight`) + + FfiConverterTypePaymentHash.allocationSize(value.`paymentHash`) + + FfiConverterTypePaymentPreimage.allocationSize(value.`paymentPreimage`) + ) + } + is LightningBalance.MaybeTimeoutClaimableHtlc -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterTypePublicKey.allocationSize(value.`counterpartyNodeId`) + + FfiConverterULong.allocationSize(value.`amountSatoshis`) + + FfiConverterUInt.allocationSize(value.`claimableHeight`) + + FfiConverterTypePaymentHash.allocationSize(value.`paymentHash`) + + FfiConverterBoolean.allocationSize(value.`outboundPayment`) + ) + } + is LightningBalance.MaybePreimageClaimableHtlc -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterTypePublicKey.allocationSize(value.`counterpartyNodeId`) + + FfiConverterULong.allocationSize(value.`amountSatoshis`) + + FfiConverterUInt.allocationSize(value.`expiryHeight`) + + FfiConverterTypePaymentHash.allocationSize(value.`paymentHash`) + ) + } + is LightningBalance.CounterpartyRevokedOutputClaimable -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterTypePublicKey.allocationSize(value.`counterpartyNodeId`) + + FfiConverterULong.allocationSize(value.`amountSatoshis`) + ) + } + } + + override fun write(value: LightningBalance, buf: ByteBuffer) { + when(value) { + is LightningBalance.ClaimableOnChannelClose -> { + buf.putInt(1) + FfiConverterTypeChannelId.write(value.`channelId`, buf) + FfiConverterTypePublicKey.write(value.`counterpartyNodeId`, buf) + FfiConverterULong.write(value.`amountSatoshis`, buf) + FfiConverterULong.write(value.`transactionFeeSatoshis`, buf) + FfiConverterULong.write(value.`outboundPaymentHtlcRoundedMsat`, buf) + FfiConverterULong.write(value.`outboundForwardedHtlcRoundedMsat`, buf) + FfiConverterULong.write(value.`inboundClaimingHtlcRoundedMsat`, buf) + FfiConverterULong.write(value.`inboundHtlcRoundedMsat`, buf) + Unit + } + is LightningBalance.ClaimableAwaitingConfirmations -> { + buf.putInt(2) + FfiConverterTypeChannelId.write(value.`channelId`, buf) + FfiConverterTypePublicKey.write(value.`counterpartyNodeId`, buf) + FfiConverterULong.write(value.`amountSatoshis`, buf) + FfiConverterUInt.write(value.`confirmationHeight`, buf) + FfiConverterTypeBalanceSource.write(value.`source`, buf) + Unit + } + is LightningBalance.ContentiousClaimable -> { + buf.putInt(3) + FfiConverterTypeChannelId.write(value.`channelId`, buf) + FfiConverterTypePublicKey.write(value.`counterpartyNodeId`, buf) + FfiConverterULong.write(value.`amountSatoshis`, buf) + FfiConverterUInt.write(value.`timeoutHeight`, buf) + FfiConverterTypePaymentHash.write(value.`paymentHash`, buf) + FfiConverterTypePaymentPreimage.write(value.`paymentPreimage`, buf) + Unit + } + is LightningBalance.MaybeTimeoutClaimableHtlc -> { + buf.putInt(4) + FfiConverterTypeChannelId.write(value.`channelId`, buf) + FfiConverterTypePublicKey.write(value.`counterpartyNodeId`, buf) + FfiConverterULong.write(value.`amountSatoshis`, buf) + FfiConverterUInt.write(value.`claimableHeight`, buf) + FfiConverterTypePaymentHash.write(value.`paymentHash`, buf) + FfiConverterBoolean.write(value.`outboundPayment`, buf) + Unit + } + is LightningBalance.MaybePreimageClaimableHtlc -> { + buf.putInt(5) + FfiConverterTypeChannelId.write(value.`channelId`, buf) + FfiConverterTypePublicKey.write(value.`counterpartyNodeId`, buf) + FfiConverterULong.write(value.`amountSatoshis`, buf) + FfiConverterUInt.write(value.`expiryHeight`, buf) + FfiConverterTypePaymentHash.write(value.`paymentHash`, buf) + Unit + } + is LightningBalance.CounterpartyRevokedOutputClaimable -> { + buf.putInt(6) + FfiConverterTypeChannelId.write(value.`channelId`, buf) + FfiConverterTypePublicKey.write(value.`counterpartyNodeId`, buf) + FfiConverterULong.write(value.`amountSatoshis`, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + +object FfiConverterTypeLogLevel: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + LogLevel.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: LogLevel) = 4UL + + override fun write(value: LogLevel, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + +object FfiConverterTypeMaxDustHTLCExposure : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): MaxDustHtlcExposure { + return when(buf.getInt()) { + 1 -> MaxDustHtlcExposure.FixedLimit( + FfiConverterULong.read(buf), + ) + 2 -> MaxDustHtlcExposure.FeeRateMultiplier( + FfiConverterULong.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: MaxDustHtlcExposure) = when(value) { + is MaxDustHtlcExposure.FixedLimit -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterULong.allocationSize(value.`limitMsat`) + ) + } + is MaxDustHtlcExposure.FeeRateMultiplier -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterULong.allocationSize(value.`multiplier`) + ) + } + } + + override fun write(value: MaxDustHtlcExposure, buf: ByteBuffer) { + when(value) { + is MaxDustHtlcExposure.FixedLimit -> { + buf.putInt(1) + FfiConverterULong.write(value.`limitMsat`, buf) + Unit + } + is MaxDustHtlcExposure.FeeRateMultiplier -> { + buf.putInt(2) + FfiConverterULong.write(value.`multiplier`, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + +object FfiConverterTypeNetwork: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + Network.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: Network) = 4UL + + override fun write(value: Network, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + +object NodeExceptionErrorHandler : UniffiRustCallStatusErrorHandler { + override fun lift(errorBuf: RustBufferByValue): NodeException = FfiConverterTypeNodeError.lift(errorBuf) +} + +object FfiConverterTypeNodeError : FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): NodeException { + return when (buf.getInt()) { + 1 -> NodeException.AlreadyRunning(FfiConverterString.read(buf)) + 2 -> NodeException.NotRunning(FfiConverterString.read(buf)) + 3 -> NodeException.OnchainTxCreationFailed(FfiConverterString.read(buf)) + 4 -> NodeException.ConnectionFailed(FfiConverterString.read(buf)) + 5 -> NodeException.InvoiceCreationFailed(FfiConverterString.read(buf)) + 6 -> NodeException.InvoiceRequestCreationFailed(FfiConverterString.read(buf)) + 7 -> NodeException.OfferCreationFailed(FfiConverterString.read(buf)) + 8 -> NodeException.RefundCreationFailed(FfiConverterString.read(buf)) + 9 -> NodeException.PaymentSendingFailed(FfiConverterString.read(buf)) + 10 -> NodeException.InvalidCustomTlvs(FfiConverterString.read(buf)) + 11 -> NodeException.ProbeSendingFailed(FfiConverterString.read(buf)) + 12 -> NodeException.RouteNotFound(FfiConverterString.read(buf)) + 13 -> NodeException.ChannelCreationFailed(FfiConverterString.read(buf)) + 14 -> NodeException.ChannelClosingFailed(FfiConverterString.read(buf)) + 15 -> NodeException.ChannelSplicingFailed(FfiConverterString.read(buf)) + 16 -> NodeException.ChannelConfigUpdateFailed(FfiConverterString.read(buf)) + 17 -> NodeException.PersistenceFailed(FfiConverterString.read(buf)) + 18 -> NodeException.FeerateEstimationUpdateFailed(FfiConverterString.read(buf)) + 19 -> NodeException.FeerateEstimationUpdateTimeout(FfiConverterString.read(buf)) + 20 -> NodeException.WalletOperationFailed(FfiConverterString.read(buf)) + 21 -> NodeException.WalletOperationTimeout(FfiConverterString.read(buf)) + 22 -> NodeException.OnchainTxSigningFailed(FfiConverterString.read(buf)) + 23 -> NodeException.TxSyncFailed(FfiConverterString.read(buf)) + 24 -> NodeException.TxSyncTimeout(FfiConverterString.read(buf)) + 25 -> NodeException.GossipUpdateFailed(FfiConverterString.read(buf)) + 26 -> NodeException.GossipUpdateTimeout(FfiConverterString.read(buf)) + 27 -> NodeException.LiquidityRequestFailed(FfiConverterString.read(buf)) + 28 -> NodeException.UriParameterParsingFailed(FfiConverterString.read(buf)) + 29 -> NodeException.InvalidAddress(FfiConverterString.read(buf)) + 30 -> NodeException.InvalidSocketAddress(FfiConverterString.read(buf)) + 31 -> NodeException.InvalidPublicKey(FfiConverterString.read(buf)) + 32 -> NodeException.InvalidSecretKey(FfiConverterString.read(buf)) + 33 -> NodeException.InvalidOfferId(FfiConverterString.read(buf)) + 34 -> NodeException.InvalidNodeId(FfiConverterString.read(buf)) + 35 -> NodeException.InvalidPaymentId(FfiConverterString.read(buf)) + 36 -> NodeException.InvalidPaymentHash(FfiConverterString.read(buf)) + 37 -> NodeException.InvalidPaymentPreimage(FfiConverterString.read(buf)) + 38 -> NodeException.InvalidPaymentSecret(FfiConverterString.read(buf)) + 39 -> NodeException.InvalidAmount(FfiConverterString.read(buf)) + 40 -> NodeException.InvalidInvoice(FfiConverterString.read(buf)) + 41 -> NodeException.InvalidOffer(FfiConverterString.read(buf)) + 42 -> NodeException.InvalidRefund(FfiConverterString.read(buf)) + 43 -> NodeException.InvalidChannelId(FfiConverterString.read(buf)) + 44 -> NodeException.InvalidNetwork(FfiConverterString.read(buf)) + 45 -> NodeException.InvalidUri(FfiConverterString.read(buf)) + 46 -> NodeException.InvalidQuantity(FfiConverterString.read(buf)) + 47 -> NodeException.InvalidNodeAlias(FfiConverterString.read(buf)) + 48 -> NodeException.InvalidDateTime(FfiConverterString.read(buf)) + 49 -> NodeException.InvalidFeeRate(FfiConverterString.read(buf)) + 50 -> NodeException.DuplicatePayment(FfiConverterString.read(buf)) + 51 -> NodeException.UnsupportedCurrency(FfiConverterString.read(buf)) + 52 -> NodeException.InsufficientFunds(FfiConverterString.read(buf)) + 53 -> NodeException.LiquiditySourceUnavailable(FfiConverterString.read(buf)) + 54 -> NodeException.LiquidityFeeTooHigh(FfiConverterString.read(buf)) + 55 -> NodeException.InvalidBlindedPaths(FfiConverterString.read(buf)) + 56 -> NodeException.AsyncPaymentServicesDisabled(FfiConverterString.read(buf)) + 57 -> NodeException.CannotRbfFundingTransaction(FfiConverterString.read(buf)) + 58 -> NodeException.TransactionNotFound(FfiConverterString.read(buf)) + 59 -> NodeException.TransactionAlreadyConfirmed(FfiConverterString.read(buf)) + 60 -> NodeException.NoSpendableOutputs(FfiConverterString.read(buf)) + 61 -> NodeException.CoinSelectionFailed(FfiConverterString.read(buf)) + 62 -> NodeException.InvalidMnemonic(FfiConverterString.read(buf)) + 63 -> NodeException.BackgroundSyncNotEnabled(FfiConverterString.read(buf)) + 64 -> NodeException.AddressTypeAlreadyMonitored(FfiConverterString.read(buf)) + 65 -> NodeException.AddressTypeIsPrimary(FfiConverterString.read(buf)) + 66 -> NodeException.AddressTypeNotMonitored(FfiConverterString.read(buf)) + 67 -> NodeException.OnchainWalletAccountNotRegistered(FfiConverterString.read(buf)) + 68 -> NodeException.InvalidSeedBytes(FfiConverterString.read(buf)) + else -> throw RuntimeException("invalid error enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: NodeException): ULong { + return 4UL + } + + override fun write(value: NodeException, buf: ByteBuffer) { + when (value) { + is NodeException.AlreadyRunning -> { + buf.putInt(1) + Unit + } + is NodeException.NotRunning -> { + buf.putInt(2) + Unit + } + is NodeException.OnchainTxCreationFailed -> { + buf.putInt(3) + Unit + } + is NodeException.ConnectionFailed -> { + buf.putInt(4) + Unit + } + is NodeException.InvoiceCreationFailed -> { + buf.putInt(5) + Unit + } + is NodeException.InvoiceRequestCreationFailed -> { + buf.putInt(6) + Unit + } + is NodeException.OfferCreationFailed -> { + buf.putInt(7) + Unit + } + is NodeException.RefundCreationFailed -> { + buf.putInt(8) + Unit + } + is NodeException.PaymentSendingFailed -> { + buf.putInt(9) + Unit + } + is NodeException.InvalidCustomTlvs -> { + buf.putInt(10) + Unit + } + is NodeException.ProbeSendingFailed -> { + buf.putInt(11) + Unit + } + is NodeException.RouteNotFound -> { + buf.putInt(12) + Unit + } + is NodeException.ChannelCreationFailed -> { + buf.putInt(13) + Unit + } + is NodeException.ChannelClosingFailed -> { + buf.putInt(14) + Unit + } + is NodeException.ChannelSplicingFailed -> { + buf.putInt(15) + Unit + } + is NodeException.ChannelConfigUpdateFailed -> { + buf.putInt(16) + Unit + } + is NodeException.PersistenceFailed -> { + buf.putInt(17) + Unit + } + is NodeException.FeerateEstimationUpdateFailed -> { + buf.putInt(18) + Unit + } + is NodeException.FeerateEstimationUpdateTimeout -> { + buf.putInt(19) + Unit + } + is NodeException.WalletOperationFailed -> { + buf.putInt(20) + Unit + } + is NodeException.WalletOperationTimeout -> { + buf.putInt(21) + Unit + } + is NodeException.OnchainTxSigningFailed -> { + buf.putInt(22) + Unit + } + is NodeException.TxSyncFailed -> { + buf.putInt(23) + Unit + } + is NodeException.TxSyncTimeout -> { + buf.putInt(24) + Unit + } + is NodeException.GossipUpdateFailed -> { + buf.putInt(25) + Unit + } + is NodeException.GossipUpdateTimeout -> { + buf.putInt(26) + Unit + } + is NodeException.LiquidityRequestFailed -> { + buf.putInt(27) + Unit + } + is NodeException.UriParameterParsingFailed -> { + buf.putInt(28) + Unit + } + is NodeException.InvalidAddress -> { + buf.putInt(29) + Unit + } + is NodeException.InvalidSocketAddress -> { + buf.putInt(30) + Unit + } + is NodeException.InvalidPublicKey -> { + buf.putInt(31) + Unit + } + is NodeException.InvalidSecretKey -> { + buf.putInt(32) + Unit + } + is NodeException.InvalidOfferId -> { + buf.putInt(33) + Unit + } + is NodeException.InvalidNodeId -> { + buf.putInt(34) + Unit + } + is NodeException.InvalidPaymentId -> { + buf.putInt(35) + Unit + } + is NodeException.InvalidPaymentHash -> { + buf.putInt(36) + Unit + } + is NodeException.InvalidPaymentPreimage -> { + buf.putInt(37) + Unit + } + is NodeException.InvalidPaymentSecret -> { + buf.putInt(38) + Unit + } + is NodeException.InvalidAmount -> { + buf.putInt(39) + Unit + } + is NodeException.InvalidInvoice -> { + buf.putInt(40) + Unit + } + is NodeException.InvalidOffer -> { + buf.putInt(41) + Unit + } + is NodeException.InvalidRefund -> { + buf.putInt(42) + Unit + } + is NodeException.InvalidChannelId -> { + buf.putInt(43) + Unit + } + is NodeException.InvalidNetwork -> { + buf.putInt(44) + Unit + } + is NodeException.InvalidUri -> { + buf.putInt(45) + Unit + } + is NodeException.InvalidQuantity -> { + buf.putInt(46) + Unit + } + is NodeException.InvalidNodeAlias -> { + buf.putInt(47) + Unit + } + is NodeException.InvalidDateTime -> { + buf.putInt(48) + Unit + } + is NodeException.InvalidFeeRate -> { + buf.putInt(49) + Unit + } + is NodeException.DuplicatePayment -> { + buf.putInt(50) + Unit + } + is NodeException.UnsupportedCurrency -> { + buf.putInt(51) + Unit + } + is NodeException.InsufficientFunds -> { + buf.putInt(52) + Unit + } + is NodeException.LiquiditySourceUnavailable -> { + buf.putInt(53) + Unit + } + is NodeException.LiquidityFeeTooHigh -> { + buf.putInt(54) + Unit + } + is NodeException.InvalidBlindedPaths -> { + buf.putInt(55) + Unit + } + is NodeException.AsyncPaymentServicesDisabled -> { + buf.putInt(56) + Unit + } + is NodeException.CannotRbfFundingTransaction -> { + buf.putInt(57) + Unit + } + is NodeException.TransactionNotFound -> { + buf.putInt(58) + Unit + } + is NodeException.TransactionAlreadyConfirmed -> { + buf.putInt(59) + Unit + } + is NodeException.NoSpendableOutputs -> { + buf.putInt(60) + Unit + } + is NodeException.CoinSelectionFailed -> { + buf.putInt(61) + Unit + } + is NodeException.InvalidMnemonic -> { + buf.putInt(62) + Unit + } + is NodeException.BackgroundSyncNotEnabled -> { + buf.putInt(63) + Unit + } + is NodeException.AddressTypeAlreadyMonitored -> { + buf.putInt(64) + Unit + } + is NodeException.AddressTypeIsPrimary -> { + buf.putInt(65) + Unit + } + is NodeException.AddressTypeNotMonitored -> { + buf.putInt(66) + Unit + } + is NodeException.OnchainWalletAccountNotRegistered -> { + buf.putInt(67) + Unit + } + is NodeException.InvalidSeedBytes -> { + buf.putInt(68) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + +object FfiConverterTypeOfferAmount : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): OfferAmount { + return when(buf.getInt()) { + 1 -> OfferAmount.Bitcoin( + FfiConverterULong.read(buf), + ) + 2 -> OfferAmount.Currency( + FfiConverterString.read(buf), + FfiConverterULong.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: OfferAmount) = when(value) { + is OfferAmount.Bitcoin -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterULong.allocationSize(value.`amountMsats`) + ) + } + is OfferAmount.Currency -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterString.allocationSize(value.`iso4217Code`) + + FfiConverterULong.allocationSize(value.`amount`) + ) + } + } + + override fun write(value: OfferAmount, buf: ByteBuffer) { + when(value) { + is OfferAmount.Bitcoin -> { + buf.putInt(1) + FfiConverterULong.write(value.`amountMsats`, buf) + Unit + } + is OfferAmount.Currency -> { + buf.putInt(2) + FfiConverterString.write(value.`iso4217Code`, buf) + FfiConverterULong.write(value.`amount`, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + +object FfiConverterTypePaymentDirection: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + PaymentDirection.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: PaymentDirection) = 4UL + + override fun write(value: PaymentDirection, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + +object FfiConverterTypePaymentFailureReason: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + PaymentFailureReason.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: PaymentFailureReason) = 4UL + + override fun write(value: PaymentFailureReason, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + +object FfiConverterTypePaymentKind : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): PaymentKind { + return when(buf.getInt()) { + 1 -> PaymentKind.Onchain( + FfiConverterTypeTxid.read(buf), + FfiConverterTypeConfirmationStatus.read(buf), + ) + 2 -> PaymentKind.Bolt11( + FfiConverterTypePaymentHash.read(buf), + FfiConverterOptionalTypePaymentPreimage.read(buf), + FfiConverterOptionalTypePaymentSecret.read(buf), + FfiConverterOptionalString.read(buf), + FfiConverterOptionalString.read(buf), + ) + 3 -> PaymentKind.Bolt11Jit( + FfiConverterTypePaymentHash.read(buf), + FfiConverterOptionalTypePaymentPreimage.read(buf), + FfiConverterOptionalTypePaymentSecret.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterTypeLSPFeeLimits.read(buf), + FfiConverterOptionalString.read(buf), + FfiConverterOptionalString.read(buf), + ) + 4 -> PaymentKind.Bolt12Offer( + FfiConverterOptionalTypePaymentHash.read(buf), + FfiConverterOptionalTypePaymentPreimage.read(buf), + FfiConverterOptionalTypePaymentSecret.read(buf), + FfiConverterTypeOfferId.read(buf), + FfiConverterOptionalTypeUntrustedString.read(buf), + FfiConverterOptionalULong.read(buf), + ) + 5 -> PaymentKind.Bolt12Refund( + FfiConverterOptionalTypePaymentHash.read(buf), + FfiConverterOptionalTypePaymentPreimage.read(buf), + FfiConverterOptionalTypePaymentSecret.read(buf), + FfiConverterOptionalTypeUntrustedString.read(buf), + FfiConverterOptionalULong.read(buf), + ) + 6 -> PaymentKind.Spontaneous( + FfiConverterTypePaymentHash.read(buf), + FfiConverterOptionalTypePaymentPreimage.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: PaymentKind) = when(value) { + is PaymentKind.Onchain -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeTxid.allocationSize(value.`txid`) + + FfiConverterTypeConfirmationStatus.allocationSize(value.`status`) + ) + } + is PaymentKind.Bolt11 -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypePaymentHash.allocationSize(value.`hash`) + + FfiConverterOptionalTypePaymentPreimage.allocationSize(value.`preimage`) + + FfiConverterOptionalTypePaymentSecret.allocationSize(value.`secret`) + + FfiConverterOptionalString.allocationSize(value.`description`) + + FfiConverterOptionalString.allocationSize(value.`bolt11`) + ) + } + is PaymentKind.Bolt11Jit -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypePaymentHash.allocationSize(value.`hash`) + + FfiConverterOptionalTypePaymentPreimage.allocationSize(value.`preimage`) + + FfiConverterOptionalTypePaymentSecret.allocationSize(value.`secret`) + + FfiConverterOptionalULong.allocationSize(value.`counterpartySkimmedFeeMsat`) + + FfiConverterTypeLSPFeeLimits.allocationSize(value.`lspFeeLimits`) + + FfiConverterOptionalString.allocationSize(value.`description`) + + FfiConverterOptionalString.allocationSize(value.`bolt11`) + ) + } + is PaymentKind.Bolt12Offer -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterOptionalTypePaymentHash.allocationSize(value.`hash`) + + FfiConverterOptionalTypePaymentPreimage.allocationSize(value.`preimage`) + + FfiConverterOptionalTypePaymentSecret.allocationSize(value.`secret`) + + FfiConverterTypeOfferId.allocationSize(value.`offerId`) + + FfiConverterOptionalTypeUntrustedString.allocationSize(value.`payerNote`) + + FfiConverterOptionalULong.allocationSize(value.`quantity`) + ) + } + is PaymentKind.Bolt12Refund -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterOptionalTypePaymentHash.allocationSize(value.`hash`) + + FfiConverterOptionalTypePaymentPreimage.allocationSize(value.`preimage`) + + FfiConverterOptionalTypePaymentSecret.allocationSize(value.`secret`) + + FfiConverterOptionalTypeUntrustedString.allocationSize(value.`payerNote`) + + FfiConverterOptionalULong.allocationSize(value.`quantity`) + ) + } + is PaymentKind.Spontaneous -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypePaymentHash.allocationSize(value.`hash`) + + FfiConverterOptionalTypePaymentPreimage.allocationSize(value.`preimage`) + ) + } + } + + override fun write(value: PaymentKind, buf: ByteBuffer) { + when(value) { + is PaymentKind.Onchain -> { + buf.putInt(1) + FfiConverterTypeTxid.write(value.`txid`, buf) + FfiConverterTypeConfirmationStatus.write(value.`status`, buf) + Unit + } + is PaymentKind.Bolt11 -> { + buf.putInt(2) + FfiConverterTypePaymentHash.write(value.`hash`, buf) + FfiConverterOptionalTypePaymentPreimage.write(value.`preimage`, buf) + FfiConverterOptionalTypePaymentSecret.write(value.`secret`, buf) + FfiConverterOptionalString.write(value.`description`, buf) + FfiConverterOptionalString.write(value.`bolt11`, buf) + Unit + } + is PaymentKind.Bolt11Jit -> { + buf.putInt(3) + FfiConverterTypePaymentHash.write(value.`hash`, buf) + FfiConverterOptionalTypePaymentPreimage.write(value.`preimage`, buf) + FfiConverterOptionalTypePaymentSecret.write(value.`secret`, buf) + FfiConverterOptionalULong.write(value.`counterpartySkimmedFeeMsat`, buf) + FfiConverterTypeLSPFeeLimits.write(value.`lspFeeLimits`, buf) + FfiConverterOptionalString.write(value.`description`, buf) + FfiConverterOptionalString.write(value.`bolt11`, buf) + Unit + } + is PaymentKind.Bolt12Offer -> { + buf.putInt(4) + FfiConverterOptionalTypePaymentHash.write(value.`hash`, buf) + FfiConverterOptionalTypePaymentPreimage.write(value.`preimage`, buf) + FfiConverterOptionalTypePaymentSecret.write(value.`secret`, buf) + FfiConverterTypeOfferId.write(value.`offerId`, buf) + FfiConverterOptionalTypeUntrustedString.write(value.`payerNote`, buf) + FfiConverterOptionalULong.write(value.`quantity`, buf) + Unit + } + is PaymentKind.Bolt12Refund -> { + buf.putInt(5) + FfiConverterOptionalTypePaymentHash.write(value.`hash`, buf) + FfiConverterOptionalTypePaymentPreimage.write(value.`preimage`, buf) + FfiConverterOptionalTypePaymentSecret.write(value.`secret`, buf) + FfiConverterOptionalTypeUntrustedString.write(value.`payerNote`, buf) + FfiConverterOptionalULong.write(value.`quantity`, buf) + Unit + } + is PaymentKind.Spontaneous -> { + buf.putInt(6) + FfiConverterTypePaymentHash.write(value.`hash`, buf) + FfiConverterOptionalTypePaymentPreimage.write(value.`preimage`, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + +object FfiConverterTypePaymentStatus: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + PaymentStatus.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: PaymentStatus) = 4UL + + override fun write(value: PaymentStatus, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + +object FfiConverterTypePendingSweepBalance : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): PendingSweepBalance { + return when(buf.getInt()) { + 1 -> PendingSweepBalance.PendingBroadcast( + FfiConverterOptionalTypeChannelId.read(buf), + FfiConverterULong.read(buf), + ) + 2 -> PendingSweepBalance.BroadcastAwaitingConfirmation( + FfiConverterOptionalTypeChannelId.read(buf), + FfiConverterUInt.read(buf), + FfiConverterTypeTxid.read(buf), + FfiConverterULong.read(buf), + ) + 3 -> PendingSweepBalance.AwaitingThresholdConfirmations( + FfiConverterOptionalTypeChannelId.read(buf), + FfiConverterTypeTxid.read(buf), + FfiConverterTypeBlockHash.read(buf), + FfiConverterUInt.read(buf), + FfiConverterULong.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: PendingSweepBalance) = when(value) { + is PendingSweepBalance.PendingBroadcast -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterOptionalTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterULong.allocationSize(value.`amountSatoshis`) + ) + } + is PendingSweepBalance.BroadcastAwaitingConfirmation -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterOptionalTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterUInt.allocationSize(value.`latestBroadcastHeight`) + + FfiConverterTypeTxid.allocationSize(value.`latestSpendingTxid`) + + FfiConverterULong.allocationSize(value.`amountSatoshis`) + ) + } + is PendingSweepBalance.AwaitingThresholdConfirmations -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterOptionalTypeChannelId.allocationSize(value.`channelId`) + + FfiConverterTypeTxid.allocationSize(value.`latestSpendingTxid`) + + FfiConverterTypeBlockHash.allocationSize(value.`confirmationHash`) + + FfiConverterUInt.allocationSize(value.`confirmationHeight`) + + FfiConverterULong.allocationSize(value.`amountSatoshis`) + ) + } + } + + override fun write(value: PendingSweepBalance, buf: ByteBuffer) { + when(value) { + is PendingSweepBalance.PendingBroadcast -> { + buf.putInt(1) + FfiConverterOptionalTypeChannelId.write(value.`channelId`, buf) + FfiConverterULong.write(value.`amountSatoshis`, buf) + Unit + } + is PendingSweepBalance.BroadcastAwaitingConfirmation -> { + buf.putInt(2) + FfiConverterOptionalTypeChannelId.write(value.`channelId`, buf) + FfiConverterUInt.write(value.`latestBroadcastHeight`, buf) + FfiConverterTypeTxid.write(value.`latestSpendingTxid`, buf) + FfiConverterULong.write(value.`amountSatoshis`, buf) + Unit + } + is PendingSweepBalance.AwaitingThresholdConfirmations -> { + buf.putInt(3) + FfiConverterOptionalTypeChannelId.write(value.`channelId`, buf) + FfiConverterTypeTxid.write(value.`latestSpendingTxid`, buf) + FfiConverterTypeBlockHash.write(value.`confirmationHash`, buf) + FfiConverterUInt.write(value.`confirmationHeight`, buf) + FfiConverterULong.write(value.`amountSatoshis`, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + +object FfiConverterTypeQrPaymentResult : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): QrPaymentResult { + return when(buf.getInt()) { + 1 -> QrPaymentResult.Onchain( + FfiConverterTypeTxid.read(buf), + ) + 2 -> QrPaymentResult.Bolt11( + FfiConverterTypePaymentId.read(buf), + ) + 3 -> QrPaymentResult.Bolt12( + FfiConverterTypePaymentId.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: QrPaymentResult) = when(value) { + is QrPaymentResult.Onchain -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeTxid.allocationSize(value.`txid`) + ) + } + is QrPaymentResult.Bolt11 -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypePaymentId.allocationSize(value.`paymentId`) + ) + } + is QrPaymentResult.Bolt12 -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypePaymentId.allocationSize(value.`paymentId`) + ) + } + } + + override fun write(value: QrPaymentResult, buf: ByteBuffer) { + when(value) { + is QrPaymentResult.Onchain -> { + buf.putInt(1) + FfiConverterTypeTxid.write(value.`txid`, buf) + Unit + } + is QrPaymentResult.Bolt11 -> { + buf.putInt(2) + FfiConverterTypePaymentId.write(value.`paymentId`, buf) + Unit + } + is QrPaymentResult.Bolt12 -> { + buf.putInt(3) + FfiConverterTypePaymentId.write(value.`paymentId`, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + +object FfiConverterTypeSyncType: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + SyncType.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: SyncType) = 4UL + + override fun write(value: SyncType, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + +object VssHeaderProviderExceptionErrorHandler : UniffiRustCallStatusErrorHandler { + override fun lift(errorBuf: RustBufferByValue): VssHeaderProviderException = FfiConverterTypeVssHeaderProviderError.lift(errorBuf) +} + +object FfiConverterTypeVssHeaderProviderError : FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): VssHeaderProviderException { + return when (buf.getInt()) { + 1 -> VssHeaderProviderException.InvalidData(FfiConverterString.read(buf)) + 2 -> VssHeaderProviderException.RequestException(FfiConverterString.read(buf)) + 3 -> VssHeaderProviderException.AuthorizationException(FfiConverterString.read(buf)) + 4 -> VssHeaderProviderException.InternalException(FfiConverterString.read(buf)) + else -> throw RuntimeException("invalid error enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: VssHeaderProviderException): ULong { + return 4UL + } + + override fun write(value: VssHeaderProviderException, buf: ByteBuffer) { + when (value) { + is VssHeaderProviderException.InvalidData -> { + buf.putInt(1) + Unit + } + is VssHeaderProviderException.RequestException -> { + buf.putInt(2) + Unit + } + is VssHeaderProviderException.AuthorizationException -> { + buf.putInt(3) + Unit + } + is VssHeaderProviderException.InternalException -> { + buf.putInt(4) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + +object FfiConverterTypeWordCount: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + WordCount.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: WordCount) = 4UL + + override fun write(value: WordCount, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + +object FfiConverterOptionalUShort: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): kotlin.UShort? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterUShort.read(buf) + } + + override fun allocationSize(value: kotlin.UShort?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterUShort.allocationSize(value) + } + } + + override fun write(value: kotlin.UShort?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterUShort.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalUInt: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): kotlin.UInt? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterUInt.read(buf) + } + + override fun allocationSize(value: kotlin.UInt?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterUInt.allocationSize(value) + } + } + + override fun write(value: kotlin.UInt?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterUInt.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalULong: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): kotlin.ULong? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterULong.read(buf) + } + + override fun allocationSize(value: kotlin.ULong?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterULong.allocationSize(value) + } + } + + override fun write(value: kotlin.ULong?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterULong.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalBoolean: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): kotlin.Boolean? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterBoolean.read(buf) + } + + override fun allocationSize(value: kotlin.Boolean?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterBoolean.allocationSize(value) + } + } + + override fun write(value: kotlin.Boolean?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterBoolean.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalString: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): kotlin.String? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterString.read(buf) + } + + override fun allocationSize(value: kotlin.String?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterString.allocationSize(value) + } + } + + override fun write(value: kotlin.String?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterString.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeFeeRate: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): FeeRate? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeFeeRate.read(buf) + } + + override fun allocationSize(value: FeeRate?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeFeeRate.allocationSize(value) + } + } + + override fun write(value: FeeRate?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeFeeRate.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeAnchorChannelsConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): AnchorChannelsConfig? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeAnchorChannelsConfig.read(buf) + } + + override fun allocationSize(value: AnchorChannelsConfig?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeAnchorChannelsConfig.allocationSize(value) + } + } + + override fun write(value: AnchorChannelsConfig?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeAnchorChannelsConfig.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeBackgroundSyncConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): BackgroundSyncConfig? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeBackgroundSyncConfig.read(buf) + } + + override fun allocationSize(value: BackgroundSyncConfig?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeBackgroundSyncConfig.allocationSize(value) + } + } + + override fun write(value: BackgroundSyncConfig?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeBackgroundSyncConfig.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeChannelConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ChannelConfig? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeChannelConfig.read(buf) + } + + override fun allocationSize(value: ChannelConfig?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeChannelConfig.allocationSize(value) + } + } + + override fun write(value: ChannelConfig?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeChannelConfig.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeChannelInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ChannelInfo? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeChannelInfo.read(buf) + } + + override fun allocationSize(value: ChannelInfo?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeChannelInfo.allocationSize(value) + } + } + + override fun write(value: ChannelInfo?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeChannelInfo.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeChannelUpdateInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ChannelUpdateInfo? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeChannelUpdateInfo.read(buf) + } + + override fun allocationSize(value: ChannelUpdateInfo?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeChannelUpdateInfo.allocationSize(value) + } + } + + override fun write(value: ChannelUpdateInfo?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeChannelUpdateInfo.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeElectrumSyncConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ElectrumSyncConfig? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeElectrumSyncConfig.read(buf) + } + + override fun allocationSize(value: ElectrumSyncConfig?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeElectrumSyncConfig.allocationSize(value) + } + } + + override fun write(value: ElectrumSyncConfig?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeElectrumSyncConfig.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeEsploraSyncConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): EsploraSyncConfig? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeEsploraSyncConfig.read(buf) + } + + override fun allocationSize(value: EsploraSyncConfig?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeEsploraSyncConfig.allocationSize(value) + } + } + + override fun write(value: EsploraSyncConfig?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeEsploraSyncConfig.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeLSPS1Bolt11PaymentInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Lsps1Bolt11PaymentInfo? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeLSPS1Bolt11PaymentInfo.read(buf) + } + + override fun allocationSize(value: Lsps1Bolt11PaymentInfo?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeLSPS1Bolt11PaymentInfo.allocationSize(value) + } + } + + override fun write(value: Lsps1Bolt11PaymentInfo?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeLSPS1Bolt11PaymentInfo.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeLSPS1ChannelInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Lsps1ChannelInfo? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeLSPS1ChannelInfo.read(buf) + } + + override fun allocationSize(value: Lsps1ChannelInfo?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeLSPS1ChannelInfo.allocationSize(value) + } + } + + override fun write(value: Lsps1ChannelInfo?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeLSPS1ChannelInfo.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeLSPS1OnchainPaymentInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Lsps1OnchainPaymentInfo? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeLSPS1OnchainPaymentInfo.read(buf) + } + + override fun allocationSize(value: Lsps1OnchainPaymentInfo?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeLSPS1OnchainPaymentInfo.allocationSize(value) + } + } + + override fun write(value: Lsps1OnchainPaymentInfo?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeLSPS1OnchainPaymentInfo.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeNodeAnnouncementInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): NodeAnnouncementInfo? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeNodeAnnouncementInfo.read(buf) + } + + override fun allocationSize(value: NodeAnnouncementInfo?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeNodeAnnouncementInfo.allocationSize(value) + } + } + + override fun write(value: NodeAnnouncementInfo?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeNodeAnnouncementInfo.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeNodeInfo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): NodeInfo? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeNodeInfo.read(buf) + } + + override fun allocationSize(value: NodeInfo?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeNodeInfo.allocationSize(value) + } + } + + override fun write(value: NodeInfo?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeNodeInfo.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeOutPoint: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): OutPoint? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeOutPoint.read(buf) + } + + override fun allocationSize(value: OutPoint?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeOutPoint.allocationSize(value) + } + } + + override fun write(value: OutPoint?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeOutPoint.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypePaymentDetails: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): PaymentDetails? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypePaymentDetails.read(buf) + } + + override fun allocationSize(value: PaymentDetails?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypePaymentDetails.allocationSize(value) + } + } + + override fun write(value: PaymentDetails?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypePaymentDetails.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeRouteParametersConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): RouteParametersConfig? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeRouteParametersConfig.read(buf) + } + + override fun allocationSize(value: RouteParametersConfig?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeRouteParametersConfig.allocationSize(value) + } + } + + override fun write(value: RouteParametersConfig?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeRouteParametersConfig.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeScoringDecayParameters: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ScoringDecayParameters? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeScoringDecayParameters.read(buf) + } + + override fun allocationSize(value: ScoringDecayParameters?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeScoringDecayParameters.allocationSize(value) + } + } + + override fun write(value: ScoringDecayParameters?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeScoringDecayParameters.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeScoringFeeParameters: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ScoringFeeParameters? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeScoringFeeParameters.read(buf) + } + + override fun allocationSize(value: ScoringFeeParameters?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeScoringFeeParameters.allocationSize(value) + } + } + + override fun write(value: ScoringFeeParameters?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeScoringFeeParameters.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeTransactionDetails: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): TransactionDetails? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeTransactionDetails.read(buf) + } + + override fun allocationSize(value: TransactionDetails?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeTransactionDetails.allocationSize(value) + } + } + + override fun write(value: TransactionDetails?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeTransactionDetails.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeAsyncPaymentsRole: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): AsyncPaymentsRole? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeAsyncPaymentsRole.read(buf) + } + + override fun allocationSize(value: AsyncPaymentsRole?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeAsyncPaymentsRole.allocationSize(value) + } + } + + override fun write(value: AsyncPaymentsRole?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeAsyncPaymentsRole.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeClosureReason: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ClosureReason? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeClosureReason.read(buf) + } + + override fun allocationSize(value: ClosureReason?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeClosureReason.allocationSize(value) + } + } + + override fun write(value: ClosureReason?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeClosureReason.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeEvent: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Event? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeEvent.read(buf) + } + + override fun allocationSize(value: Event?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeEvent.allocationSize(value) + } + } + + override fun write(value: Event?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeEvent.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeLogLevel: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): LogLevel? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeLogLevel.read(buf) + } + + override fun allocationSize(value: LogLevel?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeLogLevel.allocationSize(value) + } + } + + override fun write(value: LogLevel?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeLogLevel.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeNetwork: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Network? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeNetwork.read(buf) + } + + override fun allocationSize(value: Network?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeNetwork.allocationSize(value) + } + } + + override fun write(value: Network?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeNetwork.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeOfferAmount: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): OfferAmount? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeOfferAmount.read(buf) + } + + override fun allocationSize(value: OfferAmount?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeOfferAmount.allocationSize(value) + } + } + + override fun write(value: OfferAmount?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeOfferAmount.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypePaymentFailureReason: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): PaymentFailureReason? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypePaymentFailureReason.read(buf) + } + + override fun allocationSize(value: PaymentFailureReason?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypePaymentFailureReason.allocationSize(value) + } + } + + override fun write(value: PaymentFailureReason?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypePaymentFailureReason.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeWordCount: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): WordCount? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeWordCount.read(buf) + } + + override fun allocationSize(value: WordCount?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeWordCount.allocationSize(value) + } + } + + override fun write(value: WordCount?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeWordCount.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalSequenceUByte: FfiConverterRustBuffer?> { + override fun read(buf: ByteBuffer): List? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterSequenceUByte.read(buf) + } + + override fun allocationSize(value: List?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterSequenceUByte.allocationSize(value) + } + } + + override fun write(value: List?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterSequenceUByte.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalSequenceTypeSpendableUtxo: FfiConverterRustBuffer?> { + override fun read(buf: ByteBuffer): List? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterSequenceTypeSpendableUtxo.read(buf) + } + + override fun allocationSize(value: List?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterSequenceTypeSpendableUtxo.allocationSize(value) + } + } + + override fun write(value: List?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterSequenceTypeSpendableUtxo.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalSequenceSequenceUByte: FfiConverterRustBuffer>?> { + override fun read(buf: ByteBuffer): List>? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterSequenceSequenceUByte.read(buf) + } + + override fun allocationSize(value: List>?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterSequenceSequenceUByte.allocationSize(value) + } + } + + override fun write(value: List>?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterSequenceSequenceUByte.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalSequenceTypeSocketAddress: FfiConverterRustBuffer?> { + override fun read(buf: ByteBuffer): List? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterSequenceTypeSocketAddress.read(buf) + } + + override fun allocationSize(value: List?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterSequenceTypeSocketAddress.allocationSize(value) + } + } + + override fun write(value: List?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterSequenceTypeSocketAddress.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeAddress: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Address? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeAddress.read(buf) + } + + override fun allocationSize(value: Address?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeAddress.allocationSize(value) + } + } + + override fun write(value: Address?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeAddress.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeChannelId: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ChannelId? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeChannelId.read(buf) + } + + override fun allocationSize(value: ChannelId?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeChannelId.allocationSize(value) + } + } + + override fun write(value: ChannelId?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeChannelId.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeNodeAlias: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): NodeAlias? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeNodeAlias.read(buf) + } + + override fun allocationSize(value: NodeAlias?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeNodeAlias.allocationSize(value) + } + } + + override fun write(value: NodeAlias?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeNodeAlias.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypePaymentHash: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): PaymentHash? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypePaymentHash.read(buf) + } + + override fun allocationSize(value: PaymentHash?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypePaymentHash.allocationSize(value) + } + } + + override fun write(value: PaymentHash?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypePaymentHash.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypePaymentId: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): PaymentId? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypePaymentId.read(buf) + } + + override fun allocationSize(value: PaymentId?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypePaymentId.allocationSize(value) + } + } + + override fun write(value: PaymentId?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypePaymentId.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypePaymentPreimage: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): PaymentPreimage? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypePaymentPreimage.read(buf) + } + + override fun allocationSize(value: PaymentPreimage?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypePaymentPreimage.allocationSize(value) + } + } + + override fun write(value: PaymentPreimage?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypePaymentPreimage.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypePaymentSecret: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): PaymentSecret? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypePaymentSecret.read(buf) + } + + override fun allocationSize(value: PaymentSecret?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypePaymentSecret.allocationSize(value) + } + } + + override fun write(value: PaymentSecret?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypePaymentSecret.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypePublicKey: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): PublicKey? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypePublicKey.read(buf) + } + + override fun allocationSize(value: PublicKey?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypePublicKey.allocationSize(value) + } + } + + override fun write(value: PublicKey?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypePublicKey.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeUntrustedString: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): UntrustedString? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeUntrustedString.read(buf) + } + + override fun allocationSize(value: UntrustedString?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeUntrustedString.allocationSize(value) + } + } + + override fun write(value: UntrustedString?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeUntrustedString.write(value, buf) + } + } +} + + + + +object FfiConverterOptionalTypeUserChannelId: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): UserChannelId? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeUserChannelId.read(buf) + } + + override fun allocationSize(value: UserChannelId?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeUserChannelId.allocationSize(value) + } + } + + override fun write(value: UserChannelId?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeUserChannelId.write(value, buf) + } + } +} + + + + +object FfiConverterSequenceUByte: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterUByte.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterUByte.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterUByte.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceULong: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterULong.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterULong.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterULong.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceString: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterString.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterString.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterString.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeAddressInfo: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeAddressInfo.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeAddressInfo.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeAddressInfo.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeChannelDetails: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeChannelDetails.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeChannelDetails.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeChannelDetails.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeCustomTlvRecord: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeCustomTlvRecord.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeCustomTlvRecord.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeCustomTlvRecord.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeOnchainWalletAccount: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeOnchainWalletAccount.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeOnchainWalletAccount.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeOnchainWalletAccount.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeOnchainWalletAccountConfig: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeOnchainWalletAccountConfig.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeOnchainWalletAccountConfig.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeOnchainWalletAccountConfig.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypePaymentDetails: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypePaymentDetails.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypePaymentDetails.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypePaymentDetails.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypePeerDetails: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypePeerDetails.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypePeerDetails.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypePeerDetails.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeProbeHandle: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeProbeHandle.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeProbeHandle.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeProbeHandle.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeRouteHintHop: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeRouteHintHop.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeRouteHintHop.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeRouteHintHop.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeSpendableUtxo: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeSpendableUtxo.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeSpendableUtxo.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeSpendableUtxo.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeTxInput: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeTxInput.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeTxInput.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeTxInput.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeTxOutput: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeTxOutput.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeTxOutput.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeTxOutput.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeAddressType: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeAddressType.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeAddressType.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeAddressType.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeLightningBalance: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeLightningBalance.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeLightningBalance.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeLightningBalance.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeNetwork: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeNetwork.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeNetwork.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeNetwork.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypePendingSweepBalance: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypePendingSweepBalance.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypePendingSweepBalance.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypePendingSweepBalance.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceSequenceUByte: FfiConverterRustBuffer>> { + override fun read(buf: ByteBuffer): List> { + val len = buf.getInt() + return List>(len) { + FfiConverterSequenceUByte.read(buf) + } + } + + override fun allocationSize(value: List>): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterSequenceUByte.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List>, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterSequenceUByte.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceSequenceTypeRouteHintHop: FfiConverterRustBuffer>> { + override fun read(buf: ByteBuffer): List> { + val len = buf.getInt() + return List>(len) { + FfiConverterSequenceTypeRouteHintHop.read(buf) + } + } + + override fun allocationSize(value: List>): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterSequenceTypeRouteHintHop.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List>, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterSequenceTypeRouteHintHop.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeAddress: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List
{ + val len = buf.getInt() + return List
(len) { + FfiConverterTypeAddress.read(buf) + } + } + + override fun allocationSize(value: List
): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeAddress.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List
, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeAddress.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeNodeId: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeNodeId.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeNodeId.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeNodeId.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypePublicKey: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypePublicKey.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypePublicKey.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypePublicKey.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeSocketAddress: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeSocketAddress.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeSocketAddress.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeSocketAddress.write(it, buf) + } + } +} + + + + +object FfiConverterSequenceTypeTxid: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeTxid.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeTxid.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeTxid.write(it, buf) + } + } +} + + + +object FfiConverterMapStringString: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): Map { + val len = buf.getInt() + return buildMap(len) { + repeat(len) { + val k = FfiConverterString.read(buf) + val v = FfiConverterString.read(buf) + this[k] = v + } + } + } + + override fun allocationSize(value: Map): ULong { + val spaceForMapSize = 4UL + val spaceForChildren = value.entries.sumOf { (k, v) -> + FfiConverterString.allocationSize(k) + + FfiConverterString.allocationSize(v) + } + return spaceForMapSize + spaceForChildren + } + + override fun write(value: Map, buf: ByteBuffer) { + buf.putInt(value.size) + // The parens on `(k, v)` here ensure we're calling the right method, + // which is important for compatibility with older android devices. + // Ref https://blog.danlew.net/2017/03/16/kotlin-puzzler-whose-line-is-it-anyways/ + value.forEach { (k, v) -> + FfiConverterString.write(k, buf) + FfiConverterString.write(v, buf) + } + } +} + + + + +typealias FfiConverterTypeAddress = FfiConverterString + + + + +typealias FfiConverterTypeBlockHash = FfiConverterString + + + + +typealias FfiConverterTypeChannelId = FfiConverterString + + + + +typealias FfiConverterTypeLSPS1OrderId = FfiConverterString + + + + +typealias FfiConverterTypeLSPSDateTime = FfiConverterString + + + + +typealias FfiConverterTypeMnemonic = FfiConverterString + + + + +typealias FfiConverterTypeNodeAlias = FfiConverterString + + + + +typealias FfiConverterTypeNodeId = FfiConverterString + + + + +typealias FfiConverterTypeOfferId = FfiConverterString + + + + +typealias FfiConverterTypePaymentHash = FfiConverterString + + + + +typealias FfiConverterTypePaymentId = FfiConverterString + + + + +typealias FfiConverterTypePaymentPreimage = FfiConverterString + + + + +typealias FfiConverterTypePaymentSecret = FfiConverterString + + + + +typealias FfiConverterTypePublicKey = FfiConverterString + + + + +typealias FfiConverterTypeSocketAddress = FfiConverterString + + + + +typealias FfiConverterTypeTxid = FfiConverterString + + + + +typealias FfiConverterTypeUntrustedString = FfiConverterString + + + + +typealias FfiConverterTypeUserChannelId = FfiConverterString + + + + + + + + + + + + + +fun `batterySavingSyncIntervals`(): RuntimeSyncIntervals { + return FfiConverterTypeRuntimeSyncIntervals.lift(uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_func_battery_saving_sync_intervals( + uniffiRustCallStatus, + ) + }) +} + +fun `defaultConfig`(): Config { + return FfiConverterTypeConfig.lift(uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_func_default_config( + uniffiRustCallStatus, + ) + }) +} + +@Throws(NodeException::class) +fun `deriveNodeSecretFromMnemonic`(`mnemonic`: kotlin.String, `passphrase`: kotlin.String?): List { + return FfiConverterSequenceUByte.lift(uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_func_derive_node_secret_from_mnemonic( + FfiConverterString.lower(`mnemonic`), + FfiConverterOptionalString.lower(`passphrase`), + uniffiRustCallStatus, + ) + }) +} + +fun `generateEntropyMnemonic`(`wordCount`: WordCount?): Mnemonic { + return FfiConverterTypeMnemonic.lift(uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.INSTANCE.uniffi_ldk_node_fn_func_generate_entropy_mnemonic( + FfiConverterOptionalTypeWordCount.lower(`wordCount`), + uniffiRustCallStatus, + ) + }) +} + + +// Async support + +internal const val UNIFFI_RUST_FUTURE_POLL_READY = 0.toByte() +internal const val UNIFFI_RUST_FUTURE_POLL_MAYBE_READY = 1.toByte() + +internal val uniffiContinuationHandleMap = UniffiHandleMap>() + +// FFI type for Rust future continuations +internal suspend fun uniffiRustCallAsync( + rustFuture: Long, + pollFunc: (Long, UniffiRustFutureContinuationCallback, Long) -> Unit, + completeFunc: (Long, UniffiRustCallStatus) -> F, + freeFunc: (Long) -> Unit, + cancelFunc: (Long) -> Unit, + liftFunc: (F) -> T, + errorHandler: UniffiRustCallStatusErrorHandler +): T { + return withContext(Dispatchers.IO) { + try { + do { + val pollResult = suspendCancellableCoroutine { continuation -> + val handle = uniffiContinuationHandleMap.insert(continuation) + continuation.invokeOnCancellation { + cancelFunc(rustFuture) + } + pollFunc( + rustFuture, + uniffiRustFutureContinuationCallbackCallback, + handle + ) + } + } while (pollResult != UNIFFI_RUST_FUTURE_POLL_READY); + + return@withContext liftFunc( + uniffiRustCallWithError(errorHandler) { status -> completeFunc(rustFuture, status) } + ) + } finally { + freeFunc(rustFuture) + } + } +} + +object uniffiRustFutureContinuationCallbackCallback: UniffiRustFutureContinuationCallback { + override fun callback(data: Long, pollResult: Byte) { + uniffiContinuationHandleMap.remove(data).resume(pollResult) + } +} diff --git a/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-aarch64/libldk_node.dylib b/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-aarch64/libldk_node.dylib new file mode 100644 index 0000000000..1c41a7d0c0 Binary files /dev/null and b/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-aarch64/libldk_node.dylib differ diff --git a/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-x86-64/libldk_node.dylib b/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-x86-64/libldk_node.dylib new file mode 100644 index 0000000000..3d39962c93 Binary files /dev/null and b/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-x86-64/libldk_node.dylib differ diff --git a/bindings/kotlin/ldk-node-jvm/lib/src/test/kotlin/org/lightningdevkit/ldknode/LibraryTest.kt b/bindings/kotlin/ldk-node-jvm/lib/src/test/kotlin/org/lightningdevkit/ldknode/LibraryTest.kt index c8c43c49c0..daa3ffecd3 100644 --- a/bindings/kotlin/ldk-node-jvm/lib/src/test/kotlin/org/lightningdevkit/ldknode/LibraryTest.kt +++ b/bindings/kotlin/ldk-node-jvm/lib/src/test/kotlin/org/lightningdevkit/ldknode/LibraryTest.kt @@ -172,17 +172,18 @@ class LibraryTest { val listenAddress1 = "127.0.0.1:2323" val listenAddress2 = "127.0.0.1:2324" - val config1 = defaultConfig() - config1.storageDirPath = tmpDir1 - config1.listeningAddresses = listOf(listenAddress1) - config1.network = Network.REGTEST - + val config1 = defaultConfig().copy( + storageDirPath = tmpDir1, + listeningAddresses = listOf(listenAddress1), + network = Network.REGTEST + ) println("Config 1: $config1") - val config2 = defaultConfig() - config2.storageDirPath = tmpDir2 - config2.listeningAddresses = listOf(listenAddress2) - config2.network = Network.REGTEST + val config2 = defaultConfig().copy( + storageDirPath = tmpDir2, + listeningAddresses = listOf(listenAddress2), + network = Network.REGTEST + ) println("Config 2: $config2") val builder1 = Builder.fromConfig(config1) diff --git a/bindings/ldk_node.udl b/bindings/ldk_node.udl index ff2469c7ee..9cdcdc85b4 100644 --- a/bindings/ldk_node.udl +++ b/bindings/ldk_node.udl @@ -1,6 +1,9 @@ namespace ldk_node { Mnemonic generate_entropy_mnemonic(WordCount? word_count); Config default_config(); + RuntimeSyncIntervals battery_saving_sync_intervals(); + [Throws=NodeError] + sequence derive_node_secret_from_mnemonic(string mnemonic, string? passphrase); }; dictionary Config { @@ -13,6 +16,30 @@ dictionary Config { u64 probing_liquidity_limit_multiplier; AnchorChannelsConfig? anchor_channels_config; RouteParametersConfig? route_parameters; + ScoringFeeParameters? scoring_fee_params; + ScoringDecayParameters? scoring_decay_params; + boolean include_untrusted_pending_in_spendable; + AddressType address_type; + sequence address_types_to_monitor; + sequence onchain_wallet_accounts; +}; + +dictionary ScoringFeeParameters { + u64 base_penalty_msat; + u64 base_penalty_amount_multiplier_msat; + u64 liquidity_penalty_multiplier_msat; + u64 liquidity_penalty_amount_multiplier_msat; + u64 historical_liquidity_penalty_multiplier_msat; + u64 historical_liquidity_penalty_amount_multiplier_msat; + u64 anti_probing_penalty_msat; + u64 considered_impossible_penalty_msat; + boolean linear_success_probability; + u64 probing_diversity_penalty_msat; +}; + +dictionary ScoringDecayParameters { + u64 historical_no_updates_half_life_secs; + u64 liquidity_offset_half_life_secs; }; dictionary AnchorChannelsConfig { @@ -26,12 +53,21 @@ dictionary BackgroundSyncConfig { u64 fee_rate_cache_update_interval_secs; }; +dictionary RuntimeSyncIntervals { + u64 onchain_wallet_sync_interval_secs; + u64 lightning_wallet_sync_interval_secs; + u64 fee_rate_cache_update_interval_secs; +}; + dictionary EsploraSyncConfig { BackgroundSyncConfig? background_sync_config; }; dictionary ElectrumSyncConfig { BackgroundSyncConfig? background_sync_config; + u64 connection_timeout_secs; + u32 additional_wallet_full_scan_batch_size; + u32 additional_wallet_full_scan_stop_gap; }; dictionary LSPS2ServiceConfig { @@ -55,6 +91,35 @@ enum WordCount { "Words24", }; +enum AddressType { + "Legacy", + "NestedSegwit", + "NativeSegwit", + "Taproot", +}; + +dictionary OnchainWalletAccount { + AddressType address_type; + u32 account_index; +}; + +dictionary OnchainWalletAccountConfig { + AddressType address_type; + u32 account_index; + string xpub; +}; + +enum KeychainKind { + "External", + "Internal", +}; + +dictionary AddressInfo { + u32 index; + Address address; + KeychainKind keychain; +}; + enum LogLevel { "Gossip", "Trace", @@ -76,6 +141,11 @@ interface LogWriter { void log(LogRecord record); }; +dictionary ChannelDataMigration { + sequence? channel_manager; + sequence> channel_monitors; +}; + interface Builder { constructor(); [Name=from_config] @@ -84,6 +154,7 @@ interface Builder { [Throws=BuildError] void set_entropy_seed_bytes(sequence seed_bytes); void set_entropy_bip39_mnemonic(Mnemonic mnemonic, string? passphrase); + void set_channel_data_migration(ChannelDataMigration migration); void set_chain_source_esplora(string server_url, EsploraSyncConfig? config); void set_chain_source_electrum(string server_url, ElectrumSyncConfig? config); void set_chain_source_bitcoind_rpc(string rpc_host, u16 rpc_port, string rpc_user, string rpc_password); @@ -91,6 +162,8 @@ interface Builder { void set_gossip_source_p2p(); void set_gossip_source_rgs(string rgs_server_url); void set_pathfinding_scores_source(string url); + void set_scoring_fee_params(ScoringFeeParameters params); + void set_scoring_decay_params(ScoringDecayParameters params); void set_liquidity_source_lsps1(PublicKey node_id, SocketAddress address, string? token); void set_liquidity_source_lsps2(PublicKey node_id, SocketAddress address, string? token); void set_storage_dir_path(string storage_dir_path); @@ -98,6 +171,8 @@ interface Builder { void set_log_facade_logger(); void set_custom_logger(LogWriter log_writer); void set_network(Network network); + void set_address_type(AddressType address_type); + void set_address_types_to_monitor(sequence address_types_to_monitor); [Throws=BuildError] void set_listening_addresses(sequence listening_addresses); [Throws=BuildError] @@ -139,6 +214,9 @@ interface Node { Bolt12Payment bolt12_payment(); SpontaneousPayment spontaneous_payment(); OnchainPayment onchain_payment(); + TransactionDetails? get_transaction_details([ByRef]Txid txid); + [Throws=NodeError] + u64 get_address_balance([ByRef]string address_str); UnifiedQrPayment unified_qr_payment(); LSPS1Liquidity lsps1_liquidity(); [Throws=NodeError] @@ -165,6 +243,28 @@ interface Node { [Throws=NodeError] void remove_payment([ByRef]PaymentId payment_id); BalanceDetails list_balances(); + [Throws=NodeError] + AddressTypeBalance get_balance_for_address_type(AddressType address_type); + sequence list_monitored_address_types(); + [Throws=NodeError] + void add_address_type_to_monitor(AddressType address_type, sequence seed_bytes); + [Throws=NodeError] + void add_address_type_to_monitor_with_mnemonic(AddressType address_type, Mnemonic mnemonic, string? passphrase); + [Throws=NodeError] + void remove_address_type_from_monitor(AddressType address_type); + [Throws=NodeError] + void set_primary_address_type(AddressType address_type, sequence seed_bytes); + [Throws=NodeError] + void set_primary_address_type_with_mnemonic(AddressType address_type, Mnemonic mnemonic, string? passphrase); + [Throws=NodeError] + string export_onchain_wallet_account_xpub(AddressType address_type, u32 account_index); + [Throws=NodeError] + void add_onchain_wallet_account(AddressType address_type, u32 account_index, string xpub); + [Throws=NodeError] + void remove_onchain_wallet_account(AddressType address_type, u32 account_index); + [Throws=NodeError] + AddressTypeBalance get_balance_for_onchain_wallet_account(AddressType address_type, u32 account_index); + sequence list_onchain_wallet_accounts(); sequence list_payments(); sequence list_peers(); sequence list_channels(); @@ -173,6 +273,9 @@ interface Node { boolean verify_signature([ByRef]sequence msg, [ByRef]string sig, [ByRef]PublicKey pkey); [Throws=NodeError] bytes export_pathfinding_scores(); + [Throws=NodeError] + void update_sync_intervals(RuntimeSyncIntervals intervals); + RuntimeSyncIntervals current_sync_intervals(); }; [Enum] @@ -187,9 +290,9 @@ interface Bolt11Payment { [Throws=NodeError] PaymentId send_using_amount([ByRef]Bolt11Invoice invoice, u64 amount_msat, RouteParametersConfig? route_parameters); [Throws=NodeError] - void send_probes([ByRef]Bolt11Invoice invoice, RouteParametersConfig? route_parameters); + sequence send_probes([ByRef]Bolt11Invoice invoice, RouteParametersConfig? route_parameters); [Throws=NodeError] - void send_probes_using_amount([ByRef]Bolt11Invoice invoice, u64 amount_msat, RouteParametersConfig? route_parameters); + sequence send_probes_using_amount([ByRef]Bolt11Invoice invoice, u64 amount_msat, RouteParametersConfig? route_parameters); [Throws=NodeError] void claim_for_hash(PaymentHash payment_hash, u64 claimable_amount_msat, PaymentPreimage preimage); [Throws=NodeError] @@ -210,6 +313,10 @@ interface Bolt11Payment { Bolt11Invoice receive_variable_amount_via_jit_channel([ByRef]Bolt11InvoiceDescription description, u32 expiry_secs, u64? max_proportional_lsp_fee_limit_ppm_msat); [Throws=NodeError] Bolt11Invoice receive_variable_amount_via_jit_channel_for_hash([ByRef]Bolt11InvoiceDescription description, u32 expiry_secs, u64? max_proportional_lsp_fee_limit_ppm_msat, PaymentHash payment_hash); + [Throws=NodeError] + u64 estimate_routing_fees([ByRef]Bolt11Invoice invoice); + [Throws=NodeError] + u64 estimate_routing_fees_using_amount([ByRef]Bolt11Invoice invoice, u64 amount_msat); }; interface Bolt12Payment { @@ -243,16 +350,64 @@ interface SpontaneousPayment { [Throws=NodeError] PaymentId send_with_preimage_and_custom_tlvs(u64 amount_msat, PublicKey node_id, sequence custom_tlvs, PaymentPreimage preimage, RouteParametersConfig? route_parameters); [Throws=NodeError] - void send_probes(u64 amount_msat, PublicKey node_id); + sequence send_probes(u64 amount_msat, PublicKey node_id); }; interface OnchainPayment { - [Throws=NodeError] - Address new_address(); - [Throws=NodeError] - Txid send_to_address([ByRef]Address address, u64 amount_sats, FeeRate? fee_rate); - [Throws=NodeError] - Txid send_all_to_address([ByRef]Address address, boolean retain_reserve, FeeRate? fee_rate); + [Throws=NodeError] + Address new_address(); + [Throws=NodeError] + AddressInfo new_address_info(); + [Throws=NodeError] + Address new_address_for_type(AddressType address_type); + [Throws=NodeError] + AddressInfo new_address_info_for_type(AddressType address_type); + [Throws=NodeError] + Address new_address_for_account(AddressType address_type, u32 account_index); + [Throws=NodeError] + AddressInfo new_address_info_for_account(AddressType address_type, u32 account_index); + [Throws=NodeError] + AddressInfo address_info_for_type_at_index(AddressType address_type, KeychainKind keychain, u32 index); + [Throws=NodeError] + AddressInfo address_info_for_account_at_index(AddressType address_type, u32 account_index, KeychainKind keychain, u32 index); + [Throws=NodeError] + sequence address_infos_for_type(AddressType address_type, KeychainKind keychain, u32 start_index, u32 count); + [Throws=NodeError] + sequence address_infos_for_account(AddressType address_type, u32 account_index, KeychainKind keychain, u32 start_index, u32 count); + [Throws=NodeError] + void reveal_receive_addresses_to(AddressType address_type, u32 index); + [Throws=NodeError] + void reveal_receive_addresses_to_account(AddressType address_type, u32 account_index, u32 index); + [Throws=NodeError] + sequence list_spendable_outputs(); + [Throws=NodeError] + sequence select_utxos_with_algorithm(u64 target_amount_sats, FeeRate? fee_rate, CoinSelectionAlgorithm algorithm, sequence? utxos); + [Throws=NodeError] + Txid send_to_address([ByRef]Address address, u64 amount_sats, FeeRate? fee_rate, sequence? utxos_to_spend); + [Throws=NodeError] + Txid send_all_to_address([ByRef]Address address, boolean retain_reserve, FeeRate? fee_rate); + [Throws=NodeError] + Txid bump_fee_by_rbf([ByRef]Txid txid, FeeRate fee_rate); + [Throws=NodeError] + Txid accelerate_by_cpfp([ByRef]Txid txid, FeeRate? fee_rate, Address? destination_address); + [Throws=NodeError] + FeeRate calculate_cpfp_fee_rate([ByRef]Txid parent_txid, boolean urgent); + [Throws=NodeError] + u64 calculate_total_fee([ByRef]Address address, u64 amount_sats, FeeRate? fee_rate, sequence? utxos_to_spend); + [Throws=NodeError] + u64 calculate_send_all_fee([ByRef]Address address, boolean retain_reserves, FeeRate? fee_rate); +}; + +enum CoinSelectionAlgorithm { + "BranchAndBound", + "LargestFirst", + "OldestFirst", + "SingleRandomDraw", +}; + +dictionary SpendableUtxo { + OutPoint outpoint; + u64 value_sats; }; interface FeeRate { @@ -292,6 +447,7 @@ enum NodeError { "PaymentSendingFailed", "InvalidCustomTlvs", "ProbeSendingFailed", + "RouteNotFound", "ChannelCreationFailed", "ChannelClosingFailed", "ChannelSplicingFailed", @@ -336,6 +492,18 @@ enum NodeError { "LiquidityFeeTooHigh", "InvalidBlindedPaths", "AsyncPaymentServicesDisabled", + "CannotRbfFundingTransaction", + "TransactionNotFound", + "TransactionAlreadyConfirmed", + "NoSpendableOutputs", + "CoinSelectionFailed", + "InvalidMnemonic", + "BackgroundSyncNotEnabled", + "AddressTypeAlreadyMonitored", + "AddressTypeIsPrimary", + "AddressTypeNotMonitored", + "OnchainWalletAccountNotRegistered", + "InvalidSeedBytes", }; dictionary NodeStatus { @@ -366,6 +534,7 @@ enum BuildError { "InvalidNodeAlias", "RuntimeSetupFailed", "ReadFailed", + "DangerousValue", "WriteFailed", "StoragePathAccessFailed", "KVStoreSetupFailed", @@ -389,6 +558,34 @@ enum VssHeaderProviderError { "InternalError", }; +dictionary TxInput { + Txid txid; + u32 vout; + string scriptsig; + sequence witness; + u32 sequence; +}; + +dictionary TxOutput { + string scriptpubkey; + string? scriptpubkey_type; + string? scriptpubkey_address; + i64 value; + u32 n; +}; + +dictionary TransactionDetails { + i64 amount_sats; + sequence inputs; + sequence outputs; +}; + +enum SyncType { + "OnchainWallet", + "LightningWallet", + "FeeRateCache", +}; + [Enum] interface Event { PaymentSuccessful(PaymentId? payment_id, PaymentHash payment_hash, PaymentPreimage? payment_preimage, u64? fee_paid_msat); @@ -397,11 +594,21 @@ interface Event { PaymentClaimable(PaymentId payment_id, PaymentHash payment_hash, u64 claimable_amount_msat, u32? claim_deadline, sequence custom_records); PaymentForwarded(ChannelId prev_channel_id, ChannelId next_channel_id, UserChannelId? prev_user_channel_id, UserChannelId? next_user_channel_id, PublicKey? prev_node_id, PublicKey? next_node_id, u64? total_fee_earned_msat, u64? skimmed_fee_msat, boolean claim_from_onchain_tx, u64? outbound_amount_forwarded_msat); + ProbeSuccessful(PaymentId payment_id, PaymentHash payment_hash, u64? route_fee_msat); + ProbeFailed(PaymentId payment_id, PaymentHash payment_hash, u64? short_channel_id, u64? route_fee_msat); ChannelPending(ChannelId channel_id, UserChannelId user_channel_id, ChannelId former_temporary_channel_id, PublicKey counterparty_node_id, OutPoint funding_txo); ChannelReady(ChannelId channel_id, UserChannelId user_channel_id, PublicKey? counterparty_node_id, OutPoint? funding_txo); ChannelClosed(ChannelId channel_id, UserChannelId user_channel_id, PublicKey? counterparty_node_id, ClosureReason? reason); SplicePending(ChannelId channel_id, UserChannelId user_channel_id, PublicKey counterparty_node_id, OutPoint new_funding_txo); SpliceFailed(ChannelId channel_id, UserChannelId user_channel_id, PublicKey counterparty_node_id, OutPoint? abandoned_funding_txo); + OnchainTransactionConfirmed(Txid txid, BlockHash block_hash, u32 block_height, u64 confirmation_time, TransactionDetails details); + OnchainTransactionReceived(Txid txid, TransactionDetails details); + OnchainTransactionReplaced(Txid txid, sequence conflicts); + OnchainTransactionReorged(Txid txid); + OnchainTransactionEvicted(Txid txid); + SyncProgress(SyncType sync_type, u8 progress_percent, u32 current_block_height, u32 target_block_height); + SyncCompleted(SyncType sync_type, u32 synced_block_height); + BalanceChanged(u64 old_spendable_onchain_balance_sats, u64 new_spendable_onchain_balance_sats, u64 old_total_onchain_balance_sats, u64 new_total_onchain_balance_sats, u64 old_total_lightning_balance_sats, u64 new_total_lightning_balance_sats); }; enum PaymentFailureReason { @@ -439,8 +646,8 @@ interface ClosureReason { [Enum] interface PaymentKind { Onchain(Txid txid, ConfirmationStatus status); - Bolt11(PaymentHash hash, PaymentPreimage? preimage, PaymentSecret? secret); - Bolt11Jit(PaymentHash hash, PaymentPreimage? preimage, PaymentSecret? secret, u64? counterparty_skimmed_fee_msat, LSPFeeLimits lsp_fee_limits); + Bolt11(PaymentHash hash, PaymentPreimage? preimage, PaymentSecret? secret, string? description, string? bolt11); + Bolt11Jit(PaymentHash hash, PaymentPreimage? preimage, PaymentSecret? secret, u64? counterparty_skimmed_fee_msat, LSPFeeLimits lsp_fee_limits, string? description, string? bolt11); Bolt12Offer(PaymentHash? hash, PaymentPreimage? preimage, PaymentSecret? secret, OfferId offer_id, UntrustedString? payer_note, u64? quantity); Bolt12Refund(PaymentHash? hash, PaymentPreimage? preimage, PaymentSecret? secret, UntrustedString? payer_note, u64? quantity); Spontaneous(PaymentHash hash, PaymentPreimage? preimage); @@ -492,6 +699,11 @@ dictionary RouteParametersConfig { u8 max_channel_saturation_power_of_half; }; +dictionary ProbeHandle { + PaymentHash payment_hash; + PaymentId payment_id; +}; + dictionary CustomTlvRecord { u64 type_num; sequence value; @@ -595,6 +807,7 @@ dictionary ChannelDetails { u64 inbound_htlc_minimum_msat; u64? inbound_htlc_maximum_msat; ChannelConfig config; + u64? claimable_on_close_sats; }; dictionary PeerDetails { @@ -676,6 +889,11 @@ dictionary BalanceDetails { sequence pending_balances_from_channel_closures; }; +dictionary AddressTypeBalance { + u64 total_sats; + u64 spendable_sats; +}; + dictionary ChannelConfig { u32 forwarding_fee_proportional_millionths; u32 forwarding_fee_base_msat; diff --git a/bindings/python/pyproject.toml b/bindings/python/pyproject.toml index 496781a6a5..ea3b28162e 100644 --- a/bindings/python/pyproject.toml +++ b/bindings/python/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "ldk_node" -version = "0.6.0" +version = "0.7.0-rc.63" authors = [ { name="Elias Rohrer", email="dev@tnull.de" }, ] diff --git a/bindings/python/src/ldk_node/ldk_node.py b/bindings/python/src/ldk_node/ldk_node.py new file mode 100644 index 0000000000..0dda20db99 --- /dev/null +++ b/bindings/python/src/ldk_node/ldk_node.py @@ -0,0 +1,17744 @@ + + +# This file was autogenerated by some hot garbage in the `uniffi` crate. +# Trust me, you don't want to mess with it! + +# Common helper code. +# +# Ideally this would live in a separate .py file where it can be unittested etc +# in isolation, and perhaps even published as a re-useable package. +# +# However, it's important that the details of how this helper code works (e.g. the +# way that different builtin types are passed across the FFI) exactly match what's +# expected by the rust code on the other side of the interface. In practice right +# now that means coming from the exact some version of `uniffi` that was used to +# compile the rust component. The easiest way to ensure this is to bundle the Python +# helpers directly inline like we're doing here. + +from __future__ import annotations +import os +import sys +import ctypes +import enum +import struct +import contextlib +import datetime +import threading +import itertools +import traceback +import typing +import asyncio +import platform + +# Used for default argument values +_DEFAULT = object() # type: typing.Any + + +class _UniffiRustBuffer(ctypes.Structure): + _fields_ = [ + ("capacity", ctypes.c_uint64), + ("len", ctypes.c_uint64), + ("data", ctypes.POINTER(ctypes.c_char)), + ] + + @staticmethod + def default(): + return _UniffiRustBuffer(0, 0, None) + + @staticmethod + def alloc(size): + return _uniffi_rust_call(_UniffiLib.ffi_ldk_node_rustbuffer_alloc, size) + + @staticmethod + def reserve(rbuf, additional): + return _uniffi_rust_call(_UniffiLib.ffi_ldk_node_rustbuffer_reserve, rbuf, additional) + + def free(self): + return _uniffi_rust_call(_UniffiLib.ffi_ldk_node_rustbuffer_free, self) + + def __str__(self): + return "_UniffiRustBuffer(capacity={}, len={}, data={})".format( + self.capacity, + self.len, + self.data[0:self.len] + ) + + @contextlib.contextmanager + def alloc_with_builder(*args): + """Context-manger to allocate a buffer using a _UniffiRustBufferBuilder. + + The allocated buffer will be automatically freed if an error occurs, ensuring that + we don't accidentally leak it. + """ + builder = _UniffiRustBufferBuilder() + try: + yield builder + except: + builder.discard() + raise + + @contextlib.contextmanager + def consume_with_stream(self): + """Context-manager to consume a buffer using a _UniffiRustBufferStream. + + The _UniffiRustBuffer will be freed once the context-manager exits, ensuring that we don't + leak it even if an error occurs. + """ + try: + s = _UniffiRustBufferStream.from_rust_buffer(self) + yield s + if s.remaining() != 0: + raise RuntimeError("junk data left in buffer at end of consume_with_stream") + finally: + self.free() + + @contextlib.contextmanager + def read_with_stream(self): + """Context-manager to read a buffer using a _UniffiRustBufferStream. + + This is like consume_with_stream, but doesn't free the buffer afterwards. + It should only be used with borrowed `_UniffiRustBuffer` data. + """ + s = _UniffiRustBufferStream.from_rust_buffer(self) + yield s + if s.remaining() != 0: + raise RuntimeError("junk data left in buffer at end of read_with_stream") + +class _UniffiForeignBytes(ctypes.Structure): + _fields_ = [ + ("len", ctypes.c_int32), + ("data", ctypes.POINTER(ctypes.c_char)), + ] + + def __str__(self): + return "_UniffiForeignBytes(len={}, data={})".format(self.len, self.data[0:self.len]) + + +class _UniffiRustBufferStream: + """ + Helper for structured reading of bytes from a _UniffiRustBuffer + """ + + def __init__(self, data, len): + self.data = data + self.len = len + self.offset = 0 + + @classmethod + def from_rust_buffer(cls, buf): + return cls(buf.data, buf.len) + + def remaining(self): + return self.len - self.offset + + def _unpack_from(self, size, format): + if self.offset + size > self.len: + raise InternalError("read past end of rust buffer") + value = struct.unpack(format, self.data[self.offset:self.offset+size])[0] + self.offset += size + return value + + def read(self, size): + if self.offset + size > self.len: + raise InternalError("read past end of rust buffer") + data = self.data[self.offset:self.offset+size] + self.offset += size + return data + + def read_i8(self): + return self._unpack_from(1, ">b") + + def read_u8(self): + return self._unpack_from(1, ">B") + + def read_i16(self): + return self._unpack_from(2, ">h") + + def read_u16(self): + return self._unpack_from(2, ">H") + + def read_i32(self): + return self._unpack_from(4, ">i") + + def read_u32(self): + return self._unpack_from(4, ">I") + + def read_i64(self): + return self._unpack_from(8, ">q") + + def read_u64(self): + return self._unpack_from(8, ">Q") + + def read_float(self): + v = self._unpack_from(4, ">f") + return v + + def read_double(self): + return self._unpack_from(8, ">d") + +class _UniffiRustBufferBuilder: + """ + Helper for structured writing of bytes into a _UniffiRustBuffer. + """ + + def __init__(self): + self.rbuf = _UniffiRustBuffer.alloc(16) + self.rbuf.len = 0 + + def finalize(self): + rbuf = self.rbuf + self.rbuf = None + return rbuf + + def discard(self): + if self.rbuf is not None: + rbuf = self.finalize() + rbuf.free() + + @contextlib.contextmanager + def _reserve(self, num_bytes): + if self.rbuf.len + num_bytes > self.rbuf.capacity: + self.rbuf = _UniffiRustBuffer.reserve(self.rbuf, num_bytes) + yield None + self.rbuf.len += num_bytes + + def _pack_into(self, size, format, value): + with self._reserve(size): + # XXX TODO: I feel like I should be able to use `struct.pack_into` here but can't figure it out. + for i, byte in enumerate(struct.pack(format, value)): + self.rbuf.data[self.rbuf.len + i] = byte + + def write(self, value): + with self._reserve(len(value)): + for i, byte in enumerate(value): + self.rbuf.data[self.rbuf.len + i] = byte + + def write_i8(self, v): + self._pack_into(1, ">b", v) + + def write_u8(self, v): + self._pack_into(1, ">B", v) + + def write_i16(self, v): + self._pack_into(2, ">h", v) + + def write_u16(self, v): + self._pack_into(2, ">H", v) + + def write_i32(self, v): + self._pack_into(4, ">i", v) + + def write_u32(self, v): + self._pack_into(4, ">I", v) + + def write_i64(self, v): + self._pack_into(8, ">q", v) + + def write_u64(self, v): + self._pack_into(8, ">Q", v) + + def write_float(self, v): + self._pack_into(4, ">f", v) + + def write_double(self, v): + self._pack_into(8, ">d", v) + + def write_c_size_t(self, v): + self._pack_into(ctypes.sizeof(ctypes.c_size_t) , "@N", v) +# A handful of classes and functions to support the generated data structures. +# This would be a good candidate for isolating in its own ffi-support lib. + +class InternalError(Exception): + pass + +class _UniffiRustCallStatus(ctypes.Structure): + """ + Error runtime. + """ + _fields_ = [ + ("code", ctypes.c_int8), + ("error_buf", _UniffiRustBuffer), + ] + + # These match the values from the uniffi::rustcalls module + CALL_SUCCESS = 0 + CALL_ERROR = 1 + CALL_UNEXPECTED_ERROR = 2 + + @staticmethod + def default(): + return _UniffiRustCallStatus(code=_UniffiRustCallStatus.CALL_SUCCESS, error_buf=_UniffiRustBuffer.default()) + + def __str__(self): + if self.code == _UniffiRustCallStatus.CALL_SUCCESS: + return "_UniffiRustCallStatus(CALL_SUCCESS)" + elif self.code == _UniffiRustCallStatus.CALL_ERROR: + return "_UniffiRustCallStatus(CALL_ERROR)" + elif self.code == _UniffiRustCallStatus.CALL_UNEXPECTED_ERROR: + return "_UniffiRustCallStatus(CALL_UNEXPECTED_ERROR)" + else: + return "_UniffiRustCallStatus()" + +def _uniffi_rust_call(fn, *args): + # Call a rust function + return _uniffi_rust_call_with_error(None, fn, *args) + +def _uniffi_rust_call_with_error(error_ffi_converter, fn, *args): + # Call a rust function and handle any errors + # + # This function is used for rust calls that return Result<> and therefore can set the CALL_ERROR status code. + # error_ffi_converter must be set to the _UniffiConverter for the error class that corresponds to the result. + call_status = _UniffiRustCallStatus.default() + + args_with_error = args + (ctypes.byref(call_status),) + result = fn(*args_with_error) + _uniffi_check_call_status(error_ffi_converter, call_status) + return result + +def _uniffi_check_call_status(error_ffi_converter, call_status): + if call_status.code == _UniffiRustCallStatus.CALL_SUCCESS: + pass + elif call_status.code == _UniffiRustCallStatus.CALL_ERROR: + if error_ffi_converter is None: + call_status.error_buf.free() + raise InternalError("_uniffi_rust_call_with_error: CALL_ERROR, but error_ffi_converter is None") + else: + raise error_ffi_converter.lift(call_status.error_buf) + elif call_status.code == _UniffiRustCallStatus.CALL_UNEXPECTED_ERROR: + # When the rust code sees a panic, it tries to construct a _UniffiRustBuffer + # with the message. But if that code panics, then it just sends back + # an empty buffer. + if call_status.error_buf.len > 0: + msg = _UniffiConverterString.lift(call_status.error_buf) + else: + msg = "Unknown rust panic" + raise InternalError(msg) + else: + raise InternalError("Invalid _UniffiRustCallStatus code: {}".format( + call_status.code)) + +def _uniffi_trait_interface_call(call_status, make_call, write_return_value): + try: + return write_return_value(make_call()) + except Exception as e: + call_status.code = _UniffiRustCallStatus.CALL_UNEXPECTED_ERROR + call_status.error_buf = _UniffiConverterString.lower(repr(e)) + +def _uniffi_trait_interface_call_with_error(call_status, make_call, write_return_value, error_type, lower_error): + try: + try: + return write_return_value(make_call()) + except error_type as e: + call_status.code = _UniffiRustCallStatus.CALL_ERROR + call_status.error_buf = lower_error(e) + except Exception as e: + call_status.code = _UniffiRustCallStatus.CALL_UNEXPECTED_ERROR + call_status.error_buf = _UniffiConverterString.lower(repr(e)) +class _UniffiHandleMap: + """ + A map where inserting, getting and removing data is synchronized with a lock. + """ + + def __init__(self): + # type Handle = int + self._map = {} # type: Dict[Handle, Any] + self._lock = threading.Lock() + self._counter = itertools.count() + + def insert(self, obj): + with self._lock: + handle = next(self._counter) + self._map[handle] = obj + return handle + + def get(self, handle): + try: + with self._lock: + return self._map[handle] + except KeyError: + raise InternalError("_UniffiHandleMap.get: Invalid handle") + + def remove(self, handle): + try: + with self._lock: + return self._map.pop(handle) + except KeyError: + raise InternalError("_UniffiHandleMap.remove: Invalid handle") + + def __len__(self): + return len(self._map) +# Types conforming to `_UniffiConverterPrimitive` pass themselves directly over the FFI. +class _UniffiConverterPrimitive: + @classmethod + def lift(cls, value): + return value + + @classmethod + def lower(cls, value): + return value + +class _UniffiConverterPrimitiveInt(_UniffiConverterPrimitive): + @classmethod + def check_lower(cls, value): + try: + value = value.__index__() + except Exception: + raise TypeError("'{}' object cannot be interpreted as an integer".format(type(value).__name__)) + if not isinstance(value, int): + raise TypeError("__index__ returned non-int (type {})".format(type(value).__name__)) + if not cls.VALUE_MIN <= value < cls.VALUE_MAX: + raise ValueError("{} requires {} <= value < {}".format(cls.CLASS_NAME, cls.VALUE_MIN, cls.VALUE_MAX)) + +class _UniffiConverterPrimitiveFloat(_UniffiConverterPrimitive): + @classmethod + def check_lower(cls, value): + try: + value = value.__float__() + except Exception: + raise TypeError("must be real number, not {}".format(type(value).__name__)) + if not isinstance(value, float): + raise TypeError("__float__ returned non-float (type {})".format(type(value).__name__)) + +# Helper class for wrapper types that will always go through a _UniffiRustBuffer. +# Classes should inherit from this and implement the `read` and `write` static methods. +class _UniffiConverterRustBuffer: + @classmethod + def lift(cls, rbuf): + with rbuf.consume_with_stream() as stream: + return cls.read(stream) + + @classmethod + def lower(cls, value): + with _UniffiRustBuffer.alloc_with_builder() as builder: + cls.write(value, builder) + return builder.finalize() + +# Contains loading, initialization code, and the FFI Function declarations. +# Define some ctypes FFI types that we use in the library + +""" +Function pointer for a Rust task, which a callback function that takes a opaque pointer +""" +_UNIFFI_RUST_TASK = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_int8) + +def _uniffi_future_callback_t(return_type): + """ + Factory function to create callback function types for async functions + """ + return ctypes.CFUNCTYPE(None, ctypes.c_uint64, return_type, _UniffiRustCallStatus) + +def _uniffi_load_indirect(): + """ + This is how we find and load the dynamic library provided by the component. + For now we just look it up by name. + """ + if sys.platform == "darwin": + libname = "lib{}.dylib" + elif sys.platform.startswith("win"): + # As of python3.8, ctypes does not seem to search $PATH when loading DLLs. + # We could use `os.add_dll_directory` to configure the search path, but + # it doesn't feel right to mess with application-wide settings. Let's + # assume that the `.dll` is next to the `.py` file and load by full path. + libname = os.path.join( + os.path.dirname(__file__), + "{}.dll", + ) + else: + # Anything else must be an ELF platform - Linux, *BSD, Solaris/illumos + libname = "lib{}.so" + + libname = libname.format("ldk_node") + path = os.path.join(os.path.dirname(__file__), libname) + lib = ctypes.cdll.LoadLibrary(path) + return lib + +def _uniffi_check_contract_api_version(lib): + # Get the bindings contract version from our ComponentInterface + bindings_contract_version = 26 + # Get the scaffolding contract version by calling the into the dylib + scaffolding_contract_version = lib.ffi_ldk_node_uniffi_contract_version() + if bindings_contract_version != scaffolding_contract_version: + raise InternalError("UniFFI contract version mismatch: try cleaning and rebuilding your project") + +def _uniffi_check_api_checksums(lib): + if lib.uniffi_ldk_node_checksum_func_battery_saving_sync_intervals() != 25473: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_func_default_config() != 55381: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_func_derive_node_secret_from_mnemonic() != 15067: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_func_generate_entropy_mnemonic() != 48014: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11invoice_amount_milli_satoshis() != 50823: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11invoice_currency() != 32179: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11invoice_expiry_time_seconds() != 23625: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11invoice_fallback_addresses() != 55276: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11invoice_invoice_description() != 395: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11invoice_is_expired() != 15932: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11invoice_min_final_cltv_expiry_delta() != 8855: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11invoice_network() != 10420: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11invoice_payment_hash() != 42571: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11invoice_payment_secret() != 26081: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11invoice_recover_payee_pub_key() != 18874: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11invoice_route_hints() != 63051: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11invoice_seconds_since_epoch() != 53979: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11invoice_seconds_until_expiry() != 64193: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11invoice_signable_hash() != 30910: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11invoice_would_expire() != 30331: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11payment_claim_for_hash() != 52848: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11payment_estimate_routing_fees() != 5123: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11payment_estimate_routing_fees_using_amount() != 46411: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11payment_fail_for_hash() != 24516: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11payment_receive() != 6073: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11payment_receive_for_hash() != 27050: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount() != 4893: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount_for_hash() != 1402: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount_via_jit_channel() != 24506: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount_via_jit_channel_for_hash() != 38025: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11payment_receive_via_jit_channel() != 16532: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11payment_receive_via_jit_channel_for_hash() != 1143: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11payment_send() != 12953: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11payment_send_probes() != 16067: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11payment_send_probes_using_amount() != 37281: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt11payment_send_using_amount() != 42793: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt12invoice_absolute_expiry_seconds() != 28589: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt12invoice_amount() != 5213: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt12invoice_amount_msats() != 9297: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt12invoice_chain() != 3308: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt12invoice_created_at() != 56866: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt12invoice_encode() != 13200: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt12invoice_fallback_addresses() != 7925: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt12invoice_invoice_description() != 1713: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt12invoice_is_expired() != 39560: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt12invoice_issuer() != 65270: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt12invoice_issuer_signing_pubkey() != 55411: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt12invoice_metadata() != 37374: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt12invoice_offer_chains() != 39622: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt12invoice_payer_note() != 28018: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt12invoice_payer_signing_pubkey() != 12798: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt12invoice_payment_hash() != 63778: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt12invoice_quantity() != 43105: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt12invoice_relative_expiry() != 14024: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt12invoice_signable_hash() != 39303: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt12invoice_signing_pubkey() != 35202: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt12payment_blinded_paths_for_async_recipient() != 14695: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt12payment_initiate_refund() != 15019: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt12payment_receive() != 59252: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt12payment_receive_async() != 23867: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt12payment_receive_variable_amount() != 35484: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt12payment_request_refund_payment() != 43248: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt12payment_send() != 27679: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt12payment_send_using_amount() != 33255: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_bolt12payment_set_paths_to_static_invoice_server() != 20921: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_build() != 785: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_build_with_fs_store() != 61304: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_build_with_vss_store() != 2871: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_build_with_vss_store_and_fixed_headers() != 24910: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_build_with_vss_store_and_header_provider() != 9090: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_set_address_type() != 647: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_set_address_types_to_monitor() != 23561: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_set_announcement_addresses() != 39271: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_set_async_payments_role() != 16463: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_set_chain_source_bitcoind_rest() != 37382: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_set_chain_source_bitcoind_rpc() != 2111: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_set_chain_source_electrum() != 55552: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_set_chain_source_esplora() != 1781: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_set_channel_data_migration() != 58453: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_set_custom_logger() != 51232: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_set_entropy_bip39_mnemonic() != 827: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_set_entropy_seed_bytes() != 44799: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_set_entropy_seed_path() != 64056: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_set_filesystem_logger() != 10249: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_set_gossip_source_p2p() != 9279: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_set_gossip_source_rgs() != 64312: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_set_liquidity_source_lsps1() != 51527: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_set_liquidity_source_lsps2() != 14430: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_set_listening_addresses() != 14051: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_set_log_facade_logger() != 58410: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_set_network() != 27539: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_set_node_alias() != 18342: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_set_pathfinding_scores_source() != 63501: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_set_scoring_decay_params() != 19869: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_set_scoring_fee_params() != 11588: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_builder_set_storage_dir_path() != 59019: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_feerate_to_sat_per_kwu() != 58911: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_feerate_to_sat_per_vb_ceil() != 58575: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_feerate_to_sat_per_vb_floor() != 59617: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_lsps1liquidity_check_order_status() != 48853: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_lsps1liquidity_request_channel() != 5951: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_logwriter_log() != 3299: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_networkgraph_channel() != 38070: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_networkgraph_list_channels() != 4693: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_networkgraph_list_nodes() != 36715: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_networkgraph_node() != 48925: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_add_address_type_to_monitor() != 14706: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_add_address_type_to_monitor_with_mnemonic() != 4517: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_add_onchain_wallet_account() != 37245: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_announcement_addresses() != 61426: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_bolt11_payment() != 41402: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_bolt12_payment() != 49254: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_close_channel() != 62479: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_config() != 7511: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_connect() != 34120: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_current_sync_intervals() != 51918: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_disconnect() != 43538: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_event_handled() != 38712: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_export_onchain_wallet_account_xpub() != 5977: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_export_pathfinding_scores() != 62331: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_force_close_channel() != 48831: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_get_address_balance() != 45284: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_get_balance_for_address_type() != 34906: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_get_balance_for_onchain_wallet_account() != 18159: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_get_transaction_details() != 65000: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_list_balances() != 57528: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_list_channels() != 7954: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_list_monitored_address_types() != 25084: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_list_onchain_wallet_accounts() != 4403: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_list_payments() != 35002: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_list_peers() != 14889: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_listening_addresses() != 2665: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_lsps1_liquidity() != 5633: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_network_graph() != 2695: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_next_event() != 7682: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_next_event_async() != 25426: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_node_alias() != 29526: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_node_id() != 51489: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_onchain_payment() != 6092: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_open_announced_channel() != 36623: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_open_channel() != 40283: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_payment() != 60296: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_remove_address_type_from_monitor() != 37081: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_remove_onchain_wallet_account() != 21186: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_remove_payment() != 47952: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_set_primary_address_type() != 11005: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_set_primary_address_type_with_mnemonic() != 50783: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_sign_message() != 49319: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_splice_in() != 46431: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_splice_out() != 22115: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_spontaneous_payment() != 37403: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_start() != 58480: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_status() != 55952: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_stop() != 42188: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_sync_wallets() != 32474: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_unified_qr_payment() != 9837: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_update_channel_config() != 37852: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_update_sync_intervals() != 42322: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_verify_signature() != 20486: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_node_wait_next_event() != 55101: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_offer_absolute_expiry_seconds() != 22836: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_offer_amount() != 59890: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_offer_chains() != 59522: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_offer_expects_quantity() != 58457: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_offer_id() != 8391: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_offer_is_expired() != 22651: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_offer_is_valid_quantity() != 58469: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_offer_issuer() != 41632: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_offer_issuer_signing_pubkey() != 38162: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_offer_metadata() != 18979: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_offer_offer_description() != 11122: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_offer_supports_chain() != 2135: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_onchainpayment_accelerate_by_cpfp() != 31954: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_onchainpayment_address_info_for_account_at_index() != 63246: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_onchainpayment_address_info_for_type_at_index() != 42692: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_onchainpayment_address_infos_for_account() != 39321: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_onchainpayment_address_infos_for_type() != 3701: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_onchainpayment_bump_fee_by_rbf() != 53877: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_onchainpayment_calculate_cpfp_fee_rate() != 32879: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_onchainpayment_calculate_send_all_fee() != 16052: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_onchainpayment_calculate_total_fee() != 57218: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_onchainpayment_list_spendable_outputs() != 19144: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_onchainpayment_new_address() != 37251: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_onchainpayment_new_address_for_account() != 9932: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_onchainpayment_new_address_for_type() != 9083: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_onchainpayment_new_address_info() != 9889: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_onchainpayment_new_address_info_for_account() != 30767: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_onchainpayment_new_address_info_for_type() != 62171: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_onchainpayment_reveal_receive_addresses_to() != 44189: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_onchainpayment_reveal_receive_addresses_to_account() != 53588: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_onchainpayment_select_utxos_with_algorithm() != 14084: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_onchainpayment_send_all_to_address() != 37748: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_onchainpayment_send_to_address() != 28826: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_refund_absolute_expiry_seconds() != 43722: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_refund_amount_msats() != 26467: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_refund_chain() != 36565: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_refund_is_expired() != 10232: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_refund_issuer() != 40306: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_refund_payer_metadata() != 23501: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_refund_payer_note() != 47799: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_refund_payer_signing_pubkey() != 40880: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_refund_quantity() != 15192: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_refund_refund_description() != 39295: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_spontaneouspayment_send() != 27905: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_spontaneouspayment_send_probes() != 44206: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_spontaneouspayment_send_with_custom_tlvs() != 17876: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_spontaneouspayment_send_with_preimage() != 30854: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_spontaneouspayment_send_with_preimage_and_custom_tlvs() != 12104: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_unifiedqrpayment_receive() != 913: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_unifiedqrpayment_send() != 28285: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_method_vssheaderprovider_get_headers() != 7788: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_constructor_bolt11invoice_from_str() != 349: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_constructor_bolt12invoice_from_str() != 22276: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_constructor_builder_from_config() != 994: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_constructor_builder_new() != 40499: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_constructor_feerate_from_sat_per_kwu() != 50548: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_constructor_feerate_from_sat_per_vb_unchecked() != 41808: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_constructor_offer_from_str() != 37070: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_ldk_node_checksum_constructor_refund_from_str() != 64884: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + +# A ctypes library to expose the extern-C FFI definitions. +# This is an implementation detail which will be called internally by the public API. + +_UniffiLib = _uniffi_load_indirect() +_UNIFFI_RUST_FUTURE_CONTINUATION_CALLBACK = ctypes.CFUNCTYPE(None,ctypes.c_uint64,ctypes.c_int8, +) +_UNIFFI_FOREIGN_FUTURE_FREE = ctypes.CFUNCTYPE(None,ctypes.c_uint64, +) +_UNIFFI_CALLBACK_INTERFACE_FREE = ctypes.CFUNCTYPE(None,ctypes.c_uint64, +) +class _UniffiForeignFuture(ctypes.Structure): + _fields_ = [ + ("handle", ctypes.c_uint64), + ("free", _UNIFFI_FOREIGN_FUTURE_FREE), + ] +class _UniffiForeignFutureStructU8(ctypes.Structure): + _fields_ = [ + ("return_value", ctypes.c_uint8), + ("call_status", _UniffiRustCallStatus), + ] +_UNIFFI_FOREIGN_FUTURE_COMPLETE_U8 = ctypes.CFUNCTYPE(None,ctypes.c_uint64,_UniffiForeignFutureStructU8, +) +class _UniffiForeignFutureStructI8(ctypes.Structure): + _fields_ = [ + ("return_value", ctypes.c_int8), + ("call_status", _UniffiRustCallStatus), + ] +_UNIFFI_FOREIGN_FUTURE_COMPLETE_I8 = ctypes.CFUNCTYPE(None,ctypes.c_uint64,_UniffiForeignFutureStructI8, +) +class _UniffiForeignFutureStructU16(ctypes.Structure): + _fields_ = [ + ("return_value", ctypes.c_uint16), + ("call_status", _UniffiRustCallStatus), + ] +_UNIFFI_FOREIGN_FUTURE_COMPLETE_U16 = ctypes.CFUNCTYPE(None,ctypes.c_uint64,_UniffiForeignFutureStructU16, +) +class _UniffiForeignFutureStructI16(ctypes.Structure): + _fields_ = [ + ("return_value", ctypes.c_int16), + ("call_status", _UniffiRustCallStatus), + ] +_UNIFFI_FOREIGN_FUTURE_COMPLETE_I16 = ctypes.CFUNCTYPE(None,ctypes.c_uint64,_UniffiForeignFutureStructI16, +) +class _UniffiForeignFutureStructU32(ctypes.Structure): + _fields_ = [ + ("return_value", ctypes.c_uint32), + ("call_status", _UniffiRustCallStatus), + ] +_UNIFFI_FOREIGN_FUTURE_COMPLETE_U32 = ctypes.CFUNCTYPE(None,ctypes.c_uint64,_UniffiForeignFutureStructU32, +) +class _UniffiForeignFutureStructI32(ctypes.Structure): + _fields_ = [ + ("return_value", ctypes.c_int32), + ("call_status", _UniffiRustCallStatus), + ] +_UNIFFI_FOREIGN_FUTURE_COMPLETE_I32 = ctypes.CFUNCTYPE(None,ctypes.c_uint64,_UniffiForeignFutureStructI32, +) +class _UniffiForeignFutureStructU64(ctypes.Structure): + _fields_ = [ + ("return_value", ctypes.c_uint64), + ("call_status", _UniffiRustCallStatus), + ] +_UNIFFI_FOREIGN_FUTURE_COMPLETE_U64 = ctypes.CFUNCTYPE(None,ctypes.c_uint64,_UniffiForeignFutureStructU64, +) +class _UniffiForeignFutureStructI64(ctypes.Structure): + _fields_ = [ + ("return_value", ctypes.c_int64), + ("call_status", _UniffiRustCallStatus), + ] +_UNIFFI_FOREIGN_FUTURE_COMPLETE_I64 = ctypes.CFUNCTYPE(None,ctypes.c_uint64,_UniffiForeignFutureStructI64, +) +class _UniffiForeignFutureStructF32(ctypes.Structure): + _fields_ = [ + ("return_value", ctypes.c_float), + ("call_status", _UniffiRustCallStatus), + ] +_UNIFFI_FOREIGN_FUTURE_COMPLETE_F32 = ctypes.CFUNCTYPE(None,ctypes.c_uint64,_UniffiForeignFutureStructF32, +) +class _UniffiForeignFutureStructF64(ctypes.Structure): + _fields_ = [ + ("return_value", ctypes.c_double), + ("call_status", _UniffiRustCallStatus), + ] +_UNIFFI_FOREIGN_FUTURE_COMPLETE_F64 = ctypes.CFUNCTYPE(None,ctypes.c_uint64,_UniffiForeignFutureStructF64, +) +class _UniffiForeignFutureStructPointer(ctypes.Structure): + _fields_ = [ + ("return_value", ctypes.c_void_p), + ("call_status", _UniffiRustCallStatus), + ] +_UNIFFI_FOREIGN_FUTURE_COMPLETE_POINTER = ctypes.CFUNCTYPE(None,ctypes.c_uint64,_UniffiForeignFutureStructPointer, +) +class _UniffiForeignFutureStructRustBuffer(ctypes.Structure): + _fields_ = [ + ("return_value", _UniffiRustBuffer), + ("call_status", _UniffiRustCallStatus), + ] +_UNIFFI_FOREIGN_FUTURE_COMPLETE_RUST_BUFFER = ctypes.CFUNCTYPE(None,ctypes.c_uint64,_UniffiForeignFutureStructRustBuffer, +) +class _UniffiForeignFutureStructVoid(ctypes.Structure): + _fields_ = [ + ("call_status", _UniffiRustCallStatus), + ] +_UNIFFI_FOREIGN_FUTURE_COMPLETE_VOID = ctypes.CFUNCTYPE(None,ctypes.c_uint64,_UniffiForeignFutureStructVoid, +) +_UNIFFI_CALLBACK_INTERFACE_LOG_WRITER_METHOD0 = ctypes.CFUNCTYPE(None,ctypes.c_uint64,_UniffiRustBuffer,ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UNIFFI_CALLBACK_INTERFACE_VSS_HEADER_PROVIDER_METHOD0 = ctypes.CFUNCTYPE(None,ctypes.c_uint64,_UniffiRustBuffer,_UNIFFI_FOREIGN_FUTURE_COMPLETE_RUST_BUFFER,ctypes.c_uint64,ctypes.POINTER(_UniffiForeignFuture), +) +class _UniffiVTableCallbackInterfaceLogWriter(ctypes.Structure): + _fields_ = [ + ("log", _UNIFFI_CALLBACK_INTERFACE_LOG_WRITER_METHOD0), + ("uniffi_free", _UNIFFI_CALLBACK_INTERFACE_FREE), + ] +class _UniffiVTableCallbackInterfaceVssHeaderProvider(ctypes.Structure): + _fields_ = [ + ("get_headers", _UNIFFI_CALLBACK_INTERFACE_VSS_HEADER_PROVIDER_METHOD0), + ("uniffi_free", _UNIFFI_CALLBACK_INTERFACE_FREE), + ] +_UniffiLib.uniffi_ldk_node_fn_clone_bolt11invoice.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_clone_bolt11invoice.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_free_bolt11invoice.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_free_bolt11invoice.restype = None +_UniffiLib.uniffi_ldk_node_fn_constructor_bolt11invoice_from_str.argtypes = ( + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_constructor_bolt11invoice_from_str.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_amount_milli_satoshis.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_amount_milli_satoshis.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_currency.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_currency.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_expiry_time_seconds.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_expiry_time_seconds.restype = ctypes.c_uint64 +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_fallback_addresses.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_fallback_addresses.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_invoice_description.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_invoice_description.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_is_expired.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_is_expired.restype = ctypes.c_int8 +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_min_final_cltv_expiry_delta.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_min_final_cltv_expiry_delta.restype = ctypes.c_uint64 +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_network.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_network.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_payment_hash.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_payment_hash.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_payment_secret.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_payment_secret.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_recover_payee_pub_key.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_recover_payee_pub_key.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_route_hints.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_route_hints.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_seconds_since_epoch.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_seconds_since_epoch.restype = ctypes.c_uint64 +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_seconds_until_expiry.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_seconds_until_expiry.restype = ctypes.c_uint64 +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_signable_hash.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_signable_hash.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_would_expire.argtypes = ( + ctypes.c_void_p, + ctypes.c_uint64, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_would_expire.restype = ctypes.c_int8 +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_debug.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_debug.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_display.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_display.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_eq_eq.argtypes = ( + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_eq_eq.restype = ctypes.c_int8 +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_eq_ne.argtypes = ( + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_eq_ne.restype = ctypes.c_int8 +_UniffiLib.uniffi_ldk_node_fn_clone_bolt11payment.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_clone_bolt11payment.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_free_bolt11payment.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_free_bolt11payment.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_claim_for_hash.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.c_uint64, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_claim_for_hash.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_estimate_routing_fees.argtypes = ( + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_estimate_routing_fees.restype = ctypes.c_uint64 +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_estimate_routing_fees_using_amount.argtypes = ( + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_uint64, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_estimate_routing_fees_using_amount.restype = ctypes.c_uint64 +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_fail_for_hash.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_fail_for_hash.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_receive.argtypes = ( + ctypes.c_void_p, + ctypes.c_uint64, + _UniffiRustBuffer, + ctypes.c_uint32, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_receive.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_receive_for_hash.argtypes = ( + ctypes.c_void_p, + ctypes.c_uint64, + _UniffiRustBuffer, + ctypes.c_uint32, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_receive_for_hash.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.c_uint32, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount_for_hash.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.c_uint32, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount_for_hash.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount_via_jit_channel.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.c_uint32, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount_via_jit_channel.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount_via_jit_channel_for_hash.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.c_uint32, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount_via_jit_channel_for_hash.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_receive_via_jit_channel.argtypes = ( + ctypes.c_void_p, + ctypes.c_uint64, + _UniffiRustBuffer, + ctypes.c_uint32, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_receive_via_jit_channel.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_receive_via_jit_channel_for_hash.argtypes = ( + ctypes.c_void_p, + ctypes.c_uint64, + _UniffiRustBuffer, + ctypes.c_uint32, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_receive_via_jit_channel_for_hash.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_send.argtypes = ( + ctypes.c_void_p, + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_send.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_send_probes.argtypes = ( + ctypes.c_void_p, + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_send_probes.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_send_probes_using_amount.argtypes = ( + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_uint64, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_send_probes_using_amount.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_send_using_amount.argtypes = ( + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_uint64, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_send_using_amount.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_clone_bolt12invoice.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_clone_bolt12invoice.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_free_bolt12invoice.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_free_bolt12invoice.restype = None +_UniffiLib.uniffi_ldk_node_fn_constructor_bolt12invoice_from_str.argtypes = ( + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_constructor_bolt12invoice_from_str.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_absolute_expiry_seconds.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_absolute_expiry_seconds.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_amount.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_amount.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_amount_msats.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_amount_msats.restype = ctypes.c_uint64 +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_chain.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_chain.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_created_at.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_created_at.restype = ctypes.c_uint64 +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_encode.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_encode.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_fallback_addresses.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_fallback_addresses.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_invoice_description.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_invoice_description.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_is_expired.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_is_expired.restype = ctypes.c_int8 +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_issuer.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_issuer.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_issuer_signing_pubkey.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_issuer_signing_pubkey.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_metadata.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_metadata.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_offer_chains.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_offer_chains.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_payer_note.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_payer_note.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_payer_signing_pubkey.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_payer_signing_pubkey.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_payment_hash.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_payment_hash.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_quantity.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_quantity.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_relative_expiry.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_relative_expiry.restype = ctypes.c_uint64 +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_signable_hash.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_signable_hash.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_signing_pubkey.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_signing_pubkey.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_clone_bolt12payment.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_clone_bolt12payment.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_free_bolt12payment.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_free_bolt12payment.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_bolt12payment_blinded_paths_for_async_recipient.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt12payment_blinded_paths_for_async_recipient.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt12payment_initiate_refund.argtypes = ( + ctypes.c_void_p, + ctypes.c_uint64, + ctypes.c_uint32, + _UniffiRustBuffer, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt12payment_initiate_refund.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_bolt12payment_receive.argtypes = ( + ctypes.c_void_p, + ctypes.c_uint64, + _UniffiRustBuffer, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt12payment_receive.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_bolt12payment_receive_async.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt12payment_receive_async.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_bolt12payment_receive_variable_amount.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt12payment_receive_variable_amount.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_bolt12payment_request_refund_payment.argtypes = ( + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt12payment_request_refund_payment.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_bolt12payment_send.argtypes = ( + ctypes.c_void_p, + ctypes.c_void_p, + _UniffiRustBuffer, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt12payment_send.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt12payment_send_using_amount.argtypes = ( + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_uint64, + _UniffiRustBuffer, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt12payment_send_using_amount.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_bolt12payment_set_paths_to_static_invoice_server.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_bolt12payment_set_paths_to_static_invoice_server.restype = None +_UniffiLib.uniffi_ldk_node_fn_clone_builder.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_clone_builder.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_free_builder.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_free_builder.restype = None +_UniffiLib.uniffi_ldk_node_fn_constructor_builder_from_config.argtypes = ( + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_constructor_builder_from_config.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_constructor_builder_new.argtypes = ( + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_constructor_builder_new.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_builder_build.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_build.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_builder_build_with_fs_store.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_build_with_fs_store.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_builder_build_with_vss_store.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + _UniffiRustBuffer, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_build_with_vss_store.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_builder_build_with_vss_store_and_fixed_headers.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_build_with_vss_store_and_fixed_headers.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_builder_build_with_vss_store_and_header_provider.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_build_with_vss_store_and_header_provider.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_address_type.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_address_type.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_address_types_to_monitor.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_address_types_to_monitor.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_announcement_addresses.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_announcement_addresses.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_async_payments_role.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_async_payments_role.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_chain_source_bitcoind_rest.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.c_uint16, + _UniffiRustBuffer, + ctypes.c_uint16, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_chain_source_bitcoind_rest.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_chain_source_bitcoind_rpc.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.c_uint16, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_chain_source_bitcoind_rpc.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_chain_source_electrum.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_chain_source_electrum.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_chain_source_esplora.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_chain_source_esplora.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_channel_data_migration.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_channel_data_migration.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_custom_logger.argtypes = ( + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_custom_logger.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_entropy_bip39_mnemonic.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_entropy_bip39_mnemonic.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_entropy_seed_bytes.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_entropy_seed_bytes.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_entropy_seed_path.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_entropy_seed_path.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_filesystem_logger.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_filesystem_logger.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_gossip_source_p2p.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_gossip_source_p2p.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_gossip_source_rgs.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_gossip_source_rgs.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_liquidity_source_lsps1.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_liquidity_source_lsps1.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_liquidity_source_lsps2.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_liquidity_source_lsps2.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_listening_addresses.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_listening_addresses.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_log_facade_logger.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_log_facade_logger.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_network.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_network.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_node_alias.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_node_alias.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_pathfinding_scores_source.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_pathfinding_scores_source.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_scoring_decay_params.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_scoring_decay_params.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_scoring_fee_params.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_scoring_fee_params.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_storage_dir_path.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_builder_set_storage_dir_path.restype = None +_UniffiLib.uniffi_ldk_node_fn_clone_feerate.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_clone_feerate.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_free_feerate.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_free_feerate.restype = None +_UniffiLib.uniffi_ldk_node_fn_constructor_feerate_from_sat_per_kwu.argtypes = ( + ctypes.c_uint64, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_constructor_feerate_from_sat_per_kwu.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_constructor_feerate_from_sat_per_vb_unchecked.argtypes = ( + ctypes.c_uint64, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_constructor_feerate_from_sat_per_vb_unchecked.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_feerate_to_sat_per_kwu.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_feerate_to_sat_per_kwu.restype = ctypes.c_uint64 +_UniffiLib.uniffi_ldk_node_fn_method_feerate_to_sat_per_vb_ceil.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_feerate_to_sat_per_vb_ceil.restype = ctypes.c_uint64 +_UniffiLib.uniffi_ldk_node_fn_method_feerate_to_sat_per_vb_floor.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_feerate_to_sat_per_vb_floor.restype = ctypes.c_uint64 +_UniffiLib.uniffi_ldk_node_fn_clone_lsps1liquidity.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_clone_lsps1liquidity.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_free_lsps1liquidity.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_free_lsps1liquidity.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_lsps1liquidity_check_order_status.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_lsps1liquidity_check_order_status.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_lsps1liquidity_request_channel.argtypes = ( + ctypes.c_void_p, + ctypes.c_uint64, + ctypes.c_uint64, + ctypes.c_uint32, + ctypes.c_int8, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_lsps1liquidity_request_channel.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_clone_logwriter.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_clone_logwriter.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_free_logwriter.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_free_logwriter.restype = None +_UniffiLib.uniffi_ldk_node_fn_init_callback_vtable_logwriter.argtypes = ( + ctypes.POINTER(_UniffiVTableCallbackInterfaceLogWriter), +) +_UniffiLib.uniffi_ldk_node_fn_init_callback_vtable_logwriter.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_logwriter_log.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_logwriter_log.restype = None +_UniffiLib.uniffi_ldk_node_fn_clone_networkgraph.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_clone_networkgraph.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_free_networkgraph.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_free_networkgraph.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_networkgraph_channel.argtypes = ( + ctypes.c_void_p, + ctypes.c_uint64, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_networkgraph_channel.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_networkgraph_list_channels.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_networkgraph_list_channels.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_networkgraph_list_nodes.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_networkgraph_list_nodes.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_networkgraph_node.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_networkgraph_node.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_clone_node.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_clone_node.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_free_node.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_free_node.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_node_add_address_type_to_monitor.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_add_address_type_to_monitor.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_node_add_address_type_to_monitor_with_mnemonic.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_add_address_type_to_monitor_with_mnemonic.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_node_add_onchain_wallet_account.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.c_uint32, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_add_onchain_wallet_account.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_node_announcement_addresses.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_announcement_addresses.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_node_bolt11_payment.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_bolt11_payment.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_node_bolt12_payment.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_bolt12_payment.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_node_close_channel.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_close_channel.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_node_config.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_config.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_node_connect.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.c_int8, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_connect.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_node_current_sync_intervals.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_current_sync_intervals.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_node_disconnect.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_disconnect.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_node_event_handled.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_event_handled.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_node_export_onchain_wallet_account_xpub.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.c_uint32, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_export_onchain_wallet_account_xpub.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_node_export_pathfinding_scores.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_export_pathfinding_scores.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_node_force_close_channel.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_force_close_channel.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_node_get_address_balance.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_get_address_balance.restype = ctypes.c_uint64 +_UniffiLib.uniffi_ldk_node_fn_method_node_get_balance_for_address_type.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_get_balance_for_address_type.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_node_get_balance_for_onchain_wallet_account.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.c_uint32, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_get_balance_for_onchain_wallet_account.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_node_get_transaction_details.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_get_transaction_details.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_node_list_balances.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_list_balances.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_node_list_channels.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_list_channels.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_node_list_monitored_address_types.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_list_monitored_address_types.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_node_list_onchain_wallet_accounts.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_list_onchain_wallet_accounts.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_node_list_payments.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_list_payments.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_node_list_peers.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_list_peers.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_node_listening_addresses.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_listening_addresses.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_node_lsps1_liquidity.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_lsps1_liquidity.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_node_network_graph.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_network_graph.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_node_next_event.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_next_event.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_node_next_event_async.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.uniffi_ldk_node_fn_method_node_next_event_async.restype = ctypes.c_uint64 +_UniffiLib.uniffi_ldk_node_fn_method_node_node_alias.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_node_alias.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_node_node_id.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_node_id.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_node_onchain_payment.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_onchain_payment.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_node_open_announced_channel.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.c_uint64, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_open_announced_channel.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_node_open_channel.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.c_uint64, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_open_channel.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_node_payment.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_payment.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_node_remove_address_type_from_monitor.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_remove_address_type_from_monitor.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_node_remove_onchain_wallet_account.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.c_uint32, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_remove_onchain_wallet_account.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_node_remove_payment.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_remove_payment.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_node_set_primary_address_type.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_set_primary_address_type.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_node_set_primary_address_type_with_mnemonic.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_set_primary_address_type_with_mnemonic.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_node_sign_message.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_sign_message.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_node_splice_in.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.c_uint64, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_splice_in.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_node_splice_out.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.c_uint64, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_splice_out.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_node_spontaneous_payment.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_spontaneous_payment.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_node_start.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_start.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_node_status.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_status.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_node_stop.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_stop.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_node_sync_wallets.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_sync_wallets.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_node_unified_qr_payment.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_unified_qr_payment.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_node_update_channel_config.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_update_channel_config.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_node_update_sync_intervals.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_update_sync_intervals.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_node_verify_signature.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_verify_signature.restype = ctypes.c_int8 +_UniffiLib.uniffi_ldk_node_fn_method_node_wait_next_event.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_node_wait_next_event.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_clone_offer.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_clone_offer.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_free_offer.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_free_offer.restype = None +_UniffiLib.uniffi_ldk_node_fn_constructor_offer_from_str.argtypes = ( + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_constructor_offer_from_str.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_offer_absolute_expiry_seconds.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_offer_absolute_expiry_seconds.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_offer_amount.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_offer_amount.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_offer_chains.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_offer_chains.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_offer_expects_quantity.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_offer_expects_quantity.restype = ctypes.c_int8 +_UniffiLib.uniffi_ldk_node_fn_method_offer_id.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_offer_id.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_offer_is_expired.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_offer_is_expired.restype = ctypes.c_int8 +_UniffiLib.uniffi_ldk_node_fn_method_offer_is_valid_quantity.argtypes = ( + ctypes.c_void_p, + ctypes.c_uint64, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_offer_is_valid_quantity.restype = ctypes.c_int8 +_UniffiLib.uniffi_ldk_node_fn_method_offer_issuer.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_offer_issuer.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_offer_issuer_signing_pubkey.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_offer_issuer_signing_pubkey.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_offer_metadata.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_offer_metadata.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_offer_offer_description.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_offer_offer_description.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_offer_supports_chain.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_offer_supports_chain.restype = ctypes.c_int8 +_UniffiLib.uniffi_ldk_node_fn_method_offer_uniffi_trait_debug.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_offer_uniffi_trait_debug.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_offer_uniffi_trait_display.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_offer_uniffi_trait_display.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_offer_uniffi_trait_eq_eq.argtypes = ( + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_offer_uniffi_trait_eq_eq.restype = ctypes.c_int8 +_UniffiLib.uniffi_ldk_node_fn_method_offer_uniffi_trait_eq_ne.argtypes = ( + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_offer_uniffi_trait_eq_ne.restype = ctypes.c_int8 +_UniffiLib.uniffi_ldk_node_fn_clone_onchainpayment.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_clone_onchainpayment.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_free_onchainpayment.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_free_onchainpayment.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_accelerate_by_cpfp.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_accelerate_by_cpfp.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_address_info_for_account_at_index.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.c_uint32, + _UniffiRustBuffer, + ctypes.c_uint32, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_address_info_for_account_at_index.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_address_info_for_type_at_index.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.c_uint32, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_address_info_for_type_at_index.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_address_infos_for_account.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.c_uint32, + _UniffiRustBuffer, + ctypes.c_uint32, + ctypes.c_uint32, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_address_infos_for_account.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_address_infos_for_type.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.c_uint32, + ctypes.c_uint32, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_address_infos_for_type.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_bump_fee_by_rbf.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_bump_fee_by_rbf.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_calculate_cpfp_fee_rate.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.c_int8, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_calculate_cpfp_fee_rate.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_calculate_send_all_fee.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.c_int8, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_calculate_send_all_fee.restype = ctypes.c_uint64 +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_calculate_total_fee.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.c_uint64, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_calculate_total_fee.restype = ctypes.c_uint64 +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_list_spendable_outputs.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_list_spendable_outputs.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_new_address.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_new_address.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_new_address_for_account.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.c_uint32, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_new_address_for_account.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_new_address_for_type.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_new_address_for_type.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_new_address_info.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_new_address_info.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_new_address_info_for_account.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.c_uint32, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_new_address_info_for_account.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_new_address_info_for_type.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_new_address_info_for_type.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_reveal_receive_addresses_to.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.c_uint32, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_reveal_receive_addresses_to.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_reveal_receive_addresses_to_account.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.c_uint32, + ctypes.c_uint32, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_reveal_receive_addresses_to_account.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_select_utxos_with_algorithm.argtypes = ( + ctypes.c_void_p, + ctypes.c_uint64, + _UniffiRustBuffer, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_select_utxos_with_algorithm.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_send_all_to_address.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.c_int8, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_send_all_to_address.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_send_to_address.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + ctypes.c_uint64, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_send_to_address.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_clone_refund.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_clone_refund.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_free_refund.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_free_refund.restype = None +_UniffiLib.uniffi_ldk_node_fn_constructor_refund_from_str.argtypes = ( + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_constructor_refund_from_str.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_method_refund_absolute_expiry_seconds.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_refund_absolute_expiry_seconds.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_refund_amount_msats.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_refund_amount_msats.restype = ctypes.c_uint64 +_UniffiLib.uniffi_ldk_node_fn_method_refund_chain.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_refund_chain.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_refund_is_expired.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_refund_is_expired.restype = ctypes.c_int8 +_UniffiLib.uniffi_ldk_node_fn_method_refund_issuer.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_refund_issuer.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_refund_payer_metadata.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_refund_payer_metadata.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_refund_payer_note.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_refund_payer_note.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_refund_payer_signing_pubkey.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_refund_payer_signing_pubkey.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_refund_quantity.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_refund_quantity.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_refund_refund_description.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_refund_refund_description.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_refund_uniffi_trait_debug.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_refund_uniffi_trait_debug.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_refund_uniffi_trait_display.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_refund_uniffi_trait_display.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_refund_uniffi_trait_eq_eq.argtypes = ( + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_refund_uniffi_trait_eq_eq.restype = ctypes.c_int8 +_UniffiLib.uniffi_ldk_node_fn_method_refund_uniffi_trait_eq_ne.argtypes = ( + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_refund_uniffi_trait_eq_ne.restype = ctypes.c_int8 +_UniffiLib.uniffi_ldk_node_fn_clone_spontaneouspayment.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_clone_spontaneouspayment.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_free_spontaneouspayment.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_free_spontaneouspayment.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_spontaneouspayment_send.argtypes = ( + ctypes.c_void_p, + ctypes.c_uint64, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_spontaneouspayment_send.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_spontaneouspayment_send_probes.argtypes = ( + ctypes.c_void_p, + ctypes.c_uint64, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_spontaneouspayment_send_probes.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_spontaneouspayment_send_with_custom_tlvs.argtypes = ( + ctypes.c_void_p, + ctypes.c_uint64, + _UniffiRustBuffer, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_spontaneouspayment_send_with_custom_tlvs.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_spontaneouspayment_send_with_preimage.argtypes = ( + ctypes.c_void_p, + ctypes.c_uint64, + _UniffiRustBuffer, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_spontaneouspayment_send_with_preimage.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_spontaneouspayment_send_with_preimage_and_custom_tlvs.argtypes = ( + ctypes.c_void_p, + ctypes.c_uint64, + _UniffiRustBuffer, + _UniffiRustBuffer, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_spontaneouspayment_send_with_preimage_and_custom_tlvs.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_clone_unifiedqrpayment.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_clone_unifiedqrpayment.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_free_unifiedqrpayment.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_free_unifiedqrpayment.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_unifiedqrpayment_receive.argtypes = ( + ctypes.c_void_p, + ctypes.c_uint64, + _UniffiRustBuffer, + ctypes.c_uint32, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_unifiedqrpayment_receive.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_method_unifiedqrpayment_send.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_method_unifiedqrpayment_send.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_clone_vssheaderprovider.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_clone_vssheaderprovider.restype = ctypes.c_void_p +_UniffiLib.uniffi_ldk_node_fn_free_vssheaderprovider.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_free_vssheaderprovider.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_vssheaderprovider_get_headers.argtypes = ( + ctypes.c_void_p, + _UniffiRustBuffer, +) +_UniffiLib.uniffi_ldk_node_fn_method_vssheaderprovider_get_headers.restype = ctypes.c_uint64 +_UniffiLib.uniffi_ldk_node_fn_func_battery_saving_sync_intervals.argtypes = ( + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_func_battery_saving_sync_intervals.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_func_default_config.argtypes = ( + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_func_default_config.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_func_derive_node_secret_from_mnemonic.argtypes = ( + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_func_derive_node_secret_from_mnemonic.restype = _UniffiRustBuffer +_UniffiLib.uniffi_ldk_node_fn_func_generate_entropy_mnemonic.argtypes = ( + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_ldk_node_fn_func_generate_entropy_mnemonic.restype = _UniffiRustBuffer +_UniffiLib.ffi_ldk_node_rustbuffer_alloc.argtypes = ( + ctypes.c_uint64, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_ldk_node_rustbuffer_alloc.restype = _UniffiRustBuffer +_UniffiLib.ffi_ldk_node_rustbuffer_from_bytes.argtypes = ( + _UniffiForeignBytes, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_ldk_node_rustbuffer_from_bytes.restype = _UniffiRustBuffer +_UniffiLib.ffi_ldk_node_rustbuffer_free.argtypes = ( + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_ldk_node_rustbuffer_free.restype = None +_UniffiLib.ffi_ldk_node_rustbuffer_reserve.argtypes = ( + _UniffiRustBuffer, + ctypes.c_uint64, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_ldk_node_rustbuffer_reserve.restype = _UniffiRustBuffer +_UniffiLib.ffi_ldk_node_rust_future_poll_u8.argtypes = ( + ctypes.c_uint64, + _UNIFFI_RUST_FUTURE_CONTINUATION_CALLBACK, + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_poll_u8.restype = None +_UniffiLib.ffi_ldk_node_rust_future_cancel_u8.argtypes = ( + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_cancel_u8.restype = None +_UniffiLib.ffi_ldk_node_rust_future_free_u8.argtypes = ( + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_free_u8.restype = None +_UniffiLib.ffi_ldk_node_rust_future_complete_u8.argtypes = ( + ctypes.c_uint64, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_ldk_node_rust_future_complete_u8.restype = ctypes.c_uint8 +_UniffiLib.ffi_ldk_node_rust_future_poll_i8.argtypes = ( + ctypes.c_uint64, + _UNIFFI_RUST_FUTURE_CONTINUATION_CALLBACK, + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_poll_i8.restype = None +_UniffiLib.ffi_ldk_node_rust_future_cancel_i8.argtypes = ( + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_cancel_i8.restype = None +_UniffiLib.ffi_ldk_node_rust_future_free_i8.argtypes = ( + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_free_i8.restype = None +_UniffiLib.ffi_ldk_node_rust_future_complete_i8.argtypes = ( + ctypes.c_uint64, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_ldk_node_rust_future_complete_i8.restype = ctypes.c_int8 +_UniffiLib.ffi_ldk_node_rust_future_poll_u16.argtypes = ( + ctypes.c_uint64, + _UNIFFI_RUST_FUTURE_CONTINUATION_CALLBACK, + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_poll_u16.restype = None +_UniffiLib.ffi_ldk_node_rust_future_cancel_u16.argtypes = ( + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_cancel_u16.restype = None +_UniffiLib.ffi_ldk_node_rust_future_free_u16.argtypes = ( + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_free_u16.restype = None +_UniffiLib.ffi_ldk_node_rust_future_complete_u16.argtypes = ( + ctypes.c_uint64, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_ldk_node_rust_future_complete_u16.restype = ctypes.c_uint16 +_UniffiLib.ffi_ldk_node_rust_future_poll_i16.argtypes = ( + ctypes.c_uint64, + _UNIFFI_RUST_FUTURE_CONTINUATION_CALLBACK, + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_poll_i16.restype = None +_UniffiLib.ffi_ldk_node_rust_future_cancel_i16.argtypes = ( + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_cancel_i16.restype = None +_UniffiLib.ffi_ldk_node_rust_future_free_i16.argtypes = ( + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_free_i16.restype = None +_UniffiLib.ffi_ldk_node_rust_future_complete_i16.argtypes = ( + ctypes.c_uint64, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_ldk_node_rust_future_complete_i16.restype = ctypes.c_int16 +_UniffiLib.ffi_ldk_node_rust_future_poll_u32.argtypes = ( + ctypes.c_uint64, + _UNIFFI_RUST_FUTURE_CONTINUATION_CALLBACK, + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_poll_u32.restype = None +_UniffiLib.ffi_ldk_node_rust_future_cancel_u32.argtypes = ( + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_cancel_u32.restype = None +_UniffiLib.ffi_ldk_node_rust_future_free_u32.argtypes = ( + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_free_u32.restype = None +_UniffiLib.ffi_ldk_node_rust_future_complete_u32.argtypes = ( + ctypes.c_uint64, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_ldk_node_rust_future_complete_u32.restype = ctypes.c_uint32 +_UniffiLib.ffi_ldk_node_rust_future_poll_i32.argtypes = ( + ctypes.c_uint64, + _UNIFFI_RUST_FUTURE_CONTINUATION_CALLBACK, + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_poll_i32.restype = None +_UniffiLib.ffi_ldk_node_rust_future_cancel_i32.argtypes = ( + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_cancel_i32.restype = None +_UniffiLib.ffi_ldk_node_rust_future_free_i32.argtypes = ( + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_free_i32.restype = None +_UniffiLib.ffi_ldk_node_rust_future_complete_i32.argtypes = ( + ctypes.c_uint64, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_ldk_node_rust_future_complete_i32.restype = ctypes.c_int32 +_UniffiLib.ffi_ldk_node_rust_future_poll_u64.argtypes = ( + ctypes.c_uint64, + _UNIFFI_RUST_FUTURE_CONTINUATION_CALLBACK, + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_poll_u64.restype = None +_UniffiLib.ffi_ldk_node_rust_future_cancel_u64.argtypes = ( + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_cancel_u64.restype = None +_UniffiLib.ffi_ldk_node_rust_future_free_u64.argtypes = ( + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_free_u64.restype = None +_UniffiLib.ffi_ldk_node_rust_future_complete_u64.argtypes = ( + ctypes.c_uint64, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_ldk_node_rust_future_complete_u64.restype = ctypes.c_uint64 +_UniffiLib.ffi_ldk_node_rust_future_poll_i64.argtypes = ( + ctypes.c_uint64, + _UNIFFI_RUST_FUTURE_CONTINUATION_CALLBACK, + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_poll_i64.restype = None +_UniffiLib.ffi_ldk_node_rust_future_cancel_i64.argtypes = ( + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_cancel_i64.restype = None +_UniffiLib.ffi_ldk_node_rust_future_free_i64.argtypes = ( + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_free_i64.restype = None +_UniffiLib.ffi_ldk_node_rust_future_complete_i64.argtypes = ( + ctypes.c_uint64, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_ldk_node_rust_future_complete_i64.restype = ctypes.c_int64 +_UniffiLib.ffi_ldk_node_rust_future_poll_f32.argtypes = ( + ctypes.c_uint64, + _UNIFFI_RUST_FUTURE_CONTINUATION_CALLBACK, + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_poll_f32.restype = None +_UniffiLib.ffi_ldk_node_rust_future_cancel_f32.argtypes = ( + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_cancel_f32.restype = None +_UniffiLib.ffi_ldk_node_rust_future_free_f32.argtypes = ( + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_free_f32.restype = None +_UniffiLib.ffi_ldk_node_rust_future_complete_f32.argtypes = ( + ctypes.c_uint64, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_ldk_node_rust_future_complete_f32.restype = ctypes.c_float +_UniffiLib.ffi_ldk_node_rust_future_poll_f64.argtypes = ( + ctypes.c_uint64, + _UNIFFI_RUST_FUTURE_CONTINUATION_CALLBACK, + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_poll_f64.restype = None +_UniffiLib.ffi_ldk_node_rust_future_cancel_f64.argtypes = ( + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_cancel_f64.restype = None +_UniffiLib.ffi_ldk_node_rust_future_free_f64.argtypes = ( + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_free_f64.restype = None +_UniffiLib.ffi_ldk_node_rust_future_complete_f64.argtypes = ( + ctypes.c_uint64, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_ldk_node_rust_future_complete_f64.restype = ctypes.c_double +_UniffiLib.ffi_ldk_node_rust_future_poll_pointer.argtypes = ( + ctypes.c_uint64, + _UNIFFI_RUST_FUTURE_CONTINUATION_CALLBACK, + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_poll_pointer.restype = None +_UniffiLib.ffi_ldk_node_rust_future_cancel_pointer.argtypes = ( + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_cancel_pointer.restype = None +_UniffiLib.ffi_ldk_node_rust_future_free_pointer.argtypes = ( + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_free_pointer.restype = None +_UniffiLib.ffi_ldk_node_rust_future_complete_pointer.argtypes = ( + ctypes.c_uint64, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_ldk_node_rust_future_complete_pointer.restype = ctypes.c_void_p +_UniffiLib.ffi_ldk_node_rust_future_poll_rust_buffer.argtypes = ( + ctypes.c_uint64, + _UNIFFI_RUST_FUTURE_CONTINUATION_CALLBACK, + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_poll_rust_buffer.restype = None +_UniffiLib.ffi_ldk_node_rust_future_cancel_rust_buffer.argtypes = ( + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_cancel_rust_buffer.restype = None +_UniffiLib.ffi_ldk_node_rust_future_free_rust_buffer.argtypes = ( + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_free_rust_buffer.restype = None +_UniffiLib.ffi_ldk_node_rust_future_complete_rust_buffer.argtypes = ( + ctypes.c_uint64, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_ldk_node_rust_future_complete_rust_buffer.restype = _UniffiRustBuffer +_UniffiLib.ffi_ldk_node_rust_future_poll_void.argtypes = ( + ctypes.c_uint64, + _UNIFFI_RUST_FUTURE_CONTINUATION_CALLBACK, + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_poll_void.restype = None +_UniffiLib.ffi_ldk_node_rust_future_cancel_void.argtypes = ( + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_cancel_void.restype = None +_UniffiLib.ffi_ldk_node_rust_future_free_void.argtypes = ( + ctypes.c_uint64, +) +_UniffiLib.ffi_ldk_node_rust_future_free_void.restype = None +_UniffiLib.ffi_ldk_node_rust_future_complete_void.argtypes = ( + ctypes.c_uint64, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_ldk_node_rust_future_complete_void.restype = None +_UniffiLib.uniffi_ldk_node_checksum_func_battery_saving_sync_intervals.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_func_battery_saving_sync_intervals.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_func_default_config.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_func_default_config.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_func_derive_node_secret_from_mnemonic.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_func_derive_node_secret_from_mnemonic.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_func_generate_entropy_mnemonic.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_func_generate_entropy_mnemonic.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_amount_milli_satoshis.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_amount_milli_satoshis.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_currency.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_currency.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_expiry_time_seconds.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_expiry_time_seconds.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_fallback_addresses.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_fallback_addresses.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_invoice_description.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_invoice_description.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_is_expired.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_is_expired.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_min_final_cltv_expiry_delta.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_min_final_cltv_expiry_delta.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_network.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_network.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_payment_hash.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_payment_hash.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_payment_secret.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_payment_secret.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_recover_payee_pub_key.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_recover_payee_pub_key.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_route_hints.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_route_hints.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_seconds_since_epoch.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_seconds_since_epoch.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_seconds_until_expiry.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_seconds_until_expiry.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_signable_hash.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_signable_hash.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_would_expire.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11invoice_would_expire.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_claim_for_hash.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_claim_for_hash.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_estimate_routing_fees.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_estimate_routing_fees.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_estimate_routing_fees_using_amount.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_estimate_routing_fees_using_amount.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_fail_for_hash.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_fail_for_hash.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_receive.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_receive.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_receive_for_hash.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_receive_for_hash.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount_for_hash.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount_for_hash.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount_via_jit_channel.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount_via_jit_channel.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount_via_jit_channel_for_hash.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount_via_jit_channel_for_hash.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_receive_via_jit_channel.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_receive_via_jit_channel.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_receive_via_jit_channel_for_hash.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_receive_via_jit_channel_for_hash.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_send.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_send.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_send_probes.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_send_probes.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_send_probes_using_amount.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_send_probes_using_amount.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_send_using_amount.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt11payment_send_using_amount.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_absolute_expiry_seconds.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_absolute_expiry_seconds.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_amount.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_amount.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_amount_msats.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_amount_msats.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_chain.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_chain.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_created_at.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_created_at.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_encode.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_encode.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_fallback_addresses.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_fallback_addresses.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_invoice_description.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_invoice_description.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_is_expired.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_is_expired.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_issuer.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_issuer.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_issuer_signing_pubkey.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_issuer_signing_pubkey.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_metadata.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_metadata.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_offer_chains.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_offer_chains.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_payer_note.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_payer_note.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_payer_signing_pubkey.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_payer_signing_pubkey.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_payment_hash.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_payment_hash.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_quantity.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_quantity.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_relative_expiry.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_relative_expiry.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_signable_hash.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_signable_hash.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_signing_pubkey.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12invoice_signing_pubkey.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12payment_blinded_paths_for_async_recipient.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12payment_blinded_paths_for_async_recipient.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12payment_initiate_refund.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12payment_initiate_refund.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12payment_receive.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12payment_receive.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12payment_receive_async.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12payment_receive_async.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12payment_receive_variable_amount.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12payment_receive_variable_amount.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12payment_request_refund_payment.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12payment_request_refund_payment.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12payment_send.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12payment_send.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12payment_send_using_amount.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12payment_send_using_amount.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12payment_set_paths_to_static_invoice_server.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_bolt12payment_set_paths_to_static_invoice_server.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_build.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_build.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_build_with_fs_store.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_build_with_fs_store.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_build_with_vss_store.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_build_with_vss_store.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_build_with_vss_store_and_fixed_headers.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_build_with_vss_store_and_fixed_headers.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_build_with_vss_store_and_header_provider.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_build_with_vss_store_and_header_provider.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_address_type.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_address_type.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_address_types_to_monitor.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_address_types_to_monitor.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_announcement_addresses.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_announcement_addresses.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_async_payments_role.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_async_payments_role.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_chain_source_bitcoind_rest.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_chain_source_bitcoind_rest.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_chain_source_bitcoind_rpc.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_chain_source_bitcoind_rpc.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_chain_source_electrum.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_chain_source_electrum.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_chain_source_esplora.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_chain_source_esplora.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_channel_data_migration.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_channel_data_migration.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_custom_logger.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_custom_logger.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_entropy_bip39_mnemonic.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_entropy_bip39_mnemonic.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_entropy_seed_bytes.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_entropy_seed_bytes.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_entropy_seed_path.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_entropy_seed_path.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_filesystem_logger.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_filesystem_logger.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_gossip_source_p2p.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_gossip_source_p2p.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_gossip_source_rgs.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_gossip_source_rgs.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_liquidity_source_lsps1.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_liquidity_source_lsps1.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_liquidity_source_lsps2.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_liquidity_source_lsps2.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_listening_addresses.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_listening_addresses.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_log_facade_logger.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_log_facade_logger.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_network.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_network.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_node_alias.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_node_alias.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_pathfinding_scores_source.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_pathfinding_scores_source.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_scoring_decay_params.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_scoring_decay_params.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_scoring_fee_params.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_scoring_fee_params.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_storage_dir_path.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_builder_set_storage_dir_path.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_feerate_to_sat_per_kwu.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_feerate_to_sat_per_kwu.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_feerate_to_sat_per_vb_ceil.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_feerate_to_sat_per_vb_ceil.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_feerate_to_sat_per_vb_floor.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_feerate_to_sat_per_vb_floor.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_lsps1liquidity_check_order_status.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_lsps1liquidity_check_order_status.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_lsps1liquidity_request_channel.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_lsps1liquidity_request_channel.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_logwriter_log.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_logwriter_log.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_networkgraph_channel.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_networkgraph_channel.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_networkgraph_list_channels.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_networkgraph_list_channels.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_networkgraph_list_nodes.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_networkgraph_list_nodes.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_networkgraph_node.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_networkgraph_node.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_add_address_type_to_monitor.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_add_address_type_to_monitor.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_add_address_type_to_monitor_with_mnemonic.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_add_address_type_to_monitor_with_mnemonic.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_add_onchain_wallet_account.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_add_onchain_wallet_account.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_announcement_addresses.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_announcement_addresses.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_bolt11_payment.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_bolt11_payment.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_bolt12_payment.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_bolt12_payment.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_close_channel.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_close_channel.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_config.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_config.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_connect.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_connect.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_current_sync_intervals.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_current_sync_intervals.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_disconnect.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_disconnect.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_event_handled.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_event_handled.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_export_onchain_wallet_account_xpub.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_export_onchain_wallet_account_xpub.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_export_pathfinding_scores.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_export_pathfinding_scores.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_force_close_channel.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_force_close_channel.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_get_address_balance.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_get_address_balance.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_get_balance_for_address_type.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_get_balance_for_address_type.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_get_balance_for_onchain_wallet_account.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_get_balance_for_onchain_wallet_account.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_get_transaction_details.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_get_transaction_details.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_list_balances.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_list_balances.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_list_channels.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_list_channels.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_list_monitored_address_types.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_list_monitored_address_types.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_list_onchain_wallet_accounts.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_list_onchain_wallet_accounts.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_list_payments.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_list_payments.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_list_peers.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_list_peers.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_listening_addresses.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_listening_addresses.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_lsps1_liquidity.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_lsps1_liquidity.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_network_graph.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_network_graph.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_next_event.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_next_event.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_next_event_async.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_next_event_async.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_node_alias.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_node_alias.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_node_id.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_node_id.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_onchain_payment.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_onchain_payment.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_open_announced_channel.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_open_announced_channel.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_open_channel.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_open_channel.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_payment.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_payment.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_remove_address_type_from_monitor.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_remove_address_type_from_monitor.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_remove_onchain_wallet_account.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_remove_onchain_wallet_account.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_remove_payment.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_remove_payment.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_set_primary_address_type.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_set_primary_address_type.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_set_primary_address_type_with_mnemonic.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_set_primary_address_type_with_mnemonic.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_sign_message.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_sign_message.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_splice_in.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_splice_in.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_splice_out.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_splice_out.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_spontaneous_payment.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_spontaneous_payment.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_start.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_start.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_status.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_status.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_stop.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_stop.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_sync_wallets.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_sync_wallets.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_unified_qr_payment.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_unified_qr_payment.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_update_channel_config.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_update_channel_config.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_update_sync_intervals.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_update_sync_intervals.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_verify_signature.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_verify_signature.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_node_wait_next_event.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_node_wait_next_event.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_offer_absolute_expiry_seconds.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_offer_absolute_expiry_seconds.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_offer_amount.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_offer_amount.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_offer_chains.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_offer_chains.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_offer_expects_quantity.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_offer_expects_quantity.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_offer_id.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_offer_id.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_offer_is_expired.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_offer_is_expired.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_offer_is_valid_quantity.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_offer_is_valid_quantity.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_offer_issuer.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_offer_issuer.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_offer_issuer_signing_pubkey.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_offer_issuer_signing_pubkey.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_offer_metadata.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_offer_metadata.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_offer_offer_description.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_offer_offer_description.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_offer_supports_chain.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_offer_supports_chain.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_accelerate_by_cpfp.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_accelerate_by_cpfp.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_address_info_for_account_at_index.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_address_info_for_account_at_index.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_address_info_for_type_at_index.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_address_info_for_type_at_index.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_address_infos_for_account.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_address_infos_for_account.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_address_infos_for_type.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_address_infos_for_type.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_bump_fee_by_rbf.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_bump_fee_by_rbf.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_calculate_cpfp_fee_rate.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_calculate_cpfp_fee_rate.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_calculate_send_all_fee.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_calculate_send_all_fee.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_calculate_total_fee.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_calculate_total_fee.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_list_spendable_outputs.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_list_spendable_outputs.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_new_address.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_new_address.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_new_address_for_account.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_new_address_for_account.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_new_address_for_type.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_new_address_for_type.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_new_address_info.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_new_address_info.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_new_address_info_for_account.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_new_address_info_for_account.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_new_address_info_for_type.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_new_address_info_for_type.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_reveal_receive_addresses_to.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_reveal_receive_addresses_to.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_reveal_receive_addresses_to_account.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_reveal_receive_addresses_to_account.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_select_utxos_with_algorithm.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_select_utxos_with_algorithm.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_send_all_to_address.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_send_all_to_address.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_send_to_address.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_onchainpayment_send_to_address.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_refund_absolute_expiry_seconds.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_refund_absolute_expiry_seconds.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_refund_amount_msats.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_refund_amount_msats.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_refund_chain.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_refund_chain.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_refund_is_expired.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_refund_is_expired.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_refund_issuer.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_refund_issuer.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_refund_payer_metadata.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_refund_payer_metadata.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_refund_payer_note.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_refund_payer_note.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_refund_payer_signing_pubkey.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_refund_payer_signing_pubkey.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_refund_quantity.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_refund_quantity.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_refund_refund_description.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_refund_refund_description.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_spontaneouspayment_send.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_spontaneouspayment_send.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_spontaneouspayment_send_probes.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_spontaneouspayment_send_probes.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_spontaneouspayment_send_with_custom_tlvs.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_spontaneouspayment_send_with_custom_tlvs.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_spontaneouspayment_send_with_preimage.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_spontaneouspayment_send_with_preimage.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_spontaneouspayment_send_with_preimage_and_custom_tlvs.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_spontaneouspayment_send_with_preimage_and_custom_tlvs.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_unifiedqrpayment_receive.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_unifiedqrpayment_receive.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_unifiedqrpayment_send.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_unifiedqrpayment_send.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_method_vssheaderprovider_get_headers.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_method_vssheaderprovider_get_headers.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_constructor_bolt11invoice_from_str.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_constructor_bolt11invoice_from_str.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_constructor_bolt12invoice_from_str.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_constructor_bolt12invoice_from_str.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_constructor_builder_from_config.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_constructor_builder_from_config.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_constructor_builder_new.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_constructor_builder_new.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_constructor_feerate_from_sat_per_kwu.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_constructor_feerate_from_sat_per_kwu.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_constructor_feerate_from_sat_per_vb_unchecked.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_constructor_feerate_from_sat_per_vb_unchecked.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_constructor_offer_from_str.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_constructor_offer_from_str.restype = ctypes.c_uint16 +_UniffiLib.uniffi_ldk_node_checksum_constructor_refund_from_str.argtypes = ( +) +_UniffiLib.uniffi_ldk_node_checksum_constructor_refund_from_str.restype = ctypes.c_uint16 +_UniffiLib.ffi_ldk_node_uniffi_contract_version.argtypes = ( +) +_UniffiLib.ffi_ldk_node_uniffi_contract_version.restype = ctypes.c_uint32 + +_uniffi_check_contract_api_version(_UniffiLib) +# _uniffi_check_api_checksums(_UniffiLib) + +# Public interface members begin here. + + +class _UniffiConverterUInt8(_UniffiConverterPrimitiveInt): + CLASS_NAME = "u8" + VALUE_MIN = 0 + VALUE_MAX = 2**8 + + @staticmethod + def read(buf): + return buf.read_u8() + + @staticmethod + def write(value, buf): + buf.write_u8(value) + +class _UniffiConverterUInt16(_UniffiConverterPrimitiveInt): + CLASS_NAME = "u16" + VALUE_MIN = 0 + VALUE_MAX = 2**16 + + @staticmethod + def read(buf): + return buf.read_u16() + + @staticmethod + def write(value, buf): + buf.write_u16(value) + +class _UniffiConverterUInt32(_UniffiConverterPrimitiveInt): + CLASS_NAME = "u32" + VALUE_MIN = 0 + VALUE_MAX = 2**32 + + @staticmethod + def read(buf): + return buf.read_u32() + + @staticmethod + def write(value, buf): + buf.write_u32(value) + +class _UniffiConverterUInt64(_UniffiConverterPrimitiveInt): + CLASS_NAME = "u64" + VALUE_MIN = 0 + VALUE_MAX = 2**64 + + @staticmethod + def read(buf): + return buf.read_u64() + + @staticmethod + def write(value, buf): + buf.write_u64(value) + +class _UniffiConverterInt64(_UniffiConverterPrimitiveInt): + CLASS_NAME = "i64" + VALUE_MIN = -2**63 + VALUE_MAX = 2**63 + + @staticmethod + def read(buf): + return buf.read_i64() + + @staticmethod + def write(value, buf): + buf.write_i64(value) + +class _UniffiConverterBool: + @classmethod + def check_lower(cls, value): + return not not value + + @classmethod + def lower(cls, value): + return 1 if value else 0 + + @staticmethod + def lift(value): + return value != 0 + + @classmethod + def read(cls, buf): + return cls.lift(buf.read_u8()) + + @classmethod + def write(cls, value, buf): + buf.write_u8(value) + +class _UniffiConverterString: + @staticmethod + def check_lower(value): + if not isinstance(value, str): + raise TypeError("argument must be str, not {}".format(type(value).__name__)) + return value + + @staticmethod + def read(buf): + size = buf.read_i32() + if size < 0: + raise InternalError("Unexpected negative string length") + utf8_bytes = buf.read(size) + return utf8_bytes.decode("utf-8") + + @staticmethod + def write(value, buf): + utf8_bytes = value.encode("utf-8") + buf.write_i32(len(utf8_bytes)) + buf.write(utf8_bytes) + + @staticmethod + def lift(buf): + with buf.consume_with_stream() as stream: + return stream.read(stream.remaining()).decode("utf-8") + + @staticmethod + def lower(value): + with _UniffiRustBuffer.alloc_with_builder() as builder: + builder.write(value.encode("utf-8")) + return builder.finalize() + +class _UniffiConverterBytes(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + size = buf.read_i32() + if size < 0: + raise InternalError("Unexpected negative byte string length") + return buf.read(size) + + @staticmethod + def check_lower(value): + try: + memoryview(value) + except TypeError: + raise TypeError("a bytes-like object is required, not {!r}".format(type(value).__name__)) + + @staticmethod + def write(value, buf): + buf.write_i32(len(value)) + buf.write(value) + + + +class Bolt11InvoiceProtocol(typing.Protocol): + def amount_milli_satoshis(self, ): + raise NotImplementedError + def currency(self, ): + raise NotImplementedError + def expiry_time_seconds(self, ): + raise NotImplementedError + def fallback_addresses(self, ): + raise NotImplementedError + def invoice_description(self, ): + raise NotImplementedError + def is_expired(self, ): + raise NotImplementedError + def min_final_cltv_expiry_delta(self, ): + raise NotImplementedError + def network(self, ): + raise NotImplementedError + def payment_hash(self, ): + raise NotImplementedError + def payment_secret(self, ): + raise NotImplementedError + def recover_payee_pub_key(self, ): + raise NotImplementedError + def route_hints(self, ): + raise NotImplementedError + def seconds_since_epoch(self, ): + raise NotImplementedError + def seconds_until_expiry(self, ): + raise NotImplementedError + def signable_hash(self, ): + raise NotImplementedError + def would_expire(self, at_time_seconds: "int"): + raise NotImplementedError + + +class Bolt11Invoice: + _pointer: ctypes.c_void_p + + def __init__(self, *args, **kwargs): + raise ValueError("This class has no default constructor") + + def __del__(self): + # In case of partial initialization of instances. + pointer = getattr(self, "_pointer", None) + if pointer is not None: + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_free_bolt11invoice, pointer) + + def _uniffi_clone_pointer(self): + return _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_clone_bolt11invoice, self._pointer) + + # Used by alternative constructors or any methods which return this type. + @classmethod + def _make_instance_(cls, pointer): + # Lightly yucky way to bypass the usual __init__ logic + # and just create a new instance with the required pointer. + inst = cls.__new__(cls) + inst._pointer = pointer + return inst + @classmethod + def from_str(cls, invoice_str: "str"): + _UniffiConverterString.check_lower(invoice_str) + + # Call the (fallible) function before creating any half-baked object instances. + pointer = _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_constructor_bolt11invoice_from_str, + _UniffiConverterString.lower(invoice_str)) + return cls._make_instance_(pointer) + + + + def amount_milli_satoshis(self, ) -> "typing.Optional[int]": + return _UniffiConverterOptionalUInt64.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_amount_milli_satoshis,self._uniffi_clone_pointer(),) + ) + + + + + + def currency(self, ) -> "Currency": + return _UniffiConverterTypeCurrency.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_currency,self._uniffi_clone_pointer(),) + ) + + + + + + def expiry_time_seconds(self, ) -> "int": + return _UniffiConverterUInt64.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_expiry_time_seconds,self._uniffi_clone_pointer(),) + ) + + + + + + def fallback_addresses(self, ) -> "typing.List[Address]": + return _UniffiConverterSequenceTypeAddress.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_fallback_addresses,self._uniffi_clone_pointer(),) + ) + + + + + + def invoice_description(self, ) -> "Bolt11InvoiceDescription": + return _UniffiConverterTypeBolt11InvoiceDescription.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_invoice_description,self._uniffi_clone_pointer(),) + ) + + + + + + def is_expired(self, ) -> "bool": + return _UniffiConverterBool.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_is_expired,self._uniffi_clone_pointer(),) + ) + + + + + + def min_final_cltv_expiry_delta(self, ) -> "int": + return _UniffiConverterUInt64.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_min_final_cltv_expiry_delta,self._uniffi_clone_pointer(),) + ) + + + + + + def network(self, ) -> "Network": + return _UniffiConverterTypeNetwork.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_network,self._uniffi_clone_pointer(),) + ) + + + + + + def payment_hash(self, ) -> "PaymentHash": + return _UniffiConverterTypePaymentHash.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_payment_hash,self._uniffi_clone_pointer(),) + ) + + + + + + def payment_secret(self, ) -> "PaymentSecret": + return _UniffiConverterTypePaymentSecret.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_payment_secret,self._uniffi_clone_pointer(),) + ) + + + + + + def recover_payee_pub_key(self, ) -> "PublicKey": + return _UniffiConverterTypePublicKey.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_recover_payee_pub_key,self._uniffi_clone_pointer(),) + ) + + + + + + def route_hints(self, ) -> "typing.List[typing.List[RouteHintHop]]": + return _UniffiConverterSequenceSequenceTypeRouteHintHop.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_route_hints,self._uniffi_clone_pointer(),) + ) + + + + + + def seconds_since_epoch(self, ) -> "int": + return _UniffiConverterUInt64.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_seconds_since_epoch,self._uniffi_clone_pointer(),) + ) + + + + + + def seconds_until_expiry(self, ) -> "int": + return _UniffiConverterUInt64.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_seconds_until_expiry,self._uniffi_clone_pointer(),) + ) + + + + + + def signable_hash(self, ) -> "typing.List[int]": + return _UniffiConverterSequenceUInt8.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_signable_hash,self._uniffi_clone_pointer(),) + ) + + + + + + def would_expire(self, at_time_seconds: "int") -> "bool": + _UniffiConverterUInt64.check_lower(at_time_seconds) + + return _UniffiConverterBool.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_would_expire,self._uniffi_clone_pointer(), + _UniffiConverterUInt64.lower(at_time_seconds)) + ) + + + + + + def __repr__(self, ) -> "str": + return _UniffiConverterString.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_debug,self._uniffi_clone_pointer(),) + ) + + + + + + def __str__(self, ) -> "str": + return _UniffiConverterString.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_display,self._uniffi_clone_pointer(),) + ) + + + + def __eq__(self, other: object) -> bool: + if not isinstance(other, Bolt11Invoice): + return NotImplemented + + return _UniffiConverterBool.lift(_uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_eq_eq,self._uniffi_clone_pointer(), + _UniffiConverterTypeBolt11Invoice.lower(other))) + + def __ne__(self, other: object) -> bool: + if not isinstance(other, Bolt11Invoice): + return NotImplemented + + return _UniffiConverterBool.lift(_uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_eq_ne,self._uniffi_clone_pointer(), + _UniffiConverterTypeBolt11Invoice.lower(other))) + + + +class _UniffiConverterTypeBolt11Invoice: + + @staticmethod + def lift(value: int): + return Bolt11Invoice._make_instance_(value) + + @staticmethod + def check_lower(value: Bolt11Invoice): + if not isinstance(value, Bolt11Invoice): + raise TypeError("Expected Bolt11Invoice instance, {} found".format(type(value).__name__)) + + @staticmethod + def lower(value: Bolt11InvoiceProtocol): + if not isinstance(value, Bolt11Invoice): + raise TypeError("Expected Bolt11Invoice instance, {} found".format(type(value).__name__)) + return value._uniffi_clone_pointer() + + @classmethod + def read(cls, buf: _UniffiRustBuffer): + ptr = buf.read_u64() + if ptr == 0: + raise InternalError("Raw pointer value was null") + return cls.lift(ptr) + + @classmethod + def write(cls, value: Bolt11InvoiceProtocol, buf: _UniffiRustBuffer): + buf.write_u64(cls.lower(value)) + + + +class Bolt11PaymentProtocol(typing.Protocol): + def claim_for_hash(self, payment_hash: "PaymentHash",claimable_amount_msat: "int",preimage: "PaymentPreimage"): + raise NotImplementedError + def estimate_routing_fees(self, invoice: "Bolt11Invoice"): + raise NotImplementedError + def estimate_routing_fees_using_amount(self, invoice: "Bolt11Invoice",amount_msat: "int"): + raise NotImplementedError + def fail_for_hash(self, payment_hash: "PaymentHash"): + raise NotImplementedError + def receive(self, amount_msat: "int",description: "Bolt11InvoiceDescription",expiry_secs: "int"): + raise NotImplementedError + def receive_for_hash(self, amount_msat: "int",description: "Bolt11InvoiceDescription",expiry_secs: "int",payment_hash: "PaymentHash"): + raise NotImplementedError + def receive_variable_amount(self, description: "Bolt11InvoiceDescription",expiry_secs: "int"): + raise NotImplementedError + def receive_variable_amount_for_hash(self, description: "Bolt11InvoiceDescription",expiry_secs: "int",payment_hash: "PaymentHash"): + raise NotImplementedError + def receive_variable_amount_via_jit_channel(self, description: "Bolt11InvoiceDescription",expiry_secs: "int",max_proportional_lsp_fee_limit_ppm_msat: "typing.Optional[int]"): + raise NotImplementedError + def receive_variable_amount_via_jit_channel_for_hash(self, description: "Bolt11InvoiceDescription",expiry_secs: "int",max_proportional_lsp_fee_limit_ppm_msat: "typing.Optional[int]",payment_hash: "PaymentHash"): + raise NotImplementedError + def receive_via_jit_channel(self, amount_msat: "int",description: "Bolt11InvoiceDescription",expiry_secs: "int",max_lsp_fee_limit_msat: "typing.Optional[int]"): + raise NotImplementedError + def receive_via_jit_channel_for_hash(self, amount_msat: "int",description: "Bolt11InvoiceDescription",expiry_secs: "int",max_lsp_fee_limit_msat: "typing.Optional[int]",payment_hash: "PaymentHash"): + raise NotImplementedError + def send(self, invoice: "Bolt11Invoice",route_parameters: "typing.Optional[RouteParametersConfig]"): + raise NotImplementedError + def send_probes(self, invoice: "Bolt11Invoice",route_parameters: "typing.Optional[RouteParametersConfig]"): + raise NotImplementedError + def send_probes_using_amount(self, invoice: "Bolt11Invoice",amount_msat: "int",route_parameters: "typing.Optional[RouteParametersConfig]"): + raise NotImplementedError + def send_using_amount(self, invoice: "Bolt11Invoice",amount_msat: "int",route_parameters: "typing.Optional[RouteParametersConfig]"): + raise NotImplementedError + + +class Bolt11Payment: + _pointer: ctypes.c_void_p + + def __init__(self, *args, **kwargs): + raise ValueError("This class has no default constructor") + + def __del__(self): + # In case of partial initialization of instances. + pointer = getattr(self, "_pointer", None) + if pointer is not None: + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_free_bolt11payment, pointer) + + def _uniffi_clone_pointer(self): + return _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_clone_bolt11payment, self._pointer) + + # Used by alternative constructors or any methods which return this type. + @classmethod + def _make_instance_(cls, pointer): + # Lightly yucky way to bypass the usual __init__ logic + # and just create a new instance with the required pointer. + inst = cls.__new__(cls) + inst._pointer = pointer + return inst + + + def claim_for_hash(self, payment_hash: "PaymentHash",claimable_amount_msat: "int",preimage: "PaymentPreimage") -> None: + _UniffiConverterTypePaymentHash.check_lower(payment_hash) + + _UniffiConverterUInt64.check_lower(claimable_amount_msat) + + _UniffiConverterTypePaymentPreimage.check_lower(preimage) + + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_claim_for_hash,self._uniffi_clone_pointer(), + _UniffiConverterTypePaymentHash.lower(payment_hash), + _UniffiConverterUInt64.lower(claimable_amount_msat), + _UniffiConverterTypePaymentPreimage.lower(preimage)) + + + + + + + def estimate_routing_fees(self, invoice: "Bolt11Invoice") -> "int": + _UniffiConverterTypeBolt11Invoice.check_lower(invoice) + + return _UniffiConverterUInt64.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_estimate_routing_fees,self._uniffi_clone_pointer(), + _UniffiConverterTypeBolt11Invoice.lower(invoice)) + ) + + + + + + def estimate_routing_fees_using_amount(self, invoice: "Bolt11Invoice",amount_msat: "int") -> "int": + _UniffiConverterTypeBolt11Invoice.check_lower(invoice) + + _UniffiConverterUInt64.check_lower(amount_msat) + + return _UniffiConverterUInt64.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_estimate_routing_fees_using_amount,self._uniffi_clone_pointer(), + _UniffiConverterTypeBolt11Invoice.lower(invoice), + _UniffiConverterUInt64.lower(amount_msat)) + ) + + + + + + def fail_for_hash(self, payment_hash: "PaymentHash") -> None: + _UniffiConverterTypePaymentHash.check_lower(payment_hash) + + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_fail_for_hash,self._uniffi_clone_pointer(), + _UniffiConverterTypePaymentHash.lower(payment_hash)) + + + + + + + def receive(self, amount_msat: "int",description: "Bolt11InvoiceDescription",expiry_secs: "int") -> "Bolt11Invoice": + _UniffiConverterUInt64.check_lower(amount_msat) + + _UniffiConverterTypeBolt11InvoiceDescription.check_lower(description) + + _UniffiConverterUInt32.check_lower(expiry_secs) + + return _UniffiConverterTypeBolt11Invoice.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_receive,self._uniffi_clone_pointer(), + _UniffiConverterUInt64.lower(amount_msat), + _UniffiConverterTypeBolt11InvoiceDescription.lower(description), + _UniffiConverterUInt32.lower(expiry_secs)) + ) + + + + + + def receive_for_hash(self, amount_msat: "int",description: "Bolt11InvoiceDescription",expiry_secs: "int",payment_hash: "PaymentHash") -> "Bolt11Invoice": + _UniffiConverterUInt64.check_lower(amount_msat) + + _UniffiConverterTypeBolt11InvoiceDescription.check_lower(description) + + _UniffiConverterUInt32.check_lower(expiry_secs) + + _UniffiConverterTypePaymentHash.check_lower(payment_hash) + + return _UniffiConverterTypeBolt11Invoice.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_receive_for_hash,self._uniffi_clone_pointer(), + _UniffiConverterUInt64.lower(amount_msat), + _UniffiConverterTypeBolt11InvoiceDescription.lower(description), + _UniffiConverterUInt32.lower(expiry_secs), + _UniffiConverterTypePaymentHash.lower(payment_hash)) + ) + + + + + + def receive_variable_amount(self, description: "Bolt11InvoiceDescription",expiry_secs: "int") -> "Bolt11Invoice": + _UniffiConverterTypeBolt11InvoiceDescription.check_lower(description) + + _UniffiConverterUInt32.check_lower(expiry_secs) + + return _UniffiConverterTypeBolt11Invoice.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount,self._uniffi_clone_pointer(), + _UniffiConverterTypeBolt11InvoiceDescription.lower(description), + _UniffiConverterUInt32.lower(expiry_secs)) + ) + + + + + + def receive_variable_amount_for_hash(self, description: "Bolt11InvoiceDescription",expiry_secs: "int",payment_hash: "PaymentHash") -> "Bolt11Invoice": + _UniffiConverterTypeBolt11InvoiceDescription.check_lower(description) + + _UniffiConverterUInt32.check_lower(expiry_secs) + + _UniffiConverterTypePaymentHash.check_lower(payment_hash) + + return _UniffiConverterTypeBolt11Invoice.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount_for_hash,self._uniffi_clone_pointer(), + _UniffiConverterTypeBolt11InvoiceDescription.lower(description), + _UniffiConverterUInt32.lower(expiry_secs), + _UniffiConverterTypePaymentHash.lower(payment_hash)) + ) + + + + + + def receive_variable_amount_via_jit_channel(self, description: "Bolt11InvoiceDescription",expiry_secs: "int",max_proportional_lsp_fee_limit_ppm_msat: "typing.Optional[int]") -> "Bolt11Invoice": + _UniffiConverterTypeBolt11InvoiceDescription.check_lower(description) + + _UniffiConverterUInt32.check_lower(expiry_secs) + + _UniffiConverterOptionalUInt64.check_lower(max_proportional_lsp_fee_limit_ppm_msat) + + return _UniffiConverterTypeBolt11Invoice.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount_via_jit_channel,self._uniffi_clone_pointer(), + _UniffiConverterTypeBolt11InvoiceDescription.lower(description), + _UniffiConverterUInt32.lower(expiry_secs), + _UniffiConverterOptionalUInt64.lower(max_proportional_lsp_fee_limit_ppm_msat)) + ) + + + + + + def receive_variable_amount_via_jit_channel_for_hash(self, description: "Bolt11InvoiceDescription",expiry_secs: "int",max_proportional_lsp_fee_limit_ppm_msat: "typing.Optional[int]",payment_hash: "PaymentHash") -> "Bolt11Invoice": + _UniffiConverterTypeBolt11InvoiceDescription.check_lower(description) + + _UniffiConverterUInt32.check_lower(expiry_secs) + + _UniffiConverterOptionalUInt64.check_lower(max_proportional_lsp_fee_limit_ppm_msat) + + _UniffiConverterTypePaymentHash.check_lower(payment_hash) + + return _UniffiConverterTypeBolt11Invoice.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount_via_jit_channel_for_hash,self._uniffi_clone_pointer(), + _UniffiConverterTypeBolt11InvoiceDescription.lower(description), + _UniffiConverterUInt32.lower(expiry_secs), + _UniffiConverterOptionalUInt64.lower(max_proportional_lsp_fee_limit_ppm_msat), + _UniffiConverterTypePaymentHash.lower(payment_hash)) + ) + + + + + + def receive_via_jit_channel(self, amount_msat: "int",description: "Bolt11InvoiceDescription",expiry_secs: "int",max_lsp_fee_limit_msat: "typing.Optional[int]") -> "Bolt11Invoice": + _UniffiConverterUInt64.check_lower(amount_msat) + + _UniffiConverterTypeBolt11InvoiceDescription.check_lower(description) + + _UniffiConverterUInt32.check_lower(expiry_secs) + + _UniffiConverterOptionalUInt64.check_lower(max_lsp_fee_limit_msat) + + return _UniffiConverterTypeBolt11Invoice.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_receive_via_jit_channel,self._uniffi_clone_pointer(), + _UniffiConverterUInt64.lower(amount_msat), + _UniffiConverterTypeBolt11InvoiceDescription.lower(description), + _UniffiConverterUInt32.lower(expiry_secs), + _UniffiConverterOptionalUInt64.lower(max_lsp_fee_limit_msat)) + ) + + + + + + def receive_via_jit_channel_for_hash(self, amount_msat: "int",description: "Bolt11InvoiceDescription",expiry_secs: "int",max_lsp_fee_limit_msat: "typing.Optional[int]",payment_hash: "PaymentHash") -> "Bolt11Invoice": + _UniffiConverterUInt64.check_lower(amount_msat) + + _UniffiConverterTypeBolt11InvoiceDescription.check_lower(description) + + _UniffiConverterUInt32.check_lower(expiry_secs) + + _UniffiConverterOptionalUInt64.check_lower(max_lsp_fee_limit_msat) + + _UniffiConverterTypePaymentHash.check_lower(payment_hash) + + return _UniffiConverterTypeBolt11Invoice.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_receive_via_jit_channel_for_hash,self._uniffi_clone_pointer(), + _UniffiConverterUInt64.lower(amount_msat), + _UniffiConverterTypeBolt11InvoiceDescription.lower(description), + _UniffiConverterUInt32.lower(expiry_secs), + _UniffiConverterOptionalUInt64.lower(max_lsp_fee_limit_msat), + _UniffiConverterTypePaymentHash.lower(payment_hash)) + ) + + + + + + def send(self, invoice: "Bolt11Invoice",route_parameters: "typing.Optional[RouteParametersConfig]") -> "PaymentId": + _UniffiConverterTypeBolt11Invoice.check_lower(invoice) + + _UniffiConverterOptionalTypeRouteParametersConfig.check_lower(route_parameters) + + return _UniffiConverterTypePaymentId.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_send,self._uniffi_clone_pointer(), + _UniffiConverterTypeBolt11Invoice.lower(invoice), + _UniffiConverterOptionalTypeRouteParametersConfig.lower(route_parameters)) + ) + + + + + + def send_probes(self, invoice: "Bolt11Invoice",route_parameters: "typing.Optional[RouteParametersConfig]") -> "typing.List[ProbeHandle]": + _UniffiConverterTypeBolt11Invoice.check_lower(invoice) + + _UniffiConverterOptionalTypeRouteParametersConfig.check_lower(route_parameters) + + return _UniffiConverterSequenceTypeProbeHandle.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_send_probes,self._uniffi_clone_pointer(), + _UniffiConverterTypeBolt11Invoice.lower(invoice), + _UniffiConverterOptionalTypeRouteParametersConfig.lower(route_parameters)) + ) + + + + + + def send_probes_using_amount(self, invoice: "Bolt11Invoice",amount_msat: "int",route_parameters: "typing.Optional[RouteParametersConfig]") -> "typing.List[ProbeHandle]": + _UniffiConverterTypeBolt11Invoice.check_lower(invoice) + + _UniffiConverterUInt64.check_lower(amount_msat) + + _UniffiConverterOptionalTypeRouteParametersConfig.check_lower(route_parameters) + + return _UniffiConverterSequenceTypeProbeHandle.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_send_probes_using_amount,self._uniffi_clone_pointer(), + _UniffiConverterTypeBolt11Invoice.lower(invoice), + _UniffiConverterUInt64.lower(amount_msat), + _UniffiConverterOptionalTypeRouteParametersConfig.lower(route_parameters)) + ) + + + + + + def send_using_amount(self, invoice: "Bolt11Invoice",amount_msat: "int",route_parameters: "typing.Optional[RouteParametersConfig]") -> "PaymentId": + _UniffiConverterTypeBolt11Invoice.check_lower(invoice) + + _UniffiConverterUInt64.check_lower(amount_msat) + + _UniffiConverterOptionalTypeRouteParametersConfig.check_lower(route_parameters) + + return _UniffiConverterTypePaymentId.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_send_using_amount,self._uniffi_clone_pointer(), + _UniffiConverterTypeBolt11Invoice.lower(invoice), + _UniffiConverterUInt64.lower(amount_msat), + _UniffiConverterOptionalTypeRouteParametersConfig.lower(route_parameters)) + ) + + + + + + +class _UniffiConverterTypeBolt11Payment: + + @staticmethod + def lift(value: int): + return Bolt11Payment._make_instance_(value) + + @staticmethod + def check_lower(value: Bolt11Payment): + if not isinstance(value, Bolt11Payment): + raise TypeError("Expected Bolt11Payment instance, {} found".format(type(value).__name__)) + + @staticmethod + def lower(value: Bolt11PaymentProtocol): + if not isinstance(value, Bolt11Payment): + raise TypeError("Expected Bolt11Payment instance, {} found".format(type(value).__name__)) + return value._uniffi_clone_pointer() + + @classmethod + def read(cls, buf: _UniffiRustBuffer): + ptr = buf.read_u64() + if ptr == 0: + raise InternalError("Raw pointer value was null") + return cls.lift(ptr) + + @classmethod + def write(cls, value: Bolt11PaymentProtocol, buf: _UniffiRustBuffer): + buf.write_u64(cls.lower(value)) + + + +class Bolt12InvoiceProtocol(typing.Protocol): + def absolute_expiry_seconds(self, ): + raise NotImplementedError + def amount(self, ): + raise NotImplementedError + def amount_msats(self, ): + raise NotImplementedError + def chain(self, ): + raise NotImplementedError + def created_at(self, ): + raise NotImplementedError + def encode(self, ): + raise NotImplementedError + def fallback_addresses(self, ): + raise NotImplementedError + def invoice_description(self, ): + raise NotImplementedError + def is_expired(self, ): + raise NotImplementedError + def issuer(self, ): + raise NotImplementedError + def issuer_signing_pubkey(self, ): + raise NotImplementedError + def metadata(self, ): + raise NotImplementedError + def offer_chains(self, ): + raise NotImplementedError + def payer_note(self, ): + raise NotImplementedError + def payer_signing_pubkey(self, ): + raise NotImplementedError + def payment_hash(self, ): + raise NotImplementedError + def quantity(self, ): + raise NotImplementedError + def relative_expiry(self, ): + raise NotImplementedError + def signable_hash(self, ): + raise NotImplementedError + def signing_pubkey(self, ): + raise NotImplementedError + + +class Bolt12Invoice: + _pointer: ctypes.c_void_p + + def __init__(self, *args, **kwargs): + raise ValueError("This class has no default constructor") + + def __del__(self): + # In case of partial initialization of instances. + pointer = getattr(self, "_pointer", None) + if pointer is not None: + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_free_bolt12invoice, pointer) + + def _uniffi_clone_pointer(self): + return _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_clone_bolt12invoice, self._pointer) + + # Used by alternative constructors or any methods which return this type. + @classmethod + def _make_instance_(cls, pointer): + # Lightly yucky way to bypass the usual __init__ logic + # and just create a new instance with the required pointer. + inst = cls.__new__(cls) + inst._pointer = pointer + return inst + @classmethod + def from_str(cls, invoice_str: "str"): + _UniffiConverterString.check_lower(invoice_str) + + # Call the (fallible) function before creating any half-baked object instances. + pointer = _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_constructor_bolt12invoice_from_str, + _UniffiConverterString.lower(invoice_str)) + return cls._make_instance_(pointer) + + + + def absolute_expiry_seconds(self, ) -> "typing.Optional[int]": + return _UniffiConverterOptionalUInt64.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_absolute_expiry_seconds,self._uniffi_clone_pointer(),) + ) + + + + + + def amount(self, ) -> "typing.Optional[OfferAmount]": + return _UniffiConverterOptionalTypeOfferAmount.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_amount,self._uniffi_clone_pointer(),) + ) + + + + + + def amount_msats(self, ) -> "int": + return _UniffiConverterUInt64.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_amount_msats,self._uniffi_clone_pointer(),) + ) + + + + + + def chain(self, ) -> "typing.List[int]": + return _UniffiConverterSequenceUInt8.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_chain,self._uniffi_clone_pointer(),) + ) + + + + + + def created_at(self, ) -> "int": + return _UniffiConverterUInt64.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_created_at,self._uniffi_clone_pointer(),) + ) + + + + + + def encode(self, ) -> "typing.List[int]": + return _UniffiConverterSequenceUInt8.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_encode,self._uniffi_clone_pointer(),) + ) + + + + + + def fallback_addresses(self, ) -> "typing.List[Address]": + return _UniffiConverterSequenceTypeAddress.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_fallback_addresses,self._uniffi_clone_pointer(),) + ) + + + + + + def invoice_description(self, ) -> "typing.Optional[str]": + return _UniffiConverterOptionalString.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_invoice_description,self._uniffi_clone_pointer(),) + ) + + + + + + def is_expired(self, ) -> "bool": + return _UniffiConverterBool.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_is_expired,self._uniffi_clone_pointer(),) + ) + + + + + + def issuer(self, ) -> "typing.Optional[str]": + return _UniffiConverterOptionalString.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_issuer,self._uniffi_clone_pointer(),) + ) + + + + + + def issuer_signing_pubkey(self, ) -> "typing.Optional[PublicKey]": + return _UniffiConverterOptionalTypePublicKey.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_issuer_signing_pubkey,self._uniffi_clone_pointer(),) + ) + + + + + + def metadata(self, ) -> "typing.Optional[typing.List[int]]": + return _UniffiConverterOptionalSequenceUInt8.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_metadata,self._uniffi_clone_pointer(),) + ) + + + + + + def offer_chains(self, ) -> "typing.Optional[typing.List[typing.List[int]]]": + return _UniffiConverterOptionalSequenceSequenceUInt8.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_offer_chains,self._uniffi_clone_pointer(),) + ) + + + + + + def payer_note(self, ) -> "typing.Optional[str]": + return _UniffiConverterOptionalString.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_payer_note,self._uniffi_clone_pointer(),) + ) + + + + + + def payer_signing_pubkey(self, ) -> "PublicKey": + return _UniffiConverterTypePublicKey.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_payer_signing_pubkey,self._uniffi_clone_pointer(),) + ) + + + + + + def payment_hash(self, ) -> "PaymentHash": + return _UniffiConverterTypePaymentHash.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_payment_hash,self._uniffi_clone_pointer(),) + ) + + + + + + def quantity(self, ) -> "typing.Optional[int]": + return _UniffiConverterOptionalUInt64.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_quantity,self._uniffi_clone_pointer(),) + ) + + + + + + def relative_expiry(self, ) -> "int": + return _UniffiConverterUInt64.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_relative_expiry,self._uniffi_clone_pointer(),) + ) + + + + + + def signable_hash(self, ) -> "typing.List[int]": + return _UniffiConverterSequenceUInt8.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_signable_hash,self._uniffi_clone_pointer(),) + ) + + + + + + def signing_pubkey(self, ) -> "PublicKey": + return _UniffiConverterTypePublicKey.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_bolt12invoice_signing_pubkey,self._uniffi_clone_pointer(),) + ) + + + + + + +class _UniffiConverterTypeBolt12Invoice: + + @staticmethod + def lift(value: int): + return Bolt12Invoice._make_instance_(value) + + @staticmethod + def check_lower(value: Bolt12Invoice): + if not isinstance(value, Bolt12Invoice): + raise TypeError("Expected Bolt12Invoice instance, {} found".format(type(value).__name__)) + + @staticmethod + def lower(value: Bolt12InvoiceProtocol): + if not isinstance(value, Bolt12Invoice): + raise TypeError("Expected Bolt12Invoice instance, {} found".format(type(value).__name__)) + return value._uniffi_clone_pointer() + + @classmethod + def read(cls, buf: _UniffiRustBuffer): + ptr = buf.read_u64() + if ptr == 0: + raise InternalError("Raw pointer value was null") + return cls.lift(ptr) + + @classmethod + def write(cls, value: Bolt12InvoiceProtocol, buf: _UniffiRustBuffer): + buf.write_u64(cls.lower(value)) + + + +class Bolt12PaymentProtocol(typing.Protocol): + def blinded_paths_for_async_recipient(self, recipient_id: "bytes"): + raise NotImplementedError + def initiate_refund(self, amount_msat: "int",expiry_secs: "int",quantity: "typing.Optional[int]",payer_note: "typing.Optional[str]",route_parameters: "typing.Optional[RouteParametersConfig]"): + raise NotImplementedError + def receive(self, amount_msat: "int",description: "str",expiry_secs: "typing.Optional[int]",quantity: "typing.Optional[int]"): + raise NotImplementedError + def receive_async(self, ): + raise NotImplementedError + def receive_variable_amount(self, description: "str",expiry_secs: "typing.Optional[int]"): + raise NotImplementedError + def request_refund_payment(self, refund: "Refund"): + raise NotImplementedError + def send(self, offer: "Offer",quantity: "typing.Optional[int]",payer_note: "typing.Optional[str]",route_parameters: "typing.Optional[RouteParametersConfig]"): + raise NotImplementedError + def send_using_amount(self, offer: "Offer",amount_msat: "int",quantity: "typing.Optional[int]",payer_note: "typing.Optional[str]",route_parameters: "typing.Optional[RouteParametersConfig]"): + raise NotImplementedError + def set_paths_to_static_invoice_server(self, paths: "bytes"): + raise NotImplementedError + + +class Bolt12Payment: + _pointer: ctypes.c_void_p + + def __init__(self, *args, **kwargs): + raise ValueError("This class has no default constructor") + + def __del__(self): + # In case of partial initialization of instances. + pointer = getattr(self, "_pointer", None) + if pointer is not None: + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_free_bolt12payment, pointer) + + def _uniffi_clone_pointer(self): + return _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_clone_bolt12payment, self._pointer) + + # Used by alternative constructors or any methods which return this type. + @classmethod + def _make_instance_(cls, pointer): + # Lightly yucky way to bypass the usual __init__ logic + # and just create a new instance with the required pointer. + inst = cls.__new__(cls) + inst._pointer = pointer + return inst + + + def blinded_paths_for_async_recipient(self, recipient_id: "bytes") -> "bytes": + _UniffiConverterBytes.check_lower(recipient_id) + + return _UniffiConverterBytes.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_bolt12payment_blinded_paths_for_async_recipient,self._uniffi_clone_pointer(), + _UniffiConverterBytes.lower(recipient_id)) + ) + + + + + + def initiate_refund(self, amount_msat: "int",expiry_secs: "int",quantity: "typing.Optional[int]",payer_note: "typing.Optional[str]",route_parameters: "typing.Optional[RouteParametersConfig]") -> "Refund": + _UniffiConverterUInt64.check_lower(amount_msat) + + _UniffiConverterUInt32.check_lower(expiry_secs) + + _UniffiConverterOptionalUInt64.check_lower(quantity) + + _UniffiConverterOptionalString.check_lower(payer_note) + + _UniffiConverterOptionalTypeRouteParametersConfig.check_lower(route_parameters) + + return _UniffiConverterTypeRefund.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_bolt12payment_initiate_refund,self._uniffi_clone_pointer(), + _UniffiConverterUInt64.lower(amount_msat), + _UniffiConverterUInt32.lower(expiry_secs), + _UniffiConverterOptionalUInt64.lower(quantity), + _UniffiConverterOptionalString.lower(payer_note), + _UniffiConverterOptionalTypeRouteParametersConfig.lower(route_parameters)) + ) + + + + + + def receive(self, amount_msat: "int",description: "str",expiry_secs: "typing.Optional[int]",quantity: "typing.Optional[int]") -> "Offer": + _UniffiConverterUInt64.check_lower(amount_msat) + + _UniffiConverterString.check_lower(description) + + _UniffiConverterOptionalUInt32.check_lower(expiry_secs) + + _UniffiConverterOptionalUInt64.check_lower(quantity) + + return _UniffiConverterTypeOffer.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_bolt12payment_receive,self._uniffi_clone_pointer(), + _UniffiConverterUInt64.lower(amount_msat), + _UniffiConverterString.lower(description), + _UniffiConverterOptionalUInt32.lower(expiry_secs), + _UniffiConverterOptionalUInt64.lower(quantity)) + ) + + + + + + def receive_async(self, ) -> "Offer": + return _UniffiConverterTypeOffer.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_bolt12payment_receive_async,self._uniffi_clone_pointer(),) + ) + + + + + + def receive_variable_amount(self, description: "str",expiry_secs: "typing.Optional[int]") -> "Offer": + _UniffiConverterString.check_lower(description) + + _UniffiConverterOptionalUInt32.check_lower(expiry_secs) + + return _UniffiConverterTypeOffer.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_bolt12payment_receive_variable_amount,self._uniffi_clone_pointer(), + _UniffiConverterString.lower(description), + _UniffiConverterOptionalUInt32.lower(expiry_secs)) + ) + + + + + + def request_refund_payment(self, refund: "Refund") -> "Bolt12Invoice": + _UniffiConverterTypeRefund.check_lower(refund) + + return _UniffiConverterTypeBolt12Invoice.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_bolt12payment_request_refund_payment,self._uniffi_clone_pointer(), + _UniffiConverterTypeRefund.lower(refund)) + ) + + + + + + def send(self, offer: "Offer",quantity: "typing.Optional[int]",payer_note: "typing.Optional[str]",route_parameters: "typing.Optional[RouteParametersConfig]") -> "PaymentId": + _UniffiConverterTypeOffer.check_lower(offer) + + _UniffiConverterOptionalUInt64.check_lower(quantity) + + _UniffiConverterOptionalString.check_lower(payer_note) + + _UniffiConverterOptionalTypeRouteParametersConfig.check_lower(route_parameters) + + return _UniffiConverterTypePaymentId.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_bolt12payment_send,self._uniffi_clone_pointer(), + _UniffiConverterTypeOffer.lower(offer), + _UniffiConverterOptionalUInt64.lower(quantity), + _UniffiConverterOptionalString.lower(payer_note), + _UniffiConverterOptionalTypeRouteParametersConfig.lower(route_parameters)) + ) + + + + + + def send_using_amount(self, offer: "Offer",amount_msat: "int",quantity: "typing.Optional[int]",payer_note: "typing.Optional[str]",route_parameters: "typing.Optional[RouteParametersConfig]") -> "PaymentId": + _UniffiConverterTypeOffer.check_lower(offer) + + _UniffiConverterUInt64.check_lower(amount_msat) + + _UniffiConverterOptionalUInt64.check_lower(quantity) + + _UniffiConverterOptionalString.check_lower(payer_note) + + _UniffiConverterOptionalTypeRouteParametersConfig.check_lower(route_parameters) + + return _UniffiConverterTypePaymentId.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_bolt12payment_send_using_amount,self._uniffi_clone_pointer(), + _UniffiConverterTypeOffer.lower(offer), + _UniffiConverterUInt64.lower(amount_msat), + _UniffiConverterOptionalUInt64.lower(quantity), + _UniffiConverterOptionalString.lower(payer_note), + _UniffiConverterOptionalTypeRouteParametersConfig.lower(route_parameters)) + ) + + + + + + def set_paths_to_static_invoice_server(self, paths: "bytes") -> None: + _UniffiConverterBytes.check_lower(paths) + + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_bolt12payment_set_paths_to_static_invoice_server,self._uniffi_clone_pointer(), + _UniffiConverterBytes.lower(paths)) + + + + + + + +class _UniffiConverterTypeBolt12Payment: + + @staticmethod + def lift(value: int): + return Bolt12Payment._make_instance_(value) + + @staticmethod + def check_lower(value: Bolt12Payment): + if not isinstance(value, Bolt12Payment): + raise TypeError("Expected Bolt12Payment instance, {} found".format(type(value).__name__)) + + @staticmethod + def lower(value: Bolt12PaymentProtocol): + if not isinstance(value, Bolt12Payment): + raise TypeError("Expected Bolt12Payment instance, {} found".format(type(value).__name__)) + return value._uniffi_clone_pointer() + + @classmethod + def read(cls, buf: _UniffiRustBuffer): + ptr = buf.read_u64() + if ptr == 0: + raise InternalError("Raw pointer value was null") + return cls.lift(ptr) + + @classmethod + def write(cls, value: Bolt12PaymentProtocol, buf: _UniffiRustBuffer): + buf.write_u64(cls.lower(value)) + + + +class BuilderProtocol(typing.Protocol): + def build(self, ): + raise NotImplementedError + def build_with_fs_store(self, ): + raise NotImplementedError + def build_with_vss_store(self, vss_url: "str",store_id: "str",lnurl_auth_server_url: "str",fixed_headers: "dict[str, str]"): + raise NotImplementedError + def build_with_vss_store_and_fixed_headers(self, vss_url: "str",store_id: "str",fixed_headers: "dict[str, str]"): + raise NotImplementedError + def build_with_vss_store_and_header_provider(self, vss_url: "str",store_id: "str",header_provider: "VssHeaderProvider"): + raise NotImplementedError + def set_address_type(self, address_type: "AddressType"): + raise NotImplementedError + def set_address_types_to_monitor(self, address_types_to_monitor: "typing.List[AddressType]"): + raise NotImplementedError + def set_announcement_addresses(self, announcement_addresses: "typing.List[SocketAddress]"): + raise NotImplementedError + def set_async_payments_role(self, role: "typing.Optional[AsyncPaymentsRole]"): + raise NotImplementedError + def set_chain_source_bitcoind_rest(self, rest_host: "str",rest_port: "int",rpc_host: "str",rpc_port: "int",rpc_user: "str",rpc_password: "str"): + raise NotImplementedError + def set_chain_source_bitcoind_rpc(self, rpc_host: "str",rpc_port: "int",rpc_user: "str",rpc_password: "str"): + raise NotImplementedError + def set_chain_source_electrum(self, server_url: "str",config: "typing.Optional[ElectrumSyncConfig]"): + raise NotImplementedError + def set_chain_source_esplora(self, server_url: "str",config: "typing.Optional[EsploraSyncConfig]"): + raise NotImplementedError + def set_channel_data_migration(self, migration: "ChannelDataMigration"): + raise NotImplementedError + def set_custom_logger(self, log_writer: "LogWriter"): + raise NotImplementedError + def set_entropy_bip39_mnemonic(self, mnemonic: "Mnemonic",passphrase: "typing.Optional[str]"): + raise NotImplementedError + def set_entropy_seed_bytes(self, seed_bytes: "typing.List[int]"): + raise NotImplementedError + def set_entropy_seed_path(self, seed_path: "str"): + raise NotImplementedError + def set_filesystem_logger(self, log_file_path: "typing.Optional[str]",max_log_level: "typing.Optional[LogLevel]"): + raise NotImplementedError + def set_gossip_source_p2p(self, ): + raise NotImplementedError + def set_gossip_source_rgs(self, rgs_server_url: "str"): + raise NotImplementedError + def set_liquidity_source_lsps1(self, node_id: "PublicKey",address: "SocketAddress",token: "typing.Optional[str]"): + raise NotImplementedError + def set_liquidity_source_lsps2(self, node_id: "PublicKey",address: "SocketAddress",token: "typing.Optional[str]"): + raise NotImplementedError + def set_listening_addresses(self, listening_addresses: "typing.List[SocketAddress]"): + raise NotImplementedError + def set_log_facade_logger(self, ): + raise NotImplementedError + def set_network(self, network: "Network"): + raise NotImplementedError + def set_node_alias(self, node_alias: "str"): + raise NotImplementedError + def set_pathfinding_scores_source(self, url: "str"): + raise NotImplementedError + def set_scoring_decay_params(self, params: "ScoringDecayParameters"): + raise NotImplementedError + def set_scoring_fee_params(self, params: "ScoringFeeParameters"): + raise NotImplementedError + def set_storage_dir_path(self, storage_dir_path: "str"): + raise NotImplementedError + + +class Builder: + _pointer: ctypes.c_void_p + def __init__(self, ): + self._pointer = _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_constructor_builder_new,) + + def __del__(self): + # In case of partial initialization of instances. + pointer = getattr(self, "_pointer", None) + if pointer is not None: + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_free_builder, pointer) + + def _uniffi_clone_pointer(self): + return _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_clone_builder, self._pointer) + + # Used by alternative constructors or any methods which return this type. + @classmethod + def _make_instance_(cls, pointer): + # Lightly yucky way to bypass the usual __init__ logic + # and just create a new instance with the required pointer. + inst = cls.__new__(cls) + inst._pointer = pointer + return inst + @classmethod + def from_config(cls, config: "Config"): + _UniffiConverterTypeConfig.check_lower(config) + + # Call the (fallible) function before creating any half-baked object instances. + pointer = _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_constructor_builder_from_config, + _UniffiConverterTypeConfig.lower(config)) + return cls._make_instance_(pointer) + + + + def build(self, ) -> "Node": + return _UniffiConverterTypeNode.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeBuildError,_UniffiLib.uniffi_ldk_node_fn_method_builder_build,self._uniffi_clone_pointer(),) + ) + + + + + + def build_with_fs_store(self, ) -> "Node": + return _UniffiConverterTypeNode.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeBuildError,_UniffiLib.uniffi_ldk_node_fn_method_builder_build_with_fs_store,self._uniffi_clone_pointer(),) + ) + + + + + + def build_with_vss_store(self, vss_url: "str",store_id: "str",lnurl_auth_server_url: "str",fixed_headers: "dict[str, str]") -> "Node": + _UniffiConverterString.check_lower(vss_url) + + _UniffiConverterString.check_lower(store_id) + + _UniffiConverterString.check_lower(lnurl_auth_server_url) + + _UniffiConverterMapStringString.check_lower(fixed_headers) + + return _UniffiConverterTypeNode.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeBuildError,_UniffiLib.uniffi_ldk_node_fn_method_builder_build_with_vss_store,self._uniffi_clone_pointer(), + _UniffiConverterString.lower(vss_url), + _UniffiConverterString.lower(store_id), + _UniffiConverterString.lower(lnurl_auth_server_url), + _UniffiConverterMapStringString.lower(fixed_headers)) + ) + + + + + + def build_with_vss_store_and_fixed_headers(self, vss_url: "str",store_id: "str",fixed_headers: "dict[str, str]") -> "Node": + _UniffiConverterString.check_lower(vss_url) + + _UniffiConverterString.check_lower(store_id) + + _UniffiConverterMapStringString.check_lower(fixed_headers) + + return _UniffiConverterTypeNode.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeBuildError,_UniffiLib.uniffi_ldk_node_fn_method_builder_build_with_vss_store_and_fixed_headers,self._uniffi_clone_pointer(), + _UniffiConverterString.lower(vss_url), + _UniffiConverterString.lower(store_id), + _UniffiConverterMapStringString.lower(fixed_headers)) + ) + + + + + + def build_with_vss_store_and_header_provider(self, vss_url: "str",store_id: "str",header_provider: "VssHeaderProvider") -> "Node": + _UniffiConverterString.check_lower(vss_url) + + _UniffiConverterString.check_lower(store_id) + + _UniffiConverterTypeVssHeaderProvider.check_lower(header_provider) + + return _UniffiConverterTypeNode.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeBuildError,_UniffiLib.uniffi_ldk_node_fn_method_builder_build_with_vss_store_and_header_provider,self._uniffi_clone_pointer(), + _UniffiConverterString.lower(vss_url), + _UniffiConverterString.lower(store_id), + _UniffiConverterTypeVssHeaderProvider.lower(header_provider)) + ) + + + + + + def set_address_type(self, address_type: "AddressType") -> None: + _UniffiConverterTypeAddressType.check_lower(address_type) + + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_builder_set_address_type,self._uniffi_clone_pointer(), + _UniffiConverterTypeAddressType.lower(address_type)) + + + + + + + def set_address_types_to_monitor(self, address_types_to_monitor: "typing.List[AddressType]") -> None: + _UniffiConverterSequenceTypeAddressType.check_lower(address_types_to_monitor) + + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_builder_set_address_types_to_monitor,self._uniffi_clone_pointer(), + _UniffiConverterSequenceTypeAddressType.lower(address_types_to_monitor)) + + + + + + + def set_announcement_addresses(self, announcement_addresses: "typing.List[SocketAddress]") -> None: + _UniffiConverterSequenceTypeSocketAddress.check_lower(announcement_addresses) + + _uniffi_rust_call_with_error(_UniffiConverterTypeBuildError,_UniffiLib.uniffi_ldk_node_fn_method_builder_set_announcement_addresses,self._uniffi_clone_pointer(), + _UniffiConverterSequenceTypeSocketAddress.lower(announcement_addresses)) + + + + + + + def set_async_payments_role(self, role: "typing.Optional[AsyncPaymentsRole]") -> None: + _UniffiConverterOptionalTypeAsyncPaymentsRole.check_lower(role) + + _uniffi_rust_call_with_error(_UniffiConverterTypeBuildError,_UniffiLib.uniffi_ldk_node_fn_method_builder_set_async_payments_role,self._uniffi_clone_pointer(), + _UniffiConverterOptionalTypeAsyncPaymentsRole.lower(role)) + + + + + + + def set_chain_source_bitcoind_rest(self, rest_host: "str",rest_port: "int",rpc_host: "str",rpc_port: "int",rpc_user: "str",rpc_password: "str") -> None: + _UniffiConverterString.check_lower(rest_host) + + _UniffiConverterUInt16.check_lower(rest_port) + + _UniffiConverterString.check_lower(rpc_host) + + _UniffiConverterUInt16.check_lower(rpc_port) + + _UniffiConverterString.check_lower(rpc_user) + + _UniffiConverterString.check_lower(rpc_password) + + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_builder_set_chain_source_bitcoind_rest,self._uniffi_clone_pointer(), + _UniffiConverterString.lower(rest_host), + _UniffiConverterUInt16.lower(rest_port), + _UniffiConverterString.lower(rpc_host), + _UniffiConverterUInt16.lower(rpc_port), + _UniffiConverterString.lower(rpc_user), + _UniffiConverterString.lower(rpc_password)) + + + + + + + def set_chain_source_bitcoind_rpc(self, rpc_host: "str",rpc_port: "int",rpc_user: "str",rpc_password: "str") -> None: + _UniffiConverterString.check_lower(rpc_host) + + _UniffiConverterUInt16.check_lower(rpc_port) + + _UniffiConverterString.check_lower(rpc_user) + + _UniffiConverterString.check_lower(rpc_password) + + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_builder_set_chain_source_bitcoind_rpc,self._uniffi_clone_pointer(), + _UniffiConverterString.lower(rpc_host), + _UniffiConverterUInt16.lower(rpc_port), + _UniffiConverterString.lower(rpc_user), + _UniffiConverterString.lower(rpc_password)) + + + + + + + def set_chain_source_electrum(self, server_url: "str",config: "typing.Optional[ElectrumSyncConfig]") -> None: + _UniffiConverterString.check_lower(server_url) + + _UniffiConverterOptionalTypeElectrumSyncConfig.check_lower(config) + + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_builder_set_chain_source_electrum,self._uniffi_clone_pointer(), + _UniffiConverterString.lower(server_url), + _UniffiConverterOptionalTypeElectrumSyncConfig.lower(config)) + + + + + + + def set_chain_source_esplora(self, server_url: "str",config: "typing.Optional[EsploraSyncConfig]") -> None: + _UniffiConverterString.check_lower(server_url) + + _UniffiConverterOptionalTypeEsploraSyncConfig.check_lower(config) + + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_builder_set_chain_source_esplora,self._uniffi_clone_pointer(), + _UniffiConverterString.lower(server_url), + _UniffiConverterOptionalTypeEsploraSyncConfig.lower(config)) + + + + + + + def set_channel_data_migration(self, migration: "ChannelDataMigration") -> None: + _UniffiConverterTypeChannelDataMigration.check_lower(migration) + + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_builder_set_channel_data_migration,self._uniffi_clone_pointer(), + _UniffiConverterTypeChannelDataMigration.lower(migration)) + + + + + + + def set_custom_logger(self, log_writer: "LogWriter") -> None: + _UniffiConverterTypeLogWriter.check_lower(log_writer) + + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_builder_set_custom_logger,self._uniffi_clone_pointer(), + _UniffiConverterTypeLogWriter.lower(log_writer)) + + + + + + + def set_entropy_bip39_mnemonic(self, mnemonic: "Mnemonic",passphrase: "typing.Optional[str]") -> None: + _UniffiConverterTypeMnemonic.check_lower(mnemonic) + + _UniffiConverterOptionalString.check_lower(passphrase) + + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_builder_set_entropy_bip39_mnemonic,self._uniffi_clone_pointer(), + _UniffiConverterTypeMnemonic.lower(mnemonic), + _UniffiConverterOptionalString.lower(passphrase)) + + + + + + + def set_entropy_seed_bytes(self, seed_bytes: "typing.List[int]") -> None: + _UniffiConverterSequenceUInt8.check_lower(seed_bytes) + + _uniffi_rust_call_with_error(_UniffiConverterTypeBuildError,_UniffiLib.uniffi_ldk_node_fn_method_builder_set_entropy_seed_bytes,self._uniffi_clone_pointer(), + _UniffiConverterSequenceUInt8.lower(seed_bytes)) + + + + + + + def set_entropy_seed_path(self, seed_path: "str") -> None: + _UniffiConverterString.check_lower(seed_path) + + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_builder_set_entropy_seed_path,self._uniffi_clone_pointer(), + _UniffiConverterString.lower(seed_path)) + + + + + + + def set_filesystem_logger(self, log_file_path: "typing.Optional[str]",max_log_level: "typing.Optional[LogLevel]") -> None: + _UniffiConverterOptionalString.check_lower(log_file_path) + + _UniffiConverterOptionalTypeLogLevel.check_lower(max_log_level) + + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_builder_set_filesystem_logger,self._uniffi_clone_pointer(), + _UniffiConverterOptionalString.lower(log_file_path), + _UniffiConverterOptionalTypeLogLevel.lower(max_log_level)) + + + + + + + def set_gossip_source_p2p(self, ) -> None: + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_builder_set_gossip_source_p2p,self._uniffi_clone_pointer(),) + + + + + + + def set_gossip_source_rgs(self, rgs_server_url: "str") -> None: + _UniffiConverterString.check_lower(rgs_server_url) + + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_builder_set_gossip_source_rgs,self._uniffi_clone_pointer(), + _UniffiConverterString.lower(rgs_server_url)) + + + + + + + def set_liquidity_source_lsps1(self, node_id: "PublicKey",address: "SocketAddress",token: "typing.Optional[str]") -> None: + _UniffiConverterTypePublicKey.check_lower(node_id) + + _UniffiConverterTypeSocketAddress.check_lower(address) + + _UniffiConverterOptionalString.check_lower(token) + + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_builder_set_liquidity_source_lsps1,self._uniffi_clone_pointer(), + _UniffiConverterTypePublicKey.lower(node_id), + _UniffiConverterTypeSocketAddress.lower(address), + _UniffiConverterOptionalString.lower(token)) + + + + + + + def set_liquidity_source_lsps2(self, node_id: "PublicKey",address: "SocketAddress",token: "typing.Optional[str]") -> None: + _UniffiConverterTypePublicKey.check_lower(node_id) + + _UniffiConverterTypeSocketAddress.check_lower(address) + + _UniffiConverterOptionalString.check_lower(token) + + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_builder_set_liquidity_source_lsps2,self._uniffi_clone_pointer(), + _UniffiConverterTypePublicKey.lower(node_id), + _UniffiConverterTypeSocketAddress.lower(address), + _UniffiConverterOptionalString.lower(token)) + + + + + + + def set_listening_addresses(self, listening_addresses: "typing.List[SocketAddress]") -> None: + _UniffiConverterSequenceTypeSocketAddress.check_lower(listening_addresses) + + _uniffi_rust_call_with_error(_UniffiConverterTypeBuildError,_UniffiLib.uniffi_ldk_node_fn_method_builder_set_listening_addresses,self._uniffi_clone_pointer(), + _UniffiConverterSequenceTypeSocketAddress.lower(listening_addresses)) + + + + + + + def set_log_facade_logger(self, ) -> None: + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_builder_set_log_facade_logger,self._uniffi_clone_pointer(),) + + + + + + + def set_network(self, network: "Network") -> None: + _UniffiConverterTypeNetwork.check_lower(network) + + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_builder_set_network,self._uniffi_clone_pointer(), + _UniffiConverterTypeNetwork.lower(network)) + + + + + + + def set_node_alias(self, node_alias: "str") -> None: + _UniffiConverterString.check_lower(node_alias) + + _uniffi_rust_call_with_error(_UniffiConverterTypeBuildError,_UniffiLib.uniffi_ldk_node_fn_method_builder_set_node_alias,self._uniffi_clone_pointer(), + _UniffiConverterString.lower(node_alias)) + + + + + + + def set_pathfinding_scores_source(self, url: "str") -> None: + _UniffiConverterString.check_lower(url) + + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_builder_set_pathfinding_scores_source,self._uniffi_clone_pointer(), + _UniffiConverterString.lower(url)) + + + + + + + def set_scoring_decay_params(self, params: "ScoringDecayParameters") -> None: + _UniffiConverterTypeScoringDecayParameters.check_lower(params) + + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_builder_set_scoring_decay_params,self._uniffi_clone_pointer(), + _UniffiConverterTypeScoringDecayParameters.lower(params)) + + + + + + + def set_scoring_fee_params(self, params: "ScoringFeeParameters") -> None: + _UniffiConverterTypeScoringFeeParameters.check_lower(params) + + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_builder_set_scoring_fee_params,self._uniffi_clone_pointer(), + _UniffiConverterTypeScoringFeeParameters.lower(params)) + + + + + + + def set_storage_dir_path(self, storage_dir_path: "str") -> None: + _UniffiConverterString.check_lower(storage_dir_path) + + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_builder_set_storage_dir_path,self._uniffi_clone_pointer(), + _UniffiConverterString.lower(storage_dir_path)) + + + + + + + +class _UniffiConverterTypeBuilder: + + @staticmethod + def lift(value: int): + return Builder._make_instance_(value) + + @staticmethod + def check_lower(value: Builder): + if not isinstance(value, Builder): + raise TypeError("Expected Builder instance, {} found".format(type(value).__name__)) + + @staticmethod + def lower(value: BuilderProtocol): + if not isinstance(value, Builder): + raise TypeError("Expected Builder instance, {} found".format(type(value).__name__)) + return value._uniffi_clone_pointer() + + @classmethod + def read(cls, buf: _UniffiRustBuffer): + ptr = buf.read_u64() + if ptr == 0: + raise InternalError("Raw pointer value was null") + return cls.lift(ptr) + + @classmethod + def write(cls, value: BuilderProtocol, buf: _UniffiRustBuffer): + buf.write_u64(cls.lower(value)) + + + +class FeeRateProtocol(typing.Protocol): + def to_sat_per_kwu(self, ): + raise NotImplementedError + def to_sat_per_vb_ceil(self, ): + raise NotImplementedError + def to_sat_per_vb_floor(self, ): + raise NotImplementedError + + +class FeeRate: + _pointer: ctypes.c_void_p + + def __init__(self, *args, **kwargs): + raise ValueError("This class has no default constructor") + + def __del__(self): + # In case of partial initialization of instances. + pointer = getattr(self, "_pointer", None) + if pointer is not None: + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_free_feerate, pointer) + + def _uniffi_clone_pointer(self): + return _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_clone_feerate, self._pointer) + + # Used by alternative constructors or any methods which return this type. + @classmethod + def _make_instance_(cls, pointer): + # Lightly yucky way to bypass the usual __init__ logic + # and just create a new instance with the required pointer. + inst = cls.__new__(cls) + inst._pointer = pointer + return inst + @classmethod + def from_sat_per_kwu(cls, sat_kwu: "int"): + _UniffiConverterUInt64.check_lower(sat_kwu) + + # Call the (fallible) function before creating any half-baked object instances. + pointer = _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_constructor_feerate_from_sat_per_kwu, + _UniffiConverterUInt64.lower(sat_kwu)) + return cls._make_instance_(pointer) + + @classmethod + def from_sat_per_vb_unchecked(cls, sat_vb: "int"): + _UniffiConverterUInt64.check_lower(sat_vb) + + # Call the (fallible) function before creating any half-baked object instances. + pointer = _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_constructor_feerate_from_sat_per_vb_unchecked, + _UniffiConverterUInt64.lower(sat_vb)) + return cls._make_instance_(pointer) + + + + def to_sat_per_kwu(self, ) -> "int": + return _UniffiConverterUInt64.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_feerate_to_sat_per_kwu,self._uniffi_clone_pointer(),) + ) + + + + + + def to_sat_per_vb_ceil(self, ) -> "int": + return _UniffiConverterUInt64.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_feerate_to_sat_per_vb_ceil,self._uniffi_clone_pointer(),) + ) + + + + + + def to_sat_per_vb_floor(self, ) -> "int": + return _UniffiConverterUInt64.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_feerate_to_sat_per_vb_floor,self._uniffi_clone_pointer(),) + ) + + + + + + +class _UniffiConverterTypeFeeRate: + + @staticmethod + def lift(value: int): + return FeeRate._make_instance_(value) + + @staticmethod + def check_lower(value: FeeRate): + if not isinstance(value, FeeRate): + raise TypeError("Expected FeeRate instance, {} found".format(type(value).__name__)) + + @staticmethod + def lower(value: FeeRateProtocol): + if not isinstance(value, FeeRate): + raise TypeError("Expected FeeRate instance, {} found".format(type(value).__name__)) + return value._uniffi_clone_pointer() + + @classmethod + def read(cls, buf: _UniffiRustBuffer): + ptr = buf.read_u64() + if ptr == 0: + raise InternalError("Raw pointer value was null") + return cls.lift(ptr) + + @classmethod + def write(cls, value: FeeRateProtocol, buf: _UniffiRustBuffer): + buf.write_u64(cls.lower(value)) + + + +class LogWriter(typing.Protocol): + def log(self, record: "LogRecord"): + raise NotImplementedError + + +class LogWriterImpl: + _pointer: ctypes.c_void_p + + def __init__(self, *args, **kwargs): + raise ValueError("This class has no default constructor") + + def __del__(self): + # In case of partial initialization of instances. + pointer = getattr(self, "_pointer", None) + if pointer is not None: + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_free_logwriter, pointer) + + def _uniffi_clone_pointer(self): + return _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_clone_logwriter, self._pointer) + + # Used by alternative constructors or any methods which return this type. + @classmethod + def _make_instance_(cls, pointer): + # Lightly yucky way to bypass the usual __init__ logic + # and just create a new instance with the required pointer. + inst = cls.__new__(cls) + inst._pointer = pointer + return inst + + + def log(self, record: "LogRecord") -> None: + _UniffiConverterTypeLogRecord.check_lower(record) + + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_logwriter_log,self._uniffi_clone_pointer(), + _UniffiConverterTypeLogRecord.lower(record)) + + + + +# Magic number for the Rust proxy to call using the same mechanism as every other method, +# to free the callback once it's dropped by Rust. +_UNIFFI_IDX_CALLBACK_FREE = 0 +# Return codes for callback calls +_UNIFFI_CALLBACK_SUCCESS = 0 +_UNIFFI_CALLBACK_ERROR = 1 +_UNIFFI_CALLBACK_UNEXPECTED_ERROR = 2 + +class _UniffiCallbackInterfaceFfiConverter: + _handle_map = _UniffiHandleMap() + + @classmethod + def lift(cls, handle): + return cls._handle_map.get(handle) + + @classmethod + def read(cls, buf): + handle = buf.read_u64() + cls.lift(handle) + + @classmethod + def check_lower(cls, cb): + pass + + @classmethod + def lower(cls, cb): + handle = cls._handle_map.insert(cb) + return handle + + @classmethod + def write(cls, cb, buf): + buf.write_u64(cls.lower(cb)) + +# Put all the bits inside a class to keep the top-level namespace clean +class _UniffiTraitImplLogWriter: + # For each method, generate a callback function to pass to Rust + + @_UNIFFI_CALLBACK_INTERFACE_LOG_WRITER_METHOD0 + def log( + uniffi_handle, + record, + uniffi_out_return, + uniffi_call_status_ptr, + ): + uniffi_obj = _UniffiConverterTypeLogWriter._handle_map.get(uniffi_handle) + def make_call(): + args = (_UniffiConverterTypeLogRecord.lift(record), ) + method = uniffi_obj.log + return method(*args) + + + write_return_value = lambda v: None + _uniffi_trait_interface_call( + uniffi_call_status_ptr.contents, + make_call, + write_return_value, + ) + + @_UNIFFI_CALLBACK_INTERFACE_FREE + def _uniffi_free(uniffi_handle): + _UniffiConverterTypeLogWriter._handle_map.remove(uniffi_handle) + + # Generate the FFI VTable. This has a field for each callback interface method. + _uniffi_vtable = _UniffiVTableCallbackInterfaceLogWriter( + log, + _uniffi_free + ) + # Send Rust a pointer to the VTable. Note: this means we need to keep the struct alive forever, + # or else bad things will happen when Rust tries to access it. + _UniffiLib.uniffi_ldk_node_fn_init_callback_vtable_logwriter(ctypes.byref(_uniffi_vtable)) + + + +class _UniffiConverterTypeLogWriter: + _handle_map = _UniffiHandleMap() + + @staticmethod + def lift(value: int): + return LogWriterImpl._make_instance_(value) + + @staticmethod + def check_lower(value: LogWriter): + pass + + @staticmethod + def lower(value: LogWriter): + return _UniffiConverterTypeLogWriter._handle_map.insert(value) + + @classmethod + def read(cls, buf: _UniffiRustBuffer): + ptr = buf.read_u64() + if ptr == 0: + raise InternalError("Raw pointer value was null") + return cls.lift(ptr) + + @classmethod + def write(cls, value: LogWriter, buf: _UniffiRustBuffer): + buf.write_u64(cls.lower(value)) + + + +class Lsps1LiquidityProtocol(typing.Protocol): + def check_order_status(self, order_id: "Lsps1OrderId"): + raise NotImplementedError + def request_channel(self, lsp_balance_sat: "int",client_balance_sat: "int",channel_expiry_blocks: "int",announce_channel: "bool"): + raise NotImplementedError + + +class Lsps1Liquidity: + _pointer: ctypes.c_void_p + + def __init__(self, *args, **kwargs): + raise ValueError("This class has no default constructor") + + def __del__(self): + # In case of partial initialization of instances. + pointer = getattr(self, "_pointer", None) + if pointer is not None: + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_free_lsps1liquidity, pointer) + + def _uniffi_clone_pointer(self): + return _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_clone_lsps1liquidity, self._pointer) + + # Used by alternative constructors or any methods which return this type. + @classmethod + def _make_instance_(cls, pointer): + # Lightly yucky way to bypass the usual __init__ logic + # and just create a new instance with the required pointer. + inst = cls.__new__(cls) + inst._pointer = pointer + return inst + + + def check_order_status(self, order_id: "Lsps1OrderId") -> "Lsps1OrderStatus": + _UniffiConverterTypeLsps1OrderId.check_lower(order_id) + + return _UniffiConverterTypeLsps1OrderStatus.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_lsps1liquidity_check_order_status,self._uniffi_clone_pointer(), + _UniffiConverterTypeLsps1OrderId.lower(order_id)) + ) + + + + + + def request_channel(self, lsp_balance_sat: "int",client_balance_sat: "int",channel_expiry_blocks: "int",announce_channel: "bool") -> "Lsps1OrderStatus": + _UniffiConverterUInt64.check_lower(lsp_balance_sat) + + _UniffiConverterUInt64.check_lower(client_balance_sat) + + _UniffiConverterUInt32.check_lower(channel_expiry_blocks) + + _UniffiConverterBool.check_lower(announce_channel) + + return _UniffiConverterTypeLsps1OrderStatus.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_lsps1liquidity_request_channel,self._uniffi_clone_pointer(), + _UniffiConverterUInt64.lower(lsp_balance_sat), + _UniffiConverterUInt64.lower(client_balance_sat), + _UniffiConverterUInt32.lower(channel_expiry_blocks), + _UniffiConverterBool.lower(announce_channel)) + ) + + + + + + +class _UniffiConverterTypeLsps1Liquidity: + + @staticmethod + def lift(value: int): + return Lsps1Liquidity._make_instance_(value) + + @staticmethod + def check_lower(value: Lsps1Liquidity): + if not isinstance(value, Lsps1Liquidity): + raise TypeError("Expected Lsps1Liquidity instance, {} found".format(type(value).__name__)) + + @staticmethod + def lower(value: Lsps1LiquidityProtocol): + if not isinstance(value, Lsps1Liquidity): + raise TypeError("Expected Lsps1Liquidity instance, {} found".format(type(value).__name__)) + return value._uniffi_clone_pointer() + + @classmethod + def read(cls, buf: _UniffiRustBuffer): + ptr = buf.read_u64() + if ptr == 0: + raise InternalError("Raw pointer value was null") + return cls.lift(ptr) + + @classmethod + def write(cls, value: Lsps1LiquidityProtocol, buf: _UniffiRustBuffer): + buf.write_u64(cls.lower(value)) + + + +class NetworkGraphProtocol(typing.Protocol): + def channel(self, short_channel_id: "int"): + raise NotImplementedError + def list_channels(self, ): + raise NotImplementedError + def list_nodes(self, ): + raise NotImplementedError + def node(self, node_id: "NodeId"): + raise NotImplementedError + + +class NetworkGraph: + _pointer: ctypes.c_void_p + + def __init__(self, *args, **kwargs): + raise ValueError("This class has no default constructor") + + def __del__(self): + # In case of partial initialization of instances. + pointer = getattr(self, "_pointer", None) + if pointer is not None: + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_free_networkgraph, pointer) + + def _uniffi_clone_pointer(self): + return _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_clone_networkgraph, self._pointer) + + # Used by alternative constructors or any methods which return this type. + @classmethod + def _make_instance_(cls, pointer): + # Lightly yucky way to bypass the usual __init__ logic + # and just create a new instance with the required pointer. + inst = cls.__new__(cls) + inst._pointer = pointer + return inst + + + def channel(self, short_channel_id: "int") -> "typing.Optional[ChannelInfo]": + _UniffiConverterUInt64.check_lower(short_channel_id) + + return _UniffiConverterOptionalTypeChannelInfo.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_networkgraph_channel,self._uniffi_clone_pointer(), + _UniffiConverterUInt64.lower(short_channel_id)) + ) + + + + + + def list_channels(self, ) -> "typing.List[int]": + return _UniffiConverterSequenceUInt64.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_networkgraph_list_channels,self._uniffi_clone_pointer(),) + ) + + + + + + def list_nodes(self, ) -> "typing.List[NodeId]": + return _UniffiConverterSequenceTypeNodeId.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_networkgraph_list_nodes,self._uniffi_clone_pointer(),) + ) + + + + + + def node(self, node_id: "NodeId") -> "typing.Optional[NodeInfo]": + _UniffiConverterTypeNodeId.check_lower(node_id) + + return _UniffiConverterOptionalTypeNodeInfo.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_networkgraph_node,self._uniffi_clone_pointer(), + _UniffiConverterTypeNodeId.lower(node_id)) + ) + + + + + + +class _UniffiConverterTypeNetworkGraph: + + @staticmethod + def lift(value: int): + return NetworkGraph._make_instance_(value) + + @staticmethod + def check_lower(value: NetworkGraph): + if not isinstance(value, NetworkGraph): + raise TypeError("Expected NetworkGraph instance, {} found".format(type(value).__name__)) + + @staticmethod + def lower(value: NetworkGraphProtocol): + if not isinstance(value, NetworkGraph): + raise TypeError("Expected NetworkGraph instance, {} found".format(type(value).__name__)) + return value._uniffi_clone_pointer() + + @classmethod + def read(cls, buf: _UniffiRustBuffer): + ptr = buf.read_u64() + if ptr == 0: + raise InternalError("Raw pointer value was null") + return cls.lift(ptr) + + @classmethod + def write(cls, value: NetworkGraphProtocol, buf: _UniffiRustBuffer): + buf.write_u64(cls.lower(value)) + + + +class NodeProtocol(typing.Protocol): + def add_address_type_to_monitor(self, address_type: "AddressType",seed_bytes: "typing.List[int]"): + raise NotImplementedError + def add_address_type_to_monitor_with_mnemonic(self, address_type: "AddressType",mnemonic: "Mnemonic",passphrase: "typing.Optional[str]"): + raise NotImplementedError + def add_onchain_wallet_account(self, address_type: "AddressType",account_index: "int",xpub: "str"): + raise NotImplementedError + def announcement_addresses(self, ): + raise NotImplementedError + def bolt11_payment(self, ): + raise NotImplementedError + def bolt12_payment(self, ): + raise NotImplementedError + def close_channel(self, user_channel_id: "UserChannelId",counterparty_node_id: "PublicKey"): + raise NotImplementedError + def config(self, ): + raise NotImplementedError + def connect(self, node_id: "PublicKey",address: "SocketAddress",persist: "bool"): + raise NotImplementedError + def current_sync_intervals(self, ): + raise NotImplementedError + def disconnect(self, node_id: "PublicKey"): + raise NotImplementedError + def event_handled(self, ): + raise NotImplementedError + def export_onchain_wallet_account_xpub(self, address_type: "AddressType",account_index: "int"): + raise NotImplementedError + def export_pathfinding_scores(self, ): + raise NotImplementedError + def force_close_channel(self, user_channel_id: "UserChannelId",counterparty_node_id: "PublicKey",reason: "typing.Optional[str]"): + raise NotImplementedError + def get_address_balance(self, address_str: "str"): + raise NotImplementedError + def get_balance_for_address_type(self, address_type: "AddressType"): + raise NotImplementedError + def get_balance_for_onchain_wallet_account(self, address_type: "AddressType",account_index: "int"): + raise NotImplementedError + def get_transaction_details(self, txid: "Txid"): + raise NotImplementedError + def list_balances(self, ): + raise NotImplementedError + def list_channels(self, ): + raise NotImplementedError + def list_monitored_address_types(self, ): + raise NotImplementedError + def list_onchain_wallet_accounts(self, ): + raise NotImplementedError + def list_payments(self, ): + raise NotImplementedError + def list_peers(self, ): + raise NotImplementedError + def listening_addresses(self, ): + raise NotImplementedError + def lsps1_liquidity(self, ): + raise NotImplementedError + def network_graph(self, ): + raise NotImplementedError + def next_event(self, ): + raise NotImplementedError + def next_event_async(self, ): + raise NotImplementedError + def node_alias(self, ): + raise NotImplementedError + def node_id(self, ): + raise NotImplementedError + def onchain_payment(self, ): + raise NotImplementedError + def open_announced_channel(self, node_id: "PublicKey",address: "SocketAddress",channel_amount_sats: "int",push_to_counterparty_msat: "typing.Optional[int]",channel_config: "typing.Optional[ChannelConfig]"): + raise NotImplementedError + def open_channel(self, node_id: "PublicKey",address: "SocketAddress",channel_amount_sats: "int",push_to_counterparty_msat: "typing.Optional[int]",channel_config: "typing.Optional[ChannelConfig]"): + raise NotImplementedError + def payment(self, payment_id: "PaymentId"): + raise NotImplementedError + def remove_address_type_from_monitor(self, address_type: "AddressType"): + raise NotImplementedError + def remove_onchain_wallet_account(self, address_type: "AddressType",account_index: "int"): + raise NotImplementedError + def remove_payment(self, payment_id: "PaymentId"): + raise NotImplementedError + def set_primary_address_type(self, address_type: "AddressType",seed_bytes: "typing.List[int]"): + raise NotImplementedError + def set_primary_address_type_with_mnemonic(self, address_type: "AddressType",mnemonic: "Mnemonic",passphrase: "typing.Optional[str]"): + raise NotImplementedError + def sign_message(self, msg: "typing.List[int]"): + raise NotImplementedError + def splice_in(self, user_channel_id: "UserChannelId",counterparty_node_id: "PublicKey",splice_amount_sats: "int"): + raise NotImplementedError + def splice_out(self, user_channel_id: "UserChannelId",counterparty_node_id: "PublicKey",address: "Address",splice_amount_sats: "int"): + raise NotImplementedError + def spontaneous_payment(self, ): + raise NotImplementedError + def start(self, ): + raise NotImplementedError + def status(self, ): + raise NotImplementedError + def stop(self, ): + raise NotImplementedError + def sync_wallets(self, ): + raise NotImplementedError + def unified_qr_payment(self, ): + raise NotImplementedError + def update_channel_config(self, user_channel_id: "UserChannelId",counterparty_node_id: "PublicKey",channel_config: "ChannelConfig"): + raise NotImplementedError + def update_sync_intervals(self, intervals: "RuntimeSyncIntervals"): + raise NotImplementedError + def verify_signature(self, msg: "typing.List[int]",sig: "str",pkey: "PublicKey"): + raise NotImplementedError + def wait_next_event(self, ): + raise NotImplementedError + + +class Node: + _pointer: ctypes.c_void_p + + def __init__(self, *args, **kwargs): + raise ValueError("This class has no default constructor") + + def __del__(self): + # In case of partial initialization of instances. + pointer = getattr(self, "_pointer", None) + if pointer is not None: + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_free_node, pointer) + + def _uniffi_clone_pointer(self): + return _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_clone_node, self._pointer) + + # Used by alternative constructors or any methods which return this type. + @classmethod + def _make_instance_(cls, pointer): + # Lightly yucky way to bypass the usual __init__ logic + # and just create a new instance with the required pointer. + inst = cls.__new__(cls) + inst._pointer = pointer + return inst + + + def add_address_type_to_monitor(self, address_type: "AddressType",seed_bytes: "typing.List[int]") -> None: + _UniffiConverterTypeAddressType.check_lower(address_type) + + _UniffiConverterSequenceUInt8.check_lower(seed_bytes) + + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_node_add_address_type_to_monitor,self._uniffi_clone_pointer(), + _UniffiConverterTypeAddressType.lower(address_type), + _UniffiConverterSequenceUInt8.lower(seed_bytes)) + + + + + + + def add_address_type_to_monitor_with_mnemonic(self, address_type: "AddressType",mnemonic: "Mnemonic",passphrase: "typing.Optional[str]") -> None: + _UniffiConverterTypeAddressType.check_lower(address_type) + + _UniffiConverterTypeMnemonic.check_lower(mnemonic) + + _UniffiConverterOptionalString.check_lower(passphrase) + + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_node_add_address_type_to_monitor_with_mnemonic,self._uniffi_clone_pointer(), + _UniffiConverterTypeAddressType.lower(address_type), + _UniffiConverterTypeMnemonic.lower(mnemonic), + _UniffiConverterOptionalString.lower(passphrase)) + + + + + + + def add_onchain_wallet_account(self, address_type: "AddressType",account_index: "int",xpub: "str") -> None: + _UniffiConverterTypeAddressType.check_lower(address_type) + + _UniffiConverterUInt32.check_lower(account_index) + + _UniffiConverterString.check_lower(xpub) + + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_node_add_onchain_wallet_account,self._uniffi_clone_pointer(), + _UniffiConverterTypeAddressType.lower(address_type), + _UniffiConverterUInt32.lower(account_index), + _UniffiConverterString.lower(xpub)) + + + + + + + def announcement_addresses(self, ) -> "typing.Optional[typing.List[SocketAddress]]": + return _UniffiConverterOptionalSequenceTypeSocketAddress.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_node_announcement_addresses,self._uniffi_clone_pointer(),) + ) + + + + + + def bolt11_payment(self, ) -> "Bolt11Payment": + return _UniffiConverterTypeBolt11Payment.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_node_bolt11_payment,self._uniffi_clone_pointer(),) + ) + + + + + + def bolt12_payment(self, ) -> "Bolt12Payment": + return _UniffiConverterTypeBolt12Payment.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_node_bolt12_payment,self._uniffi_clone_pointer(),) + ) + + + + + + def close_channel(self, user_channel_id: "UserChannelId",counterparty_node_id: "PublicKey") -> None: + _UniffiConverterTypeUserChannelId.check_lower(user_channel_id) + + _UniffiConverterTypePublicKey.check_lower(counterparty_node_id) + + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_node_close_channel,self._uniffi_clone_pointer(), + _UniffiConverterTypeUserChannelId.lower(user_channel_id), + _UniffiConverterTypePublicKey.lower(counterparty_node_id)) + + + + + + + def config(self, ) -> "Config": + return _UniffiConverterTypeConfig.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_node_config,self._uniffi_clone_pointer(),) + ) + + + + + + def connect(self, node_id: "PublicKey",address: "SocketAddress",persist: "bool") -> None: + _UniffiConverterTypePublicKey.check_lower(node_id) + + _UniffiConverterTypeSocketAddress.check_lower(address) + + _UniffiConverterBool.check_lower(persist) + + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_node_connect,self._uniffi_clone_pointer(), + _UniffiConverterTypePublicKey.lower(node_id), + _UniffiConverterTypeSocketAddress.lower(address), + _UniffiConverterBool.lower(persist)) + + + + + + + def current_sync_intervals(self, ) -> "RuntimeSyncIntervals": + return _UniffiConverterTypeRuntimeSyncIntervals.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_node_current_sync_intervals,self._uniffi_clone_pointer(),) + ) + + + + + + def disconnect(self, node_id: "PublicKey") -> None: + _UniffiConverterTypePublicKey.check_lower(node_id) + + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_node_disconnect,self._uniffi_clone_pointer(), + _UniffiConverterTypePublicKey.lower(node_id)) + + + + + + + def event_handled(self, ) -> None: + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_node_event_handled,self._uniffi_clone_pointer(),) + + + + + + + def export_onchain_wallet_account_xpub(self, address_type: "AddressType",account_index: "int") -> "str": + _UniffiConverterTypeAddressType.check_lower(address_type) + + _UniffiConverterUInt32.check_lower(account_index) + + return _UniffiConverterString.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_node_export_onchain_wallet_account_xpub,self._uniffi_clone_pointer(), + _UniffiConverterTypeAddressType.lower(address_type), + _UniffiConverterUInt32.lower(account_index)) + ) + + + + + + def export_pathfinding_scores(self, ) -> "bytes": + return _UniffiConverterBytes.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_node_export_pathfinding_scores,self._uniffi_clone_pointer(),) + ) + + + + + + def force_close_channel(self, user_channel_id: "UserChannelId",counterparty_node_id: "PublicKey",reason: "typing.Optional[str]") -> None: + _UniffiConverterTypeUserChannelId.check_lower(user_channel_id) + + _UniffiConverterTypePublicKey.check_lower(counterparty_node_id) + + _UniffiConverterOptionalString.check_lower(reason) + + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_node_force_close_channel,self._uniffi_clone_pointer(), + _UniffiConverterTypeUserChannelId.lower(user_channel_id), + _UniffiConverterTypePublicKey.lower(counterparty_node_id), + _UniffiConverterOptionalString.lower(reason)) + + + + + + + def get_address_balance(self, address_str: "str") -> "int": + _UniffiConverterString.check_lower(address_str) + + return _UniffiConverterUInt64.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_node_get_address_balance,self._uniffi_clone_pointer(), + _UniffiConverterString.lower(address_str)) + ) + + + + + + def get_balance_for_address_type(self, address_type: "AddressType") -> "AddressTypeBalance": + _UniffiConverterTypeAddressType.check_lower(address_type) + + return _UniffiConverterTypeAddressTypeBalance.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_node_get_balance_for_address_type,self._uniffi_clone_pointer(), + _UniffiConverterTypeAddressType.lower(address_type)) + ) + + + + + + def get_balance_for_onchain_wallet_account(self, address_type: "AddressType",account_index: "int") -> "AddressTypeBalance": + _UniffiConverterTypeAddressType.check_lower(address_type) + + _UniffiConverterUInt32.check_lower(account_index) + + return _UniffiConverterTypeAddressTypeBalance.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_node_get_balance_for_onchain_wallet_account,self._uniffi_clone_pointer(), + _UniffiConverterTypeAddressType.lower(address_type), + _UniffiConverterUInt32.lower(account_index)) + ) + + + + + + def get_transaction_details(self, txid: "Txid") -> "typing.Optional[TransactionDetails]": + _UniffiConverterTypeTxid.check_lower(txid) + + return _UniffiConverterOptionalTypeTransactionDetails.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_node_get_transaction_details,self._uniffi_clone_pointer(), + _UniffiConverterTypeTxid.lower(txid)) + ) + + + + + + def list_balances(self, ) -> "BalanceDetails": + return _UniffiConverterTypeBalanceDetails.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_node_list_balances,self._uniffi_clone_pointer(),) + ) + + + + + + def list_channels(self, ) -> "typing.List[ChannelDetails]": + return _UniffiConverterSequenceTypeChannelDetails.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_node_list_channels,self._uniffi_clone_pointer(),) + ) + + + + + + def list_monitored_address_types(self, ) -> "typing.List[AddressType]": + return _UniffiConverterSequenceTypeAddressType.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_node_list_monitored_address_types,self._uniffi_clone_pointer(),) + ) + + + + + + def list_onchain_wallet_accounts(self, ) -> "typing.List[OnchainWalletAccount]": + return _UniffiConverterSequenceTypeOnchainWalletAccount.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_node_list_onchain_wallet_accounts,self._uniffi_clone_pointer(),) + ) + + + + + + def list_payments(self, ) -> "typing.List[PaymentDetails]": + return _UniffiConverterSequenceTypePaymentDetails.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_node_list_payments,self._uniffi_clone_pointer(),) + ) + + + + + + def list_peers(self, ) -> "typing.List[PeerDetails]": + return _UniffiConverterSequenceTypePeerDetails.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_node_list_peers,self._uniffi_clone_pointer(),) + ) + + + + + + def listening_addresses(self, ) -> "typing.Optional[typing.List[SocketAddress]]": + return _UniffiConverterOptionalSequenceTypeSocketAddress.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_node_listening_addresses,self._uniffi_clone_pointer(),) + ) + + + + + + def lsps1_liquidity(self, ) -> "Lsps1Liquidity": + return _UniffiConverterTypeLsps1Liquidity.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_node_lsps1_liquidity,self._uniffi_clone_pointer(),) + ) + + + + + + def network_graph(self, ) -> "NetworkGraph": + return _UniffiConverterTypeNetworkGraph.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_node_network_graph,self._uniffi_clone_pointer(),) + ) + + + + + + def next_event(self, ) -> "typing.Optional[Event]": + return _UniffiConverterOptionalTypeEvent.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_node_next_event,self._uniffi_clone_pointer(),) + ) + + + + + async def next_event_async(self, ) -> "Event": + return await _uniffi_rust_call_async( + _UniffiLib.uniffi_ldk_node_fn_method_node_next_event_async( + self._uniffi_clone_pointer(), + ), + _UniffiLib.ffi_ldk_node_rust_future_poll_rust_buffer, + _UniffiLib.ffi_ldk_node_rust_future_complete_rust_buffer, + _UniffiLib.ffi_ldk_node_rust_future_free_rust_buffer, + # lift function + _UniffiConverterTypeEvent.lift, + + # Error FFI converter + + None, + + ) + + + + + def node_alias(self, ) -> "typing.Optional[NodeAlias]": + return _UniffiConverterOptionalTypeNodeAlias.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_node_node_alias,self._uniffi_clone_pointer(),) + ) + + + + + + def node_id(self, ) -> "PublicKey": + return _UniffiConverterTypePublicKey.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_node_node_id,self._uniffi_clone_pointer(),) + ) + + + + + + def onchain_payment(self, ) -> "OnchainPayment": + return _UniffiConverterTypeOnchainPayment.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_node_onchain_payment,self._uniffi_clone_pointer(),) + ) + + + + + + def open_announced_channel(self, node_id: "PublicKey",address: "SocketAddress",channel_amount_sats: "int",push_to_counterparty_msat: "typing.Optional[int]",channel_config: "typing.Optional[ChannelConfig]") -> "UserChannelId": + _UniffiConverterTypePublicKey.check_lower(node_id) + + _UniffiConverterTypeSocketAddress.check_lower(address) + + _UniffiConverterUInt64.check_lower(channel_amount_sats) + + _UniffiConverterOptionalUInt64.check_lower(push_to_counterparty_msat) + + _UniffiConverterOptionalTypeChannelConfig.check_lower(channel_config) + + return _UniffiConverterTypeUserChannelId.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_node_open_announced_channel,self._uniffi_clone_pointer(), + _UniffiConverterTypePublicKey.lower(node_id), + _UniffiConverterTypeSocketAddress.lower(address), + _UniffiConverterUInt64.lower(channel_amount_sats), + _UniffiConverterOptionalUInt64.lower(push_to_counterparty_msat), + _UniffiConverterOptionalTypeChannelConfig.lower(channel_config)) + ) + + + + + + def open_channel(self, node_id: "PublicKey",address: "SocketAddress",channel_amount_sats: "int",push_to_counterparty_msat: "typing.Optional[int]",channel_config: "typing.Optional[ChannelConfig]") -> "UserChannelId": + _UniffiConverterTypePublicKey.check_lower(node_id) + + _UniffiConverterTypeSocketAddress.check_lower(address) + + _UniffiConverterUInt64.check_lower(channel_amount_sats) + + _UniffiConverterOptionalUInt64.check_lower(push_to_counterparty_msat) + + _UniffiConverterOptionalTypeChannelConfig.check_lower(channel_config) + + return _UniffiConverterTypeUserChannelId.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_node_open_channel,self._uniffi_clone_pointer(), + _UniffiConverterTypePublicKey.lower(node_id), + _UniffiConverterTypeSocketAddress.lower(address), + _UniffiConverterUInt64.lower(channel_amount_sats), + _UniffiConverterOptionalUInt64.lower(push_to_counterparty_msat), + _UniffiConverterOptionalTypeChannelConfig.lower(channel_config)) + ) + + + + + + def payment(self, payment_id: "PaymentId") -> "typing.Optional[PaymentDetails]": + _UniffiConverterTypePaymentId.check_lower(payment_id) + + return _UniffiConverterOptionalTypePaymentDetails.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_node_payment,self._uniffi_clone_pointer(), + _UniffiConverterTypePaymentId.lower(payment_id)) + ) + + + + + + def remove_address_type_from_monitor(self, address_type: "AddressType") -> None: + _UniffiConverterTypeAddressType.check_lower(address_type) + + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_node_remove_address_type_from_monitor,self._uniffi_clone_pointer(), + _UniffiConverterTypeAddressType.lower(address_type)) + + + + + + + def remove_onchain_wallet_account(self, address_type: "AddressType",account_index: "int") -> None: + _UniffiConverterTypeAddressType.check_lower(address_type) + + _UniffiConverterUInt32.check_lower(account_index) + + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_node_remove_onchain_wallet_account,self._uniffi_clone_pointer(), + _UniffiConverterTypeAddressType.lower(address_type), + _UniffiConverterUInt32.lower(account_index)) + + + + + + + def remove_payment(self, payment_id: "PaymentId") -> None: + _UniffiConverterTypePaymentId.check_lower(payment_id) + + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_node_remove_payment,self._uniffi_clone_pointer(), + _UniffiConverterTypePaymentId.lower(payment_id)) + + + + + + + def set_primary_address_type(self, address_type: "AddressType",seed_bytes: "typing.List[int]") -> None: + _UniffiConverterTypeAddressType.check_lower(address_type) + + _UniffiConverterSequenceUInt8.check_lower(seed_bytes) + + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_node_set_primary_address_type,self._uniffi_clone_pointer(), + _UniffiConverterTypeAddressType.lower(address_type), + _UniffiConverterSequenceUInt8.lower(seed_bytes)) + + + + + + + def set_primary_address_type_with_mnemonic(self, address_type: "AddressType",mnemonic: "Mnemonic",passphrase: "typing.Optional[str]") -> None: + _UniffiConverterTypeAddressType.check_lower(address_type) + + _UniffiConverterTypeMnemonic.check_lower(mnemonic) + + _UniffiConverterOptionalString.check_lower(passphrase) + + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_node_set_primary_address_type_with_mnemonic,self._uniffi_clone_pointer(), + _UniffiConverterTypeAddressType.lower(address_type), + _UniffiConverterTypeMnemonic.lower(mnemonic), + _UniffiConverterOptionalString.lower(passphrase)) + + + + + + + def sign_message(self, msg: "typing.List[int]") -> "str": + _UniffiConverterSequenceUInt8.check_lower(msg) + + return _UniffiConverterString.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_node_sign_message,self._uniffi_clone_pointer(), + _UniffiConverterSequenceUInt8.lower(msg)) + ) + + + + + + def splice_in(self, user_channel_id: "UserChannelId",counterparty_node_id: "PublicKey",splice_amount_sats: "int") -> None: + _UniffiConverterTypeUserChannelId.check_lower(user_channel_id) + + _UniffiConverterTypePublicKey.check_lower(counterparty_node_id) + + _UniffiConverterUInt64.check_lower(splice_amount_sats) + + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_node_splice_in,self._uniffi_clone_pointer(), + _UniffiConverterTypeUserChannelId.lower(user_channel_id), + _UniffiConverterTypePublicKey.lower(counterparty_node_id), + _UniffiConverterUInt64.lower(splice_amount_sats)) + + + + + + + def splice_out(self, user_channel_id: "UserChannelId",counterparty_node_id: "PublicKey",address: "Address",splice_amount_sats: "int") -> None: + _UniffiConverterTypeUserChannelId.check_lower(user_channel_id) + + _UniffiConverterTypePublicKey.check_lower(counterparty_node_id) + + _UniffiConverterTypeAddress.check_lower(address) + + _UniffiConverterUInt64.check_lower(splice_amount_sats) + + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_node_splice_out,self._uniffi_clone_pointer(), + _UniffiConverterTypeUserChannelId.lower(user_channel_id), + _UniffiConverterTypePublicKey.lower(counterparty_node_id), + _UniffiConverterTypeAddress.lower(address), + _UniffiConverterUInt64.lower(splice_amount_sats)) + + + + + + + def spontaneous_payment(self, ) -> "SpontaneousPayment": + return _UniffiConverterTypeSpontaneousPayment.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_node_spontaneous_payment,self._uniffi_clone_pointer(),) + ) + + + + + + def start(self, ) -> None: + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_node_start,self._uniffi_clone_pointer(),) + + + + + + + def status(self, ) -> "NodeStatus": + return _UniffiConverterTypeNodeStatus.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_node_status,self._uniffi_clone_pointer(),) + ) + + + + + + def stop(self, ) -> None: + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_node_stop,self._uniffi_clone_pointer(),) + + + + + + + def sync_wallets(self, ) -> None: + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_node_sync_wallets,self._uniffi_clone_pointer(),) + + + + + + + def unified_qr_payment(self, ) -> "UnifiedQrPayment": + return _UniffiConverterTypeUnifiedQrPayment.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_node_unified_qr_payment,self._uniffi_clone_pointer(),) + ) + + + + + + def update_channel_config(self, user_channel_id: "UserChannelId",counterparty_node_id: "PublicKey",channel_config: "ChannelConfig") -> None: + _UniffiConverterTypeUserChannelId.check_lower(user_channel_id) + + _UniffiConverterTypePublicKey.check_lower(counterparty_node_id) + + _UniffiConverterTypeChannelConfig.check_lower(channel_config) + + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_node_update_channel_config,self._uniffi_clone_pointer(), + _UniffiConverterTypeUserChannelId.lower(user_channel_id), + _UniffiConverterTypePublicKey.lower(counterparty_node_id), + _UniffiConverterTypeChannelConfig.lower(channel_config)) + + + + + + + def update_sync_intervals(self, intervals: "RuntimeSyncIntervals") -> None: + _UniffiConverterTypeRuntimeSyncIntervals.check_lower(intervals) + + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_node_update_sync_intervals,self._uniffi_clone_pointer(), + _UniffiConverterTypeRuntimeSyncIntervals.lower(intervals)) + + + + + + + def verify_signature(self, msg: "typing.List[int]",sig: "str",pkey: "PublicKey") -> "bool": + _UniffiConverterSequenceUInt8.check_lower(msg) + + _UniffiConverterString.check_lower(sig) + + _UniffiConverterTypePublicKey.check_lower(pkey) + + return _UniffiConverterBool.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_node_verify_signature,self._uniffi_clone_pointer(), + _UniffiConverterSequenceUInt8.lower(msg), + _UniffiConverterString.lower(sig), + _UniffiConverterTypePublicKey.lower(pkey)) + ) + + + + + + def wait_next_event(self, ) -> "Event": + return _UniffiConverterTypeEvent.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_node_wait_next_event,self._uniffi_clone_pointer(),) + ) + + + + + + +class _UniffiConverterTypeNode: + + @staticmethod + def lift(value: int): + return Node._make_instance_(value) + + @staticmethod + def check_lower(value: Node): + if not isinstance(value, Node): + raise TypeError("Expected Node instance, {} found".format(type(value).__name__)) + + @staticmethod + def lower(value: NodeProtocol): + if not isinstance(value, Node): + raise TypeError("Expected Node instance, {} found".format(type(value).__name__)) + return value._uniffi_clone_pointer() + + @classmethod + def read(cls, buf: _UniffiRustBuffer): + ptr = buf.read_u64() + if ptr == 0: + raise InternalError("Raw pointer value was null") + return cls.lift(ptr) + + @classmethod + def write(cls, value: NodeProtocol, buf: _UniffiRustBuffer): + buf.write_u64(cls.lower(value)) + + + +class OfferProtocol(typing.Protocol): + def absolute_expiry_seconds(self, ): + raise NotImplementedError + def amount(self, ): + raise NotImplementedError + def chains(self, ): + raise NotImplementedError + def expects_quantity(self, ): + raise NotImplementedError + def id(self, ): + raise NotImplementedError + def is_expired(self, ): + raise NotImplementedError + def is_valid_quantity(self, quantity: "int"): + raise NotImplementedError + def issuer(self, ): + raise NotImplementedError + def issuer_signing_pubkey(self, ): + raise NotImplementedError + def metadata(self, ): + raise NotImplementedError + def offer_description(self, ): + raise NotImplementedError + def supports_chain(self, chain: "Network"): + raise NotImplementedError + + +class Offer: + _pointer: ctypes.c_void_p + + def __init__(self, *args, **kwargs): + raise ValueError("This class has no default constructor") + + def __del__(self): + # In case of partial initialization of instances. + pointer = getattr(self, "_pointer", None) + if pointer is not None: + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_free_offer, pointer) + + def _uniffi_clone_pointer(self): + return _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_clone_offer, self._pointer) + + # Used by alternative constructors or any methods which return this type. + @classmethod + def _make_instance_(cls, pointer): + # Lightly yucky way to bypass the usual __init__ logic + # and just create a new instance with the required pointer. + inst = cls.__new__(cls) + inst._pointer = pointer + return inst + @classmethod + def from_str(cls, offer_str: "str"): + _UniffiConverterString.check_lower(offer_str) + + # Call the (fallible) function before creating any half-baked object instances. + pointer = _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_constructor_offer_from_str, + _UniffiConverterString.lower(offer_str)) + return cls._make_instance_(pointer) + + + + def absolute_expiry_seconds(self, ) -> "typing.Optional[int]": + return _UniffiConverterOptionalUInt64.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_offer_absolute_expiry_seconds,self._uniffi_clone_pointer(),) + ) + + + + + + def amount(self, ) -> "typing.Optional[OfferAmount]": + return _UniffiConverterOptionalTypeOfferAmount.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_offer_amount,self._uniffi_clone_pointer(),) + ) + + + + + + def chains(self, ) -> "typing.List[Network]": + return _UniffiConverterSequenceTypeNetwork.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_offer_chains,self._uniffi_clone_pointer(),) + ) + + + + + + def expects_quantity(self, ) -> "bool": + return _UniffiConverterBool.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_offer_expects_quantity,self._uniffi_clone_pointer(),) + ) + + + + + + def id(self, ) -> "OfferId": + return _UniffiConverterTypeOfferId.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_offer_id,self._uniffi_clone_pointer(),) + ) + + + + + + def is_expired(self, ) -> "bool": + return _UniffiConverterBool.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_offer_is_expired,self._uniffi_clone_pointer(),) + ) + + + + + + def is_valid_quantity(self, quantity: "int") -> "bool": + _UniffiConverterUInt64.check_lower(quantity) + + return _UniffiConverterBool.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_offer_is_valid_quantity,self._uniffi_clone_pointer(), + _UniffiConverterUInt64.lower(quantity)) + ) + + + + + + def issuer(self, ) -> "typing.Optional[str]": + return _UniffiConverterOptionalString.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_offer_issuer,self._uniffi_clone_pointer(),) + ) + + + + + + def issuer_signing_pubkey(self, ) -> "typing.Optional[PublicKey]": + return _UniffiConverterOptionalTypePublicKey.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_offer_issuer_signing_pubkey,self._uniffi_clone_pointer(),) + ) + + + + + + def metadata(self, ) -> "typing.Optional[typing.List[int]]": + return _UniffiConverterOptionalSequenceUInt8.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_offer_metadata,self._uniffi_clone_pointer(),) + ) + + + + + + def offer_description(self, ) -> "typing.Optional[str]": + return _UniffiConverterOptionalString.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_offer_offer_description,self._uniffi_clone_pointer(),) + ) + + + + + + def supports_chain(self, chain: "Network") -> "bool": + _UniffiConverterTypeNetwork.check_lower(chain) + + return _UniffiConverterBool.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_offer_supports_chain,self._uniffi_clone_pointer(), + _UniffiConverterTypeNetwork.lower(chain)) + ) + + + + + + def __repr__(self, ) -> "str": + return _UniffiConverterString.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_offer_uniffi_trait_debug,self._uniffi_clone_pointer(),) + ) + + + + + + def __str__(self, ) -> "str": + return _UniffiConverterString.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_offer_uniffi_trait_display,self._uniffi_clone_pointer(),) + ) + + + + def __eq__(self, other: object) -> bool: + if not isinstance(other, Offer): + return NotImplemented + + return _UniffiConverterBool.lift(_uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_offer_uniffi_trait_eq_eq,self._uniffi_clone_pointer(), + _UniffiConverterTypeOffer.lower(other))) + + def __ne__(self, other: object) -> bool: + if not isinstance(other, Offer): + return NotImplemented + + return _UniffiConverterBool.lift(_uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_offer_uniffi_trait_eq_ne,self._uniffi_clone_pointer(), + _UniffiConverterTypeOffer.lower(other))) + + + +class _UniffiConverterTypeOffer: + + @staticmethod + def lift(value: int): + return Offer._make_instance_(value) + + @staticmethod + def check_lower(value: Offer): + if not isinstance(value, Offer): + raise TypeError("Expected Offer instance, {} found".format(type(value).__name__)) + + @staticmethod + def lower(value: OfferProtocol): + if not isinstance(value, Offer): + raise TypeError("Expected Offer instance, {} found".format(type(value).__name__)) + return value._uniffi_clone_pointer() + + @classmethod + def read(cls, buf: _UniffiRustBuffer): + ptr = buf.read_u64() + if ptr == 0: + raise InternalError("Raw pointer value was null") + return cls.lift(ptr) + + @classmethod + def write(cls, value: OfferProtocol, buf: _UniffiRustBuffer): + buf.write_u64(cls.lower(value)) + + + +class OnchainPaymentProtocol(typing.Protocol): + def accelerate_by_cpfp(self, txid: "Txid",fee_rate: "typing.Optional[FeeRate]",destination_address: "typing.Optional[Address]"): + raise NotImplementedError + def address_info_for_account_at_index(self, address_type: "AddressType",account_index: "int",keychain: "KeychainKind",index: "int"): + raise NotImplementedError + def address_info_for_type_at_index(self, address_type: "AddressType",keychain: "KeychainKind",index: "int"): + raise NotImplementedError + def address_infos_for_account(self, address_type: "AddressType",account_index: "int",keychain: "KeychainKind",start_index: "int",count: "int"): + raise NotImplementedError + def address_infos_for_type(self, address_type: "AddressType",keychain: "KeychainKind",start_index: "int",count: "int"): + raise NotImplementedError + def bump_fee_by_rbf(self, txid: "Txid",fee_rate: "FeeRate"): + raise NotImplementedError + def calculate_cpfp_fee_rate(self, parent_txid: "Txid",urgent: "bool"): + raise NotImplementedError + def calculate_send_all_fee(self, address: "Address",retain_reserves: "bool",fee_rate: "typing.Optional[FeeRate]"): + raise NotImplementedError + def calculate_total_fee(self, address: "Address",amount_sats: "int",fee_rate: "typing.Optional[FeeRate]",utxos_to_spend: "typing.Optional[typing.List[SpendableUtxo]]"): + raise NotImplementedError + def list_spendable_outputs(self, ): + raise NotImplementedError + def new_address(self, ): + raise NotImplementedError + def new_address_for_account(self, address_type: "AddressType",account_index: "int"): + raise NotImplementedError + def new_address_for_type(self, address_type: "AddressType"): + raise NotImplementedError + def new_address_info(self, ): + raise NotImplementedError + def new_address_info_for_account(self, address_type: "AddressType",account_index: "int"): + raise NotImplementedError + def new_address_info_for_type(self, address_type: "AddressType"): + raise NotImplementedError + def reveal_receive_addresses_to(self, address_type: "AddressType",index: "int"): + raise NotImplementedError + def reveal_receive_addresses_to_account(self, address_type: "AddressType",account_index: "int",index: "int"): + raise NotImplementedError + def select_utxos_with_algorithm(self, target_amount_sats: "int",fee_rate: "typing.Optional[FeeRate]",algorithm: "CoinSelectionAlgorithm",utxos: "typing.Optional[typing.List[SpendableUtxo]]"): + raise NotImplementedError + def send_all_to_address(self, address: "Address",retain_reserve: "bool",fee_rate: "typing.Optional[FeeRate]"): + raise NotImplementedError + def send_to_address(self, address: "Address",amount_sats: "int",fee_rate: "typing.Optional[FeeRate]",utxos_to_spend: "typing.Optional[typing.List[SpendableUtxo]]"): + raise NotImplementedError + + +class OnchainPayment: + _pointer: ctypes.c_void_p + + def __init__(self, *args, **kwargs): + raise ValueError("This class has no default constructor") + + def __del__(self): + # In case of partial initialization of instances. + pointer = getattr(self, "_pointer", None) + if pointer is not None: + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_free_onchainpayment, pointer) + + def _uniffi_clone_pointer(self): + return _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_clone_onchainpayment, self._pointer) + + # Used by alternative constructors or any methods which return this type. + @classmethod + def _make_instance_(cls, pointer): + # Lightly yucky way to bypass the usual __init__ logic + # and just create a new instance with the required pointer. + inst = cls.__new__(cls) + inst._pointer = pointer + return inst + + + def accelerate_by_cpfp(self, txid: "Txid",fee_rate: "typing.Optional[FeeRate]",destination_address: "typing.Optional[Address]") -> "Txid": + _UniffiConverterTypeTxid.check_lower(txid) + + _UniffiConverterOptionalTypeFeeRate.check_lower(fee_rate) + + _UniffiConverterOptionalTypeAddress.check_lower(destination_address) + + return _UniffiConverterTypeTxid.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_accelerate_by_cpfp,self._uniffi_clone_pointer(), + _UniffiConverterTypeTxid.lower(txid), + _UniffiConverterOptionalTypeFeeRate.lower(fee_rate), + _UniffiConverterOptionalTypeAddress.lower(destination_address)) + ) + + + + + + def address_info_for_account_at_index(self, address_type: "AddressType",account_index: "int",keychain: "KeychainKind",index: "int") -> "AddressInfo": + _UniffiConverterTypeAddressType.check_lower(address_type) + + _UniffiConverterUInt32.check_lower(account_index) + + _UniffiConverterTypeKeychainKind.check_lower(keychain) + + _UniffiConverterUInt32.check_lower(index) + + return _UniffiConverterTypeAddressInfo.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_address_info_for_account_at_index,self._uniffi_clone_pointer(), + _UniffiConverterTypeAddressType.lower(address_type), + _UniffiConverterUInt32.lower(account_index), + _UniffiConverterTypeKeychainKind.lower(keychain), + _UniffiConverterUInt32.lower(index)) + ) + + + + + + def address_info_for_type_at_index(self, address_type: "AddressType",keychain: "KeychainKind",index: "int") -> "AddressInfo": + _UniffiConverterTypeAddressType.check_lower(address_type) + + _UniffiConverterTypeKeychainKind.check_lower(keychain) + + _UniffiConverterUInt32.check_lower(index) + + return _UniffiConverterTypeAddressInfo.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_address_info_for_type_at_index,self._uniffi_clone_pointer(), + _UniffiConverterTypeAddressType.lower(address_type), + _UniffiConverterTypeKeychainKind.lower(keychain), + _UniffiConverterUInt32.lower(index)) + ) + + + + + + def address_infos_for_account(self, address_type: "AddressType",account_index: "int",keychain: "KeychainKind",start_index: "int",count: "int") -> "typing.List[AddressInfo]": + _UniffiConverterTypeAddressType.check_lower(address_type) + + _UniffiConverterUInt32.check_lower(account_index) + + _UniffiConverterTypeKeychainKind.check_lower(keychain) + + _UniffiConverterUInt32.check_lower(start_index) + + _UniffiConverterUInt32.check_lower(count) + + return _UniffiConverterSequenceTypeAddressInfo.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_address_infos_for_account,self._uniffi_clone_pointer(), + _UniffiConverterTypeAddressType.lower(address_type), + _UniffiConverterUInt32.lower(account_index), + _UniffiConverterTypeKeychainKind.lower(keychain), + _UniffiConverterUInt32.lower(start_index), + _UniffiConverterUInt32.lower(count)) + ) + + + + + + def address_infos_for_type(self, address_type: "AddressType",keychain: "KeychainKind",start_index: "int",count: "int") -> "typing.List[AddressInfo]": + _UniffiConverterTypeAddressType.check_lower(address_type) + + _UniffiConverterTypeKeychainKind.check_lower(keychain) + + _UniffiConverterUInt32.check_lower(start_index) + + _UniffiConverterUInt32.check_lower(count) + + return _UniffiConverterSequenceTypeAddressInfo.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_address_infos_for_type,self._uniffi_clone_pointer(), + _UniffiConverterTypeAddressType.lower(address_type), + _UniffiConverterTypeKeychainKind.lower(keychain), + _UniffiConverterUInt32.lower(start_index), + _UniffiConverterUInt32.lower(count)) + ) + + + + + + def bump_fee_by_rbf(self, txid: "Txid",fee_rate: "FeeRate") -> "Txid": + _UniffiConverterTypeTxid.check_lower(txid) + + _UniffiConverterTypeFeeRate.check_lower(fee_rate) + + return _UniffiConverterTypeTxid.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_bump_fee_by_rbf,self._uniffi_clone_pointer(), + _UniffiConverterTypeTxid.lower(txid), + _UniffiConverterTypeFeeRate.lower(fee_rate)) + ) + + + + + + def calculate_cpfp_fee_rate(self, parent_txid: "Txid",urgent: "bool") -> "FeeRate": + _UniffiConverterTypeTxid.check_lower(parent_txid) + + _UniffiConverterBool.check_lower(urgent) + + return _UniffiConverterTypeFeeRate.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_calculate_cpfp_fee_rate,self._uniffi_clone_pointer(), + _UniffiConverterTypeTxid.lower(parent_txid), + _UniffiConverterBool.lower(urgent)) + ) + + + + + + def calculate_send_all_fee(self, address: "Address",retain_reserves: "bool",fee_rate: "typing.Optional[FeeRate]") -> "int": + _UniffiConverterTypeAddress.check_lower(address) + + _UniffiConverterBool.check_lower(retain_reserves) + + _UniffiConverterOptionalTypeFeeRate.check_lower(fee_rate) + + return _UniffiConverterUInt64.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_calculate_send_all_fee,self._uniffi_clone_pointer(), + _UniffiConverterTypeAddress.lower(address), + _UniffiConverterBool.lower(retain_reserves), + _UniffiConverterOptionalTypeFeeRate.lower(fee_rate)) + ) + + + + + + def calculate_total_fee(self, address: "Address",amount_sats: "int",fee_rate: "typing.Optional[FeeRate]",utxos_to_spend: "typing.Optional[typing.List[SpendableUtxo]]") -> "int": + _UniffiConverterTypeAddress.check_lower(address) + + _UniffiConverterUInt64.check_lower(amount_sats) + + _UniffiConverterOptionalTypeFeeRate.check_lower(fee_rate) + + _UniffiConverterOptionalSequenceTypeSpendableUtxo.check_lower(utxos_to_spend) + + return _UniffiConverterUInt64.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_calculate_total_fee,self._uniffi_clone_pointer(), + _UniffiConverterTypeAddress.lower(address), + _UniffiConverterUInt64.lower(amount_sats), + _UniffiConverterOptionalTypeFeeRate.lower(fee_rate), + _UniffiConverterOptionalSequenceTypeSpendableUtxo.lower(utxos_to_spend)) + ) + + + + + + def list_spendable_outputs(self, ) -> "typing.List[SpendableUtxo]": + return _UniffiConverterSequenceTypeSpendableUtxo.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_list_spendable_outputs,self._uniffi_clone_pointer(),) + ) + + + + + + def new_address(self, ) -> "Address": + return _UniffiConverterTypeAddress.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_new_address,self._uniffi_clone_pointer(),) + ) + + + + + + def new_address_for_account(self, address_type: "AddressType",account_index: "int") -> "Address": + _UniffiConverterTypeAddressType.check_lower(address_type) + + _UniffiConverterUInt32.check_lower(account_index) + + return _UniffiConverterTypeAddress.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_new_address_for_account,self._uniffi_clone_pointer(), + _UniffiConverterTypeAddressType.lower(address_type), + _UniffiConverterUInt32.lower(account_index)) + ) + + + + + + def new_address_for_type(self, address_type: "AddressType") -> "Address": + _UniffiConverterTypeAddressType.check_lower(address_type) + + return _UniffiConverterTypeAddress.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_new_address_for_type,self._uniffi_clone_pointer(), + _UniffiConverterTypeAddressType.lower(address_type)) + ) + + + + + + def new_address_info(self, ) -> "AddressInfo": + return _UniffiConverterTypeAddressInfo.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_new_address_info,self._uniffi_clone_pointer(),) + ) + + + + + + def new_address_info_for_account(self, address_type: "AddressType",account_index: "int") -> "AddressInfo": + _UniffiConverterTypeAddressType.check_lower(address_type) + + _UniffiConverterUInt32.check_lower(account_index) + + return _UniffiConverterTypeAddressInfo.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_new_address_info_for_account,self._uniffi_clone_pointer(), + _UniffiConverterTypeAddressType.lower(address_type), + _UniffiConverterUInt32.lower(account_index)) + ) + + + + + + def new_address_info_for_type(self, address_type: "AddressType") -> "AddressInfo": + _UniffiConverterTypeAddressType.check_lower(address_type) + + return _UniffiConverterTypeAddressInfo.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_new_address_info_for_type,self._uniffi_clone_pointer(), + _UniffiConverterTypeAddressType.lower(address_type)) + ) + + + + + + def reveal_receive_addresses_to(self, address_type: "AddressType",index: "int") -> None: + _UniffiConverterTypeAddressType.check_lower(address_type) + + _UniffiConverterUInt32.check_lower(index) + + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_reveal_receive_addresses_to,self._uniffi_clone_pointer(), + _UniffiConverterTypeAddressType.lower(address_type), + _UniffiConverterUInt32.lower(index)) + + + + + + + def reveal_receive_addresses_to_account(self, address_type: "AddressType",account_index: "int",index: "int") -> None: + _UniffiConverterTypeAddressType.check_lower(address_type) + + _UniffiConverterUInt32.check_lower(account_index) + + _UniffiConverterUInt32.check_lower(index) + + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_reveal_receive_addresses_to_account,self._uniffi_clone_pointer(), + _UniffiConverterTypeAddressType.lower(address_type), + _UniffiConverterUInt32.lower(account_index), + _UniffiConverterUInt32.lower(index)) + + + + + + + def select_utxos_with_algorithm(self, target_amount_sats: "int",fee_rate: "typing.Optional[FeeRate]",algorithm: "CoinSelectionAlgorithm",utxos: "typing.Optional[typing.List[SpendableUtxo]]") -> "typing.List[SpendableUtxo]": + _UniffiConverterUInt64.check_lower(target_amount_sats) + + _UniffiConverterOptionalTypeFeeRate.check_lower(fee_rate) + + _UniffiConverterTypeCoinSelectionAlgorithm.check_lower(algorithm) + + _UniffiConverterOptionalSequenceTypeSpendableUtxo.check_lower(utxos) + + return _UniffiConverterSequenceTypeSpendableUtxo.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_select_utxos_with_algorithm,self._uniffi_clone_pointer(), + _UniffiConverterUInt64.lower(target_amount_sats), + _UniffiConverterOptionalTypeFeeRate.lower(fee_rate), + _UniffiConverterTypeCoinSelectionAlgorithm.lower(algorithm), + _UniffiConverterOptionalSequenceTypeSpendableUtxo.lower(utxos)) + ) + + + + + + def send_all_to_address(self, address: "Address",retain_reserve: "bool",fee_rate: "typing.Optional[FeeRate]") -> "Txid": + _UniffiConverterTypeAddress.check_lower(address) + + _UniffiConverterBool.check_lower(retain_reserve) + + _UniffiConverterOptionalTypeFeeRate.check_lower(fee_rate) + + return _UniffiConverterTypeTxid.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_send_all_to_address,self._uniffi_clone_pointer(), + _UniffiConverterTypeAddress.lower(address), + _UniffiConverterBool.lower(retain_reserve), + _UniffiConverterOptionalTypeFeeRate.lower(fee_rate)) + ) + + + + + + def send_to_address(self, address: "Address",amount_sats: "int",fee_rate: "typing.Optional[FeeRate]",utxos_to_spend: "typing.Optional[typing.List[SpendableUtxo]]") -> "Txid": + _UniffiConverterTypeAddress.check_lower(address) + + _UniffiConverterUInt64.check_lower(amount_sats) + + _UniffiConverterOptionalTypeFeeRate.check_lower(fee_rate) + + _UniffiConverterOptionalSequenceTypeSpendableUtxo.check_lower(utxos_to_spend) + + return _UniffiConverterTypeTxid.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_onchainpayment_send_to_address,self._uniffi_clone_pointer(), + _UniffiConverterTypeAddress.lower(address), + _UniffiConverterUInt64.lower(amount_sats), + _UniffiConverterOptionalTypeFeeRate.lower(fee_rate), + _UniffiConverterOptionalSequenceTypeSpendableUtxo.lower(utxos_to_spend)) + ) + + + + + + +class _UniffiConverterTypeOnchainPayment: + + @staticmethod + def lift(value: int): + return OnchainPayment._make_instance_(value) + + @staticmethod + def check_lower(value: OnchainPayment): + if not isinstance(value, OnchainPayment): + raise TypeError("Expected OnchainPayment instance, {} found".format(type(value).__name__)) + + @staticmethod + def lower(value: OnchainPaymentProtocol): + if not isinstance(value, OnchainPayment): + raise TypeError("Expected OnchainPayment instance, {} found".format(type(value).__name__)) + return value._uniffi_clone_pointer() + + @classmethod + def read(cls, buf: _UniffiRustBuffer): + ptr = buf.read_u64() + if ptr == 0: + raise InternalError("Raw pointer value was null") + return cls.lift(ptr) + + @classmethod + def write(cls, value: OnchainPaymentProtocol, buf: _UniffiRustBuffer): + buf.write_u64(cls.lower(value)) + + + +class RefundProtocol(typing.Protocol): + def absolute_expiry_seconds(self, ): + raise NotImplementedError + def amount_msats(self, ): + raise NotImplementedError + def chain(self, ): + raise NotImplementedError + def is_expired(self, ): + raise NotImplementedError + def issuer(self, ): + raise NotImplementedError + def payer_metadata(self, ): + raise NotImplementedError + def payer_note(self, ): + raise NotImplementedError + def payer_signing_pubkey(self, ): + raise NotImplementedError + def quantity(self, ): + raise NotImplementedError + def refund_description(self, ): + raise NotImplementedError + + +class Refund: + _pointer: ctypes.c_void_p + + def __init__(self, *args, **kwargs): + raise ValueError("This class has no default constructor") + + def __del__(self): + # In case of partial initialization of instances. + pointer = getattr(self, "_pointer", None) + if pointer is not None: + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_free_refund, pointer) + + def _uniffi_clone_pointer(self): + return _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_clone_refund, self._pointer) + + # Used by alternative constructors or any methods which return this type. + @classmethod + def _make_instance_(cls, pointer): + # Lightly yucky way to bypass the usual __init__ logic + # and just create a new instance with the required pointer. + inst = cls.__new__(cls) + inst._pointer = pointer + return inst + @classmethod + def from_str(cls, refund_str: "str"): + _UniffiConverterString.check_lower(refund_str) + + # Call the (fallible) function before creating any half-baked object instances. + pointer = _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_constructor_refund_from_str, + _UniffiConverterString.lower(refund_str)) + return cls._make_instance_(pointer) + + + + def absolute_expiry_seconds(self, ) -> "typing.Optional[int]": + return _UniffiConverterOptionalUInt64.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_refund_absolute_expiry_seconds,self._uniffi_clone_pointer(),) + ) + + + + + + def amount_msats(self, ) -> "int": + return _UniffiConverterUInt64.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_refund_amount_msats,self._uniffi_clone_pointer(),) + ) + + + + + + def chain(self, ) -> "typing.Optional[Network]": + return _UniffiConverterOptionalTypeNetwork.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_refund_chain,self._uniffi_clone_pointer(),) + ) + + + + + + def is_expired(self, ) -> "bool": + return _UniffiConverterBool.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_refund_is_expired,self._uniffi_clone_pointer(),) + ) + + + + + + def issuer(self, ) -> "typing.Optional[str]": + return _UniffiConverterOptionalString.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_refund_issuer,self._uniffi_clone_pointer(),) + ) + + + + + + def payer_metadata(self, ) -> "typing.List[int]": + return _UniffiConverterSequenceUInt8.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_refund_payer_metadata,self._uniffi_clone_pointer(),) + ) + + + + + + def payer_note(self, ) -> "typing.Optional[str]": + return _UniffiConverterOptionalString.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_refund_payer_note,self._uniffi_clone_pointer(),) + ) + + + + + + def payer_signing_pubkey(self, ) -> "PublicKey": + return _UniffiConverterTypePublicKey.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_refund_payer_signing_pubkey,self._uniffi_clone_pointer(),) + ) + + + + + + def quantity(self, ) -> "typing.Optional[int]": + return _UniffiConverterOptionalUInt64.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_refund_quantity,self._uniffi_clone_pointer(),) + ) + + + + + + def refund_description(self, ) -> "str": + return _UniffiConverterString.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_refund_refund_description,self._uniffi_clone_pointer(),) + ) + + + + + + def __repr__(self, ) -> "str": + return _UniffiConverterString.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_refund_uniffi_trait_debug,self._uniffi_clone_pointer(),) + ) + + + + + + def __str__(self, ) -> "str": + return _UniffiConverterString.lift( + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_refund_uniffi_trait_display,self._uniffi_clone_pointer(),) + ) + + + + def __eq__(self, other: object) -> bool: + if not isinstance(other, Refund): + return NotImplemented + + return _UniffiConverterBool.lift(_uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_refund_uniffi_trait_eq_eq,self._uniffi_clone_pointer(), + _UniffiConverterTypeRefund.lower(other))) + + def __ne__(self, other: object) -> bool: + if not isinstance(other, Refund): + return NotImplemented + + return _UniffiConverterBool.lift(_uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_method_refund_uniffi_trait_eq_ne,self._uniffi_clone_pointer(), + _UniffiConverterTypeRefund.lower(other))) + + + +class _UniffiConverterTypeRefund: + + @staticmethod + def lift(value: int): + return Refund._make_instance_(value) + + @staticmethod + def check_lower(value: Refund): + if not isinstance(value, Refund): + raise TypeError("Expected Refund instance, {} found".format(type(value).__name__)) + + @staticmethod + def lower(value: RefundProtocol): + if not isinstance(value, Refund): + raise TypeError("Expected Refund instance, {} found".format(type(value).__name__)) + return value._uniffi_clone_pointer() + + @classmethod + def read(cls, buf: _UniffiRustBuffer): + ptr = buf.read_u64() + if ptr == 0: + raise InternalError("Raw pointer value was null") + return cls.lift(ptr) + + @classmethod + def write(cls, value: RefundProtocol, buf: _UniffiRustBuffer): + buf.write_u64(cls.lower(value)) + + + +class SpontaneousPaymentProtocol(typing.Protocol): + def send(self, amount_msat: "int",node_id: "PublicKey",route_parameters: "typing.Optional[RouteParametersConfig]"): + raise NotImplementedError + def send_probes(self, amount_msat: "int",node_id: "PublicKey"): + raise NotImplementedError + def send_with_custom_tlvs(self, amount_msat: "int",node_id: "PublicKey",route_parameters: "typing.Optional[RouteParametersConfig]",custom_tlvs: "typing.List[CustomTlvRecord]"): + raise NotImplementedError + def send_with_preimage(self, amount_msat: "int",node_id: "PublicKey",preimage: "PaymentPreimage",route_parameters: "typing.Optional[RouteParametersConfig]"): + raise NotImplementedError + def send_with_preimage_and_custom_tlvs(self, amount_msat: "int",node_id: "PublicKey",custom_tlvs: "typing.List[CustomTlvRecord]",preimage: "PaymentPreimage",route_parameters: "typing.Optional[RouteParametersConfig]"): + raise NotImplementedError + + +class SpontaneousPayment: + _pointer: ctypes.c_void_p + + def __init__(self, *args, **kwargs): + raise ValueError("This class has no default constructor") + + def __del__(self): + # In case of partial initialization of instances. + pointer = getattr(self, "_pointer", None) + if pointer is not None: + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_free_spontaneouspayment, pointer) + + def _uniffi_clone_pointer(self): + return _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_clone_spontaneouspayment, self._pointer) + + # Used by alternative constructors or any methods which return this type. + @classmethod + def _make_instance_(cls, pointer): + # Lightly yucky way to bypass the usual __init__ logic + # and just create a new instance with the required pointer. + inst = cls.__new__(cls) + inst._pointer = pointer + return inst + + + def send(self, amount_msat: "int",node_id: "PublicKey",route_parameters: "typing.Optional[RouteParametersConfig]") -> "PaymentId": + _UniffiConverterUInt64.check_lower(amount_msat) + + _UniffiConverterTypePublicKey.check_lower(node_id) + + _UniffiConverterOptionalTypeRouteParametersConfig.check_lower(route_parameters) + + return _UniffiConverterTypePaymentId.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_spontaneouspayment_send,self._uniffi_clone_pointer(), + _UniffiConverterUInt64.lower(amount_msat), + _UniffiConverterTypePublicKey.lower(node_id), + _UniffiConverterOptionalTypeRouteParametersConfig.lower(route_parameters)) + ) + + + + + + def send_probes(self, amount_msat: "int",node_id: "PublicKey") -> "typing.List[ProbeHandle]": + _UniffiConverterUInt64.check_lower(amount_msat) + + _UniffiConverterTypePublicKey.check_lower(node_id) + + return _UniffiConverterSequenceTypeProbeHandle.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_spontaneouspayment_send_probes,self._uniffi_clone_pointer(), + _UniffiConverterUInt64.lower(amount_msat), + _UniffiConverterTypePublicKey.lower(node_id)) + ) + + + + + + def send_with_custom_tlvs(self, amount_msat: "int",node_id: "PublicKey",route_parameters: "typing.Optional[RouteParametersConfig]",custom_tlvs: "typing.List[CustomTlvRecord]") -> "PaymentId": + _UniffiConverterUInt64.check_lower(amount_msat) + + _UniffiConverterTypePublicKey.check_lower(node_id) + + _UniffiConverterOptionalTypeRouteParametersConfig.check_lower(route_parameters) + + _UniffiConverterSequenceTypeCustomTlvRecord.check_lower(custom_tlvs) + + return _UniffiConverterTypePaymentId.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_spontaneouspayment_send_with_custom_tlvs,self._uniffi_clone_pointer(), + _UniffiConverterUInt64.lower(amount_msat), + _UniffiConverterTypePublicKey.lower(node_id), + _UniffiConverterOptionalTypeRouteParametersConfig.lower(route_parameters), + _UniffiConverterSequenceTypeCustomTlvRecord.lower(custom_tlvs)) + ) + + + + + + def send_with_preimage(self, amount_msat: "int",node_id: "PublicKey",preimage: "PaymentPreimage",route_parameters: "typing.Optional[RouteParametersConfig]") -> "PaymentId": + _UniffiConverterUInt64.check_lower(amount_msat) + + _UniffiConverterTypePublicKey.check_lower(node_id) + + _UniffiConverterTypePaymentPreimage.check_lower(preimage) + + _UniffiConverterOptionalTypeRouteParametersConfig.check_lower(route_parameters) + + return _UniffiConverterTypePaymentId.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_spontaneouspayment_send_with_preimage,self._uniffi_clone_pointer(), + _UniffiConverterUInt64.lower(amount_msat), + _UniffiConverterTypePublicKey.lower(node_id), + _UniffiConverterTypePaymentPreimage.lower(preimage), + _UniffiConverterOptionalTypeRouteParametersConfig.lower(route_parameters)) + ) + + + + + + def send_with_preimage_and_custom_tlvs(self, amount_msat: "int",node_id: "PublicKey",custom_tlvs: "typing.List[CustomTlvRecord]",preimage: "PaymentPreimage",route_parameters: "typing.Optional[RouteParametersConfig]") -> "PaymentId": + _UniffiConverterUInt64.check_lower(amount_msat) + + _UniffiConverterTypePublicKey.check_lower(node_id) + + _UniffiConverterSequenceTypeCustomTlvRecord.check_lower(custom_tlvs) + + _UniffiConverterTypePaymentPreimage.check_lower(preimage) + + _UniffiConverterOptionalTypeRouteParametersConfig.check_lower(route_parameters) + + return _UniffiConverterTypePaymentId.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_spontaneouspayment_send_with_preimage_and_custom_tlvs,self._uniffi_clone_pointer(), + _UniffiConverterUInt64.lower(amount_msat), + _UniffiConverterTypePublicKey.lower(node_id), + _UniffiConverterSequenceTypeCustomTlvRecord.lower(custom_tlvs), + _UniffiConverterTypePaymentPreimage.lower(preimage), + _UniffiConverterOptionalTypeRouteParametersConfig.lower(route_parameters)) + ) + + + + + + +class _UniffiConverterTypeSpontaneousPayment: + + @staticmethod + def lift(value: int): + return SpontaneousPayment._make_instance_(value) + + @staticmethod + def check_lower(value: SpontaneousPayment): + if not isinstance(value, SpontaneousPayment): + raise TypeError("Expected SpontaneousPayment instance, {} found".format(type(value).__name__)) + + @staticmethod + def lower(value: SpontaneousPaymentProtocol): + if not isinstance(value, SpontaneousPayment): + raise TypeError("Expected SpontaneousPayment instance, {} found".format(type(value).__name__)) + return value._uniffi_clone_pointer() + + @classmethod + def read(cls, buf: _UniffiRustBuffer): + ptr = buf.read_u64() + if ptr == 0: + raise InternalError("Raw pointer value was null") + return cls.lift(ptr) + + @classmethod + def write(cls, value: SpontaneousPaymentProtocol, buf: _UniffiRustBuffer): + buf.write_u64(cls.lower(value)) + + + +class UnifiedQrPaymentProtocol(typing.Protocol): + def receive(self, amount_sats: "int",message: "str",expiry_sec: "int"): + raise NotImplementedError + def send(self, uri_str: "str",route_parameters: "typing.Optional[RouteParametersConfig]"): + raise NotImplementedError + + +class UnifiedQrPayment: + _pointer: ctypes.c_void_p + + def __init__(self, *args, **kwargs): + raise ValueError("This class has no default constructor") + + def __del__(self): + # In case of partial initialization of instances. + pointer = getattr(self, "_pointer", None) + if pointer is not None: + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_free_unifiedqrpayment, pointer) + + def _uniffi_clone_pointer(self): + return _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_clone_unifiedqrpayment, self._pointer) + + # Used by alternative constructors or any methods which return this type. + @classmethod + def _make_instance_(cls, pointer): + # Lightly yucky way to bypass the usual __init__ logic + # and just create a new instance with the required pointer. + inst = cls.__new__(cls) + inst._pointer = pointer + return inst + + + def receive(self, amount_sats: "int",message: "str",expiry_sec: "int") -> "str": + _UniffiConverterUInt64.check_lower(amount_sats) + + _UniffiConverterString.check_lower(message) + + _UniffiConverterUInt32.check_lower(expiry_sec) + + return _UniffiConverterString.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_unifiedqrpayment_receive,self._uniffi_clone_pointer(), + _UniffiConverterUInt64.lower(amount_sats), + _UniffiConverterString.lower(message), + _UniffiConverterUInt32.lower(expiry_sec)) + ) + + + + + + def send(self, uri_str: "str",route_parameters: "typing.Optional[RouteParametersConfig]") -> "QrPaymentResult": + _UniffiConverterString.check_lower(uri_str) + + _UniffiConverterOptionalTypeRouteParametersConfig.check_lower(route_parameters) + + return _UniffiConverterTypeQrPaymentResult.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_unifiedqrpayment_send,self._uniffi_clone_pointer(), + _UniffiConverterString.lower(uri_str), + _UniffiConverterOptionalTypeRouteParametersConfig.lower(route_parameters)) + ) + + + + + + +class _UniffiConverterTypeUnifiedQrPayment: + + @staticmethod + def lift(value: int): + return UnifiedQrPayment._make_instance_(value) + + @staticmethod + def check_lower(value: UnifiedQrPayment): + if not isinstance(value, UnifiedQrPayment): + raise TypeError("Expected UnifiedQrPayment instance, {} found".format(type(value).__name__)) + + @staticmethod + def lower(value: UnifiedQrPaymentProtocol): + if not isinstance(value, UnifiedQrPayment): + raise TypeError("Expected UnifiedQrPayment instance, {} found".format(type(value).__name__)) + return value._uniffi_clone_pointer() + + @classmethod + def read(cls, buf: _UniffiRustBuffer): + ptr = buf.read_u64() + if ptr == 0: + raise InternalError("Raw pointer value was null") + return cls.lift(ptr) + + @classmethod + def write(cls, value: UnifiedQrPaymentProtocol, buf: _UniffiRustBuffer): + buf.write_u64(cls.lower(value)) + + + +class VssHeaderProviderProtocol(typing.Protocol): + def get_headers(self, request: "typing.List[int]"): + raise NotImplementedError + + +class VssHeaderProvider: + _pointer: ctypes.c_void_p + + def __init__(self, *args, **kwargs): + raise ValueError("This class has no default constructor") + + def __del__(self): + # In case of partial initialization of instances. + pointer = getattr(self, "_pointer", None) + if pointer is not None: + _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_free_vssheaderprovider, pointer) + + def _uniffi_clone_pointer(self): + return _uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_clone_vssheaderprovider, self._pointer) + + # Used by alternative constructors or any methods which return this type. + @classmethod + def _make_instance_(cls, pointer): + # Lightly yucky way to bypass the usual __init__ logic + # and just create a new instance with the required pointer. + inst = cls.__new__(cls) + inst._pointer = pointer + return inst + + async def get_headers(self, request: "typing.List[int]") -> "dict[str, str]": + _UniffiConverterSequenceUInt8.check_lower(request) + + return await _uniffi_rust_call_async( + _UniffiLib.uniffi_ldk_node_fn_method_vssheaderprovider_get_headers( + self._uniffi_clone_pointer(), + _UniffiConverterSequenceUInt8.lower(request) + ), + _UniffiLib.ffi_ldk_node_rust_future_poll_rust_buffer, + _UniffiLib.ffi_ldk_node_rust_future_complete_rust_buffer, + _UniffiLib.ffi_ldk_node_rust_future_free_rust_buffer, + # lift function + _UniffiConverterMapStringString.lift, + + # Error FFI converter +_UniffiConverterTypeVssHeaderProviderError, + + ) + + + + + +class _UniffiConverterTypeVssHeaderProvider: + + @staticmethod + def lift(value: int): + return VssHeaderProvider._make_instance_(value) + + @staticmethod + def check_lower(value: VssHeaderProvider): + if not isinstance(value, VssHeaderProvider): + raise TypeError("Expected VssHeaderProvider instance, {} found".format(type(value).__name__)) + + @staticmethod + def lower(value: VssHeaderProviderProtocol): + if not isinstance(value, VssHeaderProvider): + raise TypeError("Expected VssHeaderProvider instance, {} found".format(type(value).__name__)) + return value._uniffi_clone_pointer() + + @classmethod + def read(cls, buf: _UniffiRustBuffer): + ptr = buf.read_u64() + if ptr == 0: + raise InternalError("Raw pointer value was null") + return cls.lift(ptr) + + @classmethod + def write(cls, value: VssHeaderProviderProtocol, buf: _UniffiRustBuffer): + buf.write_u64(cls.lower(value)) + + +class AddressInfo: + index: "int" + address: "Address" + keychain: "KeychainKind" + def __init__(self, *, index: "int", address: "Address", keychain: "KeychainKind"): + self.index = index + self.address = address + self.keychain = keychain + + def __str__(self): + return "AddressInfo(index={}, address={}, keychain={})".format(self.index, self.address, self.keychain) + + def __eq__(self, other): + if self.index != other.index: + return False + if self.address != other.address: + return False + if self.keychain != other.keychain: + return False + return True + +class _UniffiConverterTypeAddressInfo(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return AddressInfo( + index=_UniffiConverterUInt32.read(buf), + address=_UniffiConverterTypeAddress.read(buf), + keychain=_UniffiConverterTypeKeychainKind.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterUInt32.check_lower(value.index) + _UniffiConverterTypeAddress.check_lower(value.address) + _UniffiConverterTypeKeychainKind.check_lower(value.keychain) + + @staticmethod + def write(value, buf): + _UniffiConverterUInt32.write(value.index, buf) + _UniffiConverterTypeAddress.write(value.address, buf) + _UniffiConverterTypeKeychainKind.write(value.keychain, buf) + + +class AddressTypeBalance: + total_sats: "int" + spendable_sats: "int" + def __init__(self, *, total_sats: "int", spendable_sats: "int"): + self.total_sats = total_sats + self.spendable_sats = spendable_sats + + def __str__(self): + return "AddressTypeBalance(total_sats={}, spendable_sats={})".format(self.total_sats, self.spendable_sats) + + def __eq__(self, other): + if self.total_sats != other.total_sats: + return False + if self.spendable_sats != other.spendable_sats: + return False + return True + +class _UniffiConverterTypeAddressTypeBalance(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return AddressTypeBalance( + total_sats=_UniffiConverterUInt64.read(buf), + spendable_sats=_UniffiConverterUInt64.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterUInt64.check_lower(value.total_sats) + _UniffiConverterUInt64.check_lower(value.spendable_sats) + + @staticmethod + def write(value, buf): + _UniffiConverterUInt64.write(value.total_sats, buf) + _UniffiConverterUInt64.write(value.spendable_sats, buf) + + +class AnchorChannelsConfig: + trusted_peers_no_reserve: "typing.List[PublicKey]" + per_channel_reserve_sats: "int" + def __init__(self, *, trusted_peers_no_reserve: "typing.List[PublicKey]", per_channel_reserve_sats: "int"): + self.trusted_peers_no_reserve = trusted_peers_no_reserve + self.per_channel_reserve_sats = per_channel_reserve_sats + + def __str__(self): + return "AnchorChannelsConfig(trusted_peers_no_reserve={}, per_channel_reserve_sats={})".format(self.trusted_peers_no_reserve, self.per_channel_reserve_sats) + + def __eq__(self, other): + if self.trusted_peers_no_reserve != other.trusted_peers_no_reserve: + return False + if self.per_channel_reserve_sats != other.per_channel_reserve_sats: + return False + return True + +class _UniffiConverterTypeAnchorChannelsConfig(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return AnchorChannelsConfig( + trusted_peers_no_reserve=_UniffiConverterSequenceTypePublicKey.read(buf), + per_channel_reserve_sats=_UniffiConverterUInt64.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterSequenceTypePublicKey.check_lower(value.trusted_peers_no_reserve) + _UniffiConverterUInt64.check_lower(value.per_channel_reserve_sats) + + @staticmethod + def write(value, buf): + _UniffiConverterSequenceTypePublicKey.write(value.trusted_peers_no_reserve, buf) + _UniffiConverterUInt64.write(value.per_channel_reserve_sats, buf) + + +class BackgroundSyncConfig: + onchain_wallet_sync_interval_secs: "int" + lightning_wallet_sync_interval_secs: "int" + fee_rate_cache_update_interval_secs: "int" + def __init__(self, *, onchain_wallet_sync_interval_secs: "int", lightning_wallet_sync_interval_secs: "int", fee_rate_cache_update_interval_secs: "int"): + self.onchain_wallet_sync_interval_secs = onchain_wallet_sync_interval_secs + self.lightning_wallet_sync_interval_secs = lightning_wallet_sync_interval_secs + self.fee_rate_cache_update_interval_secs = fee_rate_cache_update_interval_secs + + def __str__(self): + return "BackgroundSyncConfig(onchain_wallet_sync_interval_secs={}, lightning_wallet_sync_interval_secs={}, fee_rate_cache_update_interval_secs={})".format(self.onchain_wallet_sync_interval_secs, self.lightning_wallet_sync_interval_secs, self.fee_rate_cache_update_interval_secs) + + def __eq__(self, other): + if self.onchain_wallet_sync_interval_secs != other.onchain_wallet_sync_interval_secs: + return False + if self.lightning_wallet_sync_interval_secs != other.lightning_wallet_sync_interval_secs: + return False + if self.fee_rate_cache_update_interval_secs != other.fee_rate_cache_update_interval_secs: + return False + return True + +class _UniffiConverterTypeBackgroundSyncConfig(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return BackgroundSyncConfig( + onchain_wallet_sync_interval_secs=_UniffiConverterUInt64.read(buf), + lightning_wallet_sync_interval_secs=_UniffiConverterUInt64.read(buf), + fee_rate_cache_update_interval_secs=_UniffiConverterUInt64.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterUInt64.check_lower(value.onchain_wallet_sync_interval_secs) + _UniffiConverterUInt64.check_lower(value.lightning_wallet_sync_interval_secs) + _UniffiConverterUInt64.check_lower(value.fee_rate_cache_update_interval_secs) + + @staticmethod + def write(value, buf): + _UniffiConverterUInt64.write(value.onchain_wallet_sync_interval_secs, buf) + _UniffiConverterUInt64.write(value.lightning_wallet_sync_interval_secs, buf) + _UniffiConverterUInt64.write(value.fee_rate_cache_update_interval_secs, buf) + + +class BalanceDetails: + total_onchain_balance_sats: "int" + spendable_onchain_balance_sats: "int" + total_anchor_channels_reserve_sats: "int" + total_lightning_balance_sats: "int" + lightning_balances: "typing.List[LightningBalance]" + pending_balances_from_channel_closures: "typing.List[PendingSweepBalance]" + def __init__(self, *, total_onchain_balance_sats: "int", spendable_onchain_balance_sats: "int", total_anchor_channels_reserve_sats: "int", total_lightning_balance_sats: "int", lightning_balances: "typing.List[LightningBalance]", pending_balances_from_channel_closures: "typing.List[PendingSweepBalance]"): + self.total_onchain_balance_sats = total_onchain_balance_sats + self.spendable_onchain_balance_sats = spendable_onchain_balance_sats + self.total_anchor_channels_reserve_sats = total_anchor_channels_reserve_sats + self.total_lightning_balance_sats = total_lightning_balance_sats + self.lightning_balances = lightning_balances + self.pending_balances_from_channel_closures = pending_balances_from_channel_closures + + def __str__(self): + return "BalanceDetails(total_onchain_balance_sats={}, spendable_onchain_balance_sats={}, total_anchor_channels_reserve_sats={}, total_lightning_balance_sats={}, lightning_balances={}, pending_balances_from_channel_closures={})".format(self.total_onchain_balance_sats, self.spendable_onchain_balance_sats, self.total_anchor_channels_reserve_sats, self.total_lightning_balance_sats, self.lightning_balances, self.pending_balances_from_channel_closures) + + def __eq__(self, other): + if self.total_onchain_balance_sats != other.total_onchain_balance_sats: + return False + if self.spendable_onchain_balance_sats != other.spendable_onchain_balance_sats: + return False + if self.total_anchor_channels_reserve_sats != other.total_anchor_channels_reserve_sats: + return False + if self.total_lightning_balance_sats != other.total_lightning_balance_sats: + return False + if self.lightning_balances != other.lightning_balances: + return False + if self.pending_balances_from_channel_closures != other.pending_balances_from_channel_closures: + return False + return True + +class _UniffiConverterTypeBalanceDetails(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return BalanceDetails( + total_onchain_balance_sats=_UniffiConverterUInt64.read(buf), + spendable_onchain_balance_sats=_UniffiConverterUInt64.read(buf), + total_anchor_channels_reserve_sats=_UniffiConverterUInt64.read(buf), + total_lightning_balance_sats=_UniffiConverterUInt64.read(buf), + lightning_balances=_UniffiConverterSequenceTypeLightningBalance.read(buf), + pending_balances_from_channel_closures=_UniffiConverterSequenceTypePendingSweepBalance.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterUInt64.check_lower(value.total_onchain_balance_sats) + _UniffiConverterUInt64.check_lower(value.spendable_onchain_balance_sats) + _UniffiConverterUInt64.check_lower(value.total_anchor_channels_reserve_sats) + _UniffiConverterUInt64.check_lower(value.total_lightning_balance_sats) + _UniffiConverterSequenceTypeLightningBalance.check_lower(value.lightning_balances) + _UniffiConverterSequenceTypePendingSweepBalance.check_lower(value.pending_balances_from_channel_closures) + + @staticmethod + def write(value, buf): + _UniffiConverterUInt64.write(value.total_onchain_balance_sats, buf) + _UniffiConverterUInt64.write(value.spendable_onchain_balance_sats, buf) + _UniffiConverterUInt64.write(value.total_anchor_channels_reserve_sats, buf) + _UniffiConverterUInt64.write(value.total_lightning_balance_sats, buf) + _UniffiConverterSequenceTypeLightningBalance.write(value.lightning_balances, buf) + _UniffiConverterSequenceTypePendingSweepBalance.write(value.pending_balances_from_channel_closures, buf) + + +class BestBlock: + block_hash: "BlockHash" + height: "int" + def __init__(self, *, block_hash: "BlockHash", height: "int"): + self.block_hash = block_hash + self.height = height + + def __str__(self): + return "BestBlock(block_hash={}, height={})".format(self.block_hash, self.height) + + def __eq__(self, other): + if self.block_hash != other.block_hash: + return False + if self.height != other.height: + return False + return True + +class _UniffiConverterTypeBestBlock(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return BestBlock( + block_hash=_UniffiConverterTypeBlockHash.read(buf), + height=_UniffiConverterUInt32.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterTypeBlockHash.check_lower(value.block_hash) + _UniffiConverterUInt32.check_lower(value.height) + + @staticmethod + def write(value, buf): + _UniffiConverterTypeBlockHash.write(value.block_hash, buf) + _UniffiConverterUInt32.write(value.height, buf) + + +class ChannelConfig: + forwarding_fee_proportional_millionths: "int" + forwarding_fee_base_msat: "int" + cltv_expiry_delta: "int" + max_dust_htlc_exposure: "MaxDustHtlcExposure" + force_close_avoidance_max_fee_satoshis: "int" + accept_underpaying_htlcs: "bool" + def __init__(self, *, forwarding_fee_proportional_millionths: "int", forwarding_fee_base_msat: "int", cltv_expiry_delta: "int", max_dust_htlc_exposure: "MaxDustHtlcExposure", force_close_avoidance_max_fee_satoshis: "int", accept_underpaying_htlcs: "bool"): + self.forwarding_fee_proportional_millionths = forwarding_fee_proportional_millionths + self.forwarding_fee_base_msat = forwarding_fee_base_msat + self.cltv_expiry_delta = cltv_expiry_delta + self.max_dust_htlc_exposure = max_dust_htlc_exposure + self.force_close_avoidance_max_fee_satoshis = force_close_avoidance_max_fee_satoshis + self.accept_underpaying_htlcs = accept_underpaying_htlcs + + def __str__(self): + return "ChannelConfig(forwarding_fee_proportional_millionths={}, forwarding_fee_base_msat={}, cltv_expiry_delta={}, max_dust_htlc_exposure={}, force_close_avoidance_max_fee_satoshis={}, accept_underpaying_htlcs={})".format(self.forwarding_fee_proportional_millionths, self.forwarding_fee_base_msat, self.cltv_expiry_delta, self.max_dust_htlc_exposure, self.force_close_avoidance_max_fee_satoshis, self.accept_underpaying_htlcs) + + def __eq__(self, other): + if self.forwarding_fee_proportional_millionths != other.forwarding_fee_proportional_millionths: + return False + if self.forwarding_fee_base_msat != other.forwarding_fee_base_msat: + return False + if self.cltv_expiry_delta != other.cltv_expiry_delta: + return False + if self.max_dust_htlc_exposure != other.max_dust_htlc_exposure: + return False + if self.force_close_avoidance_max_fee_satoshis != other.force_close_avoidance_max_fee_satoshis: + return False + if self.accept_underpaying_htlcs != other.accept_underpaying_htlcs: + return False + return True + +class _UniffiConverterTypeChannelConfig(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return ChannelConfig( + forwarding_fee_proportional_millionths=_UniffiConverterUInt32.read(buf), + forwarding_fee_base_msat=_UniffiConverterUInt32.read(buf), + cltv_expiry_delta=_UniffiConverterUInt16.read(buf), + max_dust_htlc_exposure=_UniffiConverterTypeMaxDustHtlcExposure.read(buf), + force_close_avoidance_max_fee_satoshis=_UniffiConverterUInt64.read(buf), + accept_underpaying_htlcs=_UniffiConverterBool.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterUInt32.check_lower(value.forwarding_fee_proportional_millionths) + _UniffiConverterUInt32.check_lower(value.forwarding_fee_base_msat) + _UniffiConverterUInt16.check_lower(value.cltv_expiry_delta) + _UniffiConverterTypeMaxDustHtlcExposure.check_lower(value.max_dust_htlc_exposure) + _UniffiConverterUInt64.check_lower(value.force_close_avoidance_max_fee_satoshis) + _UniffiConverterBool.check_lower(value.accept_underpaying_htlcs) + + @staticmethod + def write(value, buf): + _UniffiConverterUInt32.write(value.forwarding_fee_proportional_millionths, buf) + _UniffiConverterUInt32.write(value.forwarding_fee_base_msat, buf) + _UniffiConverterUInt16.write(value.cltv_expiry_delta, buf) + _UniffiConverterTypeMaxDustHtlcExposure.write(value.max_dust_htlc_exposure, buf) + _UniffiConverterUInt64.write(value.force_close_avoidance_max_fee_satoshis, buf) + _UniffiConverterBool.write(value.accept_underpaying_htlcs, buf) + + +class ChannelDataMigration: + channel_manager: "typing.Optional[typing.List[int]]" + channel_monitors: "typing.List[typing.List[int]]" + def __init__(self, *, channel_manager: "typing.Optional[typing.List[int]]", channel_monitors: "typing.List[typing.List[int]]"): + self.channel_manager = channel_manager + self.channel_monitors = channel_monitors + + def __str__(self): + return "ChannelDataMigration(channel_manager={}, channel_monitors={})".format(self.channel_manager, self.channel_monitors) + + def __eq__(self, other): + if self.channel_manager != other.channel_manager: + return False + if self.channel_monitors != other.channel_monitors: + return False + return True + +class _UniffiConverterTypeChannelDataMigration(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return ChannelDataMigration( + channel_manager=_UniffiConverterOptionalSequenceUInt8.read(buf), + channel_monitors=_UniffiConverterSequenceSequenceUInt8.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterOptionalSequenceUInt8.check_lower(value.channel_manager) + _UniffiConverterSequenceSequenceUInt8.check_lower(value.channel_monitors) + + @staticmethod + def write(value, buf): + _UniffiConverterOptionalSequenceUInt8.write(value.channel_manager, buf) + _UniffiConverterSequenceSequenceUInt8.write(value.channel_monitors, buf) + + +class ChannelDetails: + channel_id: "ChannelId" + counterparty_node_id: "PublicKey" + funding_txo: "typing.Optional[OutPoint]" + short_channel_id: "typing.Optional[int]" + outbound_scid_alias: "typing.Optional[int]" + inbound_scid_alias: "typing.Optional[int]" + channel_value_sats: "int" + unspendable_punishment_reserve: "typing.Optional[int]" + user_channel_id: "UserChannelId" + feerate_sat_per_1000_weight: "int" + outbound_capacity_msat: "int" + inbound_capacity_msat: "int" + confirmations_required: "typing.Optional[int]" + confirmations: "typing.Optional[int]" + is_outbound: "bool" + is_channel_ready: "bool" + is_usable: "bool" + is_announced: "bool" + cltv_expiry_delta: "typing.Optional[int]" + counterparty_unspendable_punishment_reserve: "int" + counterparty_outbound_htlc_minimum_msat: "typing.Optional[int]" + counterparty_outbound_htlc_maximum_msat: "typing.Optional[int]" + counterparty_forwarding_info_fee_base_msat: "typing.Optional[int]" + counterparty_forwarding_info_fee_proportional_millionths: "typing.Optional[int]" + counterparty_forwarding_info_cltv_expiry_delta: "typing.Optional[int]" + next_outbound_htlc_limit_msat: "int" + next_outbound_htlc_minimum_msat: "int" + force_close_spend_delay: "typing.Optional[int]" + inbound_htlc_minimum_msat: "int" + inbound_htlc_maximum_msat: "typing.Optional[int]" + config: "ChannelConfig" + claimable_on_close_sats: "typing.Optional[int]" + def __init__(self, *, channel_id: "ChannelId", counterparty_node_id: "PublicKey", funding_txo: "typing.Optional[OutPoint]", short_channel_id: "typing.Optional[int]", outbound_scid_alias: "typing.Optional[int]", inbound_scid_alias: "typing.Optional[int]", channel_value_sats: "int", unspendable_punishment_reserve: "typing.Optional[int]", user_channel_id: "UserChannelId", feerate_sat_per_1000_weight: "int", outbound_capacity_msat: "int", inbound_capacity_msat: "int", confirmations_required: "typing.Optional[int]", confirmations: "typing.Optional[int]", is_outbound: "bool", is_channel_ready: "bool", is_usable: "bool", is_announced: "bool", cltv_expiry_delta: "typing.Optional[int]", counterparty_unspendable_punishment_reserve: "int", counterparty_outbound_htlc_minimum_msat: "typing.Optional[int]", counterparty_outbound_htlc_maximum_msat: "typing.Optional[int]", counterparty_forwarding_info_fee_base_msat: "typing.Optional[int]", counterparty_forwarding_info_fee_proportional_millionths: "typing.Optional[int]", counterparty_forwarding_info_cltv_expiry_delta: "typing.Optional[int]", next_outbound_htlc_limit_msat: "int", next_outbound_htlc_minimum_msat: "int", force_close_spend_delay: "typing.Optional[int]", inbound_htlc_minimum_msat: "int", inbound_htlc_maximum_msat: "typing.Optional[int]", config: "ChannelConfig", claimable_on_close_sats: "typing.Optional[int]"): + self.channel_id = channel_id + self.counterparty_node_id = counterparty_node_id + self.funding_txo = funding_txo + self.short_channel_id = short_channel_id + self.outbound_scid_alias = outbound_scid_alias + self.inbound_scid_alias = inbound_scid_alias + self.channel_value_sats = channel_value_sats + self.unspendable_punishment_reserve = unspendable_punishment_reserve + self.user_channel_id = user_channel_id + self.feerate_sat_per_1000_weight = feerate_sat_per_1000_weight + self.outbound_capacity_msat = outbound_capacity_msat + self.inbound_capacity_msat = inbound_capacity_msat + self.confirmations_required = confirmations_required + self.confirmations = confirmations + self.is_outbound = is_outbound + self.is_channel_ready = is_channel_ready + self.is_usable = is_usable + self.is_announced = is_announced + self.cltv_expiry_delta = cltv_expiry_delta + self.counterparty_unspendable_punishment_reserve = counterparty_unspendable_punishment_reserve + self.counterparty_outbound_htlc_minimum_msat = counterparty_outbound_htlc_minimum_msat + self.counterparty_outbound_htlc_maximum_msat = counterparty_outbound_htlc_maximum_msat + self.counterparty_forwarding_info_fee_base_msat = counterparty_forwarding_info_fee_base_msat + self.counterparty_forwarding_info_fee_proportional_millionths = counterparty_forwarding_info_fee_proportional_millionths + self.counterparty_forwarding_info_cltv_expiry_delta = counterparty_forwarding_info_cltv_expiry_delta + self.next_outbound_htlc_limit_msat = next_outbound_htlc_limit_msat + self.next_outbound_htlc_minimum_msat = next_outbound_htlc_minimum_msat + self.force_close_spend_delay = force_close_spend_delay + self.inbound_htlc_minimum_msat = inbound_htlc_minimum_msat + self.inbound_htlc_maximum_msat = inbound_htlc_maximum_msat + self.config = config + self.claimable_on_close_sats = claimable_on_close_sats + + def __str__(self): + return "ChannelDetails(channel_id={}, counterparty_node_id={}, funding_txo={}, short_channel_id={}, outbound_scid_alias={}, inbound_scid_alias={}, channel_value_sats={}, unspendable_punishment_reserve={}, user_channel_id={}, feerate_sat_per_1000_weight={}, outbound_capacity_msat={}, inbound_capacity_msat={}, confirmations_required={}, confirmations={}, is_outbound={}, is_channel_ready={}, is_usable={}, is_announced={}, cltv_expiry_delta={}, counterparty_unspendable_punishment_reserve={}, counterparty_outbound_htlc_minimum_msat={}, counterparty_outbound_htlc_maximum_msat={}, counterparty_forwarding_info_fee_base_msat={}, counterparty_forwarding_info_fee_proportional_millionths={}, counterparty_forwarding_info_cltv_expiry_delta={}, next_outbound_htlc_limit_msat={}, next_outbound_htlc_minimum_msat={}, force_close_spend_delay={}, inbound_htlc_minimum_msat={}, inbound_htlc_maximum_msat={}, config={}, claimable_on_close_sats={})".format(self.channel_id, self.counterparty_node_id, self.funding_txo, self.short_channel_id, self.outbound_scid_alias, self.inbound_scid_alias, self.channel_value_sats, self.unspendable_punishment_reserve, self.user_channel_id, self.feerate_sat_per_1000_weight, self.outbound_capacity_msat, self.inbound_capacity_msat, self.confirmations_required, self.confirmations, self.is_outbound, self.is_channel_ready, self.is_usable, self.is_announced, self.cltv_expiry_delta, self.counterparty_unspendable_punishment_reserve, self.counterparty_outbound_htlc_minimum_msat, self.counterparty_outbound_htlc_maximum_msat, self.counterparty_forwarding_info_fee_base_msat, self.counterparty_forwarding_info_fee_proportional_millionths, self.counterparty_forwarding_info_cltv_expiry_delta, self.next_outbound_htlc_limit_msat, self.next_outbound_htlc_minimum_msat, self.force_close_spend_delay, self.inbound_htlc_minimum_msat, self.inbound_htlc_maximum_msat, self.config, self.claimable_on_close_sats) + + def __eq__(self, other): + if self.channel_id != other.channel_id: + return False + if self.counterparty_node_id != other.counterparty_node_id: + return False + if self.funding_txo != other.funding_txo: + return False + if self.short_channel_id != other.short_channel_id: + return False + if self.outbound_scid_alias != other.outbound_scid_alias: + return False + if self.inbound_scid_alias != other.inbound_scid_alias: + return False + if self.channel_value_sats != other.channel_value_sats: + return False + if self.unspendable_punishment_reserve != other.unspendable_punishment_reserve: + return False + if self.user_channel_id != other.user_channel_id: + return False + if self.feerate_sat_per_1000_weight != other.feerate_sat_per_1000_weight: + return False + if self.outbound_capacity_msat != other.outbound_capacity_msat: + return False + if self.inbound_capacity_msat != other.inbound_capacity_msat: + return False + if self.confirmations_required != other.confirmations_required: + return False + if self.confirmations != other.confirmations: + return False + if self.is_outbound != other.is_outbound: + return False + if self.is_channel_ready != other.is_channel_ready: + return False + if self.is_usable != other.is_usable: + return False + if self.is_announced != other.is_announced: + return False + if self.cltv_expiry_delta != other.cltv_expiry_delta: + return False + if self.counterparty_unspendable_punishment_reserve != other.counterparty_unspendable_punishment_reserve: + return False + if self.counterparty_outbound_htlc_minimum_msat != other.counterparty_outbound_htlc_minimum_msat: + return False + if self.counterparty_outbound_htlc_maximum_msat != other.counterparty_outbound_htlc_maximum_msat: + return False + if self.counterparty_forwarding_info_fee_base_msat != other.counterparty_forwarding_info_fee_base_msat: + return False + if self.counterparty_forwarding_info_fee_proportional_millionths != other.counterparty_forwarding_info_fee_proportional_millionths: + return False + if self.counterparty_forwarding_info_cltv_expiry_delta != other.counterparty_forwarding_info_cltv_expiry_delta: + return False + if self.next_outbound_htlc_limit_msat != other.next_outbound_htlc_limit_msat: + return False + if self.next_outbound_htlc_minimum_msat != other.next_outbound_htlc_minimum_msat: + return False + if self.force_close_spend_delay != other.force_close_spend_delay: + return False + if self.inbound_htlc_minimum_msat != other.inbound_htlc_minimum_msat: + return False + if self.inbound_htlc_maximum_msat != other.inbound_htlc_maximum_msat: + return False + if self.config != other.config: + return False + if self.claimable_on_close_sats != other.claimable_on_close_sats: + return False + return True + +class _UniffiConverterTypeChannelDetails(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return ChannelDetails( + channel_id=_UniffiConverterTypeChannelId.read(buf), + counterparty_node_id=_UniffiConverterTypePublicKey.read(buf), + funding_txo=_UniffiConverterOptionalTypeOutPoint.read(buf), + short_channel_id=_UniffiConverterOptionalUInt64.read(buf), + outbound_scid_alias=_UniffiConverterOptionalUInt64.read(buf), + inbound_scid_alias=_UniffiConverterOptionalUInt64.read(buf), + channel_value_sats=_UniffiConverterUInt64.read(buf), + unspendable_punishment_reserve=_UniffiConverterOptionalUInt64.read(buf), + user_channel_id=_UniffiConverterTypeUserChannelId.read(buf), + feerate_sat_per_1000_weight=_UniffiConverterUInt32.read(buf), + outbound_capacity_msat=_UniffiConverterUInt64.read(buf), + inbound_capacity_msat=_UniffiConverterUInt64.read(buf), + confirmations_required=_UniffiConverterOptionalUInt32.read(buf), + confirmations=_UniffiConverterOptionalUInt32.read(buf), + is_outbound=_UniffiConverterBool.read(buf), + is_channel_ready=_UniffiConverterBool.read(buf), + is_usable=_UniffiConverterBool.read(buf), + is_announced=_UniffiConverterBool.read(buf), + cltv_expiry_delta=_UniffiConverterOptionalUInt16.read(buf), + counterparty_unspendable_punishment_reserve=_UniffiConverterUInt64.read(buf), + counterparty_outbound_htlc_minimum_msat=_UniffiConverterOptionalUInt64.read(buf), + counterparty_outbound_htlc_maximum_msat=_UniffiConverterOptionalUInt64.read(buf), + counterparty_forwarding_info_fee_base_msat=_UniffiConverterOptionalUInt32.read(buf), + counterparty_forwarding_info_fee_proportional_millionths=_UniffiConverterOptionalUInt32.read(buf), + counterparty_forwarding_info_cltv_expiry_delta=_UniffiConverterOptionalUInt16.read(buf), + next_outbound_htlc_limit_msat=_UniffiConverterUInt64.read(buf), + next_outbound_htlc_minimum_msat=_UniffiConverterUInt64.read(buf), + force_close_spend_delay=_UniffiConverterOptionalUInt16.read(buf), + inbound_htlc_minimum_msat=_UniffiConverterUInt64.read(buf), + inbound_htlc_maximum_msat=_UniffiConverterOptionalUInt64.read(buf), + config=_UniffiConverterTypeChannelConfig.read(buf), + claimable_on_close_sats=_UniffiConverterOptionalUInt64.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterTypeChannelId.check_lower(value.channel_id) + _UniffiConverterTypePublicKey.check_lower(value.counterparty_node_id) + _UniffiConverterOptionalTypeOutPoint.check_lower(value.funding_txo) + _UniffiConverterOptionalUInt64.check_lower(value.short_channel_id) + _UniffiConverterOptionalUInt64.check_lower(value.outbound_scid_alias) + _UniffiConverterOptionalUInt64.check_lower(value.inbound_scid_alias) + _UniffiConverterUInt64.check_lower(value.channel_value_sats) + _UniffiConverterOptionalUInt64.check_lower(value.unspendable_punishment_reserve) + _UniffiConverterTypeUserChannelId.check_lower(value.user_channel_id) + _UniffiConverterUInt32.check_lower(value.feerate_sat_per_1000_weight) + _UniffiConverterUInt64.check_lower(value.outbound_capacity_msat) + _UniffiConverterUInt64.check_lower(value.inbound_capacity_msat) + _UniffiConverterOptionalUInt32.check_lower(value.confirmations_required) + _UniffiConverterOptionalUInt32.check_lower(value.confirmations) + _UniffiConverterBool.check_lower(value.is_outbound) + _UniffiConverterBool.check_lower(value.is_channel_ready) + _UniffiConverterBool.check_lower(value.is_usable) + _UniffiConverterBool.check_lower(value.is_announced) + _UniffiConverterOptionalUInt16.check_lower(value.cltv_expiry_delta) + _UniffiConverterUInt64.check_lower(value.counterparty_unspendable_punishment_reserve) + _UniffiConverterOptionalUInt64.check_lower(value.counterparty_outbound_htlc_minimum_msat) + _UniffiConverterOptionalUInt64.check_lower(value.counterparty_outbound_htlc_maximum_msat) + _UniffiConverterOptionalUInt32.check_lower(value.counterparty_forwarding_info_fee_base_msat) + _UniffiConverterOptionalUInt32.check_lower(value.counterparty_forwarding_info_fee_proportional_millionths) + _UniffiConverterOptionalUInt16.check_lower(value.counterparty_forwarding_info_cltv_expiry_delta) + _UniffiConverterUInt64.check_lower(value.next_outbound_htlc_limit_msat) + _UniffiConverterUInt64.check_lower(value.next_outbound_htlc_minimum_msat) + _UniffiConverterOptionalUInt16.check_lower(value.force_close_spend_delay) + _UniffiConverterUInt64.check_lower(value.inbound_htlc_minimum_msat) + _UniffiConverterOptionalUInt64.check_lower(value.inbound_htlc_maximum_msat) + _UniffiConverterTypeChannelConfig.check_lower(value.config) + _UniffiConverterOptionalUInt64.check_lower(value.claimable_on_close_sats) + + @staticmethod + def write(value, buf): + _UniffiConverterTypeChannelId.write(value.channel_id, buf) + _UniffiConverterTypePublicKey.write(value.counterparty_node_id, buf) + _UniffiConverterOptionalTypeOutPoint.write(value.funding_txo, buf) + _UniffiConverterOptionalUInt64.write(value.short_channel_id, buf) + _UniffiConverterOptionalUInt64.write(value.outbound_scid_alias, buf) + _UniffiConverterOptionalUInt64.write(value.inbound_scid_alias, buf) + _UniffiConverterUInt64.write(value.channel_value_sats, buf) + _UniffiConverterOptionalUInt64.write(value.unspendable_punishment_reserve, buf) + _UniffiConverterTypeUserChannelId.write(value.user_channel_id, buf) + _UniffiConverterUInt32.write(value.feerate_sat_per_1000_weight, buf) + _UniffiConverterUInt64.write(value.outbound_capacity_msat, buf) + _UniffiConverterUInt64.write(value.inbound_capacity_msat, buf) + _UniffiConverterOptionalUInt32.write(value.confirmations_required, buf) + _UniffiConverterOptionalUInt32.write(value.confirmations, buf) + _UniffiConverterBool.write(value.is_outbound, buf) + _UniffiConverterBool.write(value.is_channel_ready, buf) + _UniffiConverterBool.write(value.is_usable, buf) + _UniffiConverterBool.write(value.is_announced, buf) + _UniffiConverterOptionalUInt16.write(value.cltv_expiry_delta, buf) + _UniffiConverterUInt64.write(value.counterparty_unspendable_punishment_reserve, buf) + _UniffiConverterOptionalUInt64.write(value.counterparty_outbound_htlc_minimum_msat, buf) + _UniffiConverterOptionalUInt64.write(value.counterparty_outbound_htlc_maximum_msat, buf) + _UniffiConverterOptionalUInt32.write(value.counterparty_forwarding_info_fee_base_msat, buf) + _UniffiConverterOptionalUInt32.write(value.counterparty_forwarding_info_fee_proportional_millionths, buf) + _UniffiConverterOptionalUInt16.write(value.counterparty_forwarding_info_cltv_expiry_delta, buf) + _UniffiConverterUInt64.write(value.next_outbound_htlc_limit_msat, buf) + _UniffiConverterUInt64.write(value.next_outbound_htlc_minimum_msat, buf) + _UniffiConverterOptionalUInt16.write(value.force_close_spend_delay, buf) + _UniffiConverterUInt64.write(value.inbound_htlc_minimum_msat, buf) + _UniffiConverterOptionalUInt64.write(value.inbound_htlc_maximum_msat, buf) + _UniffiConverterTypeChannelConfig.write(value.config, buf) + _UniffiConverterOptionalUInt64.write(value.claimable_on_close_sats, buf) + + +class ChannelInfo: + node_one: "NodeId" + one_to_two: "typing.Optional[ChannelUpdateInfo]" + node_two: "NodeId" + two_to_one: "typing.Optional[ChannelUpdateInfo]" + capacity_sats: "typing.Optional[int]" + def __init__(self, *, node_one: "NodeId", one_to_two: "typing.Optional[ChannelUpdateInfo]", node_two: "NodeId", two_to_one: "typing.Optional[ChannelUpdateInfo]", capacity_sats: "typing.Optional[int]"): + self.node_one = node_one + self.one_to_two = one_to_two + self.node_two = node_two + self.two_to_one = two_to_one + self.capacity_sats = capacity_sats + + def __str__(self): + return "ChannelInfo(node_one={}, one_to_two={}, node_two={}, two_to_one={}, capacity_sats={})".format(self.node_one, self.one_to_two, self.node_two, self.two_to_one, self.capacity_sats) + + def __eq__(self, other): + if self.node_one != other.node_one: + return False + if self.one_to_two != other.one_to_two: + return False + if self.node_two != other.node_two: + return False + if self.two_to_one != other.two_to_one: + return False + if self.capacity_sats != other.capacity_sats: + return False + return True + +class _UniffiConverterTypeChannelInfo(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return ChannelInfo( + node_one=_UniffiConverterTypeNodeId.read(buf), + one_to_two=_UniffiConverterOptionalTypeChannelUpdateInfo.read(buf), + node_two=_UniffiConverterTypeNodeId.read(buf), + two_to_one=_UniffiConverterOptionalTypeChannelUpdateInfo.read(buf), + capacity_sats=_UniffiConverterOptionalUInt64.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterTypeNodeId.check_lower(value.node_one) + _UniffiConverterOptionalTypeChannelUpdateInfo.check_lower(value.one_to_two) + _UniffiConverterTypeNodeId.check_lower(value.node_two) + _UniffiConverterOptionalTypeChannelUpdateInfo.check_lower(value.two_to_one) + _UniffiConverterOptionalUInt64.check_lower(value.capacity_sats) + + @staticmethod + def write(value, buf): + _UniffiConverterTypeNodeId.write(value.node_one, buf) + _UniffiConverterOptionalTypeChannelUpdateInfo.write(value.one_to_two, buf) + _UniffiConverterTypeNodeId.write(value.node_two, buf) + _UniffiConverterOptionalTypeChannelUpdateInfo.write(value.two_to_one, buf) + _UniffiConverterOptionalUInt64.write(value.capacity_sats, buf) + + +class ChannelUpdateInfo: + last_update: "int" + enabled: "bool" + cltv_expiry_delta: "int" + htlc_minimum_msat: "int" + htlc_maximum_msat: "int" + fees: "RoutingFees" + def __init__(self, *, last_update: "int", enabled: "bool", cltv_expiry_delta: "int", htlc_minimum_msat: "int", htlc_maximum_msat: "int", fees: "RoutingFees"): + self.last_update = last_update + self.enabled = enabled + self.cltv_expiry_delta = cltv_expiry_delta + self.htlc_minimum_msat = htlc_minimum_msat + self.htlc_maximum_msat = htlc_maximum_msat + self.fees = fees + + def __str__(self): + return "ChannelUpdateInfo(last_update={}, enabled={}, cltv_expiry_delta={}, htlc_minimum_msat={}, htlc_maximum_msat={}, fees={})".format(self.last_update, self.enabled, self.cltv_expiry_delta, self.htlc_minimum_msat, self.htlc_maximum_msat, self.fees) + + def __eq__(self, other): + if self.last_update != other.last_update: + return False + if self.enabled != other.enabled: + return False + if self.cltv_expiry_delta != other.cltv_expiry_delta: + return False + if self.htlc_minimum_msat != other.htlc_minimum_msat: + return False + if self.htlc_maximum_msat != other.htlc_maximum_msat: + return False + if self.fees != other.fees: + return False + return True + +class _UniffiConverterTypeChannelUpdateInfo(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return ChannelUpdateInfo( + last_update=_UniffiConverterUInt32.read(buf), + enabled=_UniffiConverterBool.read(buf), + cltv_expiry_delta=_UniffiConverterUInt16.read(buf), + htlc_minimum_msat=_UniffiConverterUInt64.read(buf), + htlc_maximum_msat=_UniffiConverterUInt64.read(buf), + fees=_UniffiConverterTypeRoutingFees.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterUInt32.check_lower(value.last_update) + _UniffiConverterBool.check_lower(value.enabled) + _UniffiConverterUInt16.check_lower(value.cltv_expiry_delta) + _UniffiConverterUInt64.check_lower(value.htlc_minimum_msat) + _UniffiConverterUInt64.check_lower(value.htlc_maximum_msat) + _UniffiConverterTypeRoutingFees.check_lower(value.fees) + + @staticmethod + def write(value, buf): + _UniffiConverterUInt32.write(value.last_update, buf) + _UniffiConverterBool.write(value.enabled, buf) + _UniffiConverterUInt16.write(value.cltv_expiry_delta, buf) + _UniffiConverterUInt64.write(value.htlc_minimum_msat, buf) + _UniffiConverterUInt64.write(value.htlc_maximum_msat, buf) + _UniffiConverterTypeRoutingFees.write(value.fees, buf) + + +class Config: + storage_dir_path: "str" + network: "Network" + listening_addresses: "typing.Optional[typing.List[SocketAddress]]" + announcement_addresses: "typing.Optional[typing.List[SocketAddress]]" + node_alias: "typing.Optional[NodeAlias]" + trusted_peers_0conf: "typing.List[PublicKey]" + probing_liquidity_limit_multiplier: "int" + anchor_channels_config: "typing.Optional[AnchorChannelsConfig]" + route_parameters: "typing.Optional[RouteParametersConfig]" + scoring_fee_params: "typing.Optional[ScoringFeeParameters]" + scoring_decay_params: "typing.Optional[ScoringDecayParameters]" + include_untrusted_pending_in_spendable: "bool" + address_type: "AddressType" + address_types_to_monitor: "typing.List[AddressType]" + onchain_wallet_accounts: "typing.List[OnchainWalletAccountConfig]" + def __init__(self, *, storage_dir_path: "str", network: "Network", listening_addresses: "typing.Optional[typing.List[SocketAddress]]", announcement_addresses: "typing.Optional[typing.List[SocketAddress]]", node_alias: "typing.Optional[NodeAlias]", trusted_peers_0conf: "typing.List[PublicKey]", probing_liquidity_limit_multiplier: "int", anchor_channels_config: "typing.Optional[AnchorChannelsConfig]", route_parameters: "typing.Optional[RouteParametersConfig]", scoring_fee_params: "typing.Optional[ScoringFeeParameters]", scoring_decay_params: "typing.Optional[ScoringDecayParameters]", include_untrusted_pending_in_spendable: "bool", address_type: "AddressType", address_types_to_monitor: "typing.List[AddressType]", onchain_wallet_accounts: "typing.List[OnchainWalletAccountConfig]"): + self.storage_dir_path = storage_dir_path + self.network = network + self.listening_addresses = listening_addresses + self.announcement_addresses = announcement_addresses + self.node_alias = node_alias + self.trusted_peers_0conf = trusted_peers_0conf + self.probing_liquidity_limit_multiplier = probing_liquidity_limit_multiplier + self.anchor_channels_config = anchor_channels_config + self.route_parameters = route_parameters + self.scoring_fee_params = scoring_fee_params + self.scoring_decay_params = scoring_decay_params + self.include_untrusted_pending_in_spendable = include_untrusted_pending_in_spendable + self.address_type = address_type + self.address_types_to_monitor = address_types_to_monitor + self.onchain_wallet_accounts = onchain_wallet_accounts + + def __str__(self): + return "Config(storage_dir_path={}, network={}, listening_addresses={}, announcement_addresses={}, node_alias={}, trusted_peers_0conf={}, probing_liquidity_limit_multiplier={}, anchor_channels_config={}, route_parameters={}, scoring_fee_params={}, scoring_decay_params={}, include_untrusted_pending_in_spendable={}, address_type={}, address_types_to_monitor={}, onchain_wallet_accounts={})".format(self.storage_dir_path, self.network, self.listening_addresses, self.announcement_addresses, self.node_alias, self.trusted_peers_0conf, self.probing_liquidity_limit_multiplier, self.anchor_channels_config, self.route_parameters, self.scoring_fee_params, self.scoring_decay_params, self.include_untrusted_pending_in_spendable, self.address_type, self.address_types_to_monitor, self.onchain_wallet_accounts) + + def __eq__(self, other): + if self.storage_dir_path != other.storage_dir_path: + return False + if self.network != other.network: + return False + if self.listening_addresses != other.listening_addresses: + return False + if self.announcement_addresses != other.announcement_addresses: + return False + if self.node_alias != other.node_alias: + return False + if self.trusted_peers_0conf != other.trusted_peers_0conf: + return False + if self.probing_liquidity_limit_multiplier != other.probing_liquidity_limit_multiplier: + return False + if self.anchor_channels_config != other.anchor_channels_config: + return False + if self.route_parameters != other.route_parameters: + return False + if self.scoring_fee_params != other.scoring_fee_params: + return False + if self.scoring_decay_params != other.scoring_decay_params: + return False + if self.include_untrusted_pending_in_spendable != other.include_untrusted_pending_in_spendable: + return False + if self.address_type != other.address_type: + return False + if self.address_types_to_monitor != other.address_types_to_monitor: + return False + if self.onchain_wallet_accounts != other.onchain_wallet_accounts: + return False + return True + +class _UniffiConverterTypeConfig(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return Config( + storage_dir_path=_UniffiConverterString.read(buf), + network=_UniffiConverterTypeNetwork.read(buf), + listening_addresses=_UniffiConverterOptionalSequenceTypeSocketAddress.read(buf), + announcement_addresses=_UniffiConverterOptionalSequenceTypeSocketAddress.read(buf), + node_alias=_UniffiConverterOptionalTypeNodeAlias.read(buf), + trusted_peers_0conf=_UniffiConverterSequenceTypePublicKey.read(buf), + probing_liquidity_limit_multiplier=_UniffiConverterUInt64.read(buf), + anchor_channels_config=_UniffiConverterOptionalTypeAnchorChannelsConfig.read(buf), + route_parameters=_UniffiConverterOptionalTypeRouteParametersConfig.read(buf), + scoring_fee_params=_UniffiConverterOptionalTypeScoringFeeParameters.read(buf), + scoring_decay_params=_UniffiConverterOptionalTypeScoringDecayParameters.read(buf), + include_untrusted_pending_in_spendable=_UniffiConverterBool.read(buf), + address_type=_UniffiConverterTypeAddressType.read(buf), + address_types_to_monitor=_UniffiConverterSequenceTypeAddressType.read(buf), + onchain_wallet_accounts=_UniffiConverterSequenceTypeOnchainWalletAccountConfig.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterString.check_lower(value.storage_dir_path) + _UniffiConverterTypeNetwork.check_lower(value.network) + _UniffiConverterOptionalSequenceTypeSocketAddress.check_lower(value.listening_addresses) + _UniffiConverterOptionalSequenceTypeSocketAddress.check_lower(value.announcement_addresses) + _UniffiConverterOptionalTypeNodeAlias.check_lower(value.node_alias) + _UniffiConverterSequenceTypePublicKey.check_lower(value.trusted_peers_0conf) + _UniffiConverterUInt64.check_lower(value.probing_liquidity_limit_multiplier) + _UniffiConverterOptionalTypeAnchorChannelsConfig.check_lower(value.anchor_channels_config) + _UniffiConverterOptionalTypeRouteParametersConfig.check_lower(value.route_parameters) + _UniffiConverterOptionalTypeScoringFeeParameters.check_lower(value.scoring_fee_params) + _UniffiConverterOptionalTypeScoringDecayParameters.check_lower(value.scoring_decay_params) + _UniffiConverterBool.check_lower(value.include_untrusted_pending_in_spendable) + _UniffiConverterTypeAddressType.check_lower(value.address_type) + _UniffiConverterSequenceTypeAddressType.check_lower(value.address_types_to_monitor) + _UniffiConverterSequenceTypeOnchainWalletAccountConfig.check_lower(value.onchain_wallet_accounts) + + @staticmethod + def write(value, buf): + _UniffiConverterString.write(value.storage_dir_path, buf) + _UniffiConverterTypeNetwork.write(value.network, buf) + _UniffiConverterOptionalSequenceTypeSocketAddress.write(value.listening_addresses, buf) + _UniffiConverterOptionalSequenceTypeSocketAddress.write(value.announcement_addresses, buf) + _UniffiConverterOptionalTypeNodeAlias.write(value.node_alias, buf) + _UniffiConverterSequenceTypePublicKey.write(value.trusted_peers_0conf, buf) + _UniffiConverterUInt64.write(value.probing_liquidity_limit_multiplier, buf) + _UniffiConverterOptionalTypeAnchorChannelsConfig.write(value.anchor_channels_config, buf) + _UniffiConverterOptionalTypeRouteParametersConfig.write(value.route_parameters, buf) + _UniffiConverterOptionalTypeScoringFeeParameters.write(value.scoring_fee_params, buf) + _UniffiConverterOptionalTypeScoringDecayParameters.write(value.scoring_decay_params, buf) + _UniffiConverterBool.write(value.include_untrusted_pending_in_spendable, buf) + _UniffiConverterTypeAddressType.write(value.address_type, buf) + _UniffiConverterSequenceTypeAddressType.write(value.address_types_to_monitor, buf) + _UniffiConverterSequenceTypeOnchainWalletAccountConfig.write(value.onchain_wallet_accounts, buf) + + +class CustomTlvRecord: + type_num: "int" + value: "typing.List[int]" + def __init__(self, *, type_num: "int", value: "typing.List[int]"): + self.type_num = type_num + self.value = value + + def __str__(self): + return "CustomTlvRecord(type_num={}, value={})".format(self.type_num, self.value) + + def __eq__(self, other): + if self.type_num != other.type_num: + return False + if self.value != other.value: + return False + return True + +class _UniffiConverterTypeCustomTlvRecord(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return CustomTlvRecord( + type_num=_UniffiConverterUInt64.read(buf), + value=_UniffiConverterSequenceUInt8.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterUInt64.check_lower(value.type_num) + _UniffiConverterSequenceUInt8.check_lower(value.value) + + @staticmethod + def write(value, buf): + _UniffiConverterUInt64.write(value.type_num, buf) + _UniffiConverterSequenceUInt8.write(value.value, buf) + + +class ElectrumSyncConfig: + background_sync_config: "typing.Optional[BackgroundSyncConfig]" + connection_timeout_secs: "int" + additional_wallet_full_scan_batch_size: "int" + additional_wallet_full_scan_stop_gap: "int" + def __init__(self, *, background_sync_config: "typing.Optional[BackgroundSyncConfig]", connection_timeout_secs: "int", additional_wallet_full_scan_batch_size: "int", additional_wallet_full_scan_stop_gap: "int"): + self.background_sync_config = background_sync_config + self.connection_timeout_secs = connection_timeout_secs + self.additional_wallet_full_scan_batch_size = additional_wallet_full_scan_batch_size + self.additional_wallet_full_scan_stop_gap = additional_wallet_full_scan_stop_gap + + def __str__(self): + return "ElectrumSyncConfig(background_sync_config={}, connection_timeout_secs={}, additional_wallet_full_scan_batch_size={}, additional_wallet_full_scan_stop_gap={})".format(self.background_sync_config, self.connection_timeout_secs, self.additional_wallet_full_scan_batch_size, self.additional_wallet_full_scan_stop_gap) + + def __eq__(self, other): + if self.background_sync_config != other.background_sync_config: + return False + if self.connection_timeout_secs != other.connection_timeout_secs: + return False + if self.additional_wallet_full_scan_batch_size != other.additional_wallet_full_scan_batch_size: + return False + if self.additional_wallet_full_scan_stop_gap != other.additional_wallet_full_scan_stop_gap: + return False + return True + +class _UniffiConverterTypeElectrumSyncConfig(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return ElectrumSyncConfig( + background_sync_config=_UniffiConverterOptionalTypeBackgroundSyncConfig.read(buf), + connection_timeout_secs=_UniffiConverterUInt64.read(buf), + additional_wallet_full_scan_batch_size=_UniffiConverterUInt32.read(buf), + additional_wallet_full_scan_stop_gap=_UniffiConverterUInt32.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterOptionalTypeBackgroundSyncConfig.check_lower(value.background_sync_config) + _UniffiConverterUInt64.check_lower(value.connection_timeout_secs) + _UniffiConverterUInt32.check_lower(value.additional_wallet_full_scan_batch_size) + _UniffiConverterUInt32.check_lower(value.additional_wallet_full_scan_stop_gap) + + @staticmethod + def write(value, buf): + _UniffiConverterOptionalTypeBackgroundSyncConfig.write(value.background_sync_config, buf) + _UniffiConverterUInt64.write(value.connection_timeout_secs, buf) + _UniffiConverterUInt32.write(value.additional_wallet_full_scan_batch_size, buf) + _UniffiConverterUInt32.write(value.additional_wallet_full_scan_stop_gap, buf) + + +class EsploraSyncConfig: + background_sync_config: "typing.Optional[BackgroundSyncConfig]" + def __init__(self, *, background_sync_config: "typing.Optional[BackgroundSyncConfig]"): + self.background_sync_config = background_sync_config + + def __str__(self): + return "EsploraSyncConfig(background_sync_config={})".format(self.background_sync_config) + + def __eq__(self, other): + if self.background_sync_config != other.background_sync_config: + return False + return True + +class _UniffiConverterTypeEsploraSyncConfig(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return EsploraSyncConfig( + background_sync_config=_UniffiConverterOptionalTypeBackgroundSyncConfig.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterOptionalTypeBackgroundSyncConfig.check_lower(value.background_sync_config) + + @staticmethod + def write(value, buf): + _UniffiConverterOptionalTypeBackgroundSyncConfig.write(value.background_sync_config, buf) + + +class LogRecord: + level: "LogLevel" + args: "str" + module_path: "str" + line: "int" + def __init__(self, *, level: "LogLevel", args: "str", module_path: "str", line: "int"): + self.level = level + self.args = args + self.module_path = module_path + self.line = line + + def __str__(self): + return "LogRecord(level={}, args={}, module_path={}, line={})".format(self.level, self.args, self.module_path, self.line) + + def __eq__(self, other): + if self.level != other.level: + return False + if self.args != other.args: + return False + if self.module_path != other.module_path: + return False + if self.line != other.line: + return False + return True + +class _UniffiConverterTypeLogRecord(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return LogRecord( + level=_UniffiConverterTypeLogLevel.read(buf), + args=_UniffiConverterString.read(buf), + module_path=_UniffiConverterString.read(buf), + line=_UniffiConverterUInt32.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterTypeLogLevel.check_lower(value.level) + _UniffiConverterString.check_lower(value.args) + _UniffiConverterString.check_lower(value.module_path) + _UniffiConverterUInt32.check_lower(value.line) + + @staticmethod + def write(value, buf): + _UniffiConverterTypeLogLevel.write(value.level, buf) + _UniffiConverterString.write(value.args, buf) + _UniffiConverterString.write(value.module_path, buf) + _UniffiConverterUInt32.write(value.line, buf) + + +class LspFeeLimits: + max_total_opening_fee_msat: "typing.Optional[int]" + max_proportional_opening_fee_ppm_msat: "typing.Optional[int]" + def __init__(self, *, max_total_opening_fee_msat: "typing.Optional[int]", max_proportional_opening_fee_ppm_msat: "typing.Optional[int]"): + self.max_total_opening_fee_msat = max_total_opening_fee_msat + self.max_proportional_opening_fee_ppm_msat = max_proportional_opening_fee_ppm_msat + + def __str__(self): + return "LspFeeLimits(max_total_opening_fee_msat={}, max_proportional_opening_fee_ppm_msat={})".format(self.max_total_opening_fee_msat, self.max_proportional_opening_fee_ppm_msat) + + def __eq__(self, other): + if self.max_total_opening_fee_msat != other.max_total_opening_fee_msat: + return False + if self.max_proportional_opening_fee_ppm_msat != other.max_proportional_opening_fee_ppm_msat: + return False + return True + +class _UniffiConverterTypeLspFeeLimits(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return LspFeeLimits( + max_total_opening_fee_msat=_UniffiConverterOptionalUInt64.read(buf), + max_proportional_opening_fee_ppm_msat=_UniffiConverterOptionalUInt64.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterOptionalUInt64.check_lower(value.max_total_opening_fee_msat) + _UniffiConverterOptionalUInt64.check_lower(value.max_proportional_opening_fee_ppm_msat) + + @staticmethod + def write(value, buf): + _UniffiConverterOptionalUInt64.write(value.max_total_opening_fee_msat, buf) + _UniffiConverterOptionalUInt64.write(value.max_proportional_opening_fee_ppm_msat, buf) + + +class Lsps1Bolt11PaymentInfo: + state: "Lsps1PaymentState" + expires_at: "LspsDateTime" + fee_total_sat: "int" + order_total_sat: "int" + invoice: "Bolt11Invoice" + def __init__(self, *, state: "Lsps1PaymentState", expires_at: "LspsDateTime", fee_total_sat: "int", order_total_sat: "int", invoice: "Bolt11Invoice"): + self.state = state + self.expires_at = expires_at + self.fee_total_sat = fee_total_sat + self.order_total_sat = order_total_sat + self.invoice = invoice + + def __str__(self): + return "Lsps1Bolt11PaymentInfo(state={}, expires_at={}, fee_total_sat={}, order_total_sat={}, invoice={})".format(self.state, self.expires_at, self.fee_total_sat, self.order_total_sat, self.invoice) + + def __eq__(self, other): + if self.state != other.state: + return False + if self.expires_at != other.expires_at: + return False + if self.fee_total_sat != other.fee_total_sat: + return False + if self.order_total_sat != other.order_total_sat: + return False + if self.invoice != other.invoice: + return False + return True + +class _UniffiConverterTypeLsps1Bolt11PaymentInfo(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return Lsps1Bolt11PaymentInfo( + state=_UniffiConverterTypeLsps1PaymentState.read(buf), + expires_at=_UniffiConverterTypeLspsDateTime.read(buf), + fee_total_sat=_UniffiConverterUInt64.read(buf), + order_total_sat=_UniffiConverterUInt64.read(buf), + invoice=_UniffiConverterTypeBolt11Invoice.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterTypeLsps1PaymentState.check_lower(value.state) + _UniffiConverterTypeLspsDateTime.check_lower(value.expires_at) + _UniffiConverterUInt64.check_lower(value.fee_total_sat) + _UniffiConverterUInt64.check_lower(value.order_total_sat) + _UniffiConverterTypeBolt11Invoice.check_lower(value.invoice) + + @staticmethod + def write(value, buf): + _UniffiConverterTypeLsps1PaymentState.write(value.state, buf) + _UniffiConverterTypeLspsDateTime.write(value.expires_at, buf) + _UniffiConverterUInt64.write(value.fee_total_sat, buf) + _UniffiConverterUInt64.write(value.order_total_sat, buf) + _UniffiConverterTypeBolt11Invoice.write(value.invoice, buf) + + +class Lsps1ChannelInfo: + funded_at: "LspsDateTime" + funding_outpoint: "OutPoint" + expires_at: "LspsDateTime" + def __init__(self, *, funded_at: "LspsDateTime", funding_outpoint: "OutPoint", expires_at: "LspsDateTime"): + self.funded_at = funded_at + self.funding_outpoint = funding_outpoint + self.expires_at = expires_at + + def __str__(self): + return "Lsps1ChannelInfo(funded_at={}, funding_outpoint={}, expires_at={})".format(self.funded_at, self.funding_outpoint, self.expires_at) + + def __eq__(self, other): + if self.funded_at != other.funded_at: + return False + if self.funding_outpoint != other.funding_outpoint: + return False + if self.expires_at != other.expires_at: + return False + return True + +class _UniffiConverterTypeLsps1ChannelInfo(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return Lsps1ChannelInfo( + funded_at=_UniffiConverterTypeLspsDateTime.read(buf), + funding_outpoint=_UniffiConverterTypeOutPoint.read(buf), + expires_at=_UniffiConverterTypeLspsDateTime.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterTypeLspsDateTime.check_lower(value.funded_at) + _UniffiConverterTypeOutPoint.check_lower(value.funding_outpoint) + _UniffiConverterTypeLspsDateTime.check_lower(value.expires_at) + + @staticmethod + def write(value, buf): + _UniffiConverterTypeLspsDateTime.write(value.funded_at, buf) + _UniffiConverterTypeOutPoint.write(value.funding_outpoint, buf) + _UniffiConverterTypeLspsDateTime.write(value.expires_at, buf) + + +class Lsps1OnchainPaymentInfo: + state: "Lsps1PaymentState" + expires_at: "LspsDateTime" + fee_total_sat: "int" + order_total_sat: "int" + address: "Address" + min_onchain_payment_confirmations: "typing.Optional[int]" + min_fee_for_0conf: "FeeRate" + refund_onchain_address: "typing.Optional[Address]" + def __init__(self, *, state: "Lsps1PaymentState", expires_at: "LspsDateTime", fee_total_sat: "int", order_total_sat: "int", address: "Address", min_onchain_payment_confirmations: "typing.Optional[int]", min_fee_for_0conf: "FeeRate", refund_onchain_address: "typing.Optional[Address]"): + self.state = state + self.expires_at = expires_at + self.fee_total_sat = fee_total_sat + self.order_total_sat = order_total_sat + self.address = address + self.min_onchain_payment_confirmations = min_onchain_payment_confirmations + self.min_fee_for_0conf = min_fee_for_0conf + self.refund_onchain_address = refund_onchain_address + + def __str__(self): + return "Lsps1OnchainPaymentInfo(state={}, expires_at={}, fee_total_sat={}, order_total_sat={}, address={}, min_onchain_payment_confirmations={}, min_fee_for_0conf={}, refund_onchain_address={})".format(self.state, self.expires_at, self.fee_total_sat, self.order_total_sat, self.address, self.min_onchain_payment_confirmations, self.min_fee_for_0conf, self.refund_onchain_address) + + def __eq__(self, other): + if self.state != other.state: + return False + if self.expires_at != other.expires_at: + return False + if self.fee_total_sat != other.fee_total_sat: + return False + if self.order_total_sat != other.order_total_sat: + return False + if self.address != other.address: + return False + if self.min_onchain_payment_confirmations != other.min_onchain_payment_confirmations: + return False + if self.min_fee_for_0conf != other.min_fee_for_0conf: + return False + if self.refund_onchain_address != other.refund_onchain_address: + return False + return True + +class _UniffiConverterTypeLsps1OnchainPaymentInfo(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return Lsps1OnchainPaymentInfo( + state=_UniffiConverterTypeLsps1PaymentState.read(buf), + expires_at=_UniffiConverterTypeLspsDateTime.read(buf), + fee_total_sat=_UniffiConverterUInt64.read(buf), + order_total_sat=_UniffiConverterUInt64.read(buf), + address=_UniffiConverterTypeAddress.read(buf), + min_onchain_payment_confirmations=_UniffiConverterOptionalUInt16.read(buf), + min_fee_for_0conf=_UniffiConverterTypeFeeRate.read(buf), + refund_onchain_address=_UniffiConverterOptionalTypeAddress.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterTypeLsps1PaymentState.check_lower(value.state) + _UniffiConverterTypeLspsDateTime.check_lower(value.expires_at) + _UniffiConverterUInt64.check_lower(value.fee_total_sat) + _UniffiConverterUInt64.check_lower(value.order_total_sat) + _UniffiConverterTypeAddress.check_lower(value.address) + _UniffiConverterOptionalUInt16.check_lower(value.min_onchain_payment_confirmations) + _UniffiConverterTypeFeeRate.check_lower(value.min_fee_for_0conf) + _UniffiConverterOptionalTypeAddress.check_lower(value.refund_onchain_address) + + @staticmethod + def write(value, buf): + _UniffiConverterTypeLsps1PaymentState.write(value.state, buf) + _UniffiConverterTypeLspsDateTime.write(value.expires_at, buf) + _UniffiConverterUInt64.write(value.fee_total_sat, buf) + _UniffiConverterUInt64.write(value.order_total_sat, buf) + _UniffiConverterTypeAddress.write(value.address, buf) + _UniffiConverterOptionalUInt16.write(value.min_onchain_payment_confirmations, buf) + _UniffiConverterTypeFeeRate.write(value.min_fee_for_0conf, buf) + _UniffiConverterOptionalTypeAddress.write(value.refund_onchain_address, buf) + + +class Lsps1OrderParams: + lsp_balance_sat: "int" + client_balance_sat: "int" + required_channel_confirmations: "int" + funding_confirms_within_blocks: "int" + channel_expiry_blocks: "int" + token: "typing.Optional[str]" + announce_channel: "bool" + def __init__(self, *, lsp_balance_sat: "int", client_balance_sat: "int", required_channel_confirmations: "int", funding_confirms_within_blocks: "int", channel_expiry_blocks: "int", token: "typing.Optional[str]", announce_channel: "bool"): + self.lsp_balance_sat = lsp_balance_sat + self.client_balance_sat = client_balance_sat + self.required_channel_confirmations = required_channel_confirmations + self.funding_confirms_within_blocks = funding_confirms_within_blocks + self.channel_expiry_blocks = channel_expiry_blocks + self.token = token + self.announce_channel = announce_channel + + def __str__(self): + return "Lsps1OrderParams(lsp_balance_sat={}, client_balance_sat={}, required_channel_confirmations={}, funding_confirms_within_blocks={}, channel_expiry_blocks={}, token={}, announce_channel={})".format(self.lsp_balance_sat, self.client_balance_sat, self.required_channel_confirmations, self.funding_confirms_within_blocks, self.channel_expiry_blocks, self.token, self.announce_channel) + + def __eq__(self, other): + if self.lsp_balance_sat != other.lsp_balance_sat: + return False + if self.client_balance_sat != other.client_balance_sat: + return False + if self.required_channel_confirmations != other.required_channel_confirmations: + return False + if self.funding_confirms_within_blocks != other.funding_confirms_within_blocks: + return False + if self.channel_expiry_blocks != other.channel_expiry_blocks: + return False + if self.token != other.token: + return False + if self.announce_channel != other.announce_channel: + return False + return True + +class _UniffiConverterTypeLsps1OrderParams(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return Lsps1OrderParams( + lsp_balance_sat=_UniffiConverterUInt64.read(buf), + client_balance_sat=_UniffiConverterUInt64.read(buf), + required_channel_confirmations=_UniffiConverterUInt16.read(buf), + funding_confirms_within_blocks=_UniffiConverterUInt16.read(buf), + channel_expiry_blocks=_UniffiConverterUInt32.read(buf), + token=_UniffiConverterOptionalString.read(buf), + announce_channel=_UniffiConverterBool.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterUInt64.check_lower(value.lsp_balance_sat) + _UniffiConverterUInt64.check_lower(value.client_balance_sat) + _UniffiConverterUInt16.check_lower(value.required_channel_confirmations) + _UniffiConverterUInt16.check_lower(value.funding_confirms_within_blocks) + _UniffiConverterUInt32.check_lower(value.channel_expiry_blocks) + _UniffiConverterOptionalString.check_lower(value.token) + _UniffiConverterBool.check_lower(value.announce_channel) + + @staticmethod + def write(value, buf): + _UniffiConverterUInt64.write(value.lsp_balance_sat, buf) + _UniffiConverterUInt64.write(value.client_balance_sat, buf) + _UniffiConverterUInt16.write(value.required_channel_confirmations, buf) + _UniffiConverterUInt16.write(value.funding_confirms_within_blocks, buf) + _UniffiConverterUInt32.write(value.channel_expiry_blocks, buf) + _UniffiConverterOptionalString.write(value.token, buf) + _UniffiConverterBool.write(value.announce_channel, buf) + + +class Lsps1OrderStatus: + order_id: "Lsps1OrderId" + order_params: "Lsps1OrderParams" + payment_options: "Lsps1PaymentInfo" + channel_state: "typing.Optional[Lsps1ChannelInfo]" + def __init__(self, *, order_id: "Lsps1OrderId", order_params: "Lsps1OrderParams", payment_options: "Lsps1PaymentInfo", channel_state: "typing.Optional[Lsps1ChannelInfo]"): + self.order_id = order_id + self.order_params = order_params + self.payment_options = payment_options + self.channel_state = channel_state + + def __str__(self): + return "Lsps1OrderStatus(order_id={}, order_params={}, payment_options={}, channel_state={})".format(self.order_id, self.order_params, self.payment_options, self.channel_state) + + def __eq__(self, other): + if self.order_id != other.order_id: + return False + if self.order_params != other.order_params: + return False + if self.payment_options != other.payment_options: + return False + if self.channel_state != other.channel_state: + return False + return True + +class _UniffiConverterTypeLsps1OrderStatus(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return Lsps1OrderStatus( + order_id=_UniffiConverterTypeLsps1OrderId.read(buf), + order_params=_UniffiConverterTypeLsps1OrderParams.read(buf), + payment_options=_UniffiConverterTypeLsps1PaymentInfo.read(buf), + channel_state=_UniffiConverterOptionalTypeLsps1ChannelInfo.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterTypeLsps1OrderId.check_lower(value.order_id) + _UniffiConverterTypeLsps1OrderParams.check_lower(value.order_params) + _UniffiConverterTypeLsps1PaymentInfo.check_lower(value.payment_options) + _UniffiConverterOptionalTypeLsps1ChannelInfo.check_lower(value.channel_state) + + @staticmethod + def write(value, buf): + _UniffiConverterTypeLsps1OrderId.write(value.order_id, buf) + _UniffiConverterTypeLsps1OrderParams.write(value.order_params, buf) + _UniffiConverterTypeLsps1PaymentInfo.write(value.payment_options, buf) + _UniffiConverterOptionalTypeLsps1ChannelInfo.write(value.channel_state, buf) + + +class Lsps1PaymentInfo: + bolt11: "typing.Optional[Lsps1Bolt11PaymentInfo]" + onchain: "typing.Optional[Lsps1OnchainPaymentInfo]" + def __init__(self, *, bolt11: "typing.Optional[Lsps1Bolt11PaymentInfo]", onchain: "typing.Optional[Lsps1OnchainPaymentInfo]"): + self.bolt11 = bolt11 + self.onchain = onchain + + def __str__(self): + return "Lsps1PaymentInfo(bolt11={}, onchain={})".format(self.bolt11, self.onchain) + + def __eq__(self, other): + if self.bolt11 != other.bolt11: + return False + if self.onchain != other.onchain: + return False + return True + +class _UniffiConverterTypeLsps1PaymentInfo(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return Lsps1PaymentInfo( + bolt11=_UniffiConverterOptionalTypeLsps1Bolt11PaymentInfo.read(buf), + onchain=_UniffiConverterOptionalTypeLsps1OnchainPaymentInfo.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterOptionalTypeLsps1Bolt11PaymentInfo.check_lower(value.bolt11) + _UniffiConverterOptionalTypeLsps1OnchainPaymentInfo.check_lower(value.onchain) + + @staticmethod + def write(value, buf): + _UniffiConverterOptionalTypeLsps1Bolt11PaymentInfo.write(value.bolt11, buf) + _UniffiConverterOptionalTypeLsps1OnchainPaymentInfo.write(value.onchain, buf) + + +class Lsps2ServiceConfig: + require_token: "typing.Optional[str]" + advertise_service: "bool" + channel_opening_fee_ppm: "int" + channel_over_provisioning_ppm: "int" + min_channel_opening_fee_msat: "int" + min_channel_lifetime: "int" + max_client_to_self_delay: "int" + min_payment_size_msat: "int" + max_payment_size_msat: "int" + client_trusts_lsp: "bool" + def __init__(self, *, require_token: "typing.Optional[str]", advertise_service: "bool", channel_opening_fee_ppm: "int", channel_over_provisioning_ppm: "int", min_channel_opening_fee_msat: "int", min_channel_lifetime: "int", max_client_to_self_delay: "int", min_payment_size_msat: "int", max_payment_size_msat: "int", client_trusts_lsp: "bool"): + self.require_token = require_token + self.advertise_service = advertise_service + self.channel_opening_fee_ppm = channel_opening_fee_ppm + self.channel_over_provisioning_ppm = channel_over_provisioning_ppm + self.min_channel_opening_fee_msat = min_channel_opening_fee_msat + self.min_channel_lifetime = min_channel_lifetime + self.max_client_to_self_delay = max_client_to_self_delay + self.min_payment_size_msat = min_payment_size_msat + self.max_payment_size_msat = max_payment_size_msat + self.client_trusts_lsp = client_trusts_lsp + + def __str__(self): + return "Lsps2ServiceConfig(require_token={}, advertise_service={}, channel_opening_fee_ppm={}, channel_over_provisioning_ppm={}, min_channel_opening_fee_msat={}, min_channel_lifetime={}, max_client_to_self_delay={}, min_payment_size_msat={}, max_payment_size_msat={}, client_trusts_lsp={})".format(self.require_token, self.advertise_service, self.channel_opening_fee_ppm, self.channel_over_provisioning_ppm, self.min_channel_opening_fee_msat, self.min_channel_lifetime, self.max_client_to_self_delay, self.min_payment_size_msat, self.max_payment_size_msat, self.client_trusts_lsp) + + def __eq__(self, other): + if self.require_token != other.require_token: + return False + if self.advertise_service != other.advertise_service: + return False + if self.channel_opening_fee_ppm != other.channel_opening_fee_ppm: + return False + if self.channel_over_provisioning_ppm != other.channel_over_provisioning_ppm: + return False + if self.min_channel_opening_fee_msat != other.min_channel_opening_fee_msat: + return False + if self.min_channel_lifetime != other.min_channel_lifetime: + return False + if self.max_client_to_self_delay != other.max_client_to_self_delay: + return False + if self.min_payment_size_msat != other.min_payment_size_msat: + return False + if self.max_payment_size_msat != other.max_payment_size_msat: + return False + if self.client_trusts_lsp != other.client_trusts_lsp: + return False + return True + +class _UniffiConverterTypeLsps2ServiceConfig(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return Lsps2ServiceConfig( + require_token=_UniffiConverterOptionalString.read(buf), + advertise_service=_UniffiConverterBool.read(buf), + channel_opening_fee_ppm=_UniffiConverterUInt32.read(buf), + channel_over_provisioning_ppm=_UniffiConverterUInt32.read(buf), + min_channel_opening_fee_msat=_UniffiConverterUInt64.read(buf), + min_channel_lifetime=_UniffiConverterUInt32.read(buf), + max_client_to_self_delay=_UniffiConverterUInt32.read(buf), + min_payment_size_msat=_UniffiConverterUInt64.read(buf), + max_payment_size_msat=_UniffiConverterUInt64.read(buf), + client_trusts_lsp=_UniffiConverterBool.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterOptionalString.check_lower(value.require_token) + _UniffiConverterBool.check_lower(value.advertise_service) + _UniffiConverterUInt32.check_lower(value.channel_opening_fee_ppm) + _UniffiConverterUInt32.check_lower(value.channel_over_provisioning_ppm) + _UniffiConverterUInt64.check_lower(value.min_channel_opening_fee_msat) + _UniffiConverterUInt32.check_lower(value.min_channel_lifetime) + _UniffiConverterUInt32.check_lower(value.max_client_to_self_delay) + _UniffiConverterUInt64.check_lower(value.min_payment_size_msat) + _UniffiConverterUInt64.check_lower(value.max_payment_size_msat) + _UniffiConverterBool.check_lower(value.client_trusts_lsp) + + @staticmethod + def write(value, buf): + _UniffiConverterOptionalString.write(value.require_token, buf) + _UniffiConverterBool.write(value.advertise_service, buf) + _UniffiConverterUInt32.write(value.channel_opening_fee_ppm, buf) + _UniffiConverterUInt32.write(value.channel_over_provisioning_ppm, buf) + _UniffiConverterUInt64.write(value.min_channel_opening_fee_msat, buf) + _UniffiConverterUInt32.write(value.min_channel_lifetime, buf) + _UniffiConverterUInt32.write(value.max_client_to_self_delay, buf) + _UniffiConverterUInt64.write(value.min_payment_size_msat, buf) + _UniffiConverterUInt64.write(value.max_payment_size_msat, buf) + _UniffiConverterBool.write(value.client_trusts_lsp, buf) + + +class NodeAnnouncementInfo: + last_update: "int" + alias: "str" + addresses: "typing.List[SocketAddress]" + def __init__(self, *, last_update: "int", alias: "str", addresses: "typing.List[SocketAddress]"): + self.last_update = last_update + self.alias = alias + self.addresses = addresses + + def __str__(self): + return "NodeAnnouncementInfo(last_update={}, alias={}, addresses={})".format(self.last_update, self.alias, self.addresses) + + def __eq__(self, other): + if self.last_update != other.last_update: + return False + if self.alias != other.alias: + return False + if self.addresses != other.addresses: + return False + return True + +class _UniffiConverterTypeNodeAnnouncementInfo(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return NodeAnnouncementInfo( + last_update=_UniffiConverterUInt32.read(buf), + alias=_UniffiConverterString.read(buf), + addresses=_UniffiConverterSequenceTypeSocketAddress.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterUInt32.check_lower(value.last_update) + _UniffiConverterString.check_lower(value.alias) + _UniffiConverterSequenceTypeSocketAddress.check_lower(value.addresses) + + @staticmethod + def write(value, buf): + _UniffiConverterUInt32.write(value.last_update, buf) + _UniffiConverterString.write(value.alias, buf) + _UniffiConverterSequenceTypeSocketAddress.write(value.addresses, buf) + + +class NodeInfo: + channels: "typing.List[int]" + announcement_info: "typing.Optional[NodeAnnouncementInfo]" + def __init__(self, *, channels: "typing.List[int]", announcement_info: "typing.Optional[NodeAnnouncementInfo]"): + self.channels = channels + self.announcement_info = announcement_info + + def __str__(self): + return "NodeInfo(channels={}, announcement_info={})".format(self.channels, self.announcement_info) + + def __eq__(self, other): + if self.channels != other.channels: + return False + if self.announcement_info != other.announcement_info: + return False + return True + +class _UniffiConverterTypeNodeInfo(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return NodeInfo( + channels=_UniffiConverterSequenceUInt64.read(buf), + announcement_info=_UniffiConverterOptionalTypeNodeAnnouncementInfo.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterSequenceUInt64.check_lower(value.channels) + _UniffiConverterOptionalTypeNodeAnnouncementInfo.check_lower(value.announcement_info) + + @staticmethod + def write(value, buf): + _UniffiConverterSequenceUInt64.write(value.channels, buf) + _UniffiConverterOptionalTypeNodeAnnouncementInfo.write(value.announcement_info, buf) + + +class NodeStatus: + is_running: "bool" + current_best_block: "BestBlock" + latest_lightning_wallet_sync_timestamp: "typing.Optional[int]" + latest_onchain_wallet_sync_timestamp: "typing.Optional[int]" + latest_fee_rate_cache_update_timestamp: "typing.Optional[int]" + latest_rgs_snapshot_timestamp: "typing.Optional[int]" + latest_pathfinding_scores_sync_timestamp: "typing.Optional[int]" + latest_node_announcement_broadcast_timestamp: "typing.Optional[int]" + latest_channel_monitor_archival_height: "typing.Optional[int]" + def __init__(self, *, is_running: "bool", current_best_block: "BestBlock", latest_lightning_wallet_sync_timestamp: "typing.Optional[int]", latest_onchain_wallet_sync_timestamp: "typing.Optional[int]", latest_fee_rate_cache_update_timestamp: "typing.Optional[int]", latest_rgs_snapshot_timestamp: "typing.Optional[int]", latest_pathfinding_scores_sync_timestamp: "typing.Optional[int]", latest_node_announcement_broadcast_timestamp: "typing.Optional[int]", latest_channel_monitor_archival_height: "typing.Optional[int]"): + self.is_running = is_running + self.current_best_block = current_best_block + self.latest_lightning_wallet_sync_timestamp = latest_lightning_wallet_sync_timestamp + self.latest_onchain_wallet_sync_timestamp = latest_onchain_wallet_sync_timestamp + self.latest_fee_rate_cache_update_timestamp = latest_fee_rate_cache_update_timestamp + self.latest_rgs_snapshot_timestamp = latest_rgs_snapshot_timestamp + self.latest_pathfinding_scores_sync_timestamp = latest_pathfinding_scores_sync_timestamp + self.latest_node_announcement_broadcast_timestamp = latest_node_announcement_broadcast_timestamp + self.latest_channel_monitor_archival_height = latest_channel_monitor_archival_height + + def __str__(self): + return "NodeStatus(is_running={}, current_best_block={}, latest_lightning_wallet_sync_timestamp={}, latest_onchain_wallet_sync_timestamp={}, latest_fee_rate_cache_update_timestamp={}, latest_rgs_snapshot_timestamp={}, latest_pathfinding_scores_sync_timestamp={}, latest_node_announcement_broadcast_timestamp={}, latest_channel_monitor_archival_height={})".format(self.is_running, self.current_best_block, self.latest_lightning_wallet_sync_timestamp, self.latest_onchain_wallet_sync_timestamp, self.latest_fee_rate_cache_update_timestamp, self.latest_rgs_snapshot_timestamp, self.latest_pathfinding_scores_sync_timestamp, self.latest_node_announcement_broadcast_timestamp, self.latest_channel_monitor_archival_height) + + def __eq__(self, other): + if self.is_running != other.is_running: + return False + if self.current_best_block != other.current_best_block: + return False + if self.latest_lightning_wallet_sync_timestamp != other.latest_lightning_wallet_sync_timestamp: + return False + if self.latest_onchain_wallet_sync_timestamp != other.latest_onchain_wallet_sync_timestamp: + return False + if self.latest_fee_rate_cache_update_timestamp != other.latest_fee_rate_cache_update_timestamp: + return False + if self.latest_rgs_snapshot_timestamp != other.latest_rgs_snapshot_timestamp: + return False + if self.latest_pathfinding_scores_sync_timestamp != other.latest_pathfinding_scores_sync_timestamp: + return False + if self.latest_node_announcement_broadcast_timestamp != other.latest_node_announcement_broadcast_timestamp: + return False + if self.latest_channel_monitor_archival_height != other.latest_channel_monitor_archival_height: + return False + return True + +class _UniffiConverterTypeNodeStatus(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return NodeStatus( + is_running=_UniffiConverterBool.read(buf), + current_best_block=_UniffiConverterTypeBestBlock.read(buf), + latest_lightning_wallet_sync_timestamp=_UniffiConverterOptionalUInt64.read(buf), + latest_onchain_wallet_sync_timestamp=_UniffiConverterOptionalUInt64.read(buf), + latest_fee_rate_cache_update_timestamp=_UniffiConverterOptionalUInt64.read(buf), + latest_rgs_snapshot_timestamp=_UniffiConverterOptionalUInt64.read(buf), + latest_pathfinding_scores_sync_timestamp=_UniffiConverterOptionalUInt64.read(buf), + latest_node_announcement_broadcast_timestamp=_UniffiConverterOptionalUInt64.read(buf), + latest_channel_monitor_archival_height=_UniffiConverterOptionalUInt32.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterBool.check_lower(value.is_running) + _UniffiConverterTypeBestBlock.check_lower(value.current_best_block) + _UniffiConverterOptionalUInt64.check_lower(value.latest_lightning_wallet_sync_timestamp) + _UniffiConverterOptionalUInt64.check_lower(value.latest_onchain_wallet_sync_timestamp) + _UniffiConverterOptionalUInt64.check_lower(value.latest_fee_rate_cache_update_timestamp) + _UniffiConverterOptionalUInt64.check_lower(value.latest_rgs_snapshot_timestamp) + _UniffiConverterOptionalUInt64.check_lower(value.latest_pathfinding_scores_sync_timestamp) + _UniffiConverterOptionalUInt64.check_lower(value.latest_node_announcement_broadcast_timestamp) + _UniffiConverterOptionalUInt32.check_lower(value.latest_channel_monitor_archival_height) + + @staticmethod + def write(value, buf): + _UniffiConverterBool.write(value.is_running, buf) + _UniffiConverterTypeBestBlock.write(value.current_best_block, buf) + _UniffiConverterOptionalUInt64.write(value.latest_lightning_wallet_sync_timestamp, buf) + _UniffiConverterOptionalUInt64.write(value.latest_onchain_wallet_sync_timestamp, buf) + _UniffiConverterOptionalUInt64.write(value.latest_fee_rate_cache_update_timestamp, buf) + _UniffiConverterOptionalUInt64.write(value.latest_rgs_snapshot_timestamp, buf) + _UniffiConverterOptionalUInt64.write(value.latest_pathfinding_scores_sync_timestamp, buf) + _UniffiConverterOptionalUInt64.write(value.latest_node_announcement_broadcast_timestamp, buf) + _UniffiConverterOptionalUInt32.write(value.latest_channel_monitor_archival_height, buf) + + +class OnchainWalletAccount: + address_type: "AddressType" + account_index: "int" + def __init__(self, *, address_type: "AddressType", account_index: "int"): + self.address_type = address_type + self.account_index = account_index + + def __str__(self): + return "OnchainWalletAccount(address_type={}, account_index={})".format(self.address_type, self.account_index) + + def __eq__(self, other): + if self.address_type != other.address_type: + return False + if self.account_index != other.account_index: + return False + return True + +class _UniffiConverterTypeOnchainWalletAccount(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return OnchainWalletAccount( + address_type=_UniffiConverterTypeAddressType.read(buf), + account_index=_UniffiConverterUInt32.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterTypeAddressType.check_lower(value.address_type) + _UniffiConverterUInt32.check_lower(value.account_index) + + @staticmethod + def write(value, buf): + _UniffiConverterTypeAddressType.write(value.address_type, buf) + _UniffiConverterUInt32.write(value.account_index, buf) + + +class OnchainWalletAccountConfig: + address_type: "AddressType" + account_index: "int" + xpub: "str" + def __init__(self, *, address_type: "AddressType", account_index: "int", xpub: "str"): + self.address_type = address_type + self.account_index = account_index + self.xpub = xpub + + def __str__(self): + return "OnchainWalletAccountConfig(address_type={}, account_index={}, xpub={})".format(self.address_type, self.account_index, self.xpub) + + def __eq__(self, other): + if self.address_type != other.address_type: + return False + if self.account_index != other.account_index: + return False + if self.xpub != other.xpub: + return False + return True + +class _UniffiConverterTypeOnchainWalletAccountConfig(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return OnchainWalletAccountConfig( + address_type=_UniffiConverterTypeAddressType.read(buf), + account_index=_UniffiConverterUInt32.read(buf), + xpub=_UniffiConverterString.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterTypeAddressType.check_lower(value.address_type) + _UniffiConverterUInt32.check_lower(value.account_index) + _UniffiConverterString.check_lower(value.xpub) + + @staticmethod + def write(value, buf): + _UniffiConverterTypeAddressType.write(value.address_type, buf) + _UniffiConverterUInt32.write(value.account_index, buf) + _UniffiConverterString.write(value.xpub, buf) + + +class OutPoint: + txid: "Txid" + vout: "int" + def __init__(self, *, txid: "Txid", vout: "int"): + self.txid = txid + self.vout = vout + + def __str__(self): + return "OutPoint(txid={}, vout={})".format(self.txid, self.vout) + + def __eq__(self, other): + if self.txid != other.txid: + return False + if self.vout != other.vout: + return False + return True + +class _UniffiConverterTypeOutPoint(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return OutPoint( + txid=_UniffiConverterTypeTxid.read(buf), + vout=_UniffiConverterUInt32.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterTypeTxid.check_lower(value.txid) + _UniffiConverterUInt32.check_lower(value.vout) + + @staticmethod + def write(value, buf): + _UniffiConverterTypeTxid.write(value.txid, buf) + _UniffiConverterUInt32.write(value.vout, buf) + + +class PaymentDetails: + id: "PaymentId" + kind: "PaymentKind" + amount_msat: "typing.Optional[int]" + fee_paid_msat: "typing.Optional[int]" + direction: "PaymentDirection" + status: "PaymentStatus" + latest_update_timestamp: "int" + def __init__(self, *, id: "PaymentId", kind: "PaymentKind", amount_msat: "typing.Optional[int]", fee_paid_msat: "typing.Optional[int]", direction: "PaymentDirection", status: "PaymentStatus", latest_update_timestamp: "int"): + self.id = id + self.kind = kind + self.amount_msat = amount_msat + self.fee_paid_msat = fee_paid_msat + self.direction = direction + self.status = status + self.latest_update_timestamp = latest_update_timestamp + + def __str__(self): + return "PaymentDetails(id={}, kind={}, amount_msat={}, fee_paid_msat={}, direction={}, status={}, latest_update_timestamp={})".format(self.id, self.kind, self.amount_msat, self.fee_paid_msat, self.direction, self.status, self.latest_update_timestamp) + + def __eq__(self, other): + if self.id != other.id: + return False + if self.kind != other.kind: + return False + if self.amount_msat != other.amount_msat: + return False + if self.fee_paid_msat != other.fee_paid_msat: + return False + if self.direction != other.direction: + return False + if self.status != other.status: + return False + if self.latest_update_timestamp != other.latest_update_timestamp: + return False + return True + +class _UniffiConverterTypePaymentDetails(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return PaymentDetails( + id=_UniffiConverterTypePaymentId.read(buf), + kind=_UniffiConverterTypePaymentKind.read(buf), + amount_msat=_UniffiConverterOptionalUInt64.read(buf), + fee_paid_msat=_UniffiConverterOptionalUInt64.read(buf), + direction=_UniffiConverterTypePaymentDirection.read(buf), + status=_UniffiConverterTypePaymentStatus.read(buf), + latest_update_timestamp=_UniffiConverterUInt64.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterTypePaymentId.check_lower(value.id) + _UniffiConverterTypePaymentKind.check_lower(value.kind) + _UniffiConverterOptionalUInt64.check_lower(value.amount_msat) + _UniffiConverterOptionalUInt64.check_lower(value.fee_paid_msat) + _UniffiConverterTypePaymentDirection.check_lower(value.direction) + _UniffiConverterTypePaymentStatus.check_lower(value.status) + _UniffiConverterUInt64.check_lower(value.latest_update_timestamp) + + @staticmethod + def write(value, buf): + _UniffiConverterTypePaymentId.write(value.id, buf) + _UniffiConverterTypePaymentKind.write(value.kind, buf) + _UniffiConverterOptionalUInt64.write(value.amount_msat, buf) + _UniffiConverterOptionalUInt64.write(value.fee_paid_msat, buf) + _UniffiConverterTypePaymentDirection.write(value.direction, buf) + _UniffiConverterTypePaymentStatus.write(value.status, buf) + _UniffiConverterUInt64.write(value.latest_update_timestamp, buf) + + +class PeerDetails: + node_id: "PublicKey" + address: "SocketAddress" + is_persisted: "bool" + is_connected: "bool" + def __init__(self, *, node_id: "PublicKey", address: "SocketAddress", is_persisted: "bool", is_connected: "bool"): + self.node_id = node_id + self.address = address + self.is_persisted = is_persisted + self.is_connected = is_connected + + def __str__(self): + return "PeerDetails(node_id={}, address={}, is_persisted={}, is_connected={})".format(self.node_id, self.address, self.is_persisted, self.is_connected) + + def __eq__(self, other): + if self.node_id != other.node_id: + return False + if self.address != other.address: + return False + if self.is_persisted != other.is_persisted: + return False + if self.is_connected != other.is_connected: + return False + return True + +class _UniffiConverterTypePeerDetails(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return PeerDetails( + node_id=_UniffiConverterTypePublicKey.read(buf), + address=_UniffiConverterTypeSocketAddress.read(buf), + is_persisted=_UniffiConverterBool.read(buf), + is_connected=_UniffiConverterBool.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterTypePublicKey.check_lower(value.node_id) + _UniffiConverterTypeSocketAddress.check_lower(value.address) + _UniffiConverterBool.check_lower(value.is_persisted) + _UniffiConverterBool.check_lower(value.is_connected) + + @staticmethod + def write(value, buf): + _UniffiConverterTypePublicKey.write(value.node_id, buf) + _UniffiConverterTypeSocketAddress.write(value.address, buf) + _UniffiConverterBool.write(value.is_persisted, buf) + _UniffiConverterBool.write(value.is_connected, buf) + + +class ProbeHandle: + payment_hash: "PaymentHash" + payment_id: "PaymentId" + def __init__(self, *, payment_hash: "PaymentHash", payment_id: "PaymentId"): + self.payment_hash = payment_hash + self.payment_id = payment_id + + def __str__(self): + return "ProbeHandle(payment_hash={}, payment_id={})".format(self.payment_hash, self.payment_id) + + def __eq__(self, other): + if self.payment_hash != other.payment_hash: + return False + if self.payment_id != other.payment_id: + return False + return True + +class _UniffiConverterTypeProbeHandle(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return ProbeHandle( + payment_hash=_UniffiConverterTypePaymentHash.read(buf), + payment_id=_UniffiConverterTypePaymentId.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterTypePaymentHash.check_lower(value.payment_hash) + _UniffiConverterTypePaymentId.check_lower(value.payment_id) + + @staticmethod + def write(value, buf): + _UniffiConverterTypePaymentHash.write(value.payment_hash, buf) + _UniffiConverterTypePaymentId.write(value.payment_id, buf) + + +class RouteHintHop: + src_node_id: "PublicKey" + short_channel_id: "int" + cltv_expiry_delta: "int" + htlc_minimum_msat: "typing.Optional[int]" + htlc_maximum_msat: "typing.Optional[int]" + fees: "RoutingFees" + def __init__(self, *, src_node_id: "PublicKey", short_channel_id: "int", cltv_expiry_delta: "int", htlc_minimum_msat: "typing.Optional[int]", htlc_maximum_msat: "typing.Optional[int]", fees: "RoutingFees"): + self.src_node_id = src_node_id + self.short_channel_id = short_channel_id + self.cltv_expiry_delta = cltv_expiry_delta + self.htlc_minimum_msat = htlc_minimum_msat + self.htlc_maximum_msat = htlc_maximum_msat + self.fees = fees + + def __str__(self): + return "RouteHintHop(src_node_id={}, short_channel_id={}, cltv_expiry_delta={}, htlc_minimum_msat={}, htlc_maximum_msat={}, fees={})".format(self.src_node_id, self.short_channel_id, self.cltv_expiry_delta, self.htlc_minimum_msat, self.htlc_maximum_msat, self.fees) + + def __eq__(self, other): + if self.src_node_id != other.src_node_id: + return False + if self.short_channel_id != other.short_channel_id: + return False + if self.cltv_expiry_delta != other.cltv_expiry_delta: + return False + if self.htlc_minimum_msat != other.htlc_minimum_msat: + return False + if self.htlc_maximum_msat != other.htlc_maximum_msat: + return False + if self.fees != other.fees: + return False + return True + +class _UniffiConverterTypeRouteHintHop(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return RouteHintHop( + src_node_id=_UniffiConverterTypePublicKey.read(buf), + short_channel_id=_UniffiConverterUInt64.read(buf), + cltv_expiry_delta=_UniffiConverterUInt16.read(buf), + htlc_minimum_msat=_UniffiConverterOptionalUInt64.read(buf), + htlc_maximum_msat=_UniffiConverterOptionalUInt64.read(buf), + fees=_UniffiConverterTypeRoutingFees.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterTypePublicKey.check_lower(value.src_node_id) + _UniffiConverterUInt64.check_lower(value.short_channel_id) + _UniffiConverterUInt16.check_lower(value.cltv_expiry_delta) + _UniffiConverterOptionalUInt64.check_lower(value.htlc_minimum_msat) + _UniffiConverterOptionalUInt64.check_lower(value.htlc_maximum_msat) + _UniffiConverterTypeRoutingFees.check_lower(value.fees) + + @staticmethod + def write(value, buf): + _UniffiConverterTypePublicKey.write(value.src_node_id, buf) + _UniffiConverterUInt64.write(value.short_channel_id, buf) + _UniffiConverterUInt16.write(value.cltv_expiry_delta, buf) + _UniffiConverterOptionalUInt64.write(value.htlc_minimum_msat, buf) + _UniffiConverterOptionalUInt64.write(value.htlc_maximum_msat, buf) + _UniffiConverterTypeRoutingFees.write(value.fees, buf) + + +class RouteParametersConfig: + max_total_routing_fee_msat: "typing.Optional[int]" + max_total_cltv_expiry_delta: "int" + max_path_count: "int" + max_channel_saturation_power_of_half: "int" + def __init__(self, *, max_total_routing_fee_msat: "typing.Optional[int]", max_total_cltv_expiry_delta: "int", max_path_count: "int", max_channel_saturation_power_of_half: "int"): + self.max_total_routing_fee_msat = max_total_routing_fee_msat + self.max_total_cltv_expiry_delta = max_total_cltv_expiry_delta + self.max_path_count = max_path_count + self.max_channel_saturation_power_of_half = max_channel_saturation_power_of_half + + def __str__(self): + return "RouteParametersConfig(max_total_routing_fee_msat={}, max_total_cltv_expiry_delta={}, max_path_count={}, max_channel_saturation_power_of_half={})".format(self.max_total_routing_fee_msat, self.max_total_cltv_expiry_delta, self.max_path_count, self.max_channel_saturation_power_of_half) + + def __eq__(self, other): + if self.max_total_routing_fee_msat != other.max_total_routing_fee_msat: + return False + if self.max_total_cltv_expiry_delta != other.max_total_cltv_expiry_delta: + return False + if self.max_path_count != other.max_path_count: + return False + if self.max_channel_saturation_power_of_half != other.max_channel_saturation_power_of_half: + return False + return True + +class _UniffiConverterTypeRouteParametersConfig(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return RouteParametersConfig( + max_total_routing_fee_msat=_UniffiConverterOptionalUInt64.read(buf), + max_total_cltv_expiry_delta=_UniffiConverterUInt32.read(buf), + max_path_count=_UniffiConverterUInt8.read(buf), + max_channel_saturation_power_of_half=_UniffiConverterUInt8.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterOptionalUInt64.check_lower(value.max_total_routing_fee_msat) + _UniffiConverterUInt32.check_lower(value.max_total_cltv_expiry_delta) + _UniffiConverterUInt8.check_lower(value.max_path_count) + _UniffiConverterUInt8.check_lower(value.max_channel_saturation_power_of_half) + + @staticmethod + def write(value, buf): + _UniffiConverterOptionalUInt64.write(value.max_total_routing_fee_msat, buf) + _UniffiConverterUInt32.write(value.max_total_cltv_expiry_delta, buf) + _UniffiConverterUInt8.write(value.max_path_count, buf) + _UniffiConverterUInt8.write(value.max_channel_saturation_power_of_half, buf) + + +class RoutingFees: + base_msat: "int" + proportional_millionths: "int" + def __init__(self, *, base_msat: "int", proportional_millionths: "int"): + self.base_msat = base_msat + self.proportional_millionths = proportional_millionths + + def __str__(self): + return "RoutingFees(base_msat={}, proportional_millionths={})".format(self.base_msat, self.proportional_millionths) + + def __eq__(self, other): + if self.base_msat != other.base_msat: + return False + if self.proportional_millionths != other.proportional_millionths: + return False + return True + +class _UniffiConverterTypeRoutingFees(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return RoutingFees( + base_msat=_UniffiConverterUInt32.read(buf), + proportional_millionths=_UniffiConverterUInt32.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterUInt32.check_lower(value.base_msat) + _UniffiConverterUInt32.check_lower(value.proportional_millionths) + + @staticmethod + def write(value, buf): + _UniffiConverterUInt32.write(value.base_msat, buf) + _UniffiConverterUInt32.write(value.proportional_millionths, buf) + + +class RuntimeSyncIntervals: + onchain_wallet_sync_interval_secs: "int" + lightning_wallet_sync_interval_secs: "int" + fee_rate_cache_update_interval_secs: "int" + def __init__(self, *, onchain_wallet_sync_interval_secs: "int", lightning_wallet_sync_interval_secs: "int", fee_rate_cache_update_interval_secs: "int"): + self.onchain_wallet_sync_interval_secs = onchain_wallet_sync_interval_secs + self.lightning_wallet_sync_interval_secs = lightning_wallet_sync_interval_secs + self.fee_rate_cache_update_interval_secs = fee_rate_cache_update_interval_secs + + def __str__(self): + return "RuntimeSyncIntervals(onchain_wallet_sync_interval_secs={}, lightning_wallet_sync_interval_secs={}, fee_rate_cache_update_interval_secs={})".format(self.onchain_wallet_sync_interval_secs, self.lightning_wallet_sync_interval_secs, self.fee_rate_cache_update_interval_secs) + + def __eq__(self, other): + if self.onchain_wallet_sync_interval_secs != other.onchain_wallet_sync_interval_secs: + return False + if self.lightning_wallet_sync_interval_secs != other.lightning_wallet_sync_interval_secs: + return False + if self.fee_rate_cache_update_interval_secs != other.fee_rate_cache_update_interval_secs: + return False + return True + +class _UniffiConverterTypeRuntimeSyncIntervals(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return RuntimeSyncIntervals( + onchain_wallet_sync_interval_secs=_UniffiConverterUInt64.read(buf), + lightning_wallet_sync_interval_secs=_UniffiConverterUInt64.read(buf), + fee_rate_cache_update_interval_secs=_UniffiConverterUInt64.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterUInt64.check_lower(value.onchain_wallet_sync_interval_secs) + _UniffiConverterUInt64.check_lower(value.lightning_wallet_sync_interval_secs) + _UniffiConverterUInt64.check_lower(value.fee_rate_cache_update_interval_secs) + + @staticmethod + def write(value, buf): + _UniffiConverterUInt64.write(value.onchain_wallet_sync_interval_secs, buf) + _UniffiConverterUInt64.write(value.lightning_wallet_sync_interval_secs, buf) + _UniffiConverterUInt64.write(value.fee_rate_cache_update_interval_secs, buf) + + +class ScoringDecayParameters: + historical_no_updates_half_life_secs: "int" + liquidity_offset_half_life_secs: "int" + def __init__(self, *, historical_no_updates_half_life_secs: "int", liquidity_offset_half_life_secs: "int"): + self.historical_no_updates_half_life_secs = historical_no_updates_half_life_secs + self.liquidity_offset_half_life_secs = liquidity_offset_half_life_secs + + def __str__(self): + return "ScoringDecayParameters(historical_no_updates_half_life_secs={}, liquidity_offset_half_life_secs={})".format(self.historical_no_updates_half_life_secs, self.liquidity_offset_half_life_secs) + + def __eq__(self, other): + if self.historical_no_updates_half_life_secs != other.historical_no_updates_half_life_secs: + return False + if self.liquidity_offset_half_life_secs != other.liquidity_offset_half_life_secs: + return False + return True + +class _UniffiConverterTypeScoringDecayParameters(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return ScoringDecayParameters( + historical_no_updates_half_life_secs=_UniffiConverterUInt64.read(buf), + liquidity_offset_half_life_secs=_UniffiConverterUInt64.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterUInt64.check_lower(value.historical_no_updates_half_life_secs) + _UniffiConverterUInt64.check_lower(value.liquidity_offset_half_life_secs) + + @staticmethod + def write(value, buf): + _UniffiConverterUInt64.write(value.historical_no_updates_half_life_secs, buf) + _UniffiConverterUInt64.write(value.liquidity_offset_half_life_secs, buf) + + +class ScoringFeeParameters: + base_penalty_msat: "int" + base_penalty_amount_multiplier_msat: "int" + liquidity_penalty_multiplier_msat: "int" + liquidity_penalty_amount_multiplier_msat: "int" + historical_liquidity_penalty_multiplier_msat: "int" + historical_liquidity_penalty_amount_multiplier_msat: "int" + anti_probing_penalty_msat: "int" + considered_impossible_penalty_msat: "int" + linear_success_probability: "bool" + probing_diversity_penalty_msat: "int" + def __init__(self, *, base_penalty_msat: "int", base_penalty_amount_multiplier_msat: "int", liquidity_penalty_multiplier_msat: "int", liquidity_penalty_amount_multiplier_msat: "int", historical_liquidity_penalty_multiplier_msat: "int", historical_liquidity_penalty_amount_multiplier_msat: "int", anti_probing_penalty_msat: "int", considered_impossible_penalty_msat: "int", linear_success_probability: "bool", probing_diversity_penalty_msat: "int"): + self.base_penalty_msat = base_penalty_msat + self.base_penalty_amount_multiplier_msat = base_penalty_amount_multiplier_msat + self.liquidity_penalty_multiplier_msat = liquidity_penalty_multiplier_msat + self.liquidity_penalty_amount_multiplier_msat = liquidity_penalty_amount_multiplier_msat + self.historical_liquidity_penalty_multiplier_msat = historical_liquidity_penalty_multiplier_msat + self.historical_liquidity_penalty_amount_multiplier_msat = historical_liquidity_penalty_amount_multiplier_msat + self.anti_probing_penalty_msat = anti_probing_penalty_msat + self.considered_impossible_penalty_msat = considered_impossible_penalty_msat + self.linear_success_probability = linear_success_probability + self.probing_diversity_penalty_msat = probing_diversity_penalty_msat + + def __str__(self): + return "ScoringFeeParameters(base_penalty_msat={}, base_penalty_amount_multiplier_msat={}, liquidity_penalty_multiplier_msat={}, liquidity_penalty_amount_multiplier_msat={}, historical_liquidity_penalty_multiplier_msat={}, historical_liquidity_penalty_amount_multiplier_msat={}, anti_probing_penalty_msat={}, considered_impossible_penalty_msat={}, linear_success_probability={}, probing_diversity_penalty_msat={})".format(self.base_penalty_msat, self.base_penalty_amount_multiplier_msat, self.liquidity_penalty_multiplier_msat, self.liquidity_penalty_amount_multiplier_msat, self.historical_liquidity_penalty_multiplier_msat, self.historical_liquidity_penalty_amount_multiplier_msat, self.anti_probing_penalty_msat, self.considered_impossible_penalty_msat, self.linear_success_probability, self.probing_diversity_penalty_msat) + + def __eq__(self, other): + if self.base_penalty_msat != other.base_penalty_msat: + return False + if self.base_penalty_amount_multiplier_msat != other.base_penalty_amount_multiplier_msat: + return False + if self.liquidity_penalty_multiplier_msat != other.liquidity_penalty_multiplier_msat: + return False + if self.liquidity_penalty_amount_multiplier_msat != other.liquidity_penalty_amount_multiplier_msat: + return False + if self.historical_liquidity_penalty_multiplier_msat != other.historical_liquidity_penalty_multiplier_msat: + return False + if self.historical_liquidity_penalty_amount_multiplier_msat != other.historical_liquidity_penalty_amount_multiplier_msat: + return False + if self.anti_probing_penalty_msat != other.anti_probing_penalty_msat: + return False + if self.considered_impossible_penalty_msat != other.considered_impossible_penalty_msat: + return False + if self.linear_success_probability != other.linear_success_probability: + return False + if self.probing_diversity_penalty_msat != other.probing_diversity_penalty_msat: + return False + return True + +class _UniffiConverterTypeScoringFeeParameters(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return ScoringFeeParameters( + base_penalty_msat=_UniffiConverterUInt64.read(buf), + base_penalty_amount_multiplier_msat=_UniffiConverterUInt64.read(buf), + liquidity_penalty_multiplier_msat=_UniffiConverterUInt64.read(buf), + liquidity_penalty_amount_multiplier_msat=_UniffiConverterUInt64.read(buf), + historical_liquidity_penalty_multiplier_msat=_UniffiConverterUInt64.read(buf), + historical_liquidity_penalty_amount_multiplier_msat=_UniffiConverterUInt64.read(buf), + anti_probing_penalty_msat=_UniffiConverterUInt64.read(buf), + considered_impossible_penalty_msat=_UniffiConverterUInt64.read(buf), + linear_success_probability=_UniffiConverterBool.read(buf), + probing_diversity_penalty_msat=_UniffiConverterUInt64.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterUInt64.check_lower(value.base_penalty_msat) + _UniffiConverterUInt64.check_lower(value.base_penalty_amount_multiplier_msat) + _UniffiConverterUInt64.check_lower(value.liquidity_penalty_multiplier_msat) + _UniffiConverterUInt64.check_lower(value.liquidity_penalty_amount_multiplier_msat) + _UniffiConverterUInt64.check_lower(value.historical_liquidity_penalty_multiplier_msat) + _UniffiConverterUInt64.check_lower(value.historical_liquidity_penalty_amount_multiplier_msat) + _UniffiConverterUInt64.check_lower(value.anti_probing_penalty_msat) + _UniffiConverterUInt64.check_lower(value.considered_impossible_penalty_msat) + _UniffiConverterBool.check_lower(value.linear_success_probability) + _UniffiConverterUInt64.check_lower(value.probing_diversity_penalty_msat) + + @staticmethod + def write(value, buf): + _UniffiConverterUInt64.write(value.base_penalty_msat, buf) + _UniffiConverterUInt64.write(value.base_penalty_amount_multiplier_msat, buf) + _UniffiConverterUInt64.write(value.liquidity_penalty_multiplier_msat, buf) + _UniffiConverterUInt64.write(value.liquidity_penalty_amount_multiplier_msat, buf) + _UniffiConverterUInt64.write(value.historical_liquidity_penalty_multiplier_msat, buf) + _UniffiConverterUInt64.write(value.historical_liquidity_penalty_amount_multiplier_msat, buf) + _UniffiConverterUInt64.write(value.anti_probing_penalty_msat, buf) + _UniffiConverterUInt64.write(value.considered_impossible_penalty_msat, buf) + _UniffiConverterBool.write(value.linear_success_probability, buf) + _UniffiConverterUInt64.write(value.probing_diversity_penalty_msat, buf) + + +class SpendableUtxo: + outpoint: "OutPoint" + value_sats: "int" + def __init__(self, *, outpoint: "OutPoint", value_sats: "int"): + self.outpoint = outpoint + self.value_sats = value_sats + + def __str__(self): + return "SpendableUtxo(outpoint={}, value_sats={})".format(self.outpoint, self.value_sats) + + def __eq__(self, other): + if self.outpoint != other.outpoint: + return False + if self.value_sats != other.value_sats: + return False + return True + +class _UniffiConverterTypeSpendableUtxo(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return SpendableUtxo( + outpoint=_UniffiConverterTypeOutPoint.read(buf), + value_sats=_UniffiConverterUInt64.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterTypeOutPoint.check_lower(value.outpoint) + _UniffiConverterUInt64.check_lower(value.value_sats) + + @staticmethod + def write(value, buf): + _UniffiConverterTypeOutPoint.write(value.outpoint, buf) + _UniffiConverterUInt64.write(value.value_sats, buf) + + +class TransactionDetails: + amount_sats: "int" + inputs: "typing.List[TxInput]" + outputs: "typing.List[TxOutput]" + def __init__(self, *, amount_sats: "int", inputs: "typing.List[TxInput]", outputs: "typing.List[TxOutput]"): + self.amount_sats = amount_sats + self.inputs = inputs + self.outputs = outputs + + def __str__(self): + return "TransactionDetails(amount_sats={}, inputs={}, outputs={})".format(self.amount_sats, self.inputs, self.outputs) + + def __eq__(self, other): + if self.amount_sats != other.amount_sats: + return False + if self.inputs != other.inputs: + return False + if self.outputs != other.outputs: + return False + return True + +class _UniffiConverterTypeTransactionDetails(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return TransactionDetails( + amount_sats=_UniffiConverterInt64.read(buf), + inputs=_UniffiConverterSequenceTypeTxInput.read(buf), + outputs=_UniffiConverterSequenceTypeTxOutput.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterInt64.check_lower(value.amount_sats) + _UniffiConverterSequenceTypeTxInput.check_lower(value.inputs) + _UniffiConverterSequenceTypeTxOutput.check_lower(value.outputs) + + @staticmethod + def write(value, buf): + _UniffiConverterInt64.write(value.amount_sats, buf) + _UniffiConverterSequenceTypeTxInput.write(value.inputs, buf) + _UniffiConverterSequenceTypeTxOutput.write(value.outputs, buf) + + +class TxInput: + txid: "Txid" + vout: "int" + scriptsig: "str" + witness: "typing.List[str]" + sequence: "int" + def __init__(self, *, txid: "Txid", vout: "int", scriptsig: "str", witness: "typing.List[str]", sequence: "int"): + self.txid = txid + self.vout = vout + self.scriptsig = scriptsig + self.witness = witness + self.sequence = sequence + + def __str__(self): + return "TxInput(txid={}, vout={}, scriptsig={}, witness={}, sequence={})".format(self.txid, self.vout, self.scriptsig, self.witness, self.sequence) + + def __eq__(self, other): + if self.txid != other.txid: + return False + if self.vout != other.vout: + return False + if self.scriptsig != other.scriptsig: + return False + if self.witness != other.witness: + return False + if self.sequence != other.sequence: + return False + return True + +class _UniffiConverterTypeTxInput(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return TxInput( + txid=_UniffiConverterTypeTxid.read(buf), + vout=_UniffiConverterUInt32.read(buf), + scriptsig=_UniffiConverterString.read(buf), + witness=_UniffiConverterSequenceString.read(buf), + sequence=_UniffiConverterUInt32.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterTypeTxid.check_lower(value.txid) + _UniffiConverterUInt32.check_lower(value.vout) + _UniffiConverterString.check_lower(value.scriptsig) + _UniffiConverterSequenceString.check_lower(value.witness) + _UniffiConverterUInt32.check_lower(value.sequence) + + @staticmethod + def write(value, buf): + _UniffiConverterTypeTxid.write(value.txid, buf) + _UniffiConverterUInt32.write(value.vout, buf) + _UniffiConverterString.write(value.scriptsig, buf) + _UniffiConverterSequenceString.write(value.witness, buf) + _UniffiConverterUInt32.write(value.sequence, buf) + + +class TxOutput: + scriptpubkey: "str" + scriptpubkey_type: "typing.Optional[str]" + scriptpubkey_address: "typing.Optional[str]" + value: "int" + n: "int" + def __init__(self, *, scriptpubkey: "str", scriptpubkey_type: "typing.Optional[str]", scriptpubkey_address: "typing.Optional[str]", value: "int", n: "int"): + self.scriptpubkey = scriptpubkey + self.scriptpubkey_type = scriptpubkey_type + self.scriptpubkey_address = scriptpubkey_address + self.value = value + self.n = n + + def __str__(self): + return "TxOutput(scriptpubkey={}, scriptpubkey_type={}, scriptpubkey_address={}, value={}, n={})".format(self.scriptpubkey, self.scriptpubkey_type, self.scriptpubkey_address, self.value, self.n) + + def __eq__(self, other): + if self.scriptpubkey != other.scriptpubkey: + return False + if self.scriptpubkey_type != other.scriptpubkey_type: + return False + if self.scriptpubkey_address != other.scriptpubkey_address: + return False + if self.value != other.value: + return False + if self.n != other.n: + return False + return True + +class _UniffiConverterTypeTxOutput(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return TxOutput( + scriptpubkey=_UniffiConverterString.read(buf), + scriptpubkey_type=_UniffiConverterOptionalString.read(buf), + scriptpubkey_address=_UniffiConverterOptionalString.read(buf), + value=_UniffiConverterInt64.read(buf), + n=_UniffiConverterUInt32.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterString.check_lower(value.scriptpubkey) + _UniffiConverterOptionalString.check_lower(value.scriptpubkey_type) + _UniffiConverterOptionalString.check_lower(value.scriptpubkey_address) + _UniffiConverterInt64.check_lower(value.value) + _UniffiConverterUInt32.check_lower(value.n) + + @staticmethod + def write(value, buf): + _UniffiConverterString.write(value.scriptpubkey, buf) + _UniffiConverterOptionalString.write(value.scriptpubkey_type, buf) + _UniffiConverterOptionalString.write(value.scriptpubkey_address, buf) + _UniffiConverterInt64.write(value.value, buf) + _UniffiConverterUInt32.write(value.n, buf) + + + + + +class AddressType(enum.Enum): + LEGACY = 0 + + NESTED_SEGWIT = 1 + + NATIVE_SEGWIT = 2 + + TAPROOT = 3 + + + +class _UniffiConverterTypeAddressType(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return AddressType.LEGACY + if variant == 2: + return AddressType.NESTED_SEGWIT + if variant == 3: + return AddressType.NATIVE_SEGWIT + if variant == 4: + return AddressType.TAPROOT + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if value == AddressType.LEGACY: + return + if value == AddressType.NESTED_SEGWIT: + return + if value == AddressType.NATIVE_SEGWIT: + return + if value == AddressType.TAPROOT: + return + raise ValueError(value) + + @staticmethod + def write(value, buf): + if value == AddressType.LEGACY: + buf.write_i32(1) + if value == AddressType.NESTED_SEGWIT: + buf.write_i32(2) + if value == AddressType.NATIVE_SEGWIT: + buf.write_i32(3) + if value == AddressType.TAPROOT: + buf.write_i32(4) + + + + + + + +class AsyncPaymentsRole(enum.Enum): + CLIENT = 0 + + SERVER = 1 + + + +class _UniffiConverterTypeAsyncPaymentsRole(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return AsyncPaymentsRole.CLIENT + if variant == 2: + return AsyncPaymentsRole.SERVER + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if value == AsyncPaymentsRole.CLIENT: + return + if value == AsyncPaymentsRole.SERVER: + return + raise ValueError(value) + + @staticmethod + def write(value, buf): + if value == AsyncPaymentsRole.CLIENT: + buf.write_i32(1) + if value == AsyncPaymentsRole.SERVER: + buf.write_i32(2) + + + + + + + +class BalanceSource(enum.Enum): + HOLDER_FORCE_CLOSED = 0 + + COUNTERPARTY_FORCE_CLOSED = 1 + + COOP_CLOSE = 2 + + HTLC = 3 + + + +class _UniffiConverterTypeBalanceSource(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return BalanceSource.HOLDER_FORCE_CLOSED + if variant == 2: + return BalanceSource.COUNTERPARTY_FORCE_CLOSED + if variant == 3: + return BalanceSource.COOP_CLOSE + if variant == 4: + return BalanceSource.HTLC + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if value == BalanceSource.HOLDER_FORCE_CLOSED: + return + if value == BalanceSource.COUNTERPARTY_FORCE_CLOSED: + return + if value == BalanceSource.COOP_CLOSE: + return + if value == BalanceSource.HTLC: + return + raise ValueError(value) + + @staticmethod + def write(value, buf): + if value == BalanceSource.HOLDER_FORCE_CLOSED: + buf.write_i32(1) + if value == BalanceSource.COUNTERPARTY_FORCE_CLOSED: + buf.write_i32(2) + if value == BalanceSource.COOP_CLOSE: + buf.write_i32(3) + if value == BalanceSource.HTLC: + buf.write_i32(4) + + + + + + + +class Bolt11InvoiceDescription: + def __init__(self): + raise RuntimeError("Bolt11InvoiceDescription cannot be instantiated directly") + + # Each enum variant is a nested class of the enum itself. + class HASH: + hash: "str" + + def __init__(self,hash: "str"): + self.hash = hash + + def __str__(self): + return "Bolt11InvoiceDescription.HASH(hash={})".format(self.hash) + + def __eq__(self, other): + if not other.is_hash(): + return False + if self.hash != other.hash: + return False + return True + + class DIRECT: + description: "str" + + def __init__(self,description: "str"): + self.description = description + + def __str__(self): + return "Bolt11InvoiceDescription.DIRECT(description={})".format(self.description) + + def __eq__(self, other): + if not other.is_direct(): + return False + if self.description != other.description: + return False + return True + + + + # For each variant, we have an `is_NAME` method for easily checking + # whether an instance is that variant. + def is_hash(self) -> bool: + return isinstance(self, Bolt11InvoiceDescription.HASH) + def is_direct(self) -> bool: + return isinstance(self, Bolt11InvoiceDescription.DIRECT) + + +# Now, a little trick - we make each nested variant class be a subclass of the main +# enum class, so that method calls and instance checks etc will work intuitively. +# We might be able to do this a little more neatly with a metaclass, but this'll do. +Bolt11InvoiceDescription.HASH = type("Bolt11InvoiceDescription.HASH", (Bolt11InvoiceDescription.HASH, Bolt11InvoiceDescription,), {}) # type: ignore +Bolt11InvoiceDescription.DIRECT = type("Bolt11InvoiceDescription.DIRECT", (Bolt11InvoiceDescription.DIRECT, Bolt11InvoiceDescription,), {}) # type: ignore + + + + +class _UniffiConverterTypeBolt11InvoiceDescription(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return Bolt11InvoiceDescription.HASH( + _UniffiConverterString.read(buf), + ) + if variant == 2: + return Bolt11InvoiceDescription.DIRECT( + _UniffiConverterString.read(buf), + ) + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if value.is_hash(): + _UniffiConverterString.check_lower(value.hash) + return + if value.is_direct(): + _UniffiConverterString.check_lower(value.description) + return + raise ValueError(value) + + @staticmethod + def write(value, buf): + if value.is_hash(): + buf.write_i32(1) + _UniffiConverterString.write(value.hash, buf) + if value.is_direct(): + buf.write_i32(2) + _UniffiConverterString.write(value.description, buf) + + + + +# BuildError +# We want to define each variant as a nested class that's also a subclass, +# which is tricky in Python. To accomplish this we're going to create each +# class separately, then manually add the child classes to the base class's +# __dict__. All of this happens in dummy class to avoid polluting the module +# namespace. +class BuildError(Exception): + pass + +_UniffiTempBuildError = BuildError + +class BuildError: # type: ignore + class InvalidSeedBytes(_UniffiTempBuildError): + + def __repr__(self): + return "BuildError.InvalidSeedBytes({})".format(repr(str(self))) + _UniffiTempBuildError.InvalidSeedBytes = InvalidSeedBytes # type: ignore + class InvalidSeedFile(_UniffiTempBuildError): + + def __repr__(self): + return "BuildError.InvalidSeedFile({})".format(repr(str(self))) + _UniffiTempBuildError.InvalidSeedFile = InvalidSeedFile # type: ignore + class InvalidSystemTime(_UniffiTempBuildError): + + def __repr__(self): + return "BuildError.InvalidSystemTime({})".format(repr(str(self))) + _UniffiTempBuildError.InvalidSystemTime = InvalidSystemTime # type: ignore + class InvalidChannelMonitor(_UniffiTempBuildError): + + def __repr__(self): + return "BuildError.InvalidChannelMonitor({})".format(repr(str(self))) + _UniffiTempBuildError.InvalidChannelMonitor = InvalidChannelMonitor # type: ignore + class InvalidListeningAddresses(_UniffiTempBuildError): + + def __repr__(self): + return "BuildError.InvalidListeningAddresses({})".format(repr(str(self))) + _UniffiTempBuildError.InvalidListeningAddresses = InvalidListeningAddresses # type: ignore + class InvalidAnnouncementAddresses(_UniffiTempBuildError): + + def __repr__(self): + return "BuildError.InvalidAnnouncementAddresses({})".format(repr(str(self))) + _UniffiTempBuildError.InvalidAnnouncementAddresses = InvalidAnnouncementAddresses # type: ignore + class InvalidNodeAlias(_UniffiTempBuildError): + + def __repr__(self): + return "BuildError.InvalidNodeAlias({})".format(repr(str(self))) + _UniffiTempBuildError.InvalidNodeAlias = InvalidNodeAlias # type: ignore + class RuntimeSetupFailed(_UniffiTempBuildError): + + def __repr__(self): + return "BuildError.RuntimeSetupFailed({})".format(repr(str(self))) + _UniffiTempBuildError.RuntimeSetupFailed = RuntimeSetupFailed # type: ignore + class ReadFailed(_UniffiTempBuildError): + + def __repr__(self): + return "BuildError.ReadFailed({})".format(repr(str(self))) + _UniffiTempBuildError.ReadFailed = ReadFailed # type: ignore + class DangerousValue(_UniffiTempBuildError): + + def __repr__(self): + return "BuildError.DangerousValue({})".format(repr(str(self))) + _UniffiTempBuildError.DangerousValue = DangerousValue # type: ignore + class WriteFailed(_UniffiTempBuildError): + + def __repr__(self): + return "BuildError.WriteFailed({})".format(repr(str(self))) + _UniffiTempBuildError.WriteFailed = WriteFailed # type: ignore + class StoragePathAccessFailed(_UniffiTempBuildError): + + def __repr__(self): + return "BuildError.StoragePathAccessFailed({})".format(repr(str(self))) + _UniffiTempBuildError.StoragePathAccessFailed = StoragePathAccessFailed # type: ignore + class KvStoreSetupFailed(_UniffiTempBuildError): + + def __repr__(self): + return "BuildError.KvStoreSetupFailed({})".format(repr(str(self))) + _UniffiTempBuildError.KvStoreSetupFailed = KvStoreSetupFailed # type: ignore + class WalletSetupFailed(_UniffiTempBuildError): + + def __repr__(self): + return "BuildError.WalletSetupFailed({})".format(repr(str(self))) + _UniffiTempBuildError.WalletSetupFailed = WalletSetupFailed # type: ignore + class LoggerSetupFailed(_UniffiTempBuildError): + + def __repr__(self): + return "BuildError.LoggerSetupFailed({})".format(repr(str(self))) + _UniffiTempBuildError.LoggerSetupFailed = LoggerSetupFailed # type: ignore + class NetworkMismatch(_UniffiTempBuildError): + + def __repr__(self): + return "BuildError.NetworkMismatch({})".format(repr(str(self))) + _UniffiTempBuildError.NetworkMismatch = NetworkMismatch # type: ignore + class AsyncPaymentsConfigMismatch(_UniffiTempBuildError): + + def __repr__(self): + return "BuildError.AsyncPaymentsConfigMismatch({})".format(repr(str(self))) + _UniffiTempBuildError.AsyncPaymentsConfigMismatch = AsyncPaymentsConfigMismatch # type: ignore + +BuildError = _UniffiTempBuildError # type: ignore +del _UniffiTempBuildError + + +class _UniffiConverterTypeBuildError(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return BuildError.InvalidSeedBytes( + _UniffiConverterString.read(buf), + ) + if variant == 2: + return BuildError.InvalidSeedFile( + _UniffiConverterString.read(buf), + ) + if variant == 3: + return BuildError.InvalidSystemTime( + _UniffiConverterString.read(buf), + ) + if variant == 4: + return BuildError.InvalidChannelMonitor( + _UniffiConverterString.read(buf), + ) + if variant == 5: + return BuildError.InvalidListeningAddresses( + _UniffiConverterString.read(buf), + ) + if variant == 6: + return BuildError.InvalidAnnouncementAddresses( + _UniffiConverterString.read(buf), + ) + if variant == 7: + return BuildError.InvalidNodeAlias( + _UniffiConverterString.read(buf), + ) + if variant == 8: + return BuildError.RuntimeSetupFailed( + _UniffiConverterString.read(buf), + ) + if variant == 9: + return BuildError.ReadFailed( + _UniffiConverterString.read(buf), + ) + if variant == 10: + return BuildError.DangerousValue( + _UniffiConverterString.read(buf), + ) + if variant == 11: + return BuildError.WriteFailed( + _UniffiConverterString.read(buf), + ) + if variant == 12: + return BuildError.StoragePathAccessFailed( + _UniffiConverterString.read(buf), + ) + if variant == 13: + return BuildError.KvStoreSetupFailed( + _UniffiConverterString.read(buf), + ) + if variant == 14: + return BuildError.WalletSetupFailed( + _UniffiConverterString.read(buf), + ) + if variant == 15: + return BuildError.LoggerSetupFailed( + _UniffiConverterString.read(buf), + ) + if variant == 16: + return BuildError.NetworkMismatch( + _UniffiConverterString.read(buf), + ) + if variant == 17: + return BuildError.AsyncPaymentsConfigMismatch( + _UniffiConverterString.read(buf), + ) + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if isinstance(value, BuildError.InvalidSeedBytes): + return + if isinstance(value, BuildError.InvalidSeedFile): + return + if isinstance(value, BuildError.InvalidSystemTime): + return + if isinstance(value, BuildError.InvalidChannelMonitor): + return + if isinstance(value, BuildError.InvalidListeningAddresses): + return + if isinstance(value, BuildError.InvalidAnnouncementAddresses): + return + if isinstance(value, BuildError.InvalidNodeAlias): + return + if isinstance(value, BuildError.RuntimeSetupFailed): + return + if isinstance(value, BuildError.ReadFailed): + return + if isinstance(value, BuildError.DangerousValue): + return + if isinstance(value, BuildError.WriteFailed): + return + if isinstance(value, BuildError.StoragePathAccessFailed): + return + if isinstance(value, BuildError.KvStoreSetupFailed): + return + if isinstance(value, BuildError.WalletSetupFailed): + return + if isinstance(value, BuildError.LoggerSetupFailed): + return + if isinstance(value, BuildError.NetworkMismatch): + return + if isinstance(value, BuildError.AsyncPaymentsConfigMismatch): + return + + @staticmethod + def write(value, buf): + if isinstance(value, BuildError.InvalidSeedBytes): + buf.write_i32(1) + if isinstance(value, BuildError.InvalidSeedFile): + buf.write_i32(2) + if isinstance(value, BuildError.InvalidSystemTime): + buf.write_i32(3) + if isinstance(value, BuildError.InvalidChannelMonitor): + buf.write_i32(4) + if isinstance(value, BuildError.InvalidListeningAddresses): + buf.write_i32(5) + if isinstance(value, BuildError.InvalidAnnouncementAddresses): + buf.write_i32(6) + if isinstance(value, BuildError.InvalidNodeAlias): + buf.write_i32(7) + if isinstance(value, BuildError.RuntimeSetupFailed): + buf.write_i32(8) + if isinstance(value, BuildError.ReadFailed): + buf.write_i32(9) + if isinstance(value, BuildError.DangerousValue): + buf.write_i32(10) + if isinstance(value, BuildError.WriteFailed): + buf.write_i32(11) + if isinstance(value, BuildError.StoragePathAccessFailed): + buf.write_i32(12) + if isinstance(value, BuildError.KvStoreSetupFailed): + buf.write_i32(13) + if isinstance(value, BuildError.WalletSetupFailed): + buf.write_i32(14) + if isinstance(value, BuildError.LoggerSetupFailed): + buf.write_i32(15) + if isinstance(value, BuildError.NetworkMismatch): + buf.write_i32(16) + if isinstance(value, BuildError.AsyncPaymentsConfigMismatch): + buf.write_i32(17) + + + + + +class ClosureReason: + def __init__(self): + raise RuntimeError("ClosureReason cannot be instantiated directly") + + # Each enum variant is a nested class of the enum itself. + class COUNTERPARTY_FORCE_CLOSED: + peer_msg: "UntrustedString" + + def __init__(self,peer_msg: "UntrustedString"): + self.peer_msg = peer_msg + + def __str__(self): + return "ClosureReason.COUNTERPARTY_FORCE_CLOSED(peer_msg={})".format(self.peer_msg) + + def __eq__(self, other): + if not other.is_counterparty_force_closed(): + return False + if self.peer_msg != other.peer_msg: + return False + return True + + class HOLDER_FORCE_CLOSED: + broadcasted_latest_txn: "typing.Optional[bool]" + message: "str" + + def __init__(self,broadcasted_latest_txn: "typing.Optional[bool]", message: "str"): + self.broadcasted_latest_txn = broadcasted_latest_txn + self.message = message + + def __str__(self): + return "ClosureReason.HOLDER_FORCE_CLOSED(broadcasted_latest_txn={}, message={})".format(self.broadcasted_latest_txn, self.message) + + def __eq__(self, other): + if not other.is_holder_force_closed(): + return False + if self.broadcasted_latest_txn != other.broadcasted_latest_txn: + return False + if self.message != other.message: + return False + return True + + class LEGACY_COOPERATIVE_CLOSURE: + + def __init__(self,): + pass + + def __str__(self): + return "ClosureReason.LEGACY_COOPERATIVE_CLOSURE()".format() + + def __eq__(self, other): + if not other.is_legacy_cooperative_closure(): + return False + return True + + class COUNTERPARTY_INITIATED_COOPERATIVE_CLOSURE: + + def __init__(self,): + pass + + def __str__(self): + return "ClosureReason.COUNTERPARTY_INITIATED_COOPERATIVE_CLOSURE()".format() + + def __eq__(self, other): + if not other.is_counterparty_initiated_cooperative_closure(): + return False + return True + + class LOCALLY_INITIATED_COOPERATIVE_CLOSURE: + + def __init__(self,): + pass + + def __str__(self): + return "ClosureReason.LOCALLY_INITIATED_COOPERATIVE_CLOSURE()".format() + + def __eq__(self, other): + if not other.is_locally_initiated_cooperative_closure(): + return False + return True + + class COMMITMENT_TX_CONFIRMED: + + def __init__(self,): + pass + + def __str__(self): + return "ClosureReason.COMMITMENT_TX_CONFIRMED()".format() + + def __eq__(self, other): + if not other.is_commitment_tx_confirmed(): + return False + return True + + class FUNDING_TIMED_OUT: + + def __init__(self,): + pass + + def __str__(self): + return "ClosureReason.FUNDING_TIMED_OUT()".format() + + def __eq__(self, other): + if not other.is_funding_timed_out(): + return False + return True + + class PROCESSING_ERROR: + err: "str" + + def __init__(self,err: "str"): + self.err = err + + def __str__(self): + return "ClosureReason.PROCESSING_ERROR(err={})".format(self.err) + + def __eq__(self, other): + if not other.is_processing_error(): + return False + if self.err != other.err: + return False + return True + + class DISCONNECTED_PEER: + + def __init__(self,): + pass + + def __str__(self): + return "ClosureReason.DISCONNECTED_PEER()".format() + + def __eq__(self, other): + if not other.is_disconnected_peer(): + return False + return True + + class OUTDATED_CHANNEL_MANAGER: + + def __init__(self,): + pass + + def __str__(self): + return "ClosureReason.OUTDATED_CHANNEL_MANAGER()".format() + + def __eq__(self, other): + if not other.is_outdated_channel_manager(): + return False + return True + + class COUNTERPARTY_COOP_CLOSED_UNFUNDED_CHANNEL: + + def __init__(self,): + pass + + def __str__(self): + return "ClosureReason.COUNTERPARTY_COOP_CLOSED_UNFUNDED_CHANNEL()".format() + + def __eq__(self, other): + if not other.is_counterparty_coop_closed_unfunded_channel(): + return False + return True + + class LOCALLY_COOP_CLOSED_UNFUNDED_CHANNEL: + + def __init__(self,): + pass + + def __str__(self): + return "ClosureReason.LOCALLY_COOP_CLOSED_UNFUNDED_CHANNEL()".format() + + def __eq__(self, other): + if not other.is_locally_coop_closed_unfunded_channel(): + return False + return True + + class FUNDING_BATCH_CLOSURE: + + def __init__(self,): + pass + + def __str__(self): + return "ClosureReason.FUNDING_BATCH_CLOSURE()".format() + + def __eq__(self, other): + if not other.is_funding_batch_closure(): + return False + return True + + class HTL_CS_TIMED_OUT: + payment_hash: "typing.Optional[PaymentHash]" + + def __init__(self,payment_hash: "typing.Optional[PaymentHash]"): + self.payment_hash = payment_hash + + def __str__(self): + return "ClosureReason.HTL_CS_TIMED_OUT(payment_hash={})".format(self.payment_hash) + + def __eq__(self, other): + if not other.is_htl_cs_timed_out(): + return False + if self.payment_hash != other.payment_hash: + return False + return True + + class PEER_FEERATE_TOO_LOW: + peer_feerate_sat_per_kw: "int" + required_feerate_sat_per_kw: "int" + + def __init__(self,peer_feerate_sat_per_kw: "int", required_feerate_sat_per_kw: "int"): + self.peer_feerate_sat_per_kw = peer_feerate_sat_per_kw + self.required_feerate_sat_per_kw = required_feerate_sat_per_kw + + def __str__(self): + return "ClosureReason.PEER_FEERATE_TOO_LOW(peer_feerate_sat_per_kw={}, required_feerate_sat_per_kw={})".format(self.peer_feerate_sat_per_kw, self.required_feerate_sat_per_kw) + + def __eq__(self, other): + if not other.is_peer_feerate_too_low(): + return False + if self.peer_feerate_sat_per_kw != other.peer_feerate_sat_per_kw: + return False + if self.required_feerate_sat_per_kw != other.required_feerate_sat_per_kw: + return False + return True + + + + # For each variant, we have an `is_NAME` method for easily checking + # whether an instance is that variant. + def is_counterparty_force_closed(self) -> bool: + return isinstance(self, ClosureReason.COUNTERPARTY_FORCE_CLOSED) + def is_holder_force_closed(self) -> bool: + return isinstance(self, ClosureReason.HOLDER_FORCE_CLOSED) + def is_legacy_cooperative_closure(self) -> bool: + return isinstance(self, ClosureReason.LEGACY_COOPERATIVE_CLOSURE) + def is_counterparty_initiated_cooperative_closure(self) -> bool: + return isinstance(self, ClosureReason.COUNTERPARTY_INITIATED_COOPERATIVE_CLOSURE) + def is_locally_initiated_cooperative_closure(self) -> bool: + return isinstance(self, ClosureReason.LOCALLY_INITIATED_COOPERATIVE_CLOSURE) + def is_commitment_tx_confirmed(self) -> bool: + return isinstance(self, ClosureReason.COMMITMENT_TX_CONFIRMED) + def is_funding_timed_out(self) -> bool: + return isinstance(self, ClosureReason.FUNDING_TIMED_OUT) + def is_processing_error(self) -> bool: + return isinstance(self, ClosureReason.PROCESSING_ERROR) + def is_disconnected_peer(self) -> bool: + return isinstance(self, ClosureReason.DISCONNECTED_PEER) + def is_outdated_channel_manager(self) -> bool: + return isinstance(self, ClosureReason.OUTDATED_CHANNEL_MANAGER) + def is_counterparty_coop_closed_unfunded_channel(self) -> bool: + return isinstance(self, ClosureReason.COUNTERPARTY_COOP_CLOSED_UNFUNDED_CHANNEL) + def is_locally_coop_closed_unfunded_channel(self) -> bool: + return isinstance(self, ClosureReason.LOCALLY_COOP_CLOSED_UNFUNDED_CHANNEL) + def is_funding_batch_closure(self) -> bool: + return isinstance(self, ClosureReason.FUNDING_BATCH_CLOSURE) + def is_htl_cs_timed_out(self) -> bool: + return isinstance(self, ClosureReason.HTL_CS_TIMED_OUT) + def is_peer_feerate_too_low(self) -> bool: + return isinstance(self, ClosureReason.PEER_FEERATE_TOO_LOW) + + +# Now, a little trick - we make each nested variant class be a subclass of the main +# enum class, so that method calls and instance checks etc will work intuitively. +# We might be able to do this a little more neatly with a metaclass, but this'll do. +ClosureReason.COUNTERPARTY_FORCE_CLOSED = type("ClosureReason.COUNTERPARTY_FORCE_CLOSED", (ClosureReason.COUNTERPARTY_FORCE_CLOSED, ClosureReason,), {}) # type: ignore +ClosureReason.HOLDER_FORCE_CLOSED = type("ClosureReason.HOLDER_FORCE_CLOSED", (ClosureReason.HOLDER_FORCE_CLOSED, ClosureReason,), {}) # type: ignore +ClosureReason.LEGACY_COOPERATIVE_CLOSURE = type("ClosureReason.LEGACY_COOPERATIVE_CLOSURE", (ClosureReason.LEGACY_COOPERATIVE_CLOSURE, ClosureReason,), {}) # type: ignore +ClosureReason.COUNTERPARTY_INITIATED_COOPERATIVE_CLOSURE = type("ClosureReason.COUNTERPARTY_INITIATED_COOPERATIVE_CLOSURE", (ClosureReason.COUNTERPARTY_INITIATED_COOPERATIVE_CLOSURE, ClosureReason,), {}) # type: ignore +ClosureReason.LOCALLY_INITIATED_COOPERATIVE_CLOSURE = type("ClosureReason.LOCALLY_INITIATED_COOPERATIVE_CLOSURE", (ClosureReason.LOCALLY_INITIATED_COOPERATIVE_CLOSURE, ClosureReason,), {}) # type: ignore +ClosureReason.COMMITMENT_TX_CONFIRMED = type("ClosureReason.COMMITMENT_TX_CONFIRMED", (ClosureReason.COMMITMENT_TX_CONFIRMED, ClosureReason,), {}) # type: ignore +ClosureReason.FUNDING_TIMED_OUT = type("ClosureReason.FUNDING_TIMED_OUT", (ClosureReason.FUNDING_TIMED_OUT, ClosureReason,), {}) # type: ignore +ClosureReason.PROCESSING_ERROR = type("ClosureReason.PROCESSING_ERROR", (ClosureReason.PROCESSING_ERROR, ClosureReason,), {}) # type: ignore +ClosureReason.DISCONNECTED_PEER = type("ClosureReason.DISCONNECTED_PEER", (ClosureReason.DISCONNECTED_PEER, ClosureReason,), {}) # type: ignore +ClosureReason.OUTDATED_CHANNEL_MANAGER = type("ClosureReason.OUTDATED_CHANNEL_MANAGER", (ClosureReason.OUTDATED_CHANNEL_MANAGER, ClosureReason,), {}) # type: ignore +ClosureReason.COUNTERPARTY_COOP_CLOSED_UNFUNDED_CHANNEL = type("ClosureReason.COUNTERPARTY_COOP_CLOSED_UNFUNDED_CHANNEL", (ClosureReason.COUNTERPARTY_COOP_CLOSED_UNFUNDED_CHANNEL, ClosureReason,), {}) # type: ignore +ClosureReason.LOCALLY_COOP_CLOSED_UNFUNDED_CHANNEL = type("ClosureReason.LOCALLY_COOP_CLOSED_UNFUNDED_CHANNEL", (ClosureReason.LOCALLY_COOP_CLOSED_UNFUNDED_CHANNEL, ClosureReason,), {}) # type: ignore +ClosureReason.FUNDING_BATCH_CLOSURE = type("ClosureReason.FUNDING_BATCH_CLOSURE", (ClosureReason.FUNDING_BATCH_CLOSURE, ClosureReason,), {}) # type: ignore +ClosureReason.HTL_CS_TIMED_OUT = type("ClosureReason.HTL_CS_TIMED_OUT", (ClosureReason.HTL_CS_TIMED_OUT, ClosureReason,), {}) # type: ignore +ClosureReason.PEER_FEERATE_TOO_LOW = type("ClosureReason.PEER_FEERATE_TOO_LOW", (ClosureReason.PEER_FEERATE_TOO_LOW, ClosureReason,), {}) # type: ignore + + + + +class _UniffiConverterTypeClosureReason(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return ClosureReason.COUNTERPARTY_FORCE_CLOSED( + _UniffiConverterTypeUntrustedString.read(buf), + ) + if variant == 2: + return ClosureReason.HOLDER_FORCE_CLOSED( + _UniffiConverterOptionalBool.read(buf), + _UniffiConverterString.read(buf), + ) + if variant == 3: + return ClosureReason.LEGACY_COOPERATIVE_CLOSURE( + ) + if variant == 4: + return ClosureReason.COUNTERPARTY_INITIATED_COOPERATIVE_CLOSURE( + ) + if variant == 5: + return ClosureReason.LOCALLY_INITIATED_COOPERATIVE_CLOSURE( + ) + if variant == 6: + return ClosureReason.COMMITMENT_TX_CONFIRMED( + ) + if variant == 7: + return ClosureReason.FUNDING_TIMED_OUT( + ) + if variant == 8: + return ClosureReason.PROCESSING_ERROR( + _UniffiConverterString.read(buf), + ) + if variant == 9: + return ClosureReason.DISCONNECTED_PEER( + ) + if variant == 10: + return ClosureReason.OUTDATED_CHANNEL_MANAGER( + ) + if variant == 11: + return ClosureReason.COUNTERPARTY_COOP_CLOSED_UNFUNDED_CHANNEL( + ) + if variant == 12: + return ClosureReason.LOCALLY_COOP_CLOSED_UNFUNDED_CHANNEL( + ) + if variant == 13: + return ClosureReason.FUNDING_BATCH_CLOSURE( + ) + if variant == 14: + return ClosureReason.HTL_CS_TIMED_OUT( + _UniffiConverterOptionalTypePaymentHash.read(buf), + ) + if variant == 15: + return ClosureReason.PEER_FEERATE_TOO_LOW( + _UniffiConverterUInt32.read(buf), + _UniffiConverterUInt32.read(buf), + ) + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if value.is_counterparty_force_closed(): + _UniffiConverterTypeUntrustedString.check_lower(value.peer_msg) + return + if value.is_holder_force_closed(): + _UniffiConverterOptionalBool.check_lower(value.broadcasted_latest_txn) + _UniffiConverterString.check_lower(value.message) + return + if value.is_legacy_cooperative_closure(): + return + if value.is_counterparty_initiated_cooperative_closure(): + return + if value.is_locally_initiated_cooperative_closure(): + return + if value.is_commitment_tx_confirmed(): + return + if value.is_funding_timed_out(): + return + if value.is_processing_error(): + _UniffiConverterString.check_lower(value.err) + return + if value.is_disconnected_peer(): + return + if value.is_outdated_channel_manager(): + return + if value.is_counterparty_coop_closed_unfunded_channel(): + return + if value.is_locally_coop_closed_unfunded_channel(): + return + if value.is_funding_batch_closure(): + return + if value.is_htl_cs_timed_out(): + _UniffiConverterOptionalTypePaymentHash.check_lower(value.payment_hash) + return + if value.is_peer_feerate_too_low(): + _UniffiConverterUInt32.check_lower(value.peer_feerate_sat_per_kw) + _UniffiConverterUInt32.check_lower(value.required_feerate_sat_per_kw) + return + raise ValueError(value) + + @staticmethod + def write(value, buf): + if value.is_counterparty_force_closed(): + buf.write_i32(1) + _UniffiConverterTypeUntrustedString.write(value.peer_msg, buf) + if value.is_holder_force_closed(): + buf.write_i32(2) + _UniffiConverterOptionalBool.write(value.broadcasted_latest_txn, buf) + _UniffiConverterString.write(value.message, buf) + if value.is_legacy_cooperative_closure(): + buf.write_i32(3) + if value.is_counterparty_initiated_cooperative_closure(): + buf.write_i32(4) + if value.is_locally_initiated_cooperative_closure(): + buf.write_i32(5) + if value.is_commitment_tx_confirmed(): + buf.write_i32(6) + if value.is_funding_timed_out(): + buf.write_i32(7) + if value.is_processing_error(): + buf.write_i32(8) + _UniffiConverterString.write(value.err, buf) + if value.is_disconnected_peer(): + buf.write_i32(9) + if value.is_outdated_channel_manager(): + buf.write_i32(10) + if value.is_counterparty_coop_closed_unfunded_channel(): + buf.write_i32(11) + if value.is_locally_coop_closed_unfunded_channel(): + buf.write_i32(12) + if value.is_funding_batch_closure(): + buf.write_i32(13) + if value.is_htl_cs_timed_out(): + buf.write_i32(14) + _UniffiConverterOptionalTypePaymentHash.write(value.payment_hash, buf) + if value.is_peer_feerate_too_low(): + buf.write_i32(15) + _UniffiConverterUInt32.write(value.peer_feerate_sat_per_kw, buf) + _UniffiConverterUInt32.write(value.required_feerate_sat_per_kw, buf) + + + + + + + +class CoinSelectionAlgorithm(enum.Enum): + BRANCH_AND_BOUND = 0 + + LARGEST_FIRST = 1 + + OLDEST_FIRST = 2 + + SINGLE_RANDOM_DRAW = 3 + + + +class _UniffiConverterTypeCoinSelectionAlgorithm(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return CoinSelectionAlgorithm.BRANCH_AND_BOUND + if variant == 2: + return CoinSelectionAlgorithm.LARGEST_FIRST + if variant == 3: + return CoinSelectionAlgorithm.OLDEST_FIRST + if variant == 4: + return CoinSelectionAlgorithm.SINGLE_RANDOM_DRAW + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if value == CoinSelectionAlgorithm.BRANCH_AND_BOUND: + return + if value == CoinSelectionAlgorithm.LARGEST_FIRST: + return + if value == CoinSelectionAlgorithm.OLDEST_FIRST: + return + if value == CoinSelectionAlgorithm.SINGLE_RANDOM_DRAW: + return + raise ValueError(value) + + @staticmethod + def write(value, buf): + if value == CoinSelectionAlgorithm.BRANCH_AND_BOUND: + buf.write_i32(1) + if value == CoinSelectionAlgorithm.LARGEST_FIRST: + buf.write_i32(2) + if value == CoinSelectionAlgorithm.OLDEST_FIRST: + buf.write_i32(3) + if value == CoinSelectionAlgorithm.SINGLE_RANDOM_DRAW: + buf.write_i32(4) + + + + + + + +class ConfirmationStatus: + def __init__(self): + raise RuntimeError("ConfirmationStatus cannot be instantiated directly") + + # Each enum variant is a nested class of the enum itself. + class CONFIRMED: + block_hash: "BlockHash" + height: "int" + timestamp: "int" + + def __init__(self,block_hash: "BlockHash", height: "int", timestamp: "int"): + self.block_hash = block_hash + self.height = height + self.timestamp = timestamp + + def __str__(self): + return "ConfirmationStatus.CONFIRMED(block_hash={}, height={}, timestamp={})".format(self.block_hash, self.height, self.timestamp) + + def __eq__(self, other): + if not other.is_confirmed(): + return False + if self.block_hash != other.block_hash: + return False + if self.height != other.height: + return False + if self.timestamp != other.timestamp: + return False + return True + + class UNCONFIRMED: + + def __init__(self,): + pass + + def __str__(self): + return "ConfirmationStatus.UNCONFIRMED()".format() + + def __eq__(self, other): + if not other.is_unconfirmed(): + return False + return True + + + + # For each variant, we have an `is_NAME` method for easily checking + # whether an instance is that variant. + def is_confirmed(self) -> bool: + return isinstance(self, ConfirmationStatus.CONFIRMED) + def is_unconfirmed(self) -> bool: + return isinstance(self, ConfirmationStatus.UNCONFIRMED) + + +# Now, a little trick - we make each nested variant class be a subclass of the main +# enum class, so that method calls and instance checks etc will work intuitively. +# We might be able to do this a little more neatly with a metaclass, but this'll do. +ConfirmationStatus.CONFIRMED = type("ConfirmationStatus.CONFIRMED", (ConfirmationStatus.CONFIRMED, ConfirmationStatus,), {}) # type: ignore +ConfirmationStatus.UNCONFIRMED = type("ConfirmationStatus.UNCONFIRMED", (ConfirmationStatus.UNCONFIRMED, ConfirmationStatus,), {}) # type: ignore + + + + +class _UniffiConverterTypeConfirmationStatus(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return ConfirmationStatus.CONFIRMED( + _UniffiConverterTypeBlockHash.read(buf), + _UniffiConverterUInt32.read(buf), + _UniffiConverterUInt64.read(buf), + ) + if variant == 2: + return ConfirmationStatus.UNCONFIRMED( + ) + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if value.is_confirmed(): + _UniffiConverterTypeBlockHash.check_lower(value.block_hash) + _UniffiConverterUInt32.check_lower(value.height) + _UniffiConverterUInt64.check_lower(value.timestamp) + return + if value.is_unconfirmed(): + return + raise ValueError(value) + + @staticmethod + def write(value, buf): + if value.is_confirmed(): + buf.write_i32(1) + _UniffiConverterTypeBlockHash.write(value.block_hash, buf) + _UniffiConverterUInt32.write(value.height, buf) + _UniffiConverterUInt64.write(value.timestamp, buf) + if value.is_unconfirmed(): + buf.write_i32(2) + + + + + + + +class Currency(enum.Enum): + BITCOIN = 0 + + BITCOIN_TESTNET = 1 + + REGTEST = 2 + + SIMNET = 3 + + SIGNET = 4 + + + +class _UniffiConverterTypeCurrency(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return Currency.BITCOIN + if variant == 2: + return Currency.BITCOIN_TESTNET + if variant == 3: + return Currency.REGTEST + if variant == 4: + return Currency.SIMNET + if variant == 5: + return Currency.SIGNET + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if value == Currency.BITCOIN: + return + if value == Currency.BITCOIN_TESTNET: + return + if value == Currency.REGTEST: + return + if value == Currency.SIMNET: + return + if value == Currency.SIGNET: + return + raise ValueError(value) + + @staticmethod + def write(value, buf): + if value == Currency.BITCOIN: + buf.write_i32(1) + if value == Currency.BITCOIN_TESTNET: + buf.write_i32(2) + if value == Currency.REGTEST: + buf.write_i32(3) + if value == Currency.SIMNET: + buf.write_i32(4) + if value == Currency.SIGNET: + buf.write_i32(5) + + + + + + + +class Event: + def __init__(self): + raise RuntimeError("Event cannot be instantiated directly") + + # Each enum variant is a nested class of the enum itself. + class PAYMENT_SUCCESSFUL: + payment_id: "typing.Optional[PaymentId]" + payment_hash: "PaymentHash" + payment_preimage: "typing.Optional[PaymentPreimage]" + fee_paid_msat: "typing.Optional[int]" + + def __init__(self,payment_id: "typing.Optional[PaymentId]", payment_hash: "PaymentHash", payment_preimage: "typing.Optional[PaymentPreimage]", fee_paid_msat: "typing.Optional[int]"): + self.payment_id = payment_id + self.payment_hash = payment_hash + self.payment_preimage = payment_preimage + self.fee_paid_msat = fee_paid_msat + + def __str__(self): + return "Event.PAYMENT_SUCCESSFUL(payment_id={}, payment_hash={}, payment_preimage={}, fee_paid_msat={})".format(self.payment_id, self.payment_hash, self.payment_preimage, self.fee_paid_msat) + + def __eq__(self, other): + if not other.is_payment_successful(): + return False + if self.payment_id != other.payment_id: + return False + if self.payment_hash != other.payment_hash: + return False + if self.payment_preimage != other.payment_preimage: + return False + if self.fee_paid_msat != other.fee_paid_msat: + return False + return True + + class PAYMENT_FAILED: + payment_id: "typing.Optional[PaymentId]" + payment_hash: "typing.Optional[PaymentHash]" + reason: "typing.Optional[PaymentFailureReason]" + + def __init__(self,payment_id: "typing.Optional[PaymentId]", payment_hash: "typing.Optional[PaymentHash]", reason: "typing.Optional[PaymentFailureReason]"): + self.payment_id = payment_id + self.payment_hash = payment_hash + self.reason = reason + + def __str__(self): + return "Event.PAYMENT_FAILED(payment_id={}, payment_hash={}, reason={})".format(self.payment_id, self.payment_hash, self.reason) + + def __eq__(self, other): + if not other.is_payment_failed(): + return False + if self.payment_id != other.payment_id: + return False + if self.payment_hash != other.payment_hash: + return False + if self.reason != other.reason: + return False + return True + + class PAYMENT_RECEIVED: + payment_id: "typing.Optional[PaymentId]" + payment_hash: "PaymentHash" + amount_msat: "int" + custom_records: "typing.List[CustomTlvRecord]" + + def __init__(self,payment_id: "typing.Optional[PaymentId]", payment_hash: "PaymentHash", amount_msat: "int", custom_records: "typing.List[CustomTlvRecord]"): + self.payment_id = payment_id + self.payment_hash = payment_hash + self.amount_msat = amount_msat + self.custom_records = custom_records + + def __str__(self): + return "Event.PAYMENT_RECEIVED(payment_id={}, payment_hash={}, amount_msat={}, custom_records={})".format(self.payment_id, self.payment_hash, self.amount_msat, self.custom_records) + + def __eq__(self, other): + if not other.is_payment_received(): + return False + if self.payment_id != other.payment_id: + return False + if self.payment_hash != other.payment_hash: + return False + if self.amount_msat != other.amount_msat: + return False + if self.custom_records != other.custom_records: + return False + return True + + class PAYMENT_CLAIMABLE: + payment_id: "PaymentId" + payment_hash: "PaymentHash" + claimable_amount_msat: "int" + claim_deadline: "typing.Optional[int]" + custom_records: "typing.List[CustomTlvRecord]" + + def __init__(self,payment_id: "PaymentId", payment_hash: "PaymentHash", claimable_amount_msat: "int", claim_deadline: "typing.Optional[int]", custom_records: "typing.List[CustomTlvRecord]"): + self.payment_id = payment_id + self.payment_hash = payment_hash + self.claimable_amount_msat = claimable_amount_msat + self.claim_deadline = claim_deadline + self.custom_records = custom_records + + def __str__(self): + return "Event.PAYMENT_CLAIMABLE(payment_id={}, payment_hash={}, claimable_amount_msat={}, claim_deadline={}, custom_records={})".format(self.payment_id, self.payment_hash, self.claimable_amount_msat, self.claim_deadline, self.custom_records) + + def __eq__(self, other): + if not other.is_payment_claimable(): + return False + if self.payment_id != other.payment_id: + return False + if self.payment_hash != other.payment_hash: + return False + if self.claimable_amount_msat != other.claimable_amount_msat: + return False + if self.claim_deadline != other.claim_deadline: + return False + if self.custom_records != other.custom_records: + return False + return True + + class PAYMENT_FORWARDED: + prev_channel_id: "ChannelId" + next_channel_id: "ChannelId" + prev_user_channel_id: "typing.Optional[UserChannelId]" + next_user_channel_id: "typing.Optional[UserChannelId]" + prev_node_id: "typing.Optional[PublicKey]" + next_node_id: "typing.Optional[PublicKey]" + total_fee_earned_msat: "typing.Optional[int]" + skimmed_fee_msat: "typing.Optional[int]" + claim_from_onchain_tx: "bool" + outbound_amount_forwarded_msat: "typing.Optional[int]" + + def __init__(self,prev_channel_id: "ChannelId", next_channel_id: "ChannelId", prev_user_channel_id: "typing.Optional[UserChannelId]", next_user_channel_id: "typing.Optional[UserChannelId]", prev_node_id: "typing.Optional[PublicKey]", next_node_id: "typing.Optional[PublicKey]", total_fee_earned_msat: "typing.Optional[int]", skimmed_fee_msat: "typing.Optional[int]", claim_from_onchain_tx: "bool", outbound_amount_forwarded_msat: "typing.Optional[int]"): + self.prev_channel_id = prev_channel_id + self.next_channel_id = next_channel_id + self.prev_user_channel_id = prev_user_channel_id + self.next_user_channel_id = next_user_channel_id + self.prev_node_id = prev_node_id + self.next_node_id = next_node_id + self.total_fee_earned_msat = total_fee_earned_msat + self.skimmed_fee_msat = skimmed_fee_msat + self.claim_from_onchain_tx = claim_from_onchain_tx + self.outbound_amount_forwarded_msat = outbound_amount_forwarded_msat + + def __str__(self): + return "Event.PAYMENT_FORWARDED(prev_channel_id={}, next_channel_id={}, prev_user_channel_id={}, next_user_channel_id={}, prev_node_id={}, next_node_id={}, total_fee_earned_msat={}, skimmed_fee_msat={}, claim_from_onchain_tx={}, outbound_amount_forwarded_msat={})".format(self.prev_channel_id, self.next_channel_id, self.prev_user_channel_id, self.next_user_channel_id, self.prev_node_id, self.next_node_id, self.total_fee_earned_msat, self.skimmed_fee_msat, self.claim_from_onchain_tx, self.outbound_amount_forwarded_msat) + + def __eq__(self, other): + if not other.is_payment_forwarded(): + return False + if self.prev_channel_id != other.prev_channel_id: + return False + if self.next_channel_id != other.next_channel_id: + return False + if self.prev_user_channel_id != other.prev_user_channel_id: + return False + if self.next_user_channel_id != other.next_user_channel_id: + return False + if self.prev_node_id != other.prev_node_id: + return False + if self.next_node_id != other.next_node_id: + return False + if self.total_fee_earned_msat != other.total_fee_earned_msat: + return False + if self.skimmed_fee_msat != other.skimmed_fee_msat: + return False + if self.claim_from_onchain_tx != other.claim_from_onchain_tx: + return False + if self.outbound_amount_forwarded_msat != other.outbound_amount_forwarded_msat: + return False + return True + + class PROBE_SUCCESSFUL: + payment_id: "PaymentId" + payment_hash: "PaymentHash" + route_fee_msat: "typing.Optional[int]" + + def __init__(self,payment_id: "PaymentId", payment_hash: "PaymentHash", route_fee_msat: "typing.Optional[int]"): + self.payment_id = payment_id + self.payment_hash = payment_hash + self.route_fee_msat = route_fee_msat + + def __str__(self): + return "Event.PROBE_SUCCESSFUL(payment_id={}, payment_hash={}, route_fee_msat={})".format(self.payment_id, self.payment_hash, self.route_fee_msat) + + def __eq__(self, other): + if not other.is_probe_successful(): + return False + if self.payment_id != other.payment_id: + return False + if self.payment_hash != other.payment_hash: + return False + if self.route_fee_msat != other.route_fee_msat: + return False + return True + + class PROBE_FAILED: + payment_id: "PaymentId" + payment_hash: "PaymentHash" + short_channel_id: "typing.Optional[int]" + route_fee_msat: "typing.Optional[int]" + + def __init__(self,payment_id: "PaymentId", payment_hash: "PaymentHash", short_channel_id: "typing.Optional[int]", route_fee_msat: "typing.Optional[int]"): + self.payment_id = payment_id + self.payment_hash = payment_hash + self.short_channel_id = short_channel_id + self.route_fee_msat = route_fee_msat + + def __str__(self): + return "Event.PROBE_FAILED(payment_id={}, payment_hash={}, short_channel_id={}, route_fee_msat={})".format(self.payment_id, self.payment_hash, self.short_channel_id, self.route_fee_msat) + + def __eq__(self, other): + if not other.is_probe_failed(): + return False + if self.payment_id != other.payment_id: + return False + if self.payment_hash != other.payment_hash: + return False + if self.short_channel_id != other.short_channel_id: + return False + if self.route_fee_msat != other.route_fee_msat: + return False + return True + + class CHANNEL_PENDING: + channel_id: "ChannelId" + user_channel_id: "UserChannelId" + former_temporary_channel_id: "ChannelId" + counterparty_node_id: "PublicKey" + funding_txo: "OutPoint" + + def __init__(self,channel_id: "ChannelId", user_channel_id: "UserChannelId", former_temporary_channel_id: "ChannelId", counterparty_node_id: "PublicKey", funding_txo: "OutPoint"): + self.channel_id = channel_id + self.user_channel_id = user_channel_id + self.former_temporary_channel_id = former_temporary_channel_id + self.counterparty_node_id = counterparty_node_id + self.funding_txo = funding_txo + + def __str__(self): + return "Event.CHANNEL_PENDING(channel_id={}, user_channel_id={}, former_temporary_channel_id={}, counterparty_node_id={}, funding_txo={})".format(self.channel_id, self.user_channel_id, self.former_temporary_channel_id, self.counterparty_node_id, self.funding_txo) + + def __eq__(self, other): + if not other.is_channel_pending(): + return False + if self.channel_id != other.channel_id: + return False + if self.user_channel_id != other.user_channel_id: + return False + if self.former_temporary_channel_id != other.former_temporary_channel_id: + return False + if self.counterparty_node_id != other.counterparty_node_id: + return False + if self.funding_txo != other.funding_txo: + return False + return True + + class CHANNEL_READY: + channel_id: "ChannelId" + user_channel_id: "UserChannelId" + counterparty_node_id: "typing.Optional[PublicKey]" + funding_txo: "typing.Optional[OutPoint]" + + def __init__(self,channel_id: "ChannelId", user_channel_id: "UserChannelId", counterparty_node_id: "typing.Optional[PublicKey]", funding_txo: "typing.Optional[OutPoint]"): + self.channel_id = channel_id + self.user_channel_id = user_channel_id + self.counterparty_node_id = counterparty_node_id + self.funding_txo = funding_txo + + def __str__(self): + return "Event.CHANNEL_READY(channel_id={}, user_channel_id={}, counterparty_node_id={}, funding_txo={})".format(self.channel_id, self.user_channel_id, self.counterparty_node_id, self.funding_txo) + + def __eq__(self, other): + if not other.is_channel_ready(): + return False + if self.channel_id != other.channel_id: + return False + if self.user_channel_id != other.user_channel_id: + return False + if self.counterparty_node_id != other.counterparty_node_id: + return False + if self.funding_txo != other.funding_txo: + return False + return True + + class CHANNEL_CLOSED: + channel_id: "ChannelId" + user_channel_id: "UserChannelId" + counterparty_node_id: "typing.Optional[PublicKey]" + reason: "typing.Optional[ClosureReason]" + + def __init__(self,channel_id: "ChannelId", user_channel_id: "UserChannelId", counterparty_node_id: "typing.Optional[PublicKey]", reason: "typing.Optional[ClosureReason]"): + self.channel_id = channel_id + self.user_channel_id = user_channel_id + self.counterparty_node_id = counterparty_node_id + self.reason = reason + + def __str__(self): + return "Event.CHANNEL_CLOSED(channel_id={}, user_channel_id={}, counterparty_node_id={}, reason={})".format(self.channel_id, self.user_channel_id, self.counterparty_node_id, self.reason) + + def __eq__(self, other): + if not other.is_channel_closed(): + return False + if self.channel_id != other.channel_id: + return False + if self.user_channel_id != other.user_channel_id: + return False + if self.counterparty_node_id != other.counterparty_node_id: + return False + if self.reason != other.reason: + return False + return True + + class SPLICE_PENDING: + channel_id: "ChannelId" + user_channel_id: "UserChannelId" + counterparty_node_id: "PublicKey" + new_funding_txo: "OutPoint" + + def __init__(self,channel_id: "ChannelId", user_channel_id: "UserChannelId", counterparty_node_id: "PublicKey", new_funding_txo: "OutPoint"): + self.channel_id = channel_id + self.user_channel_id = user_channel_id + self.counterparty_node_id = counterparty_node_id + self.new_funding_txo = new_funding_txo + + def __str__(self): + return "Event.SPLICE_PENDING(channel_id={}, user_channel_id={}, counterparty_node_id={}, new_funding_txo={})".format(self.channel_id, self.user_channel_id, self.counterparty_node_id, self.new_funding_txo) + + def __eq__(self, other): + if not other.is_splice_pending(): + return False + if self.channel_id != other.channel_id: + return False + if self.user_channel_id != other.user_channel_id: + return False + if self.counterparty_node_id != other.counterparty_node_id: + return False + if self.new_funding_txo != other.new_funding_txo: + return False + return True + + class SPLICE_FAILED: + channel_id: "ChannelId" + user_channel_id: "UserChannelId" + counterparty_node_id: "PublicKey" + abandoned_funding_txo: "typing.Optional[OutPoint]" + + def __init__(self,channel_id: "ChannelId", user_channel_id: "UserChannelId", counterparty_node_id: "PublicKey", abandoned_funding_txo: "typing.Optional[OutPoint]"): + self.channel_id = channel_id + self.user_channel_id = user_channel_id + self.counterparty_node_id = counterparty_node_id + self.abandoned_funding_txo = abandoned_funding_txo + + def __str__(self): + return "Event.SPLICE_FAILED(channel_id={}, user_channel_id={}, counterparty_node_id={}, abandoned_funding_txo={})".format(self.channel_id, self.user_channel_id, self.counterparty_node_id, self.abandoned_funding_txo) + + def __eq__(self, other): + if not other.is_splice_failed(): + return False + if self.channel_id != other.channel_id: + return False + if self.user_channel_id != other.user_channel_id: + return False + if self.counterparty_node_id != other.counterparty_node_id: + return False + if self.abandoned_funding_txo != other.abandoned_funding_txo: + return False + return True + + class ONCHAIN_TRANSACTION_CONFIRMED: + txid: "Txid" + block_hash: "BlockHash" + block_height: "int" + confirmation_time: "int" + details: "TransactionDetails" + + def __init__(self,txid: "Txid", block_hash: "BlockHash", block_height: "int", confirmation_time: "int", details: "TransactionDetails"): + self.txid = txid + self.block_hash = block_hash + self.block_height = block_height + self.confirmation_time = confirmation_time + self.details = details + + def __str__(self): + return "Event.ONCHAIN_TRANSACTION_CONFIRMED(txid={}, block_hash={}, block_height={}, confirmation_time={}, details={})".format(self.txid, self.block_hash, self.block_height, self.confirmation_time, self.details) + + def __eq__(self, other): + if not other.is_onchain_transaction_confirmed(): + return False + if self.txid != other.txid: + return False + if self.block_hash != other.block_hash: + return False + if self.block_height != other.block_height: + return False + if self.confirmation_time != other.confirmation_time: + return False + if self.details != other.details: + return False + return True + + class ONCHAIN_TRANSACTION_RECEIVED: + txid: "Txid" + details: "TransactionDetails" + + def __init__(self,txid: "Txid", details: "TransactionDetails"): + self.txid = txid + self.details = details + + def __str__(self): + return "Event.ONCHAIN_TRANSACTION_RECEIVED(txid={}, details={})".format(self.txid, self.details) + + def __eq__(self, other): + if not other.is_onchain_transaction_received(): + return False + if self.txid != other.txid: + return False + if self.details != other.details: + return False + return True + + class ONCHAIN_TRANSACTION_REPLACED: + txid: "Txid" + conflicts: "typing.List[Txid]" + + def __init__(self,txid: "Txid", conflicts: "typing.List[Txid]"): + self.txid = txid + self.conflicts = conflicts + + def __str__(self): + return "Event.ONCHAIN_TRANSACTION_REPLACED(txid={}, conflicts={})".format(self.txid, self.conflicts) + + def __eq__(self, other): + if not other.is_onchain_transaction_replaced(): + return False + if self.txid != other.txid: + return False + if self.conflicts != other.conflicts: + return False + return True + + class ONCHAIN_TRANSACTION_REORGED: + txid: "Txid" + + def __init__(self,txid: "Txid"): + self.txid = txid + + def __str__(self): + return "Event.ONCHAIN_TRANSACTION_REORGED(txid={})".format(self.txid) + + def __eq__(self, other): + if not other.is_onchain_transaction_reorged(): + return False + if self.txid != other.txid: + return False + return True + + class ONCHAIN_TRANSACTION_EVICTED: + txid: "Txid" + + def __init__(self,txid: "Txid"): + self.txid = txid + + def __str__(self): + return "Event.ONCHAIN_TRANSACTION_EVICTED(txid={})".format(self.txid) + + def __eq__(self, other): + if not other.is_onchain_transaction_evicted(): + return False + if self.txid != other.txid: + return False + return True + + class SYNC_PROGRESS: + sync_type: "SyncType" + progress_percent: "int" + current_block_height: "int" + target_block_height: "int" + + def __init__(self,sync_type: "SyncType", progress_percent: "int", current_block_height: "int", target_block_height: "int"): + self.sync_type = sync_type + self.progress_percent = progress_percent + self.current_block_height = current_block_height + self.target_block_height = target_block_height + + def __str__(self): + return "Event.SYNC_PROGRESS(sync_type={}, progress_percent={}, current_block_height={}, target_block_height={})".format(self.sync_type, self.progress_percent, self.current_block_height, self.target_block_height) + + def __eq__(self, other): + if not other.is_sync_progress(): + return False + if self.sync_type != other.sync_type: + return False + if self.progress_percent != other.progress_percent: + return False + if self.current_block_height != other.current_block_height: + return False + if self.target_block_height != other.target_block_height: + return False + return True + + class SYNC_COMPLETED: + sync_type: "SyncType" + synced_block_height: "int" + + def __init__(self,sync_type: "SyncType", synced_block_height: "int"): + self.sync_type = sync_type + self.synced_block_height = synced_block_height + + def __str__(self): + return "Event.SYNC_COMPLETED(sync_type={}, synced_block_height={})".format(self.sync_type, self.synced_block_height) + + def __eq__(self, other): + if not other.is_sync_completed(): + return False + if self.sync_type != other.sync_type: + return False + if self.synced_block_height != other.synced_block_height: + return False + return True + + class BALANCE_CHANGED: + old_spendable_onchain_balance_sats: "int" + new_spendable_onchain_balance_sats: "int" + old_total_onchain_balance_sats: "int" + new_total_onchain_balance_sats: "int" + old_total_lightning_balance_sats: "int" + new_total_lightning_balance_sats: "int" + + def __init__(self,old_spendable_onchain_balance_sats: "int", new_spendable_onchain_balance_sats: "int", old_total_onchain_balance_sats: "int", new_total_onchain_balance_sats: "int", old_total_lightning_balance_sats: "int", new_total_lightning_balance_sats: "int"): + self.old_spendable_onchain_balance_sats = old_spendable_onchain_balance_sats + self.new_spendable_onchain_balance_sats = new_spendable_onchain_balance_sats + self.old_total_onchain_balance_sats = old_total_onchain_balance_sats + self.new_total_onchain_balance_sats = new_total_onchain_balance_sats + self.old_total_lightning_balance_sats = old_total_lightning_balance_sats + self.new_total_lightning_balance_sats = new_total_lightning_balance_sats + + def __str__(self): + return "Event.BALANCE_CHANGED(old_spendable_onchain_balance_sats={}, new_spendable_onchain_balance_sats={}, old_total_onchain_balance_sats={}, new_total_onchain_balance_sats={}, old_total_lightning_balance_sats={}, new_total_lightning_balance_sats={})".format(self.old_spendable_onchain_balance_sats, self.new_spendable_onchain_balance_sats, self.old_total_onchain_balance_sats, self.new_total_onchain_balance_sats, self.old_total_lightning_balance_sats, self.new_total_lightning_balance_sats) + + def __eq__(self, other): + if not other.is_balance_changed(): + return False + if self.old_spendable_onchain_balance_sats != other.old_spendable_onchain_balance_sats: + return False + if self.new_spendable_onchain_balance_sats != other.new_spendable_onchain_balance_sats: + return False + if self.old_total_onchain_balance_sats != other.old_total_onchain_balance_sats: + return False + if self.new_total_onchain_balance_sats != other.new_total_onchain_balance_sats: + return False + if self.old_total_lightning_balance_sats != other.old_total_lightning_balance_sats: + return False + if self.new_total_lightning_balance_sats != other.new_total_lightning_balance_sats: + return False + return True + + + + # For each variant, we have an `is_NAME` method for easily checking + # whether an instance is that variant. + def is_payment_successful(self) -> bool: + return isinstance(self, Event.PAYMENT_SUCCESSFUL) + def is_payment_failed(self) -> bool: + return isinstance(self, Event.PAYMENT_FAILED) + def is_payment_received(self) -> bool: + return isinstance(self, Event.PAYMENT_RECEIVED) + def is_payment_claimable(self) -> bool: + return isinstance(self, Event.PAYMENT_CLAIMABLE) + def is_payment_forwarded(self) -> bool: + return isinstance(self, Event.PAYMENT_FORWARDED) + def is_probe_successful(self) -> bool: + return isinstance(self, Event.PROBE_SUCCESSFUL) + def is_probe_failed(self) -> bool: + return isinstance(self, Event.PROBE_FAILED) + def is_channel_pending(self) -> bool: + return isinstance(self, Event.CHANNEL_PENDING) + def is_channel_ready(self) -> bool: + return isinstance(self, Event.CHANNEL_READY) + def is_channel_closed(self) -> bool: + return isinstance(self, Event.CHANNEL_CLOSED) + def is_splice_pending(self) -> bool: + return isinstance(self, Event.SPLICE_PENDING) + def is_splice_failed(self) -> bool: + return isinstance(self, Event.SPLICE_FAILED) + def is_onchain_transaction_confirmed(self) -> bool: + return isinstance(self, Event.ONCHAIN_TRANSACTION_CONFIRMED) + def is_onchain_transaction_received(self) -> bool: + return isinstance(self, Event.ONCHAIN_TRANSACTION_RECEIVED) + def is_onchain_transaction_replaced(self) -> bool: + return isinstance(self, Event.ONCHAIN_TRANSACTION_REPLACED) + def is_onchain_transaction_reorged(self) -> bool: + return isinstance(self, Event.ONCHAIN_TRANSACTION_REORGED) + def is_onchain_transaction_evicted(self) -> bool: + return isinstance(self, Event.ONCHAIN_TRANSACTION_EVICTED) + def is_sync_progress(self) -> bool: + return isinstance(self, Event.SYNC_PROGRESS) + def is_sync_completed(self) -> bool: + return isinstance(self, Event.SYNC_COMPLETED) + def is_balance_changed(self) -> bool: + return isinstance(self, Event.BALANCE_CHANGED) + + +# Now, a little trick - we make each nested variant class be a subclass of the main +# enum class, so that method calls and instance checks etc will work intuitively. +# We might be able to do this a little more neatly with a metaclass, but this'll do. +Event.PAYMENT_SUCCESSFUL = type("Event.PAYMENT_SUCCESSFUL", (Event.PAYMENT_SUCCESSFUL, Event,), {}) # type: ignore +Event.PAYMENT_FAILED = type("Event.PAYMENT_FAILED", (Event.PAYMENT_FAILED, Event,), {}) # type: ignore +Event.PAYMENT_RECEIVED = type("Event.PAYMENT_RECEIVED", (Event.PAYMENT_RECEIVED, Event,), {}) # type: ignore +Event.PAYMENT_CLAIMABLE = type("Event.PAYMENT_CLAIMABLE", (Event.PAYMENT_CLAIMABLE, Event,), {}) # type: ignore +Event.PAYMENT_FORWARDED = type("Event.PAYMENT_FORWARDED", (Event.PAYMENT_FORWARDED, Event,), {}) # type: ignore +Event.PROBE_SUCCESSFUL = type("Event.PROBE_SUCCESSFUL", (Event.PROBE_SUCCESSFUL, Event,), {}) # type: ignore +Event.PROBE_FAILED = type("Event.PROBE_FAILED", (Event.PROBE_FAILED, Event,), {}) # type: ignore +Event.CHANNEL_PENDING = type("Event.CHANNEL_PENDING", (Event.CHANNEL_PENDING, Event,), {}) # type: ignore +Event.CHANNEL_READY = type("Event.CHANNEL_READY", (Event.CHANNEL_READY, Event,), {}) # type: ignore +Event.CHANNEL_CLOSED = type("Event.CHANNEL_CLOSED", (Event.CHANNEL_CLOSED, Event,), {}) # type: ignore +Event.SPLICE_PENDING = type("Event.SPLICE_PENDING", (Event.SPLICE_PENDING, Event,), {}) # type: ignore +Event.SPLICE_FAILED = type("Event.SPLICE_FAILED", (Event.SPLICE_FAILED, Event,), {}) # type: ignore +Event.ONCHAIN_TRANSACTION_CONFIRMED = type("Event.ONCHAIN_TRANSACTION_CONFIRMED", (Event.ONCHAIN_TRANSACTION_CONFIRMED, Event,), {}) # type: ignore +Event.ONCHAIN_TRANSACTION_RECEIVED = type("Event.ONCHAIN_TRANSACTION_RECEIVED", (Event.ONCHAIN_TRANSACTION_RECEIVED, Event,), {}) # type: ignore +Event.ONCHAIN_TRANSACTION_REPLACED = type("Event.ONCHAIN_TRANSACTION_REPLACED", (Event.ONCHAIN_TRANSACTION_REPLACED, Event,), {}) # type: ignore +Event.ONCHAIN_TRANSACTION_REORGED = type("Event.ONCHAIN_TRANSACTION_REORGED", (Event.ONCHAIN_TRANSACTION_REORGED, Event,), {}) # type: ignore +Event.ONCHAIN_TRANSACTION_EVICTED = type("Event.ONCHAIN_TRANSACTION_EVICTED", (Event.ONCHAIN_TRANSACTION_EVICTED, Event,), {}) # type: ignore +Event.SYNC_PROGRESS = type("Event.SYNC_PROGRESS", (Event.SYNC_PROGRESS, Event,), {}) # type: ignore +Event.SYNC_COMPLETED = type("Event.SYNC_COMPLETED", (Event.SYNC_COMPLETED, Event,), {}) # type: ignore +Event.BALANCE_CHANGED = type("Event.BALANCE_CHANGED", (Event.BALANCE_CHANGED, Event,), {}) # type: ignore + + + + +class _UniffiConverterTypeEvent(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return Event.PAYMENT_SUCCESSFUL( + _UniffiConverterOptionalTypePaymentId.read(buf), + _UniffiConverterTypePaymentHash.read(buf), + _UniffiConverterOptionalTypePaymentPreimage.read(buf), + _UniffiConverterOptionalUInt64.read(buf), + ) + if variant == 2: + return Event.PAYMENT_FAILED( + _UniffiConverterOptionalTypePaymentId.read(buf), + _UniffiConverterOptionalTypePaymentHash.read(buf), + _UniffiConverterOptionalTypePaymentFailureReason.read(buf), + ) + if variant == 3: + return Event.PAYMENT_RECEIVED( + _UniffiConverterOptionalTypePaymentId.read(buf), + _UniffiConverterTypePaymentHash.read(buf), + _UniffiConverterUInt64.read(buf), + _UniffiConverterSequenceTypeCustomTlvRecord.read(buf), + ) + if variant == 4: + return Event.PAYMENT_CLAIMABLE( + _UniffiConverterTypePaymentId.read(buf), + _UniffiConverterTypePaymentHash.read(buf), + _UniffiConverterUInt64.read(buf), + _UniffiConverterOptionalUInt32.read(buf), + _UniffiConverterSequenceTypeCustomTlvRecord.read(buf), + ) + if variant == 5: + return Event.PAYMENT_FORWARDED( + _UniffiConverterTypeChannelId.read(buf), + _UniffiConverterTypeChannelId.read(buf), + _UniffiConverterOptionalTypeUserChannelId.read(buf), + _UniffiConverterOptionalTypeUserChannelId.read(buf), + _UniffiConverterOptionalTypePublicKey.read(buf), + _UniffiConverterOptionalTypePublicKey.read(buf), + _UniffiConverterOptionalUInt64.read(buf), + _UniffiConverterOptionalUInt64.read(buf), + _UniffiConverterBool.read(buf), + _UniffiConverterOptionalUInt64.read(buf), + ) + if variant == 6: + return Event.PROBE_SUCCESSFUL( + _UniffiConverterTypePaymentId.read(buf), + _UniffiConverterTypePaymentHash.read(buf), + _UniffiConverterOptionalUInt64.read(buf), + ) + if variant == 7: + return Event.PROBE_FAILED( + _UniffiConverterTypePaymentId.read(buf), + _UniffiConverterTypePaymentHash.read(buf), + _UniffiConverterOptionalUInt64.read(buf), + _UniffiConverterOptionalUInt64.read(buf), + ) + if variant == 8: + return Event.CHANNEL_PENDING( + _UniffiConverterTypeChannelId.read(buf), + _UniffiConverterTypeUserChannelId.read(buf), + _UniffiConverterTypeChannelId.read(buf), + _UniffiConverterTypePublicKey.read(buf), + _UniffiConverterTypeOutPoint.read(buf), + ) + if variant == 9: + return Event.CHANNEL_READY( + _UniffiConverterTypeChannelId.read(buf), + _UniffiConverterTypeUserChannelId.read(buf), + _UniffiConverterOptionalTypePublicKey.read(buf), + _UniffiConverterOptionalTypeOutPoint.read(buf), + ) + if variant == 10: + return Event.CHANNEL_CLOSED( + _UniffiConverterTypeChannelId.read(buf), + _UniffiConverterTypeUserChannelId.read(buf), + _UniffiConverterOptionalTypePublicKey.read(buf), + _UniffiConverterOptionalTypeClosureReason.read(buf), + ) + if variant == 11: + return Event.SPLICE_PENDING( + _UniffiConverterTypeChannelId.read(buf), + _UniffiConverterTypeUserChannelId.read(buf), + _UniffiConverterTypePublicKey.read(buf), + _UniffiConverterTypeOutPoint.read(buf), + ) + if variant == 12: + return Event.SPLICE_FAILED( + _UniffiConverterTypeChannelId.read(buf), + _UniffiConverterTypeUserChannelId.read(buf), + _UniffiConverterTypePublicKey.read(buf), + _UniffiConverterOptionalTypeOutPoint.read(buf), + ) + if variant == 13: + return Event.ONCHAIN_TRANSACTION_CONFIRMED( + _UniffiConverterTypeTxid.read(buf), + _UniffiConverterTypeBlockHash.read(buf), + _UniffiConverterUInt32.read(buf), + _UniffiConverterUInt64.read(buf), + _UniffiConverterTypeTransactionDetails.read(buf), + ) + if variant == 14: + return Event.ONCHAIN_TRANSACTION_RECEIVED( + _UniffiConverterTypeTxid.read(buf), + _UniffiConverterTypeTransactionDetails.read(buf), + ) + if variant == 15: + return Event.ONCHAIN_TRANSACTION_REPLACED( + _UniffiConverterTypeTxid.read(buf), + _UniffiConverterSequenceTypeTxid.read(buf), + ) + if variant == 16: + return Event.ONCHAIN_TRANSACTION_REORGED( + _UniffiConverterTypeTxid.read(buf), + ) + if variant == 17: + return Event.ONCHAIN_TRANSACTION_EVICTED( + _UniffiConverterTypeTxid.read(buf), + ) + if variant == 18: + return Event.SYNC_PROGRESS( + _UniffiConverterTypeSyncType.read(buf), + _UniffiConverterUInt8.read(buf), + _UniffiConverterUInt32.read(buf), + _UniffiConverterUInt32.read(buf), + ) + if variant == 19: + return Event.SYNC_COMPLETED( + _UniffiConverterTypeSyncType.read(buf), + _UniffiConverterUInt32.read(buf), + ) + if variant == 20: + return Event.BALANCE_CHANGED( + _UniffiConverterUInt64.read(buf), + _UniffiConverterUInt64.read(buf), + _UniffiConverterUInt64.read(buf), + _UniffiConverterUInt64.read(buf), + _UniffiConverterUInt64.read(buf), + _UniffiConverterUInt64.read(buf), + ) + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if value.is_payment_successful(): + _UniffiConverterOptionalTypePaymentId.check_lower(value.payment_id) + _UniffiConverterTypePaymentHash.check_lower(value.payment_hash) + _UniffiConverterOptionalTypePaymentPreimage.check_lower(value.payment_preimage) + _UniffiConverterOptionalUInt64.check_lower(value.fee_paid_msat) + return + if value.is_payment_failed(): + _UniffiConverterOptionalTypePaymentId.check_lower(value.payment_id) + _UniffiConverterOptionalTypePaymentHash.check_lower(value.payment_hash) + _UniffiConverterOptionalTypePaymentFailureReason.check_lower(value.reason) + return + if value.is_payment_received(): + _UniffiConverterOptionalTypePaymentId.check_lower(value.payment_id) + _UniffiConverterTypePaymentHash.check_lower(value.payment_hash) + _UniffiConverterUInt64.check_lower(value.amount_msat) + _UniffiConverterSequenceTypeCustomTlvRecord.check_lower(value.custom_records) + return + if value.is_payment_claimable(): + _UniffiConverterTypePaymentId.check_lower(value.payment_id) + _UniffiConverterTypePaymentHash.check_lower(value.payment_hash) + _UniffiConverterUInt64.check_lower(value.claimable_amount_msat) + _UniffiConverterOptionalUInt32.check_lower(value.claim_deadline) + _UniffiConverterSequenceTypeCustomTlvRecord.check_lower(value.custom_records) + return + if value.is_payment_forwarded(): + _UniffiConverterTypeChannelId.check_lower(value.prev_channel_id) + _UniffiConverterTypeChannelId.check_lower(value.next_channel_id) + _UniffiConverterOptionalTypeUserChannelId.check_lower(value.prev_user_channel_id) + _UniffiConverterOptionalTypeUserChannelId.check_lower(value.next_user_channel_id) + _UniffiConverterOptionalTypePublicKey.check_lower(value.prev_node_id) + _UniffiConverterOptionalTypePublicKey.check_lower(value.next_node_id) + _UniffiConverterOptionalUInt64.check_lower(value.total_fee_earned_msat) + _UniffiConverterOptionalUInt64.check_lower(value.skimmed_fee_msat) + _UniffiConverterBool.check_lower(value.claim_from_onchain_tx) + _UniffiConverterOptionalUInt64.check_lower(value.outbound_amount_forwarded_msat) + return + if value.is_probe_successful(): + _UniffiConverterTypePaymentId.check_lower(value.payment_id) + _UniffiConverterTypePaymentHash.check_lower(value.payment_hash) + _UniffiConverterOptionalUInt64.check_lower(value.route_fee_msat) + return + if value.is_probe_failed(): + _UniffiConverterTypePaymentId.check_lower(value.payment_id) + _UniffiConverterTypePaymentHash.check_lower(value.payment_hash) + _UniffiConverterOptionalUInt64.check_lower(value.short_channel_id) + _UniffiConverterOptionalUInt64.check_lower(value.route_fee_msat) + return + if value.is_channel_pending(): + _UniffiConverterTypeChannelId.check_lower(value.channel_id) + _UniffiConverterTypeUserChannelId.check_lower(value.user_channel_id) + _UniffiConverterTypeChannelId.check_lower(value.former_temporary_channel_id) + _UniffiConverterTypePublicKey.check_lower(value.counterparty_node_id) + _UniffiConverterTypeOutPoint.check_lower(value.funding_txo) + return + if value.is_channel_ready(): + _UniffiConverterTypeChannelId.check_lower(value.channel_id) + _UniffiConverterTypeUserChannelId.check_lower(value.user_channel_id) + _UniffiConverterOptionalTypePublicKey.check_lower(value.counterparty_node_id) + _UniffiConverterOptionalTypeOutPoint.check_lower(value.funding_txo) + return + if value.is_channel_closed(): + _UniffiConverterTypeChannelId.check_lower(value.channel_id) + _UniffiConverterTypeUserChannelId.check_lower(value.user_channel_id) + _UniffiConverterOptionalTypePublicKey.check_lower(value.counterparty_node_id) + _UniffiConverterOptionalTypeClosureReason.check_lower(value.reason) + return + if value.is_splice_pending(): + _UniffiConverterTypeChannelId.check_lower(value.channel_id) + _UniffiConverterTypeUserChannelId.check_lower(value.user_channel_id) + _UniffiConverterTypePublicKey.check_lower(value.counterparty_node_id) + _UniffiConverterTypeOutPoint.check_lower(value.new_funding_txo) + return + if value.is_splice_failed(): + _UniffiConverterTypeChannelId.check_lower(value.channel_id) + _UniffiConverterTypeUserChannelId.check_lower(value.user_channel_id) + _UniffiConverterTypePublicKey.check_lower(value.counterparty_node_id) + _UniffiConverterOptionalTypeOutPoint.check_lower(value.abandoned_funding_txo) + return + if value.is_onchain_transaction_confirmed(): + _UniffiConverterTypeTxid.check_lower(value.txid) + _UniffiConverterTypeBlockHash.check_lower(value.block_hash) + _UniffiConverterUInt32.check_lower(value.block_height) + _UniffiConverterUInt64.check_lower(value.confirmation_time) + _UniffiConverterTypeTransactionDetails.check_lower(value.details) + return + if value.is_onchain_transaction_received(): + _UniffiConverterTypeTxid.check_lower(value.txid) + _UniffiConverterTypeTransactionDetails.check_lower(value.details) + return + if value.is_onchain_transaction_replaced(): + _UniffiConverterTypeTxid.check_lower(value.txid) + _UniffiConverterSequenceTypeTxid.check_lower(value.conflicts) + return + if value.is_onchain_transaction_reorged(): + _UniffiConverterTypeTxid.check_lower(value.txid) + return + if value.is_onchain_transaction_evicted(): + _UniffiConverterTypeTxid.check_lower(value.txid) + return + if value.is_sync_progress(): + _UniffiConverterTypeSyncType.check_lower(value.sync_type) + _UniffiConverterUInt8.check_lower(value.progress_percent) + _UniffiConverterUInt32.check_lower(value.current_block_height) + _UniffiConverterUInt32.check_lower(value.target_block_height) + return + if value.is_sync_completed(): + _UniffiConverterTypeSyncType.check_lower(value.sync_type) + _UniffiConverterUInt32.check_lower(value.synced_block_height) + return + if value.is_balance_changed(): + _UniffiConverterUInt64.check_lower(value.old_spendable_onchain_balance_sats) + _UniffiConverterUInt64.check_lower(value.new_spendable_onchain_balance_sats) + _UniffiConverterUInt64.check_lower(value.old_total_onchain_balance_sats) + _UniffiConverterUInt64.check_lower(value.new_total_onchain_balance_sats) + _UniffiConverterUInt64.check_lower(value.old_total_lightning_balance_sats) + _UniffiConverterUInt64.check_lower(value.new_total_lightning_balance_sats) + return + raise ValueError(value) + + @staticmethod + def write(value, buf): + if value.is_payment_successful(): + buf.write_i32(1) + _UniffiConverterOptionalTypePaymentId.write(value.payment_id, buf) + _UniffiConverterTypePaymentHash.write(value.payment_hash, buf) + _UniffiConverterOptionalTypePaymentPreimage.write(value.payment_preimage, buf) + _UniffiConverterOptionalUInt64.write(value.fee_paid_msat, buf) + if value.is_payment_failed(): + buf.write_i32(2) + _UniffiConverterOptionalTypePaymentId.write(value.payment_id, buf) + _UniffiConverterOptionalTypePaymentHash.write(value.payment_hash, buf) + _UniffiConverterOptionalTypePaymentFailureReason.write(value.reason, buf) + if value.is_payment_received(): + buf.write_i32(3) + _UniffiConverterOptionalTypePaymentId.write(value.payment_id, buf) + _UniffiConverterTypePaymentHash.write(value.payment_hash, buf) + _UniffiConverterUInt64.write(value.amount_msat, buf) + _UniffiConverterSequenceTypeCustomTlvRecord.write(value.custom_records, buf) + if value.is_payment_claimable(): + buf.write_i32(4) + _UniffiConverterTypePaymentId.write(value.payment_id, buf) + _UniffiConverterTypePaymentHash.write(value.payment_hash, buf) + _UniffiConverterUInt64.write(value.claimable_amount_msat, buf) + _UniffiConverterOptionalUInt32.write(value.claim_deadline, buf) + _UniffiConverterSequenceTypeCustomTlvRecord.write(value.custom_records, buf) + if value.is_payment_forwarded(): + buf.write_i32(5) + _UniffiConverterTypeChannelId.write(value.prev_channel_id, buf) + _UniffiConverterTypeChannelId.write(value.next_channel_id, buf) + _UniffiConverterOptionalTypeUserChannelId.write(value.prev_user_channel_id, buf) + _UniffiConverterOptionalTypeUserChannelId.write(value.next_user_channel_id, buf) + _UniffiConverterOptionalTypePublicKey.write(value.prev_node_id, buf) + _UniffiConverterOptionalTypePublicKey.write(value.next_node_id, buf) + _UniffiConverterOptionalUInt64.write(value.total_fee_earned_msat, buf) + _UniffiConverterOptionalUInt64.write(value.skimmed_fee_msat, buf) + _UniffiConverterBool.write(value.claim_from_onchain_tx, buf) + _UniffiConverterOptionalUInt64.write(value.outbound_amount_forwarded_msat, buf) + if value.is_probe_successful(): + buf.write_i32(6) + _UniffiConverterTypePaymentId.write(value.payment_id, buf) + _UniffiConverterTypePaymentHash.write(value.payment_hash, buf) + _UniffiConverterOptionalUInt64.write(value.route_fee_msat, buf) + if value.is_probe_failed(): + buf.write_i32(7) + _UniffiConverterTypePaymentId.write(value.payment_id, buf) + _UniffiConverterTypePaymentHash.write(value.payment_hash, buf) + _UniffiConverterOptionalUInt64.write(value.short_channel_id, buf) + _UniffiConverterOptionalUInt64.write(value.route_fee_msat, buf) + if value.is_channel_pending(): + buf.write_i32(8) + _UniffiConverterTypeChannelId.write(value.channel_id, buf) + _UniffiConverterTypeUserChannelId.write(value.user_channel_id, buf) + _UniffiConverterTypeChannelId.write(value.former_temporary_channel_id, buf) + _UniffiConverterTypePublicKey.write(value.counterparty_node_id, buf) + _UniffiConverterTypeOutPoint.write(value.funding_txo, buf) + if value.is_channel_ready(): + buf.write_i32(9) + _UniffiConverterTypeChannelId.write(value.channel_id, buf) + _UniffiConverterTypeUserChannelId.write(value.user_channel_id, buf) + _UniffiConverterOptionalTypePublicKey.write(value.counterparty_node_id, buf) + _UniffiConverterOptionalTypeOutPoint.write(value.funding_txo, buf) + if value.is_channel_closed(): + buf.write_i32(10) + _UniffiConverterTypeChannelId.write(value.channel_id, buf) + _UniffiConverterTypeUserChannelId.write(value.user_channel_id, buf) + _UniffiConverterOptionalTypePublicKey.write(value.counterparty_node_id, buf) + _UniffiConverterOptionalTypeClosureReason.write(value.reason, buf) + if value.is_splice_pending(): + buf.write_i32(11) + _UniffiConverterTypeChannelId.write(value.channel_id, buf) + _UniffiConverterTypeUserChannelId.write(value.user_channel_id, buf) + _UniffiConverterTypePublicKey.write(value.counterparty_node_id, buf) + _UniffiConverterTypeOutPoint.write(value.new_funding_txo, buf) + if value.is_splice_failed(): + buf.write_i32(12) + _UniffiConverterTypeChannelId.write(value.channel_id, buf) + _UniffiConverterTypeUserChannelId.write(value.user_channel_id, buf) + _UniffiConverterTypePublicKey.write(value.counterparty_node_id, buf) + _UniffiConverterOptionalTypeOutPoint.write(value.abandoned_funding_txo, buf) + if value.is_onchain_transaction_confirmed(): + buf.write_i32(13) + _UniffiConverterTypeTxid.write(value.txid, buf) + _UniffiConverterTypeBlockHash.write(value.block_hash, buf) + _UniffiConverterUInt32.write(value.block_height, buf) + _UniffiConverterUInt64.write(value.confirmation_time, buf) + _UniffiConverterTypeTransactionDetails.write(value.details, buf) + if value.is_onchain_transaction_received(): + buf.write_i32(14) + _UniffiConverterTypeTxid.write(value.txid, buf) + _UniffiConverterTypeTransactionDetails.write(value.details, buf) + if value.is_onchain_transaction_replaced(): + buf.write_i32(15) + _UniffiConverterTypeTxid.write(value.txid, buf) + _UniffiConverterSequenceTypeTxid.write(value.conflicts, buf) + if value.is_onchain_transaction_reorged(): + buf.write_i32(16) + _UniffiConverterTypeTxid.write(value.txid, buf) + if value.is_onchain_transaction_evicted(): + buf.write_i32(17) + _UniffiConverterTypeTxid.write(value.txid, buf) + if value.is_sync_progress(): + buf.write_i32(18) + _UniffiConverterTypeSyncType.write(value.sync_type, buf) + _UniffiConverterUInt8.write(value.progress_percent, buf) + _UniffiConverterUInt32.write(value.current_block_height, buf) + _UniffiConverterUInt32.write(value.target_block_height, buf) + if value.is_sync_completed(): + buf.write_i32(19) + _UniffiConverterTypeSyncType.write(value.sync_type, buf) + _UniffiConverterUInt32.write(value.synced_block_height, buf) + if value.is_balance_changed(): + buf.write_i32(20) + _UniffiConverterUInt64.write(value.old_spendable_onchain_balance_sats, buf) + _UniffiConverterUInt64.write(value.new_spendable_onchain_balance_sats, buf) + _UniffiConverterUInt64.write(value.old_total_onchain_balance_sats, buf) + _UniffiConverterUInt64.write(value.new_total_onchain_balance_sats, buf) + _UniffiConverterUInt64.write(value.old_total_lightning_balance_sats, buf) + _UniffiConverterUInt64.write(value.new_total_lightning_balance_sats, buf) + + + + + + + +class KeychainKind(enum.Enum): + EXTERNAL = 0 + + INTERNAL = 1 + + + +class _UniffiConverterTypeKeychainKind(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return KeychainKind.EXTERNAL + if variant == 2: + return KeychainKind.INTERNAL + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if value == KeychainKind.EXTERNAL: + return + if value == KeychainKind.INTERNAL: + return + raise ValueError(value) + + @staticmethod + def write(value, buf): + if value == KeychainKind.EXTERNAL: + buf.write_i32(1) + if value == KeychainKind.INTERNAL: + buf.write_i32(2) + + + + + + + +class LightningBalance: + def __init__(self): + raise RuntimeError("LightningBalance cannot be instantiated directly") + + # Each enum variant is a nested class of the enum itself. + class CLAIMABLE_ON_CHANNEL_CLOSE: + channel_id: "ChannelId" + counterparty_node_id: "PublicKey" + amount_satoshis: "int" + transaction_fee_satoshis: "int" + outbound_payment_htlc_rounded_msat: "int" + outbound_forwarded_htlc_rounded_msat: "int" + inbound_claiming_htlc_rounded_msat: "int" + inbound_htlc_rounded_msat: "int" + + def __init__(self,channel_id: "ChannelId", counterparty_node_id: "PublicKey", amount_satoshis: "int", transaction_fee_satoshis: "int", outbound_payment_htlc_rounded_msat: "int", outbound_forwarded_htlc_rounded_msat: "int", inbound_claiming_htlc_rounded_msat: "int", inbound_htlc_rounded_msat: "int"): + self.channel_id = channel_id + self.counterparty_node_id = counterparty_node_id + self.amount_satoshis = amount_satoshis + self.transaction_fee_satoshis = transaction_fee_satoshis + self.outbound_payment_htlc_rounded_msat = outbound_payment_htlc_rounded_msat + self.outbound_forwarded_htlc_rounded_msat = outbound_forwarded_htlc_rounded_msat + self.inbound_claiming_htlc_rounded_msat = inbound_claiming_htlc_rounded_msat + self.inbound_htlc_rounded_msat = inbound_htlc_rounded_msat + + def __str__(self): + return "LightningBalance.CLAIMABLE_ON_CHANNEL_CLOSE(channel_id={}, counterparty_node_id={}, amount_satoshis={}, transaction_fee_satoshis={}, outbound_payment_htlc_rounded_msat={}, outbound_forwarded_htlc_rounded_msat={}, inbound_claiming_htlc_rounded_msat={}, inbound_htlc_rounded_msat={})".format(self.channel_id, self.counterparty_node_id, self.amount_satoshis, self.transaction_fee_satoshis, self.outbound_payment_htlc_rounded_msat, self.outbound_forwarded_htlc_rounded_msat, self.inbound_claiming_htlc_rounded_msat, self.inbound_htlc_rounded_msat) + + def __eq__(self, other): + if not other.is_claimable_on_channel_close(): + return False + if self.channel_id != other.channel_id: + return False + if self.counterparty_node_id != other.counterparty_node_id: + return False + if self.amount_satoshis != other.amount_satoshis: + return False + if self.transaction_fee_satoshis != other.transaction_fee_satoshis: + return False + if self.outbound_payment_htlc_rounded_msat != other.outbound_payment_htlc_rounded_msat: + return False + if self.outbound_forwarded_htlc_rounded_msat != other.outbound_forwarded_htlc_rounded_msat: + return False + if self.inbound_claiming_htlc_rounded_msat != other.inbound_claiming_htlc_rounded_msat: + return False + if self.inbound_htlc_rounded_msat != other.inbound_htlc_rounded_msat: + return False + return True + + class CLAIMABLE_AWAITING_CONFIRMATIONS: + channel_id: "ChannelId" + counterparty_node_id: "PublicKey" + amount_satoshis: "int" + confirmation_height: "int" + source: "BalanceSource" + + def __init__(self,channel_id: "ChannelId", counterparty_node_id: "PublicKey", amount_satoshis: "int", confirmation_height: "int", source: "BalanceSource"): + self.channel_id = channel_id + self.counterparty_node_id = counterparty_node_id + self.amount_satoshis = amount_satoshis + self.confirmation_height = confirmation_height + self.source = source + + def __str__(self): + return "LightningBalance.CLAIMABLE_AWAITING_CONFIRMATIONS(channel_id={}, counterparty_node_id={}, amount_satoshis={}, confirmation_height={}, source={})".format(self.channel_id, self.counterparty_node_id, self.amount_satoshis, self.confirmation_height, self.source) + + def __eq__(self, other): + if not other.is_claimable_awaiting_confirmations(): + return False + if self.channel_id != other.channel_id: + return False + if self.counterparty_node_id != other.counterparty_node_id: + return False + if self.amount_satoshis != other.amount_satoshis: + return False + if self.confirmation_height != other.confirmation_height: + return False + if self.source != other.source: + return False + return True + + class CONTENTIOUS_CLAIMABLE: + channel_id: "ChannelId" + counterparty_node_id: "PublicKey" + amount_satoshis: "int" + timeout_height: "int" + payment_hash: "PaymentHash" + payment_preimage: "PaymentPreimage" + + def __init__(self,channel_id: "ChannelId", counterparty_node_id: "PublicKey", amount_satoshis: "int", timeout_height: "int", payment_hash: "PaymentHash", payment_preimage: "PaymentPreimage"): + self.channel_id = channel_id + self.counterparty_node_id = counterparty_node_id + self.amount_satoshis = amount_satoshis + self.timeout_height = timeout_height + self.payment_hash = payment_hash + self.payment_preimage = payment_preimage + + def __str__(self): + return "LightningBalance.CONTENTIOUS_CLAIMABLE(channel_id={}, counterparty_node_id={}, amount_satoshis={}, timeout_height={}, payment_hash={}, payment_preimage={})".format(self.channel_id, self.counterparty_node_id, self.amount_satoshis, self.timeout_height, self.payment_hash, self.payment_preimage) + + def __eq__(self, other): + if not other.is_contentious_claimable(): + return False + if self.channel_id != other.channel_id: + return False + if self.counterparty_node_id != other.counterparty_node_id: + return False + if self.amount_satoshis != other.amount_satoshis: + return False + if self.timeout_height != other.timeout_height: + return False + if self.payment_hash != other.payment_hash: + return False + if self.payment_preimage != other.payment_preimage: + return False + return True + + class MAYBE_TIMEOUT_CLAIMABLE_HTLC: + channel_id: "ChannelId" + counterparty_node_id: "PublicKey" + amount_satoshis: "int" + claimable_height: "int" + payment_hash: "PaymentHash" + outbound_payment: "bool" + + def __init__(self,channel_id: "ChannelId", counterparty_node_id: "PublicKey", amount_satoshis: "int", claimable_height: "int", payment_hash: "PaymentHash", outbound_payment: "bool"): + self.channel_id = channel_id + self.counterparty_node_id = counterparty_node_id + self.amount_satoshis = amount_satoshis + self.claimable_height = claimable_height + self.payment_hash = payment_hash + self.outbound_payment = outbound_payment + + def __str__(self): + return "LightningBalance.MAYBE_TIMEOUT_CLAIMABLE_HTLC(channel_id={}, counterparty_node_id={}, amount_satoshis={}, claimable_height={}, payment_hash={}, outbound_payment={})".format(self.channel_id, self.counterparty_node_id, self.amount_satoshis, self.claimable_height, self.payment_hash, self.outbound_payment) + + def __eq__(self, other): + if not other.is_maybe_timeout_claimable_htlc(): + return False + if self.channel_id != other.channel_id: + return False + if self.counterparty_node_id != other.counterparty_node_id: + return False + if self.amount_satoshis != other.amount_satoshis: + return False + if self.claimable_height != other.claimable_height: + return False + if self.payment_hash != other.payment_hash: + return False + if self.outbound_payment != other.outbound_payment: + return False + return True + + class MAYBE_PREIMAGE_CLAIMABLE_HTLC: + channel_id: "ChannelId" + counterparty_node_id: "PublicKey" + amount_satoshis: "int" + expiry_height: "int" + payment_hash: "PaymentHash" + + def __init__(self,channel_id: "ChannelId", counterparty_node_id: "PublicKey", amount_satoshis: "int", expiry_height: "int", payment_hash: "PaymentHash"): + self.channel_id = channel_id + self.counterparty_node_id = counterparty_node_id + self.amount_satoshis = amount_satoshis + self.expiry_height = expiry_height + self.payment_hash = payment_hash + + def __str__(self): + return "LightningBalance.MAYBE_PREIMAGE_CLAIMABLE_HTLC(channel_id={}, counterparty_node_id={}, amount_satoshis={}, expiry_height={}, payment_hash={})".format(self.channel_id, self.counterparty_node_id, self.amount_satoshis, self.expiry_height, self.payment_hash) + + def __eq__(self, other): + if not other.is_maybe_preimage_claimable_htlc(): + return False + if self.channel_id != other.channel_id: + return False + if self.counterparty_node_id != other.counterparty_node_id: + return False + if self.amount_satoshis != other.amount_satoshis: + return False + if self.expiry_height != other.expiry_height: + return False + if self.payment_hash != other.payment_hash: + return False + return True + + class COUNTERPARTY_REVOKED_OUTPUT_CLAIMABLE: + channel_id: "ChannelId" + counterparty_node_id: "PublicKey" + amount_satoshis: "int" + + def __init__(self,channel_id: "ChannelId", counterparty_node_id: "PublicKey", amount_satoshis: "int"): + self.channel_id = channel_id + self.counterparty_node_id = counterparty_node_id + self.amount_satoshis = amount_satoshis + + def __str__(self): + return "LightningBalance.COUNTERPARTY_REVOKED_OUTPUT_CLAIMABLE(channel_id={}, counterparty_node_id={}, amount_satoshis={})".format(self.channel_id, self.counterparty_node_id, self.amount_satoshis) + + def __eq__(self, other): + if not other.is_counterparty_revoked_output_claimable(): + return False + if self.channel_id != other.channel_id: + return False + if self.counterparty_node_id != other.counterparty_node_id: + return False + if self.amount_satoshis != other.amount_satoshis: + return False + return True + + + + # For each variant, we have an `is_NAME` method for easily checking + # whether an instance is that variant. + def is_claimable_on_channel_close(self) -> bool: + return isinstance(self, LightningBalance.CLAIMABLE_ON_CHANNEL_CLOSE) + def is_claimable_awaiting_confirmations(self) -> bool: + return isinstance(self, LightningBalance.CLAIMABLE_AWAITING_CONFIRMATIONS) + def is_contentious_claimable(self) -> bool: + return isinstance(self, LightningBalance.CONTENTIOUS_CLAIMABLE) + def is_maybe_timeout_claimable_htlc(self) -> bool: + return isinstance(self, LightningBalance.MAYBE_TIMEOUT_CLAIMABLE_HTLC) + def is_maybe_preimage_claimable_htlc(self) -> bool: + return isinstance(self, LightningBalance.MAYBE_PREIMAGE_CLAIMABLE_HTLC) + def is_counterparty_revoked_output_claimable(self) -> bool: + return isinstance(self, LightningBalance.COUNTERPARTY_REVOKED_OUTPUT_CLAIMABLE) + + +# Now, a little trick - we make each nested variant class be a subclass of the main +# enum class, so that method calls and instance checks etc will work intuitively. +# We might be able to do this a little more neatly with a metaclass, but this'll do. +LightningBalance.CLAIMABLE_ON_CHANNEL_CLOSE = type("LightningBalance.CLAIMABLE_ON_CHANNEL_CLOSE", (LightningBalance.CLAIMABLE_ON_CHANNEL_CLOSE, LightningBalance,), {}) # type: ignore +LightningBalance.CLAIMABLE_AWAITING_CONFIRMATIONS = type("LightningBalance.CLAIMABLE_AWAITING_CONFIRMATIONS", (LightningBalance.CLAIMABLE_AWAITING_CONFIRMATIONS, LightningBalance,), {}) # type: ignore +LightningBalance.CONTENTIOUS_CLAIMABLE = type("LightningBalance.CONTENTIOUS_CLAIMABLE", (LightningBalance.CONTENTIOUS_CLAIMABLE, LightningBalance,), {}) # type: ignore +LightningBalance.MAYBE_TIMEOUT_CLAIMABLE_HTLC = type("LightningBalance.MAYBE_TIMEOUT_CLAIMABLE_HTLC", (LightningBalance.MAYBE_TIMEOUT_CLAIMABLE_HTLC, LightningBalance,), {}) # type: ignore +LightningBalance.MAYBE_PREIMAGE_CLAIMABLE_HTLC = type("LightningBalance.MAYBE_PREIMAGE_CLAIMABLE_HTLC", (LightningBalance.MAYBE_PREIMAGE_CLAIMABLE_HTLC, LightningBalance,), {}) # type: ignore +LightningBalance.COUNTERPARTY_REVOKED_OUTPUT_CLAIMABLE = type("LightningBalance.COUNTERPARTY_REVOKED_OUTPUT_CLAIMABLE", (LightningBalance.COUNTERPARTY_REVOKED_OUTPUT_CLAIMABLE, LightningBalance,), {}) # type: ignore + + + + +class _UniffiConverterTypeLightningBalance(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return LightningBalance.CLAIMABLE_ON_CHANNEL_CLOSE( + _UniffiConverterTypeChannelId.read(buf), + _UniffiConverterTypePublicKey.read(buf), + _UniffiConverterUInt64.read(buf), + _UniffiConverterUInt64.read(buf), + _UniffiConverterUInt64.read(buf), + _UniffiConverterUInt64.read(buf), + _UniffiConverterUInt64.read(buf), + _UniffiConverterUInt64.read(buf), + ) + if variant == 2: + return LightningBalance.CLAIMABLE_AWAITING_CONFIRMATIONS( + _UniffiConverterTypeChannelId.read(buf), + _UniffiConverterTypePublicKey.read(buf), + _UniffiConverterUInt64.read(buf), + _UniffiConverterUInt32.read(buf), + _UniffiConverterTypeBalanceSource.read(buf), + ) + if variant == 3: + return LightningBalance.CONTENTIOUS_CLAIMABLE( + _UniffiConverterTypeChannelId.read(buf), + _UniffiConverterTypePublicKey.read(buf), + _UniffiConverterUInt64.read(buf), + _UniffiConverterUInt32.read(buf), + _UniffiConverterTypePaymentHash.read(buf), + _UniffiConverterTypePaymentPreimage.read(buf), + ) + if variant == 4: + return LightningBalance.MAYBE_TIMEOUT_CLAIMABLE_HTLC( + _UniffiConverterTypeChannelId.read(buf), + _UniffiConverterTypePublicKey.read(buf), + _UniffiConverterUInt64.read(buf), + _UniffiConverterUInt32.read(buf), + _UniffiConverterTypePaymentHash.read(buf), + _UniffiConverterBool.read(buf), + ) + if variant == 5: + return LightningBalance.MAYBE_PREIMAGE_CLAIMABLE_HTLC( + _UniffiConverterTypeChannelId.read(buf), + _UniffiConverterTypePublicKey.read(buf), + _UniffiConverterUInt64.read(buf), + _UniffiConverterUInt32.read(buf), + _UniffiConverterTypePaymentHash.read(buf), + ) + if variant == 6: + return LightningBalance.COUNTERPARTY_REVOKED_OUTPUT_CLAIMABLE( + _UniffiConverterTypeChannelId.read(buf), + _UniffiConverterTypePublicKey.read(buf), + _UniffiConverterUInt64.read(buf), + ) + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if value.is_claimable_on_channel_close(): + _UniffiConverterTypeChannelId.check_lower(value.channel_id) + _UniffiConverterTypePublicKey.check_lower(value.counterparty_node_id) + _UniffiConverterUInt64.check_lower(value.amount_satoshis) + _UniffiConverterUInt64.check_lower(value.transaction_fee_satoshis) + _UniffiConverterUInt64.check_lower(value.outbound_payment_htlc_rounded_msat) + _UniffiConverterUInt64.check_lower(value.outbound_forwarded_htlc_rounded_msat) + _UniffiConverterUInt64.check_lower(value.inbound_claiming_htlc_rounded_msat) + _UniffiConverterUInt64.check_lower(value.inbound_htlc_rounded_msat) + return + if value.is_claimable_awaiting_confirmations(): + _UniffiConverterTypeChannelId.check_lower(value.channel_id) + _UniffiConverterTypePublicKey.check_lower(value.counterparty_node_id) + _UniffiConverterUInt64.check_lower(value.amount_satoshis) + _UniffiConverterUInt32.check_lower(value.confirmation_height) + _UniffiConverterTypeBalanceSource.check_lower(value.source) + return + if value.is_contentious_claimable(): + _UniffiConverterTypeChannelId.check_lower(value.channel_id) + _UniffiConverterTypePublicKey.check_lower(value.counterparty_node_id) + _UniffiConverterUInt64.check_lower(value.amount_satoshis) + _UniffiConverterUInt32.check_lower(value.timeout_height) + _UniffiConverterTypePaymentHash.check_lower(value.payment_hash) + _UniffiConverterTypePaymentPreimage.check_lower(value.payment_preimage) + return + if value.is_maybe_timeout_claimable_htlc(): + _UniffiConverterTypeChannelId.check_lower(value.channel_id) + _UniffiConverterTypePublicKey.check_lower(value.counterparty_node_id) + _UniffiConverterUInt64.check_lower(value.amount_satoshis) + _UniffiConverterUInt32.check_lower(value.claimable_height) + _UniffiConverterTypePaymentHash.check_lower(value.payment_hash) + _UniffiConverterBool.check_lower(value.outbound_payment) + return + if value.is_maybe_preimage_claimable_htlc(): + _UniffiConverterTypeChannelId.check_lower(value.channel_id) + _UniffiConverterTypePublicKey.check_lower(value.counterparty_node_id) + _UniffiConverterUInt64.check_lower(value.amount_satoshis) + _UniffiConverterUInt32.check_lower(value.expiry_height) + _UniffiConverterTypePaymentHash.check_lower(value.payment_hash) + return + if value.is_counterparty_revoked_output_claimable(): + _UniffiConverterTypeChannelId.check_lower(value.channel_id) + _UniffiConverterTypePublicKey.check_lower(value.counterparty_node_id) + _UniffiConverterUInt64.check_lower(value.amount_satoshis) + return + raise ValueError(value) + + @staticmethod + def write(value, buf): + if value.is_claimable_on_channel_close(): + buf.write_i32(1) + _UniffiConverterTypeChannelId.write(value.channel_id, buf) + _UniffiConverterTypePublicKey.write(value.counterparty_node_id, buf) + _UniffiConverterUInt64.write(value.amount_satoshis, buf) + _UniffiConverterUInt64.write(value.transaction_fee_satoshis, buf) + _UniffiConverterUInt64.write(value.outbound_payment_htlc_rounded_msat, buf) + _UniffiConverterUInt64.write(value.outbound_forwarded_htlc_rounded_msat, buf) + _UniffiConverterUInt64.write(value.inbound_claiming_htlc_rounded_msat, buf) + _UniffiConverterUInt64.write(value.inbound_htlc_rounded_msat, buf) + if value.is_claimable_awaiting_confirmations(): + buf.write_i32(2) + _UniffiConverterTypeChannelId.write(value.channel_id, buf) + _UniffiConverterTypePublicKey.write(value.counterparty_node_id, buf) + _UniffiConverterUInt64.write(value.amount_satoshis, buf) + _UniffiConverterUInt32.write(value.confirmation_height, buf) + _UniffiConverterTypeBalanceSource.write(value.source, buf) + if value.is_contentious_claimable(): + buf.write_i32(3) + _UniffiConverterTypeChannelId.write(value.channel_id, buf) + _UniffiConverterTypePublicKey.write(value.counterparty_node_id, buf) + _UniffiConverterUInt64.write(value.amount_satoshis, buf) + _UniffiConverterUInt32.write(value.timeout_height, buf) + _UniffiConverterTypePaymentHash.write(value.payment_hash, buf) + _UniffiConverterTypePaymentPreimage.write(value.payment_preimage, buf) + if value.is_maybe_timeout_claimable_htlc(): + buf.write_i32(4) + _UniffiConverterTypeChannelId.write(value.channel_id, buf) + _UniffiConverterTypePublicKey.write(value.counterparty_node_id, buf) + _UniffiConverterUInt64.write(value.amount_satoshis, buf) + _UniffiConverterUInt32.write(value.claimable_height, buf) + _UniffiConverterTypePaymentHash.write(value.payment_hash, buf) + _UniffiConverterBool.write(value.outbound_payment, buf) + if value.is_maybe_preimage_claimable_htlc(): + buf.write_i32(5) + _UniffiConverterTypeChannelId.write(value.channel_id, buf) + _UniffiConverterTypePublicKey.write(value.counterparty_node_id, buf) + _UniffiConverterUInt64.write(value.amount_satoshis, buf) + _UniffiConverterUInt32.write(value.expiry_height, buf) + _UniffiConverterTypePaymentHash.write(value.payment_hash, buf) + if value.is_counterparty_revoked_output_claimable(): + buf.write_i32(6) + _UniffiConverterTypeChannelId.write(value.channel_id, buf) + _UniffiConverterTypePublicKey.write(value.counterparty_node_id, buf) + _UniffiConverterUInt64.write(value.amount_satoshis, buf) + + + + + + + +class LogLevel(enum.Enum): + GOSSIP = 0 + + TRACE = 1 + + DEBUG = 2 + + INFO = 3 + + WARN = 4 + + ERROR = 5 + + + +class _UniffiConverterTypeLogLevel(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return LogLevel.GOSSIP + if variant == 2: + return LogLevel.TRACE + if variant == 3: + return LogLevel.DEBUG + if variant == 4: + return LogLevel.INFO + if variant == 5: + return LogLevel.WARN + if variant == 6: + return LogLevel.ERROR + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if value == LogLevel.GOSSIP: + return + if value == LogLevel.TRACE: + return + if value == LogLevel.DEBUG: + return + if value == LogLevel.INFO: + return + if value == LogLevel.WARN: + return + if value == LogLevel.ERROR: + return + raise ValueError(value) + + @staticmethod + def write(value, buf): + if value == LogLevel.GOSSIP: + buf.write_i32(1) + if value == LogLevel.TRACE: + buf.write_i32(2) + if value == LogLevel.DEBUG: + buf.write_i32(3) + if value == LogLevel.INFO: + buf.write_i32(4) + if value == LogLevel.WARN: + buf.write_i32(5) + if value == LogLevel.ERROR: + buf.write_i32(6) + + + + + + + +class Lsps1PaymentState(enum.Enum): + EXPECT_PAYMENT = 0 + + PAID = 1 + + REFUNDED = 2 + + + +class _UniffiConverterTypeLsps1PaymentState(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return Lsps1PaymentState.EXPECT_PAYMENT + if variant == 2: + return Lsps1PaymentState.PAID + if variant == 3: + return Lsps1PaymentState.REFUNDED + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if value == Lsps1PaymentState.EXPECT_PAYMENT: + return + if value == Lsps1PaymentState.PAID: + return + if value == Lsps1PaymentState.REFUNDED: + return + raise ValueError(value) + + @staticmethod + def write(value, buf): + if value == Lsps1PaymentState.EXPECT_PAYMENT: + buf.write_i32(1) + if value == Lsps1PaymentState.PAID: + buf.write_i32(2) + if value == Lsps1PaymentState.REFUNDED: + buf.write_i32(3) + + + + + + + +class MaxDustHtlcExposure: + def __init__(self): + raise RuntimeError("MaxDustHtlcExposure cannot be instantiated directly") + + # Each enum variant is a nested class of the enum itself. + class FIXED_LIMIT: + limit_msat: "int" + + def __init__(self,limit_msat: "int"): + self.limit_msat = limit_msat + + def __str__(self): + return "MaxDustHtlcExposure.FIXED_LIMIT(limit_msat={})".format(self.limit_msat) + + def __eq__(self, other): + if not other.is_fixed_limit(): + return False + if self.limit_msat != other.limit_msat: + return False + return True + + class FEE_RATE_MULTIPLIER: + multiplier: "int" + + def __init__(self,multiplier: "int"): + self.multiplier = multiplier + + def __str__(self): + return "MaxDustHtlcExposure.FEE_RATE_MULTIPLIER(multiplier={})".format(self.multiplier) + + def __eq__(self, other): + if not other.is_fee_rate_multiplier(): + return False + if self.multiplier != other.multiplier: + return False + return True + + + + # For each variant, we have an `is_NAME` method for easily checking + # whether an instance is that variant. + def is_fixed_limit(self) -> bool: + return isinstance(self, MaxDustHtlcExposure.FIXED_LIMIT) + def is_fee_rate_multiplier(self) -> bool: + return isinstance(self, MaxDustHtlcExposure.FEE_RATE_MULTIPLIER) + + +# Now, a little trick - we make each nested variant class be a subclass of the main +# enum class, so that method calls and instance checks etc will work intuitively. +# We might be able to do this a little more neatly with a metaclass, but this'll do. +MaxDustHtlcExposure.FIXED_LIMIT = type("MaxDustHtlcExposure.FIXED_LIMIT", (MaxDustHtlcExposure.FIXED_LIMIT, MaxDustHtlcExposure,), {}) # type: ignore +MaxDustHtlcExposure.FEE_RATE_MULTIPLIER = type("MaxDustHtlcExposure.FEE_RATE_MULTIPLIER", (MaxDustHtlcExposure.FEE_RATE_MULTIPLIER, MaxDustHtlcExposure,), {}) # type: ignore + + + + +class _UniffiConverterTypeMaxDustHtlcExposure(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return MaxDustHtlcExposure.FIXED_LIMIT( + _UniffiConverterUInt64.read(buf), + ) + if variant == 2: + return MaxDustHtlcExposure.FEE_RATE_MULTIPLIER( + _UniffiConverterUInt64.read(buf), + ) + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if value.is_fixed_limit(): + _UniffiConverterUInt64.check_lower(value.limit_msat) + return + if value.is_fee_rate_multiplier(): + _UniffiConverterUInt64.check_lower(value.multiplier) + return + raise ValueError(value) + + @staticmethod + def write(value, buf): + if value.is_fixed_limit(): + buf.write_i32(1) + _UniffiConverterUInt64.write(value.limit_msat, buf) + if value.is_fee_rate_multiplier(): + buf.write_i32(2) + _UniffiConverterUInt64.write(value.multiplier, buf) + + + + + + + +class Network(enum.Enum): + BITCOIN = 0 + + TESTNET = 1 + + SIGNET = 2 + + REGTEST = 3 + + + +class _UniffiConverterTypeNetwork(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return Network.BITCOIN + if variant == 2: + return Network.TESTNET + if variant == 3: + return Network.SIGNET + if variant == 4: + return Network.REGTEST + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if value == Network.BITCOIN: + return + if value == Network.TESTNET: + return + if value == Network.SIGNET: + return + if value == Network.REGTEST: + return + raise ValueError(value) + + @staticmethod + def write(value, buf): + if value == Network.BITCOIN: + buf.write_i32(1) + if value == Network.TESTNET: + buf.write_i32(2) + if value == Network.SIGNET: + buf.write_i32(3) + if value == Network.REGTEST: + buf.write_i32(4) + + + + +# NodeError +# We want to define each variant as a nested class that's also a subclass, +# which is tricky in Python. To accomplish this we're going to create each +# class separately, then manually add the child classes to the base class's +# __dict__. All of this happens in dummy class to avoid polluting the module +# namespace. +class NodeError(Exception): + pass + +_UniffiTempNodeError = NodeError + +class NodeError: # type: ignore + class AlreadyRunning(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.AlreadyRunning({})".format(repr(str(self))) + _UniffiTempNodeError.AlreadyRunning = AlreadyRunning # type: ignore + class NotRunning(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.NotRunning({})".format(repr(str(self))) + _UniffiTempNodeError.NotRunning = NotRunning # type: ignore + class OnchainTxCreationFailed(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.OnchainTxCreationFailed({})".format(repr(str(self))) + _UniffiTempNodeError.OnchainTxCreationFailed = OnchainTxCreationFailed # type: ignore + class ConnectionFailed(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.ConnectionFailed({})".format(repr(str(self))) + _UniffiTempNodeError.ConnectionFailed = ConnectionFailed # type: ignore + class InvoiceCreationFailed(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.InvoiceCreationFailed({})".format(repr(str(self))) + _UniffiTempNodeError.InvoiceCreationFailed = InvoiceCreationFailed # type: ignore + class InvoiceRequestCreationFailed(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.InvoiceRequestCreationFailed({})".format(repr(str(self))) + _UniffiTempNodeError.InvoiceRequestCreationFailed = InvoiceRequestCreationFailed # type: ignore + class OfferCreationFailed(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.OfferCreationFailed({})".format(repr(str(self))) + _UniffiTempNodeError.OfferCreationFailed = OfferCreationFailed # type: ignore + class RefundCreationFailed(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.RefundCreationFailed({})".format(repr(str(self))) + _UniffiTempNodeError.RefundCreationFailed = RefundCreationFailed # type: ignore + class PaymentSendingFailed(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.PaymentSendingFailed({})".format(repr(str(self))) + _UniffiTempNodeError.PaymentSendingFailed = PaymentSendingFailed # type: ignore + class InvalidCustomTlvs(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.InvalidCustomTlvs({})".format(repr(str(self))) + _UniffiTempNodeError.InvalidCustomTlvs = InvalidCustomTlvs # type: ignore + class ProbeSendingFailed(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.ProbeSendingFailed({})".format(repr(str(self))) + _UniffiTempNodeError.ProbeSendingFailed = ProbeSendingFailed # type: ignore + class RouteNotFound(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.RouteNotFound({})".format(repr(str(self))) + _UniffiTempNodeError.RouteNotFound = RouteNotFound # type: ignore + class ChannelCreationFailed(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.ChannelCreationFailed({})".format(repr(str(self))) + _UniffiTempNodeError.ChannelCreationFailed = ChannelCreationFailed # type: ignore + class ChannelClosingFailed(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.ChannelClosingFailed({})".format(repr(str(self))) + _UniffiTempNodeError.ChannelClosingFailed = ChannelClosingFailed # type: ignore + class ChannelSplicingFailed(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.ChannelSplicingFailed({})".format(repr(str(self))) + _UniffiTempNodeError.ChannelSplicingFailed = ChannelSplicingFailed # type: ignore + class ChannelConfigUpdateFailed(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.ChannelConfigUpdateFailed({})".format(repr(str(self))) + _UniffiTempNodeError.ChannelConfigUpdateFailed = ChannelConfigUpdateFailed # type: ignore + class PersistenceFailed(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.PersistenceFailed({})".format(repr(str(self))) + _UniffiTempNodeError.PersistenceFailed = PersistenceFailed # type: ignore + class FeerateEstimationUpdateFailed(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.FeerateEstimationUpdateFailed({})".format(repr(str(self))) + _UniffiTempNodeError.FeerateEstimationUpdateFailed = FeerateEstimationUpdateFailed # type: ignore + class FeerateEstimationUpdateTimeout(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.FeerateEstimationUpdateTimeout({})".format(repr(str(self))) + _UniffiTempNodeError.FeerateEstimationUpdateTimeout = FeerateEstimationUpdateTimeout # type: ignore + class WalletOperationFailed(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.WalletOperationFailed({})".format(repr(str(self))) + _UniffiTempNodeError.WalletOperationFailed = WalletOperationFailed # type: ignore + class WalletOperationTimeout(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.WalletOperationTimeout({})".format(repr(str(self))) + _UniffiTempNodeError.WalletOperationTimeout = WalletOperationTimeout # type: ignore + class OnchainTxSigningFailed(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.OnchainTxSigningFailed({})".format(repr(str(self))) + _UniffiTempNodeError.OnchainTxSigningFailed = OnchainTxSigningFailed # type: ignore + class TxSyncFailed(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.TxSyncFailed({})".format(repr(str(self))) + _UniffiTempNodeError.TxSyncFailed = TxSyncFailed # type: ignore + class TxSyncTimeout(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.TxSyncTimeout({})".format(repr(str(self))) + _UniffiTempNodeError.TxSyncTimeout = TxSyncTimeout # type: ignore + class GossipUpdateFailed(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.GossipUpdateFailed({})".format(repr(str(self))) + _UniffiTempNodeError.GossipUpdateFailed = GossipUpdateFailed # type: ignore + class GossipUpdateTimeout(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.GossipUpdateTimeout({})".format(repr(str(self))) + _UniffiTempNodeError.GossipUpdateTimeout = GossipUpdateTimeout # type: ignore + class LiquidityRequestFailed(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.LiquidityRequestFailed({})".format(repr(str(self))) + _UniffiTempNodeError.LiquidityRequestFailed = LiquidityRequestFailed # type: ignore + class UriParameterParsingFailed(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.UriParameterParsingFailed({})".format(repr(str(self))) + _UniffiTempNodeError.UriParameterParsingFailed = UriParameterParsingFailed # type: ignore + class InvalidAddress(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.InvalidAddress({})".format(repr(str(self))) + _UniffiTempNodeError.InvalidAddress = InvalidAddress # type: ignore + class InvalidSocketAddress(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.InvalidSocketAddress({})".format(repr(str(self))) + _UniffiTempNodeError.InvalidSocketAddress = InvalidSocketAddress # type: ignore + class InvalidPublicKey(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.InvalidPublicKey({})".format(repr(str(self))) + _UniffiTempNodeError.InvalidPublicKey = InvalidPublicKey # type: ignore + class InvalidSecretKey(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.InvalidSecretKey({})".format(repr(str(self))) + _UniffiTempNodeError.InvalidSecretKey = InvalidSecretKey # type: ignore + class InvalidOfferId(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.InvalidOfferId({})".format(repr(str(self))) + _UniffiTempNodeError.InvalidOfferId = InvalidOfferId # type: ignore + class InvalidNodeId(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.InvalidNodeId({})".format(repr(str(self))) + _UniffiTempNodeError.InvalidNodeId = InvalidNodeId # type: ignore + class InvalidPaymentId(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.InvalidPaymentId({})".format(repr(str(self))) + _UniffiTempNodeError.InvalidPaymentId = InvalidPaymentId # type: ignore + class InvalidPaymentHash(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.InvalidPaymentHash({})".format(repr(str(self))) + _UniffiTempNodeError.InvalidPaymentHash = InvalidPaymentHash # type: ignore + class InvalidPaymentPreimage(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.InvalidPaymentPreimage({})".format(repr(str(self))) + _UniffiTempNodeError.InvalidPaymentPreimage = InvalidPaymentPreimage # type: ignore + class InvalidPaymentSecret(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.InvalidPaymentSecret({})".format(repr(str(self))) + _UniffiTempNodeError.InvalidPaymentSecret = InvalidPaymentSecret # type: ignore + class InvalidAmount(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.InvalidAmount({})".format(repr(str(self))) + _UniffiTempNodeError.InvalidAmount = InvalidAmount # type: ignore + class InvalidInvoice(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.InvalidInvoice({})".format(repr(str(self))) + _UniffiTempNodeError.InvalidInvoice = InvalidInvoice # type: ignore + class InvalidOffer(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.InvalidOffer({})".format(repr(str(self))) + _UniffiTempNodeError.InvalidOffer = InvalidOffer # type: ignore + class InvalidRefund(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.InvalidRefund({})".format(repr(str(self))) + _UniffiTempNodeError.InvalidRefund = InvalidRefund # type: ignore + class InvalidChannelId(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.InvalidChannelId({})".format(repr(str(self))) + _UniffiTempNodeError.InvalidChannelId = InvalidChannelId # type: ignore + class InvalidNetwork(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.InvalidNetwork({})".format(repr(str(self))) + _UniffiTempNodeError.InvalidNetwork = InvalidNetwork # type: ignore + class InvalidUri(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.InvalidUri({})".format(repr(str(self))) + _UniffiTempNodeError.InvalidUri = InvalidUri # type: ignore + class InvalidQuantity(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.InvalidQuantity({})".format(repr(str(self))) + _UniffiTempNodeError.InvalidQuantity = InvalidQuantity # type: ignore + class InvalidNodeAlias(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.InvalidNodeAlias({})".format(repr(str(self))) + _UniffiTempNodeError.InvalidNodeAlias = InvalidNodeAlias # type: ignore + class InvalidDateTime(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.InvalidDateTime({})".format(repr(str(self))) + _UniffiTempNodeError.InvalidDateTime = InvalidDateTime # type: ignore + class InvalidFeeRate(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.InvalidFeeRate({})".format(repr(str(self))) + _UniffiTempNodeError.InvalidFeeRate = InvalidFeeRate # type: ignore + class DuplicatePayment(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.DuplicatePayment({})".format(repr(str(self))) + _UniffiTempNodeError.DuplicatePayment = DuplicatePayment # type: ignore + class UnsupportedCurrency(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.UnsupportedCurrency({})".format(repr(str(self))) + _UniffiTempNodeError.UnsupportedCurrency = UnsupportedCurrency # type: ignore + class InsufficientFunds(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.InsufficientFunds({})".format(repr(str(self))) + _UniffiTempNodeError.InsufficientFunds = InsufficientFunds # type: ignore + class LiquiditySourceUnavailable(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.LiquiditySourceUnavailable({})".format(repr(str(self))) + _UniffiTempNodeError.LiquiditySourceUnavailable = LiquiditySourceUnavailable # type: ignore + class LiquidityFeeTooHigh(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.LiquidityFeeTooHigh({})".format(repr(str(self))) + _UniffiTempNodeError.LiquidityFeeTooHigh = LiquidityFeeTooHigh # type: ignore + class InvalidBlindedPaths(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.InvalidBlindedPaths({})".format(repr(str(self))) + _UniffiTempNodeError.InvalidBlindedPaths = InvalidBlindedPaths # type: ignore + class AsyncPaymentServicesDisabled(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.AsyncPaymentServicesDisabled({})".format(repr(str(self))) + _UniffiTempNodeError.AsyncPaymentServicesDisabled = AsyncPaymentServicesDisabled # type: ignore + class CannotRbfFundingTransaction(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.CannotRbfFundingTransaction({})".format(repr(str(self))) + _UniffiTempNodeError.CannotRbfFundingTransaction = CannotRbfFundingTransaction # type: ignore + class TransactionNotFound(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.TransactionNotFound({})".format(repr(str(self))) + _UniffiTempNodeError.TransactionNotFound = TransactionNotFound # type: ignore + class TransactionAlreadyConfirmed(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.TransactionAlreadyConfirmed({})".format(repr(str(self))) + _UniffiTempNodeError.TransactionAlreadyConfirmed = TransactionAlreadyConfirmed # type: ignore + class NoSpendableOutputs(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.NoSpendableOutputs({})".format(repr(str(self))) + _UniffiTempNodeError.NoSpendableOutputs = NoSpendableOutputs # type: ignore + class CoinSelectionFailed(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.CoinSelectionFailed({})".format(repr(str(self))) + _UniffiTempNodeError.CoinSelectionFailed = CoinSelectionFailed # type: ignore + class InvalidMnemonic(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.InvalidMnemonic({})".format(repr(str(self))) + _UniffiTempNodeError.InvalidMnemonic = InvalidMnemonic # type: ignore + class BackgroundSyncNotEnabled(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.BackgroundSyncNotEnabled({})".format(repr(str(self))) + _UniffiTempNodeError.BackgroundSyncNotEnabled = BackgroundSyncNotEnabled # type: ignore + class AddressTypeAlreadyMonitored(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.AddressTypeAlreadyMonitored({})".format(repr(str(self))) + _UniffiTempNodeError.AddressTypeAlreadyMonitored = AddressTypeAlreadyMonitored # type: ignore + class AddressTypeIsPrimary(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.AddressTypeIsPrimary({})".format(repr(str(self))) + _UniffiTempNodeError.AddressTypeIsPrimary = AddressTypeIsPrimary # type: ignore + class AddressTypeNotMonitored(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.AddressTypeNotMonitored({})".format(repr(str(self))) + _UniffiTempNodeError.AddressTypeNotMonitored = AddressTypeNotMonitored # type: ignore + class OnchainWalletAccountNotRegistered(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.OnchainWalletAccountNotRegistered({})".format(repr(str(self))) + _UniffiTempNodeError.OnchainWalletAccountNotRegistered = OnchainWalletAccountNotRegistered # type: ignore + class InvalidSeedBytes(_UniffiTempNodeError): + + def __repr__(self): + return "NodeError.InvalidSeedBytes({})".format(repr(str(self))) + _UniffiTempNodeError.InvalidSeedBytes = InvalidSeedBytes # type: ignore + +NodeError = _UniffiTempNodeError # type: ignore +del _UniffiTempNodeError + + +class _UniffiConverterTypeNodeError(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return NodeError.AlreadyRunning( + _UniffiConverterString.read(buf), + ) + if variant == 2: + return NodeError.NotRunning( + _UniffiConverterString.read(buf), + ) + if variant == 3: + return NodeError.OnchainTxCreationFailed( + _UniffiConverterString.read(buf), + ) + if variant == 4: + return NodeError.ConnectionFailed( + _UniffiConverterString.read(buf), + ) + if variant == 5: + return NodeError.InvoiceCreationFailed( + _UniffiConverterString.read(buf), + ) + if variant == 6: + return NodeError.InvoiceRequestCreationFailed( + _UniffiConverterString.read(buf), + ) + if variant == 7: + return NodeError.OfferCreationFailed( + _UniffiConverterString.read(buf), + ) + if variant == 8: + return NodeError.RefundCreationFailed( + _UniffiConverterString.read(buf), + ) + if variant == 9: + return NodeError.PaymentSendingFailed( + _UniffiConverterString.read(buf), + ) + if variant == 10: + return NodeError.InvalidCustomTlvs( + _UniffiConverterString.read(buf), + ) + if variant == 11: + return NodeError.ProbeSendingFailed( + _UniffiConverterString.read(buf), + ) + if variant == 12: + return NodeError.RouteNotFound( + _UniffiConverterString.read(buf), + ) + if variant == 13: + return NodeError.ChannelCreationFailed( + _UniffiConverterString.read(buf), + ) + if variant == 14: + return NodeError.ChannelClosingFailed( + _UniffiConverterString.read(buf), + ) + if variant == 15: + return NodeError.ChannelSplicingFailed( + _UniffiConverterString.read(buf), + ) + if variant == 16: + return NodeError.ChannelConfigUpdateFailed( + _UniffiConverterString.read(buf), + ) + if variant == 17: + return NodeError.PersistenceFailed( + _UniffiConverterString.read(buf), + ) + if variant == 18: + return NodeError.FeerateEstimationUpdateFailed( + _UniffiConverterString.read(buf), + ) + if variant == 19: + return NodeError.FeerateEstimationUpdateTimeout( + _UniffiConverterString.read(buf), + ) + if variant == 20: + return NodeError.WalletOperationFailed( + _UniffiConverterString.read(buf), + ) + if variant == 21: + return NodeError.WalletOperationTimeout( + _UniffiConverterString.read(buf), + ) + if variant == 22: + return NodeError.OnchainTxSigningFailed( + _UniffiConverterString.read(buf), + ) + if variant == 23: + return NodeError.TxSyncFailed( + _UniffiConverterString.read(buf), + ) + if variant == 24: + return NodeError.TxSyncTimeout( + _UniffiConverterString.read(buf), + ) + if variant == 25: + return NodeError.GossipUpdateFailed( + _UniffiConverterString.read(buf), + ) + if variant == 26: + return NodeError.GossipUpdateTimeout( + _UniffiConverterString.read(buf), + ) + if variant == 27: + return NodeError.LiquidityRequestFailed( + _UniffiConverterString.read(buf), + ) + if variant == 28: + return NodeError.UriParameterParsingFailed( + _UniffiConverterString.read(buf), + ) + if variant == 29: + return NodeError.InvalidAddress( + _UniffiConverterString.read(buf), + ) + if variant == 30: + return NodeError.InvalidSocketAddress( + _UniffiConverterString.read(buf), + ) + if variant == 31: + return NodeError.InvalidPublicKey( + _UniffiConverterString.read(buf), + ) + if variant == 32: + return NodeError.InvalidSecretKey( + _UniffiConverterString.read(buf), + ) + if variant == 33: + return NodeError.InvalidOfferId( + _UniffiConverterString.read(buf), + ) + if variant == 34: + return NodeError.InvalidNodeId( + _UniffiConverterString.read(buf), + ) + if variant == 35: + return NodeError.InvalidPaymentId( + _UniffiConverterString.read(buf), + ) + if variant == 36: + return NodeError.InvalidPaymentHash( + _UniffiConverterString.read(buf), + ) + if variant == 37: + return NodeError.InvalidPaymentPreimage( + _UniffiConverterString.read(buf), + ) + if variant == 38: + return NodeError.InvalidPaymentSecret( + _UniffiConverterString.read(buf), + ) + if variant == 39: + return NodeError.InvalidAmount( + _UniffiConverterString.read(buf), + ) + if variant == 40: + return NodeError.InvalidInvoice( + _UniffiConverterString.read(buf), + ) + if variant == 41: + return NodeError.InvalidOffer( + _UniffiConverterString.read(buf), + ) + if variant == 42: + return NodeError.InvalidRefund( + _UniffiConverterString.read(buf), + ) + if variant == 43: + return NodeError.InvalidChannelId( + _UniffiConverterString.read(buf), + ) + if variant == 44: + return NodeError.InvalidNetwork( + _UniffiConverterString.read(buf), + ) + if variant == 45: + return NodeError.InvalidUri( + _UniffiConverterString.read(buf), + ) + if variant == 46: + return NodeError.InvalidQuantity( + _UniffiConverterString.read(buf), + ) + if variant == 47: + return NodeError.InvalidNodeAlias( + _UniffiConverterString.read(buf), + ) + if variant == 48: + return NodeError.InvalidDateTime( + _UniffiConverterString.read(buf), + ) + if variant == 49: + return NodeError.InvalidFeeRate( + _UniffiConverterString.read(buf), + ) + if variant == 50: + return NodeError.DuplicatePayment( + _UniffiConverterString.read(buf), + ) + if variant == 51: + return NodeError.UnsupportedCurrency( + _UniffiConverterString.read(buf), + ) + if variant == 52: + return NodeError.InsufficientFunds( + _UniffiConverterString.read(buf), + ) + if variant == 53: + return NodeError.LiquiditySourceUnavailable( + _UniffiConverterString.read(buf), + ) + if variant == 54: + return NodeError.LiquidityFeeTooHigh( + _UniffiConverterString.read(buf), + ) + if variant == 55: + return NodeError.InvalidBlindedPaths( + _UniffiConverterString.read(buf), + ) + if variant == 56: + return NodeError.AsyncPaymentServicesDisabled( + _UniffiConverterString.read(buf), + ) + if variant == 57: + return NodeError.CannotRbfFundingTransaction( + _UniffiConverterString.read(buf), + ) + if variant == 58: + return NodeError.TransactionNotFound( + _UniffiConverterString.read(buf), + ) + if variant == 59: + return NodeError.TransactionAlreadyConfirmed( + _UniffiConverterString.read(buf), + ) + if variant == 60: + return NodeError.NoSpendableOutputs( + _UniffiConverterString.read(buf), + ) + if variant == 61: + return NodeError.CoinSelectionFailed( + _UniffiConverterString.read(buf), + ) + if variant == 62: + return NodeError.InvalidMnemonic( + _UniffiConverterString.read(buf), + ) + if variant == 63: + return NodeError.BackgroundSyncNotEnabled( + _UniffiConverterString.read(buf), + ) + if variant == 64: + return NodeError.AddressTypeAlreadyMonitored( + _UniffiConverterString.read(buf), + ) + if variant == 65: + return NodeError.AddressTypeIsPrimary( + _UniffiConverterString.read(buf), + ) + if variant == 66: + return NodeError.AddressTypeNotMonitored( + _UniffiConverterString.read(buf), + ) + if variant == 67: + return NodeError.OnchainWalletAccountNotRegistered( + _UniffiConverterString.read(buf), + ) + if variant == 68: + return NodeError.InvalidSeedBytes( + _UniffiConverterString.read(buf), + ) + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if isinstance(value, NodeError.AlreadyRunning): + return + if isinstance(value, NodeError.NotRunning): + return + if isinstance(value, NodeError.OnchainTxCreationFailed): + return + if isinstance(value, NodeError.ConnectionFailed): + return + if isinstance(value, NodeError.InvoiceCreationFailed): + return + if isinstance(value, NodeError.InvoiceRequestCreationFailed): + return + if isinstance(value, NodeError.OfferCreationFailed): + return + if isinstance(value, NodeError.RefundCreationFailed): + return + if isinstance(value, NodeError.PaymentSendingFailed): + return + if isinstance(value, NodeError.InvalidCustomTlvs): + return + if isinstance(value, NodeError.ProbeSendingFailed): + return + if isinstance(value, NodeError.RouteNotFound): + return + if isinstance(value, NodeError.ChannelCreationFailed): + return + if isinstance(value, NodeError.ChannelClosingFailed): + return + if isinstance(value, NodeError.ChannelSplicingFailed): + return + if isinstance(value, NodeError.ChannelConfigUpdateFailed): + return + if isinstance(value, NodeError.PersistenceFailed): + return + if isinstance(value, NodeError.FeerateEstimationUpdateFailed): + return + if isinstance(value, NodeError.FeerateEstimationUpdateTimeout): + return + if isinstance(value, NodeError.WalletOperationFailed): + return + if isinstance(value, NodeError.WalletOperationTimeout): + return + if isinstance(value, NodeError.OnchainTxSigningFailed): + return + if isinstance(value, NodeError.TxSyncFailed): + return + if isinstance(value, NodeError.TxSyncTimeout): + return + if isinstance(value, NodeError.GossipUpdateFailed): + return + if isinstance(value, NodeError.GossipUpdateTimeout): + return + if isinstance(value, NodeError.LiquidityRequestFailed): + return + if isinstance(value, NodeError.UriParameterParsingFailed): + return + if isinstance(value, NodeError.InvalidAddress): + return + if isinstance(value, NodeError.InvalidSocketAddress): + return + if isinstance(value, NodeError.InvalidPublicKey): + return + if isinstance(value, NodeError.InvalidSecretKey): + return + if isinstance(value, NodeError.InvalidOfferId): + return + if isinstance(value, NodeError.InvalidNodeId): + return + if isinstance(value, NodeError.InvalidPaymentId): + return + if isinstance(value, NodeError.InvalidPaymentHash): + return + if isinstance(value, NodeError.InvalidPaymentPreimage): + return + if isinstance(value, NodeError.InvalidPaymentSecret): + return + if isinstance(value, NodeError.InvalidAmount): + return + if isinstance(value, NodeError.InvalidInvoice): + return + if isinstance(value, NodeError.InvalidOffer): + return + if isinstance(value, NodeError.InvalidRefund): + return + if isinstance(value, NodeError.InvalidChannelId): + return + if isinstance(value, NodeError.InvalidNetwork): + return + if isinstance(value, NodeError.InvalidUri): + return + if isinstance(value, NodeError.InvalidQuantity): + return + if isinstance(value, NodeError.InvalidNodeAlias): + return + if isinstance(value, NodeError.InvalidDateTime): + return + if isinstance(value, NodeError.InvalidFeeRate): + return + if isinstance(value, NodeError.DuplicatePayment): + return + if isinstance(value, NodeError.UnsupportedCurrency): + return + if isinstance(value, NodeError.InsufficientFunds): + return + if isinstance(value, NodeError.LiquiditySourceUnavailable): + return + if isinstance(value, NodeError.LiquidityFeeTooHigh): + return + if isinstance(value, NodeError.InvalidBlindedPaths): + return + if isinstance(value, NodeError.AsyncPaymentServicesDisabled): + return + if isinstance(value, NodeError.CannotRbfFundingTransaction): + return + if isinstance(value, NodeError.TransactionNotFound): + return + if isinstance(value, NodeError.TransactionAlreadyConfirmed): + return + if isinstance(value, NodeError.NoSpendableOutputs): + return + if isinstance(value, NodeError.CoinSelectionFailed): + return + if isinstance(value, NodeError.InvalidMnemonic): + return + if isinstance(value, NodeError.BackgroundSyncNotEnabled): + return + if isinstance(value, NodeError.AddressTypeAlreadyMonitored): + return + if isinstance(value, NodeError.AddressTypeIsPrimary): + return + if isinstance(value, NodeError.AddressTypeNotMonitored): + return + if isinstance(value, NodeError.OnchainWalletAccountNotRegistered): + return + if isinstance(value, NodeError.InvalidSeedBytes): + return + + @staticmethod + def write(value, buf): + if isinstance(value, NodeError.AlreadyRunning): + buf.write_i32(1) + if isinstance(value, NodeError.NotRunning): + buf.write_i32(2) + if isinstance(value, NodeError.OnchainTxCreationFailed): + buf.write_i32(3) + if isinstance(value, NodeError.ConnectionFailed): + buf.write_i32(4) + if isinstance(value, NodeError.InvoiceCreationFailed): + buf.write_i32(5) + if isinstance(value, NodeError.InvoiceRequestCreationFailed): + buf.write_i32(6) + if isinstance(value, NodeError.OfferCreationFailed): + buf.write_i32(7) + if isinstance(value, NodeError.RefundCreationFailed): + buf.write_i32(8) + if isinstance(value, NodeError.PaymentSendingFailed): + buf.write_i32(9) + if isinstance(value, NodeError.InvalidCustomTlvs): + buf.write_i32(10) + if isinstance(value, NodeError.ProbeSendingFailed): + buf.write_i32(11) + if isinstance(value, NodeError.RouteNotFound): + buf.write_i32(12) + if isinstance(value, NodeError.ChannelCreationFailed): + buf.write_i32(13) + if isinstance(value, NodeError.ChannelClosingFailed): + buf.write_i32(14) + if isinstance(value, NodeError.ChannelSplicingFailed): + buf.write_i32(15) + if isinstance(value, NodeError.ChannelConfigUpdateFailed): + buf.write_i32(16) + if isinstance(value, NodeError.PersistenceFailed): + buf.write_i32(17) + if isinstance(value, NodeError.FeerateEstimationUpdateFailed): + buf.write_i32(18) + if isinstance(value, NodeError.FeerateEstimationUpdateTimeout): + buf.write_i32(19) + if isinstance(value, NodeError.WalletOperationFailed): + buf.write_i32(20) + if isinstance(value, NodeError.WalletOperationTimeout): + buf.write_i32(21) + if isinstance(value, NodeError.OnchainTxSigningFailed): + buf.write_i32(22) + if isinstance(value, NodeError.TxSyncFailed): + buf.write_i32(23) + if isinstance(value, NodeError.TxSyncTimeout): + buf.write_i32(24) + if isinstance(value, NodeError.GossipUpdateFailed): + buf.write_i32(25) + if isinstance(value, NodeError.GossipUpdateTimeout): + buf.write_i32(26) + if isinstance(value, NodeError.LiquidityRequestFailed): + buf.write_i32(27) + if isinstance(value, NodeError.UriParameterParsingFailed): + buf.write_i32(28) + if isinstance(value, NodeError.InvalidAddress): + buf.write_i32(29) + if isinstance(value, NodeError.InvalidSocketAddress): + buf.write_i32(30) + if isinstance(value, NodeError.InvalidPublicKey): + buf.write_i32(31) + if isinstance(value, NodeError.InvalidSecretKey): + buf.write_i32(32) + if isinstance(value, NodeError.InvalidOfferId): + buf.write_i32(33) + if isinstance(value, NodeError.InvalidNodeId): + buf.write_i32(34) + if isinstance(value, NodeError.InvalidPaymentId): + buf.write_i32(35) + if isinstance(value, NodeError.InvalidPaymentHash): + buf.write_i32(36) + if isinstance(value, NodeError.InvalidPaymentPreimage): + buf.write_i32(37) + if isinstance(value, NodeError.InvalidPaymentSecret): + buf.write_i32(38) + if isinstance(value, NodeError.InvalidAmount): + buf.write_i32(39) + if isinstance(value, NodeError.InvalidInvoice): + buf.write_i32(40) + if isinstance(value, NodeError.InvalidOffer): + buf.write_i32(41) + if isinstance(value, NodeError.InvalidRefund): + buf.write_i32(42) + if isinstance(value, NodeError.InvalidChannelId): + buf.write_i32(43) + if isinstance(value, NodeError.InvalidNetwork): + buf.write_i32(44) + if isinstance(value, NodeError.InvalidUri): + buf.write_i32(45) + if isinstance(value, NodeError.InvalidQuantity): + buf.write_i32(46) + if isinstance(value, NodeError.InvalidNodeAlias): + buf.write_i32(47) + if isinstance(value, NodeError.InvalidDateTime): + buf.write_i32(48) + if isinstance(value, NodeError.InvalidFeeRate): + buf.write_i32(49) + if isinstance(value, NodeError.DuplicatePayment): + buf.write_i32(50) + if isinstance(value, NodeError.UnsupportedCurrency): + buf.write_i32(51) + if isinstance(value, NodeError.InsufficientFunds): + buf.write_i32(52) + if isinstance(value, NodeError.LiquiditySourceUnavailable): + buf.write_i32(53) + if isinstance(value, NodeError.LiquidityFeeTooHigh): + buf.write_i32(54) + if isinstance(value, NodeError.InvalidBlindedPaths): + buf.write_i32(55) + if isinstance(value, NodeError.AsyncPaymentServicesDisabled): + buf.write_i32(56) + if isinstance(value, NodeError.CannotRbfFundingTransaction): + buf.write_i32(57) + if isinstance(value, NodeError.TransactionNotFound): + buf.write_i32(58) + if isinstance(value, NodeError.TransactionAlreadyConfirmed): + buf.write_i32(59) + if isinstance(value, NodeError.NoSpendableOutputs): + buf.write_i32(60) + if isinstance(value, NodeError.CoinSelectionFailed): + buf.write_i32(61) + if isinstance(value, NodeError.InvalidMnemonic): + buf.write_i32(62) + if isinstance(value, NodeError.BackgroundSyncNotEnabled): + buf.write_i32(63) + if isinstance(value, NodeError.AddressTypeAlreadyMonitored): + buf.write_i32(64) + if isinstance(value, NodeError.AddressTypeIsPrimary): + buf.write_i32(65) + if isinstance(value, NodeError.AddressTypeNotMonitored): + buf.write_i32(66) + if isinstance(value, NodeError.OnchainWalletAccountNotRegistered): + buf.write_i32(67) + if isinstance(value, NodeError.InvalidSeedBytes): + buf.write_i32(68) + + + + + +class OfferAmount: + def __init__(self): + raise RuntimeError("OfferAmount cannot be instantiated directly") + + # Each enum variant is a nested class of the enum itself. + class BITCOIN: + amount_msats: "int" + + def __init__(self,amount_msats: "int"): + self.amount_msats = amount_msats + + def __str__(self): + return "OfferAmount.BITCOIN(amount_msats={})".format(self.amount_msats) + + def __eq__(self, other): + if not other.is_bitcoin(): + return False + if self.amount_msats != other.amount_msats: + return False + return True + + class CURRENCY: + iso4217_code: "str" + amount: "int" + + def __init__(self,iso4217_code: "str", amount: "int"): + self.iso4217_code = iso4217_code + self.amount = amount + + def __str__(self): + return "OfferAmount.CURRENCY(iso4217_code={}, amount={})".format(self.iso4217_code, self.amount) + + def __eq__(self, other): + if not other.is_currency(): + return False + if self.iso4217_code != other.iso4217_code: + return False + if self.amount != other.amount: + return False + return True + + + + # For each variant, we have an `is_NAME` method for easily checking + # whether an instance is that variant. + def is_bitcoin(self) -> bool: + return isinstance(self, OfferAmount.BITCOIN) + def is_currency(self) -> bool: + return isinstance(self, OfferAmount.CURRENCY) + + +# Now, a little trick - we make each nested variant class be a subclass of the main +# enum class, so that method calls and instance checks etc will work intuitively. +# We might be able to do this a little more neatly with a metaclass, but this'll do. +OfferAmount.BITCOIN = type("OfferAmount.BITCOIN", (OfferAmount.BITCOIN, OfferAmount,), {}) # type: ignore +OfferAmount.CURRENCY = type("OfferAmount.CURRENCY", (OfferAmount.CURRENCY, OfferAmount,), {}) # type: ignore + + + + +class _UniffiConverterTypeOfferAmount(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return OfferAmount.BITCOIN( + _UniffiConverterUInt64.read(buf), + ) + if variant == 2: + return OfferAmount.CURRENCY( + _UniffiConverterString.read(buf), + _UniffiConverterUInt64.read(buf), + ) + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if value.is_bitcoin(): + _UniffiConverterUInt64.check_lower(value.amount_msats) + return + if value.is_currency(): + _UniffiConverterString.check_lower(value.iso4217_code) + _UniffiConverterUInt64.check_lower(value.amount) + return + raise ValueError(value) + + @staticmethod + def write(value, buf): + if value.is_bitcoin(): + buf.write_i32(1) + _UniffiConverterUInt64.write(value.amount_msats, buf) + if value.is_currency(): + buf.write_i32(2) + _UniffiConverterString.write(value.iso4217_code, buf) + _UniffiConverterUInt64.write(value.amount, buf) + + + + + + + +class PaymentDirection(enum.Enum): + INBOUND = 0 + + OUTBOUND = 1 + + + +class _UniffiConverterTypePaymentDirection(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return PaymentDirection.INBOUND + if variant == 2: + return PaymentDirection.OUTBOUND + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if value == PaymentDirection.INBOUND: + return + if value == PaymentDirection.OUTBOUND: + return + raise ValueError(value) + + @staticmethod + def write(value, buf): + if value == PaymentDirection.INBOUND: + buf.write_i32(1) + if value == PaymentDirection.OUTBOUND: + buf.write_i32(2) + + + + + + + +class PaymentFailureReason(enum.Enum): + RECIPIENT_REJECTED = 0 + + USER_ABANDONED = 1 + + RETRIES_EXHAUSTED = 2 + + PAYMENT_EXPIRED = 3 + + ROUTE_NOT_FOUND = 4 + + UNEXPECTED_ERROR = 5 + + UNKNOWN_REQUIRED_FEATURES = 6 + + INVOICE_REQUEST_EXPIRED = 7 + + INVOICE_REQUEST_REJECTED = 8 + + BLINDED_PATH_CREATION_FAILED = 9 + + + +class _UniffiConverterTypePaymentFailureReason(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return PaymentFailureReason.RECIPIENT_REJECTED + if variant == 2: + return PaymentFailureReason.USER_ABANDONED + if variant == 3: + return PaymentFailureReason.RETRIES_EXHAUSTED + if variant == 4: + return PaymentFailureReason.PAYMENT_EXPIRED + if variant == 5: + return PaymentFailureReason.ROUTE_NOT_FOUND + if variant == 6: + return PaymentFailureReason.UNEXPECTED_ERROR + if variant == 7: + return PaymentFailureReason.UNKNOWN_REQUIRED_FEATURES + if variant == 8: + return PaymentFailureReason.INVOICE_REQUEST_EXPIRED + if variant == 9: + return PaymentFailureReason.INVOICE_REQUEST_REJECTED + if variant == 10: + return PaymentFailureReason.BLINDED_PATH_CREATION_FAILED + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if value == PaymentFailureReason.RECIPIENT_REJECTED: + return + if value == PaymentFailureReason.USER_ABANDONED: + return + if value == PaymentFailureReason.RETRIES_EXHAUSTED: + return + if value == PaymentFailureReason.PAYMENT_EXPIRED: + return + if value == PaymentFailureReason.ROUTE_NOT_FOUND: + return + if value == PaymentFailureReason.UNEXPECTED_ERROR: + return + if value == PaymentFailureReason.UNKNOWN_REQUIRED_FEATURES: + return + if value == PaymentFailureReason.INVOICE_REQUEST_EXPIRED: + return + if value == PaymentFailureReason.INVOICE_REQUEST_REJECTED: + return + if value == PaymentFailureReason.BLINDED_PATH_CREATION_FAILED: + return + raise ValueError(value) + + @staticmethod + def write(value, buf): + if value == PaymentFailureReason.RECIPIENT_REJECTED: + buf.write_i32(1) + if value == PaymentFailureReason.USER_ABANDONED: + buf.write_i32(2) + if value == PaymentFailureReason.RETRIES_EXHAUSTED: + buf.write_i32(3) + if value == PaymentFailureReason.PAYMENT_EXPIRED: + buf.write_i32(4) + if value == PaymentFailureReason.ROUTE_NOT_FOUND: + buf.write_i32(5) + if value == PaymentFailureReason.UNEXPECTED_ERROR: + buf.write_i32(6) + if value == PaymentFailureReason.UNKNOWN_REQUIRED_FEATURES: + buf.write_i32(7) + if value == PaymentFailureReason.INVOICE_REQUEST_EXPIRED: + buf.write_i32(8) + if value == PaymentFailureReason.INVOICE_REQUEST_REJECTED: + buf.write_i32(9) + if value == PaymentFailureReason.BLINDED_PATH_CREATION_FAILED: + buf.write_i32(10) + + + + + + + +class PaymentKind: + def __init__(self): + raise RuntimeError("PaymentKind cannot be instantiated directly") + + # Each enum variant is a nested class of the enum itself. + class ONCHAIN: + txid: "Txid" + status: "ConfirmationStatus" + + def __init__(self,txid: "Txid", status: "ConfirmationStatus"): + self.txid = txid + self.status = status + + def __str__(self): + return "PaymentKind.ONCHAIN(txid={}, status={})".format(self.txid, self.status) + + def __eq__(self, other): + if not other.is_onchain(): + return False + if self.txid != other.txid: + return False + if self.status != other.status: + return False + return True + + class BOLT11: + hash: "PaymentHash" + preimage: "typing.Optional[PaymentPreimage]" + secret: "typing.Optional[PaymentSecret]" + description: "typing.Optional[str]" + bolt11: "typing.Optional[str]" + + def __init__(self,hash: "PaymentHash", preimage: "typing.Optional[PaymentPreimage]", secret: "typing.Optional[PaymentSecret]", description: "typing.Optional[str]", bolt11: "typing.Optional[str]"): + self.hash = hash + self.preimage = preimage + self.secret = secret + self.description = description + self.bolt11 = bolt11 + + def __str__(self): + return "PaymentKind.BOLT11(hash={}, preimage={}, secret={}, description={}, bolt11={})".format(self.hash, self.preimage, self.secret, self.description, self.bolt11) + + def __eq__(self, other): + if not other.is_bolt11(): + return False + if self.hash != other.hash: + return False + if self.preimage != other.preimage: + return False + if self.secret != other.secret: + return False + if self.description != other.description: + return False + if self.bolt11 != other.bolt11: + return False + return True + + class BOLT11_JIT: + hash: "PaymentHash" + preimage: "typing.Optional[PaymentPreimage]" + secret: "typing.Optional[PaymentSecret]" + counterparty_skimmed_fee_msat: "typing.Optional[int]" + lsp_fee_limits: "LspFeeLimits" + description: "typing.Optional[str]" + bolt11: "typing.Optional[str]" + + def __init__(self,hash: "PaymentHash", preimage: "typing.Optional[PaymentPreimage]", secret: "typing.Optional[PaymentSecret]", counterparty_skimmed_fee_msat: "typing.Optional[int]", lsp_fee_limits: "LspFeeLimits", description: "typing.Optional[str]", bolt11: "typing.Optional[str]"): + self.hash = hash + self.preimage = preimage + self.secret = secret + self.counterparty_skimmed_fee_msat = counterparty_skimmed_fee_msat + self.lsp_fee_limits = lsp_fee_limits + self.description = description + self.bolt11 = bolt11 + + def __str__(self): + return "PaymentKind.BOLT11_JIT(hash={}, preimage={}, secret={}, counterparty_skimmed_fee_msat={}, lsp_fee_limits={}, description={}, bolt11={})".format(self.hash, self.preimage, self.secret, self.counterparty_skimmed_fee_msat, self.lsp_fee_limits, self.description, self.bolt11) + + def __eq__(self, other): + if not other.is_bolt11_jit(): + return False + if self.hash != other.hash: + return False + if self.preimage != other.preimage: + return False + if self.secret != other.secret: + return False + if self.counterparty_skimmed_fee_msat != other.counterparty_skimmed_fee_msat: + return False + if self.lsp_fee_limits != other.lsp_fee_limits: + return False + if self.description != other.description: + return False + if self.bolt11 != other.bolt11: + return False + return True + + class BOLT12_OFFER: + hash: "typing.Optional[PaymentHash]" + preimage: "typing.Optional[PaymentPreimage]" + secret: "typing.Optional[PaymentSecret]" + offer_id: "OfferId" + payer_note: "typing.Optional[UntrustedString]" + quantity: "typing.Optional[int]" + + def __init__(self,hash: "typing.Optional[PaymentHash]", preimage: "typing.Optional[PaymentPreimage]", secret: "typing.Optional[PaymentSecret]", offer_id: "OfferId", payer_note: "typing.Optional[UntrustedString]", quantity: "typing.Optional[int]"): + self.hash = hash + self.preimage = preimage + self.secret = secret + self.offer_id = offer_id + self.payer_note = payer_note + self.quantity = quantity + + def __str__(self): + return "PaymentKind.BOLT12_OFFER(hash={}, preimage={}, secret={}, offer_id={}, payer_note={}, quantity={})".format(self.hash, self.preimage, self.secret, self.offer_id, self.payer_note, self.quantity) + + def __eq__(self, other): + if not other.is_bolt12_offer(): + return False + if self.hash != other.hash: + return False + if self.preimage != other.preimage: + return False + if self.secret != other.secret: + return False + if self.offer_id != other.offer_id: + return False + if self.payer_note != other.payer_note: + return False + if self.quantity != other.quantity: + return False + return True + + class BOLT12_REFUND: + hash: "typing.Optional[PaymentHash]" + preimage: "typing.Optional[PaymentPreimage]" + secret: "typing.Optional[PaymentSecret]" + payer_note: "typing.Optional[UntrustedString]" + quantity: "typing.Optional[int]" + + def __init__(self,hash: "typing.Optional[PaymentHash]", preimage: "typing.Optional[PaymentPreimage]", secret: "typing.Optional[PaymentSecret]", payer_note: "typing.Optional[UntrustedString]", quantity: "typing.Optional[int]"): + self.hash = hash + self.preimage = preimage + self.secret = secret + self.payer_note = payer_note + self.quantity = quantity + + def __str__(self): + return "PaymentKind.BOLT12_REFUND(hash={}, preimage={}, secret={}, payer_note={}, quantity={})".format(self.hash, self.preimage, self.secret, self.payer_note, self.quantity) + + def __eq__(self, other): + if not other.is_bolt12_refund(): + return False + if self.hash != other.hash: + return False + if self.preimage != other.preimage: + return False + if self.secret != other.secret: + return False + if self.payer_note != other.payer_note: + return False + if self.quantity != other.quantity: + return False + return True + + class SPONTANEOUS: + hash: "PaymentHash" + preimage: "typing.Optional[PaymentPreimage]" + + def __init__(self,hash: "PaymentHash", preimage: "typing.Optional[PaymentPreimage]"): + self.hash = hash + self.preimage = preimage + + def __str__(self): + return "PaymentKind.SPONTANEOUS(hash={}, preimage={})".format(self.hash, self.preimage) + + def __eq__(self, other): + if not other.is_spontaneous(): + return False + if self.hash != other.hash: + return False + if self.preimage != other.preimage: + return False + return True + + + + # For each variant, we have an `is_NAME` method for easily checking + # whether an instance is that variant. + def is_onchain(self) -> bool: + return isinstance(self, PaymentKind.ONCHAIN) + def is_bolt11(self) -> bool: + return isinstance(self, PaymentKind.BOLT11) + def is_bolt11_jit(self) -> bool: + return isinstance(self, PaymentKind.BOLT11_JIT) + def is_bolt12_offer(self) -> bool: + return isinstance(self, PaymentKind.BOLT12_OFFER) + def is_bolt12_refund(self) -> bool: + return isinstance(self, PaymentKind.BOLT12_REFUND) + def is_spontaneous(self) -> bool: + return isinstance(self, PaymentKind.SPONTANEOUS) + + +# Now, a little trick - we make each nested variant class be a subclass of the main +# enum class, so that method calls and instance checks etc will work intuitively. +# We might be able to do this a little more neatly with a metaclass, but this'll do. +PaymentKind.ONCHAIN = type("PaymentKind.ONCHAIN", (PaymentKind.ONCHAIN, PaymentKind,), {}) # type: ignore +PaymentKind.BOLT11 = type("PaymentKind.BOLT11", (PaymentKind.BOLT11, PaymentKind,), {}) # type: ignore +PaymentKind.BOLT11_JIT = type("PaymentKind.BOLT11_JIT", (PaymentKind.BOLT11_JIT, PaymentKind,), {}) # type: ignore +PaymentKind.BOLT12_OFFER = type("PaymentKind.BOLT12_OFFER", (PaymentKind.BOLT12_OFFER, PaymentKind,), {}) # type: ignore +PaymentKind.BOLT12_REFUND = type("PaymentKind.BOLT12_REFUND", (PaymentKind.BOLT12_REFUND, PaymentKind,), {}) # type: ignore +PaymentKind.SPONTANEOUS = type("PaymentKind.SPONTANEOUS", (PaymentKind.SPONTANEOUS, PaymentKind,), {}) # type: ignore + + + + +class _UniffiConverterTypePaymentKind(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return PaymentKind.ONCHAIN( + _UniffiConverterTypeTxid.read(buf), + _UniffiConverterTypeConfirmationStatus.read(buf), + ) + if variant == 2: + return PaymentKind.BOLT11( + _UniffiConverterTypePaymentHash.read(buf), + _UniffiConverterOptionalTypePaymentPreimage.read(buf), + _UniffiConverterOptionalTypePaymentSecret.read(buf), + _UniffiConverterOptionalString.read(buf), + _UniffiConverterOptionalString.read(buf), + ) + if variant == 3: + return PaymentKind.BOLT11_JIT( + _UniffiConverterTypePaymentHash.read(buf), + _UniffiConverterOptionalTypePaymentPreimage.read(buf), + _UniffiConverterOptionalTypePaymentSecret.read(buf), + _UniffiConverterOptionalUInt64.read(buf), + _UniffiConverterTypeLspFeeLimits.read(buf), + _UniffiConverterOptionalString.read(buf), + _UniffiConverterOptionalString.read(buf), + ) + if variant == 4: + return PaymentKind.BOLT12_OFFER( + _UniffiConverterOptionalTypePaymentHash.read(buf), + _UniffiConverterOptionalTypePaymentPreimage.read(buf), + _UniffiConverterOptionalTypePaymentSecret.read(buf), + _UniffiConverterTypeOfferId.read(buf), + _UniffiConverterOptionalTypeUntrustedString.read(buf), + _UniffiConverterOptionalUInt64.read(buf), + ) + if variant == 5: + return PaymentKind.BOLT12_REFUND( + _UniffiConverterOptionalTypePaymentHash.read(buf), + _UniffiConverterOptionalTypePaymentPreimage.read(buf), + _UniffiConverterOptionalTypePaymentSecret.read(buf), + _UniffiConverterOptionalTypeUntrustedString.read(buf), + _UniffiConverterOptionalUInt64.read(buf), + ) + if variant == 6: + return PaymentKind.SPONTANEOUS( + _UniffiConverterTypePaymentHash.read(buf), + _UniffiConverterOptionalTypePaymentPreimage.read(buf), + ) + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if value.is_onchain(): + _UniffiConverterTypeTxid.check_lower(value.txid) + _UniffiConverterTypeConfirmationStatus.check_lower(value.status) + return + if value.is_bolt11(): + _UniffiConverterTypePaymentHash.check_lower(value.hash) + _UniffiConverterOptionalTypePaymentPreimage.check_lower(value.preimage) + _UniffiConverterOptionalTypePaymentSecret.check_lower(value.secret) + _UniffiConverterOptionalString.check_lower(value.description) + _UniffiConverterOptionalString.check_lower(value.bolt11) + return + if value.is_bolt11_jit(): + _UniffiConverterTypePaymentHash.check_lower(value.hash) + _UniffiConverterOptionalTypePaymentPreimage.check_lower(value.preimage) + _UniffiConverterOptionalTypePaymentSecret.check_lower(value.secret) + _UniffiConverterOptionalUInt64.check_lower(value.counterparty_skimmed_fee_msat) + _UniffiConverterTypeLspFeeLimits.check_lower(value.lsp_fee_limits) + _UniffiConverterOptionalString.check_lower(value.description) + _UniffiConverterOptionalString.check_lower(value.bolt11) + return + if value.is_bolt12_offer(): + _UniffiConverterOptionalTypePaymentHash.check_lower(value.hash) + _UniffiConverterOptionalTypePaymentPreimage.check_lower(value.preimage) + _UniffiConverterOptionalTypePaymentSecret.check_lower(value.secret) + _UniffiConverterTypeOfferId.check_lower(value.offer_id) + _UniffiConverterOptionalTypeUntrustedString.check_lower(value.payer_note) + _UniffiConverterOptionalUInt64.check_lower(value.quantity) + return + if value.is_bolt12_refund(): + _UniffiConverterOptionalTypePaymentHash.check_lower(value.hash) + _UniffiConverterOptionalTypePaymentPreimage.check_lower(value.preimage) + _UniffiConverterOptionalTypePaymentSecret.check_lower(value.secret) + _UniffiConverterOptionalTypeUntrustedString.check_lower(value.payer_note) + _UniffiConverterOptionalUInt64.check_lower(value.quantity) + return + if value.is_spontaneous(): + _UniffiConverterTypePaymentHash.check_lower(value.hash) + _UniffiConverterOptionalTypePaymentPreimage.check_lower(value.preimage) + return + raise ValueError(value) + + @staticmethod + def write(value, buf): + if value.is_onchain(): + buf.write_i32(1) + _UniffiConverterTypeTxid.write(value.txid, buf) + _UniffiConverterTypeConfirmationStatus.write(value.status, buf) + if value.is_bolt11(): + buf.write_i32(2) + _UniffiConverterTypePaymentHash.write(value.hash, buf) + _UniffiConverterOptionalTypePaymentPreimage.write(value.preimage, buf) + _UniffiConverterOptionalTypePaymentSecret.write(value.secret, buf) + _UniffiConverterOptionalString.write(value.description, buf) + _UniffiConverterOptionalString.write(value.bolt11, buf) + if value.is_bolt11_jit(): + buf.write_i32(3) + _UniffiConverterTypePaymentHash.write(value.hash, buf) + _UniffiConverterOptionalTypePaymentPreimage.write(value.preimage, buf) + _UniffiConverterOptionalTypePaymentSecret.write(value.secret, buf) + _UniffiConverterOptionalUInt64.write(value.counterparty_skimmed_fee_msat, buf) + _UniffiConverterTypeLspFeeLimits.write(value.lsp_fee_limits, buf) + _UniffiConverterOptionalString.write(value.description, buf) + _UniffiConverterOptionalString.write(value.bolt11, buf) + if value.is_bolt12_offer(): + buf.write_i32(4) + _UniffiConverterOptionalTypePaymentHash.write(value.hash, buf) + _UniffiConverterOptionalTypePaymentPreimage.write(value.preimage, buf) + _UniffiConverterOptionalTypePaymentSecret.write(value.secret, buf) + _UniffiConverterTypeOfferId.write(value.offer_id, buf) + _UniffiConverterOptionalTypeUntrustedString.write(value.payer_note, buf) + _UniffiConverterOptionalUInt64.write(value.quantity, buf) + if value.is_bolt12_refund(): + buf.write_i32(5) + _UniffiConverterOptionalTypePaymentHash.write(value.hash, buf) + _UniffiConverterOptionalTypePaymentPreimage.write(value.preimage, buf) + _UniffiConverterOptionalTypePaymentSecret.write(value.secret, buf) + _UniffiConverterOptionalTypeUntrustedString.write(value.payer_note, buf) + _UniffiConverterOptionalUInt64.write(value.quantity, buf) + if value.is_spontaneous(): + buf.write_i32(6) + _UniffiConverterTypePaymentHash.write(value.hash, buf) + _UniffiConverterOptionalTypePaymentPreimage.write(value.preimage, buf) + + + + + + + +class PaymentStatus(enum.Enum): + PENDING = 0 + + SUCCEEDED = 1 + + FAILED = 2 + + + +class _UniffiConverterTypePaymentStatus(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return PaymentStatus.PENDING + if variant == 2: + return PaymentStatus.SUCCEEDED + if variant == 3: + return PaymentStatus.FAILED + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if value == PaymentStatus.PENDING: + return + if value == PaymentStatus.SUCCEEDED: + return + if value == PaymentStatus.FAILED: + return + raise ValueError(value) + + @staticmethod + def write(value, buf): + if value == PaymentStatus.PENDING: + buf.write_i32(1) + if value == PaymentStatus.SUCCEEDED: + buf.write_i32(2) + if value == PaymentStatus.FAILED: + buf.write_i32(3) + + + + + + + +class PendingSweepBalance: + def __init__(self): + raise RuntimeError("PendingSweepBalance cannot be instantiated directly") + + # Each enum variant is a nested class of the enum itself. + class PENDING_BROADCAST: + channel_id: "typing.Optional[ChannelId]" + amount_satoshis: "int" + + def __init__(self,channel_id: "typing.Optional[ChannelId]", amount_satoshis: "int"): + self.channel_id = channel_id + self.amount_satoshis = amount_satoshis + + def __str__(self): + return "PendingSweepBalance.PENDING_BROADCAST(channel_id={}, amount_satoshis={})".format(self.channel_id, self.amount_satoshis) + + def __eq__(self, other): + if not other.is_pending_broadcast(): + return False + if self.channel_id != other.channel_id: + return False + if self.amount_satoshis != other.amount_satoshis: + return False + return True + + class BROADCAST_AWAITING_CONFIRMATION: + channel_id: "typing.Optional[ChannelId]" + latest_broadcast_height: "int" + latest_spending_txid: "Txid" + amount_satoshis: "int" + + def __init__(self,channel_id: "typing.Optional[ChannelId]", latest_broadcast_height: "int", latest_spending_txid: "Txid", amount_satoshis: "int"): + self.channel_id = channel_id + self.latest_broadcast_height = latest_broadcast_height + self.latest_spending_txid = latest_spending_txid + self.amount_satoshis = amount_satoshis + + def __str__(self): + return "PendingSweepBalance.BROADCAST_AWAITING_CONFIRMATION(channel_id={}, latest_broadcast_height={}, latest_spending_txid={}, amount_satoshis={})".format(self.channel_id, self.latest_broadcast_height, self.latest_spending_txid, self.amount_satoshis) + + def __eq__(self, other): + if not other.is_broadcast_awaiting_confirmation(): + return False + if self.channel_id != other.channel_id: + return False + if self.latest_broadcast_height != other.latest_broadcast_height: + return False + if self.latest_spending_txid != other.latest_spending_txid: + return False + if self.amount_satoshis != other.amount_satoshis: + return False + return True + + class AWAITING_THRESHOLD_CONFIRMATIONS: + channel_id: "typing.Optional[ChannelId]" + latest_spending_txid: "Txid" + confirmation_hash: "BlockHash" + confirmation_height: "int" + amount_satoshis: "int" + + def __init__(self,channel_id: "typing.Optional[ChannelId]", latest_spending_txid: "Txid", confirmation_hash: "BlockHash", confirmation_height: "int", amount_satoshis: "int"): + self.channel_id = channel_id + self.latest_spending_txid = latest_spending_txid + self.confirmation_hash = confirmation_hash + self.confirmation_height = confirmation_height + self.amount_satoshis = amount_satoshis + + def __str__(self): + return "PendingSweepBalance.AWAITING_THRESHOLD_CONFIRMATIONS(channel_id={}, latest_spending_txid={}, confirmation_hash={}, confirmation_height={}, amount_satoshis={})".format(self.channel_id, self.latest_spending_txid, self.confirmation_hash, self.confirmation_height, self.amount_satoshis) + + def __eq__(self, other): + if not other.is_awaiting_threshold_confirmations(): + return False + if self.channel_id != other.channel_id: + return False + if self.latest_spending_txid != other.latest_spending_txid: + return False + if self.confirmation_hash != other.confirmation_hash: + return False + if self.confirmation_height != other.confirmation_height: + return False + if self.amount_satoshis != other.amount_satoshis: + return False + return True + + + + # For each variant, we have an `is_NAME` method for easily checking + # whether an instance is that variant. + def is_pending_broadcast(self) -> bool: + return isinstance(self, PendingSweepBalance.PENDING_BROADCAST) + def is_broadcast_awaiting_confirmation(self) -> bool: + return isinstance(self, PendingSweepBalance.BROADCAST_AWAITING_CONFIRMATION) + def is_awaiting_threshold_confirmations(self) -> bool: + return isinstance(self, PendingSweepBalance.AWAITING_THRESHOLD_CONFIRMATIONS) + + +# Now, a little trick - we make each nested variant class be a subclass of the main +# enum class, so that method calls and instance checks etc will work intuitively. +# We might be able to do this a little more neatly with a metaclass, but this'll do. +PendingSweepBalance.PENDING_BROADCAST = type("PendingSweepBalance.PENDING_BROADCAST", (PendingSweepBalance.PENDING_BROADCAST, PendingSweepBalance,), {}) # type: ignore +PendingSweepBalance.BROADCAST_AWAITING_CONFIRMATION = type("PendingSweepBalance.BROADCAST_AWAITING_CONFIRMATION", (PendingSweepBalance.BROADCAST_AWAITING_CONFIRMATION, PendingSweepBalance,), {}) # type: ignore +PendingSweepBalance.AWAITING_THRESHOLD_CONFIRMATIONS = type("PendingSweepBalance.AWAITING_THRESHOLD_CONFIRMATIONS", (PendingSweepBalance.AWAITING_THRESHOLD_CONFIRMATIONS, PendingSweepBalance,), {}) # type: ignore + + + + +class _UniffiConverterTypePendingSweepBalance(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return PendingSweepBalance.PENDING_BROADCAST( + _UniffiConverterOptionalTypeChannelId.read(buf), + _UniffiConverterUInt64.read(buf), + ) + if variant == 2: + return PendingSweepBalance.BROADCAST_AWAITING_CONFIRMATION( + _UniffiConverterOptionalTypeChannelId.read(buf), + _UniffiConverterUInt32.read(buf), + _UniffiConverterTypeTxid.read(buf), + _UniffiConverterUInt64.read(buf), + ) + if variant == 3: + return PendingSweepBalance.AWAITING_THRESHOLD_CONFIRMATIONS( + _UniffiConverterOptionalTypeChannelId.read(buf), + _UniffiConverterTypeTxid.read(buf), + _UniffiConverterTypeBlockHash.read(buf), + _UniffiConverterUInt32.read(buf), + _UniffiConverterUInt64.read(buf), + ) + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if value.is_pending_broadcast(): + _UniffiConverterOptionalTypeChannelId.check_lower(value.channel_id) + _UniffiConverterUInt64.check_lower(value.amount_satoshis) + return + if value.is_broadcast_awaiting_confirmation(): + _UniffiConverterOptionalTypeChannelId.check_lower(value.channel_id) + _UniffiConverterUInt32.check_lower(value.latest_broadcast_height) + _UniffiConverterTypeTxid.check_lower(value.latest_spending_txid) + _UniffiConverterUInt64.check_lower(value.amount_satoshis) + return + if value.is_awaiting_threshold_confirmations(): + _UniffiConverterOptionalTypeChannelId.check_lower(value.channel_id) + _UniffiConverterTypeTxid.check_lower(value.latest_spending_txid) + _UniffiConverterTypeBlockHash.check_lower(value.confirmation_hash) + _UniffiConverterUInt32.check_lower(value.confirmation_height) + _UniffiConverterUInt64.check_lower(value.amount_satoshis) + return + raise ValueError(value) + + @staticmethod + def write(value, buf): + if value.is_pending_broadcast(): + buf.write_i32(1) + _UniffiConverterOptionalTypeChannelId.write(value.channel_id, buf) + _UniffiConverterUInt64.write(value.amount_satoshis, buf) + if value.is_broadcast_awaiting_confirmation(): + buf.write_i32(2) + _UniffiConverterOptionalTypeChannelId.write(value.channel_id, buf) + _UniffiConverterUInt32.write(value.latest_broadcast_height, buf) + _UniffiConverterTypeTxid.write(value.latest_spending_txid, buf) + _UniffiConverterUInt64.write(value.amount_satoshis, buf) + if value.is_awaiting_threshold_confirmations(): + buf.write_i32(3) + _UniffiConverterOptionalTypeChannelId.write(value.channel_id, buf) + _UniffiConverterTypeTxid.write(value.latest_spending_txid, buf) + _UniffiConverterTypeBlockHash.write(value.confirmation_hash, buf) + _UniffiConverterUInt32.write(value.confirmation_height, buf) + _UniffiConverterUInt64.write(value.amount_satoshis, buf) + + + + + + + +class QrPaymentResult: + def __init__(self): + raise RuntimeError("QrPaymentResult cannot be instantiated directly") + + # Each enum variant is a nested class of the enum itself. + class ONCHAIN: + txid: "Txid" + + def __init__(self,txid: "Txid"): + self.txid = txid + + def __str__(self): + return "QrPaymentResult.ONCHAIN(txid={})".format(self.txid) + + def __eq__(self, other): + if not other.is_onchain(): + return False + if self.txid != other.txid: + return False + return True + + class BOLT11: + payment_id: "PaymentId" + + def __init__(self,payment_id: "PaymentId"): + self.payment_id = payment_id + + def __str__(self): + return "QrPaymentResult.BOLT11(payment_id={})".format(self.payment_id) + + def __eq__(self, other): + if not other.is_bolt11(): + return False + if self.payment_id != other.payment_id: + return False + return True + + class BOLT12: + payment_id: "PaymentId" + + def __init__(self,payment_id: "PaymentId"): + self.payment_id = payment_id + + def __str__(self): + return "QrPaymentResult.BOLT12(payment_id={})".format(self.payment_id) + + def __eq__(self, other): + if not other.is_bolt12(): + return False + if self.payment_id != other.payment_id: + return False + return True + + + + # For each variant, we have an `is_NAME` method for easily checking + # whether an instance is that variant. + def is_onchain(self) -> bool: + return isinstance(self, QrPaymentResult.ONCHAIN) + def is_bolt11(self) -> bool: + return isinstance(self, QrPaymentResult.BOLT11) + def is_bolt12(self) -> bool: + return isinstance(self, QrPaymentResult.BOLT12) + + +# Now, a little trick - we make each nested variant class be a subclass of the main +# enum class, so that method calls and instance checks etc will work intuitively. +# We might be able to do this a little more neatly with a metaclass, but this'll do. +QrPaymentResult.ONCHAIN = type("QrPaymentResult.ONCHAIN", (QrPaymentResult.ONCHAIN, QrPaymentResult,), {}) # type: ignore +QrPaymentResult.BOLT11 = type("QrPaymentResult.BOLT11", (QrPaymentResult.BOLT11, QrPaymentResult,), {}) # type: ignore +QrPaymentResult.BOLT12 = type("QrPaymentResult.BOLT12", (QrPaymentResult.BOLT12, QrPaymentResult,), {}) # type: ignore + + + + +class _UniffiConverterTypeQrPaymentResult(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return QrPaymentResult.ONCHAIN( + _UniffiConverterTypeTxid.read(buf), + ) + if variant == 2: + return QrPaymentResult.BOLT11( + _UniffiConverterTypePaymentId.read(buf), + ) + if variant == 3: + return QrPaymentResult.BOLT12( + _UniffiConverterTypePaymentId.read(buf), + ) + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if value.is_onchain(): + _UniffiConverterTypeTxid.check_lower(value.txid) + return + if value.is_bolt11(): + _UniffiConverterTypePaymentId.check_lower(value.payment_id) + return + if value.is_bolt12(): + _UniffiConverterTypePaymentId.check_lower(value.payment_id) + return + raise ValueError(value) + + @staticmethod + def write(value, buf): + if value.is_onchain(): + buf.write_i32(1) + _UniffiConverterTypeTxid.write(value.txid, buf) + if value.is_bolt11(): + buf.write_i32(2) + _UniffiConverterTypePaymentId.write(value.payment_id, buf) + if value.is_bolt12(): + buf.write_i32(3) + _UniffiConverterTypePaymentId.write(value.payment_id, buf) + + + + + + + +class SyncType(enum.Enum): + ONCHAIN_WALLET = 0 + + LIGHTNING_WALLET = 1 + + FEE_RATE_CACHE = 2 + + + +class _UniffiConverterTypeSyncType(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return SyncType.ONCHAIN_WALLET + if variant == 2: + return SyncType.LIGHTNING_WALLET + if variant == 3: + return SyncType.FEE_RATE_CACHE + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if value == SyncType.ONCHAIN_WALLET: + return + if value == SyncType.LIGHTNING_WALLET: + return + if value == SyncType.FEE_RATE_CACHE: + return + raise ValueError(value) + + @staticmethod + def write(value, buf): + if value == SyncType.ONCHAIN_WALLET: + buf.write_i32(1) + if value == SyncType.LIGHTNING_WALLET: + buf.write_i32(2) + if value == SyncType.FEE_RATE_CACHE: + buf.write_i32(3) + + + + +# VssHeaderProviderError +# We want to define each variant as a nested class that's also a subclass, +# which is tricky in Python. To accomplish this we're going to create each +# class separately, then manually add the child classes to the base class's +# __dict__. All of this happens in dummy class to avoid polluting the module +# namespace. +class VssHeaderProviderError(Exception): + pass + +_UniffiTempVssHeaderProviderError = VssHeaderProviderError + +class VssHeaderProviderError: # type: ignore + class InvalidData(_UniffiTempVssHeaderProviderError): + + def __repr__(self): + return "VssHeaderProviderError.InvalidData({})".format(repr(str(self))) + _UniffiTempVssHeaderProviderError.InvalidData = InvalidData # type: ignore + class RequestError(_UniffiTempVssHeaderProviderError): + + def __repr__(self): + return "VssHeaderProviderError.RequestError({})".format(repr(str(self))) + _UniffiTempVssHeaderProviderError.RequestError = RequestError # type: ignore + class AuthorizationError(_UniffiTempVssHeaderProviderError): + + def __repr__(self): + return "VssHeaderProviderError.AuthorizationError({})".format(repr(str(self))) + _UniffiTempVssHeaderProviderError.AuthorizationError = AuthorizationError # type: ignore + class InternalError(_UniffiTempVssHeaderProviderError): + + def __repr__(self): + return "VssHeaderProviderError.InternalError({})".format(repr(str(self))) + _UniffiTempVssHeaderProviderError.InternalError = InternalError # type: ignore + +VssHeaderProviderError = _UniffiTempVssHeaderProviderError # type: ignore +del _UniffiTempVssHeaderProviderError + + +class _UniffiConverterTypeVssHeaderProviderError(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return VssHeaderProviderError.InvalidData( + _UniffiConverterString.read(buf), + ) + if variant == 2: + return VssHeaderProviderError.RequestError( + _UniffiConverterString.read(buf), + ) + if variant == 3: + return VssHeaderProviderError.AuthorizationError( + _UniffiConverterString.read(buf), + ) + if variant == 4: + return VssHeaderProviderError.InternalError( + _UniffiConverterString.read(buf), + ) + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if isinstance(value, VssHeaderProviderError.InvalidData): + return + if isinstance(value, VssHeaderProviderError.RequestError): + return + if isinstance(value, VssHeaderProviderError.AuthorizationError): + return + if isinstance(value, VssHeaderProviderError.InternalError): + return + + @staticmethod + def write(value, buf): + if isinstance(value, VssHeaderProviderError.InvalidData): + buf.write_i32(1) + if isinstance(value, VssHeaderProviderError.RequestError): + buf.write_i32(2) + if isinstance(value, VssHeaderProviderError.AuthorizationError): + buf.write_i32(3) + if isinstance(value, VssHeaderProviderError.InternalError): + buf.write_i32(4) + + + + + +class WordCount(enum.Enum): + WORDS12 = 0 + + WORDS15 = 1 + + WORDS18 = 2 + + WORDS21 = 3 + + WORDS24 = 4 + + + +class _UniffiConverterTypeWordCount(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return WordCount.WORDS12 + if variant == 2: + return WordCount.WORDS15 + if variant == 3: + return WordCount.WORDS18 + if variant == 4: + return WordCount.WORDS21 + if variant == 5: + return WordCount.WORDS24 + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if value == WordCount.WORDS12: + return + if value == WordCount.WORDS15: + return + if value == WordCount.WORDS18: + return + if value == WordCount.WORDS21: + return + if value == WordCount.WORDS24: + return + raise ValueError(value) + + @staticmethod + def write(value, buf): + if value == WordCount.WORDS12: + buf.write_i32(1) + if value == WordCount.WORDS15: + buf.write_i32(2) + if value == WordCount.WORDS18: + buf.write_i32(3) + if value == WordCount.WORDS21: + buf.write_i32(4) + if value == WordCount.WORDS24: + buf.write_i32(5) + + + + + +class _UniffiConverterOptionalUInt16(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterUInt16.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterUInt16.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterUInt16.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalUInt32(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterUInt32.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterUInt32.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterUInt32.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalUInt64(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterUInt64.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterUInt64.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterUInt64.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalBool(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterBool.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterBool.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterBool.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalString(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterString.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterString.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterString.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeFeeRate(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeFeeRate.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeFeeRate.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeFeeRate.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeAnchorChannelsConfig(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeAnchorChannelsConfig.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeAnchorChannelsConfig.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeAnchorChannelsConfig.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeBackgroundSyncConfig(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeBackgroundSyncConfig.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeBackgroundSyncConfig.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeBackgroundSyncConfig.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeChannelConfig(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeChannelConfig.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeChannelConfig.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeChannelConfig.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeChannelInfo(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeChannelInfo.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeChannelInfo.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeChannelInfo.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeChannelUpdateInfo(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeChannelUpdateInfo.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeChannelUpdateInfo.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeChannelUpdateInfo.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeElectrumSyncConfig(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeElectrumSyncConfig.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeElectrumSyncConfig.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeElectrumSyncConfig.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeEsploraSyncConfig(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeEsploraSyncConfig.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeEsploraSyncConfig.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeEsploraSyncConfig.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeLsps1Bolt11PaymentInfo(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeLsps1Bolt11PaymentInfo.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeLsps1Bolt11PaymentInfo.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeLsps1Bolt11PaymentInfo.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeLsps1ChannelInfo(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeLsps1ChannelInfo.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeLsps1ChannelInfo.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeLsps1ChannelInfo.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeLsps1OnchainPaymentInfo(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeLsps1OnchainPaymentInfo.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeLsps1OnchainPaymentInfo.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeLsps1OnchainPaymentInfo.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeNodeAnnouncementInfo(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeNodeAnnouncementInfo.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeNodeAnnouncementInfo.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeNodeAnnouncementInfo.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeNodeInfo(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeNodeInfo.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeNodeInfo.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeNodeInfo.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeOutPoint(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeOutPoint.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeOutPoint.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeOutPoint.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypePaymentDetails(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypePaymentDetails.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypePaymentDetails.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypePaymentDetails.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeRouteParametersConfig(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeRouteParametersConfig.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeRouteParametersConfig.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeRouteParametersConfig.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeScoringDecayParameters(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeScoringDecayParameters.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeScoringDecayParameters.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeScoringDecayParameters.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeScoringFeeParameters(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeScoringFeeParameters.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeScoringFeeParameters.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeScoringFeeParameters.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeTransactionDetails(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeTransactionDetails.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeTransactionDetails.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeTransactionDetails.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeAsyncPaymentsRole(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeAsyncPaymentsRole.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeAsyncPaymentsRole.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeAsyncPaymentsRole.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeClosureReason(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeClosureReason.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeClosureReason.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeClosureReason.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeEvent(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeEvent.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeEvent.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeEvent.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeLogLevel(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeLogLevel.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeLogLevel.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeLogLevel.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeNetwork(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeNetwork.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeNetwork.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeNetwork.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeOfferAmount(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeOfferAmount.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeOfferAmount.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeOfferAmount.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypePaymentFailureReason(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypePaymentFailureReason.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypePaymentFailureReason.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypePaymentFailureReason.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeWordCount(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeWordCount.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeWordCount.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeWordCount.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalSequenceUInt8(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterSequenceUInt8.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterSequenceUInt8.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterSequenceUInt8.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalSequenceTypeSpendableUtxo(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterSequenceTypeSpendableUtxo.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterSequenceTypeSpendableUtxo.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterSequenceTypeSpendableUtxo.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalSequenceSequenceUInt8(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterSequenceSequenceUInt8.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterSequenceSequenceUInt8.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterSequenceSequenceUInt8.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalSequenceTypeSocketAddress(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterSequenceTypeSocketAddress.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterSequenceTypeSocketAddress.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterSequenceTypeSocketAddress.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeAddress(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeAddress.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeAddress.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeAddress.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeChannelId(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeChannelId.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeChannelId.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeChannelId.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeNodeAlias(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeNodeAlias.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeNodeAlias.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeNodeAlias.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypePaymentHash(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypePaymentHash.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypePaymentHash.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypePaymentHash.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypePaymentId(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypePaymentId.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypePaymentId.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypePaymentId.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypePaymentPreimage(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypePaymentPreimage.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypePaymentPreimage.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypePaymentPreimage.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypePaymentSecret(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypePaymentSecret.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypePaymentSecret.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypePaymentSecret.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypePublicKey(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypePublicKey.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypePublicKey.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypePublicKey.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeUntrustedString(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeUntrustedString.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeUntrustedString.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeUntrustedString.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeUserChannelId(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeUserChannelId.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeUserChannelId.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeUserChannelId.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterSequenceUInt8(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterUInt8.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterUInt8.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterUInt8.read(buf) for i in range(count) + ] + + + +class _UniffiConverterSequenceUInt64(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterUInt64.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterUInt64.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterUInt64.read(buf) for i in range(count) + ] + + + +class _UniffiConverterSequenceString(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterString.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterString.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterString.read(buf) for i in range(count) + ] + + + +class _UniffiConverterSequenceTypeAddressInfo(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterTypeAddressInfo.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterTypeAddressInfo.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterTypeAddressInfo.read(buf) for i in range(count) + ] + + + +class _UniffiConverterSequenceTypeChannelDetails(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterTypeChannelDetails.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterTypeChannelDetails.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterTypeChannelDetails.read(buf) for i in range(count) + ] + + + +class _UniffiConverterSequenceTypeCustomTlvRecord(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterTypeCustomTlvRecord.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterTypeCustomTlvRecord.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterTypeCustomTlvRecord.read(buf) for i in range(count) + ] + + + +class _UniffiConverterSequenceTypeOnchainWalletAccount(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterTypeOnchainWalletAccount.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterTypeOnchainWalletAccount.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterTypeOnchainWalletAccount.read(buf) for i in range(count) + ] + + + +class _UniffiConverterSequenceTypeOnchainWalletAccountConfig(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterTypeOnchainWalletAccountConfig.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterTypeOnchainWalletAccountConfig.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterTypeOnchainWalletAccountConfig.read(buf) for i in range(count) + ] + + + +class _UniffiConverterSequenceTypePaymentDetails(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterTypePaymentDetails.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterTypePaymentDetails.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterTypePaymentDetails.read(buf) for i in range(count) + ] + + + +class _UniffiConverterSequenceTypePeerDetails(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterTypePeerDetails.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterTypePeerDetails.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterTypePeerDetails.read(buf) for i in range(count) + ] + + + +class _UniffiConverterSequenceTypeProbeHandle(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterTypeProbeHandle.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterTypeProbeHandle.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterTypeProbeHandle.read(buf) for i in range(count) + ] + + + +class _UniffiConverterSequenceTypeRouteHintHop(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterTypeRouteHintHop.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterTypeRouteHintHop.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterTypeRouteHintHop.read(buf) for i in range(count) + ] + + + +class _UniffiConverterSequenceTypeSpendableUtxo(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterTypeSpendableUtxo.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterTypeSpendableUtxo.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterTypeSpendableUtxo.read(buf) for i in range(count) + ] + + + +class _UniffiConverterSequenceTypeTxInput(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterTypeTxInput.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterTypeTxInput.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterTypeTxInput.read(buf) for i in range(count) + ] + + + +class _UniffiConverterSequenceTypeTxOutput(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterTypeTxOutput.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterTypeTxOutput.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterTypeTxOutput.read(buf) for i in range(count) + ] + + + +class _UniffiConverterSequenceTypeAddressType(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterTypeAddressType.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterTypeAddressType.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterTypeAddressType.read(buf) for i in range(count) + ] + + + +class _UniffiConverterSequenceTypeLightningBalance(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterTypeLightningBalance.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterTypeLightningBalance.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterTypeLightningBalance.read(buf) for i in range(count) + ] + + + +class _UniffiConverterSequenceTypeNetwork(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterTypeNetwork.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterTypeNetwork.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterTypeNetwork.read(buf) for i in range(count) + ] + + + +class _UniffiConverterSequenceTypePendingSweepBalance(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterTypePendingSweepBalance.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterTypePendingSweepBalance.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterTypePendingSweepBalance.read(buf) for i in range(count) + ] + + + +class _UniffiConverterSequenceSequenceUInt8(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterSequenceUInt8.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterSequenceUInt8.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterSequenceUInt8.read(buf) for i in range(count) + ] + + + +class _UniffiConverterSequenceSequenceTypeRouteHintHop(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterSequenceTypeRouteHintHop.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterSequenceTypeRouteHintHop.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterSequenceTypeRouteHintHop.read(buf) for i in range(count) + ] + + + +class _UniffiConverterSequenceTypeAddress(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterTypeAddress.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterTypeAddress.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterTypeAddress.read(buf) for i in range(count) + ] + + + +class _UniffiConverterSequenceTypeNodeId(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterTypeNodeId.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterTypeNodeId.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterTypeNodeId.read(buf) for i in range(count) + ] + + + +class _UniffiConverterSequenceTypePublicKey(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterTypePublicKey.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterTypePublicKey.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterTypePublicKey.read(buf) for i in range(count) + ] + + + +class _UniffiConverterSequenceTypeSocketAddress(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterTypeSocketAddress.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterTypeSocketAddress.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterTypeSocketAddress.read(buf) for i in range(count) + ] + + + +class _UniffiConverterSequenceTypeTxid(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterTypeTxid.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterTypeTxid.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterTypeTxid.read(buf) for i in range(count) + ] + + + +class _UniffiConverterMapStringString(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, items): + for (key, value) in items.items(): + _UniffiConverterString.check_lower(key) + _UniffiConverterString.check_lower(value) + + @classmethod + def write(cls, items, buf): + buf.write_i32(len(items)) + for (key, value) in items.items(): + _UniffiConverterString.write(key, buf) + _UniffiConverterString.write(value, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative map size") + + # It would be nice to use a dict comprehension, + # but in Python 3.7 and before the evaluation order is not according to spec, + # so we we're reading the value before the key. + # This loop makes the order explicit: first reading the key, then the value. + d = {} + for i in range(count): + key = _UniffiConverterString.read(buf) + val = _UniffiConverterString.read(buf) + d[key] = val + return d + + +class _UniffiConverterTypeAddress: + @staticmethod + def write(value, buf): + _UniffiConverterString.write(value, buf) + + @staticmethod + def read(buf): + return _UniffiConverterString.read(buf) + + @staticmethod + def lift(value): + return _UniffiConverterString.lift(value) + + @staticmethod + def check_lower(value): + return _UniffiConverterString.check_lower(value) + + @staticmethod + def lower(value): + return _UniffiConverterString.lower(value) + + +class _UniffiConverterTypeBlockHash: + @staticmethod + def write(value, buf): + _UniffiConverterString.write(value, buf) + + @staticmethod + def read(buf): + return _UniffiConverterString.read(buf) + + @staticmethod + def lift(value): + return _UniffiConverterString.lift(value) + + @staticmethod + def check_lower(value): + return _UniffiConverterString.check_lower(value) + + @staticmethod + def lower(value): + return _UniffiConverterString.lower(value) + + +class _UniffiConverterTypeChannelId: + @staticmethod + def write(value, buf): + _UniffiConverterString.write(value, buf) + + @staticmethod + def read(buf): + return _UniffiConverterString.read(buf) + + @staticmethod + def lift(value): + return _UniffiConverterString.lift(value) + + @staticmethod + def check_lower(value): + return _UniffiConverterString.check_lower(value) + + @staticmethod + def lower(value): + return _UniffiConverterString.lower(value) + + +class _UniffiConverterTypeLsps1OrderId: + @staticmethod + def write(value, buf): + _UniffiConverterString.write(value, buf) + + @staticmethod + def read(buf): + return _UniffiConverterString.read(buf) + + @staticmethod + def lift(value): + return _UniffiConverterString.lift(value) + + @staticmethod + def check_lower(value): + return _UniffiConverterString.check_lower(value) + + @staticmethod + def lower(value): + return _UniffiConverterString.lower(value) + + +class _UniffiConverterTypeLspsDateTime: + @staticmethod + def write(value, buf): + _UniffiConverterString.write(value, buf) + + @staticmethod + def read(buf): + return _UniffiConverterString.read(buf) + + @staticmethod + def lift(value): + return _UniffiConverterString.lift(value) + + @staticmethod + def check_lower(value): + return _UniffiConverterString.check_lower(value) + + @staticmethod + def lower(value): + return _UniffiConverterString.lower(value) + + +class _UniffiConverterTypeMnemonic: + @staticmethod + def write(value, buf): + _UniffiConverterString.write(value, buf) + + @staticmethod + def read(buf): + return _UniffiConverterString.read(buf) + + @staticmethod + def lift(value): + return _UniffiConverterString.lift(value) + + @staticmethod + def check_lower(value): + return _UniffiConverterString.check_lower(value) + + @staticmethod + def lower(value): + return _UniffiConverterString.lower(value) + + +class _UniffiConverterTypeNodeAlias: + @staticmethod + def write(value, buf): + _UniffiConverterString.write(value, buf) + + @staticmethod + def read(buf): + return _UniffiConverterString.read(buf) + + @staticmethod + def lift(value): + return _UniffiConverterString.lift(value) + + @staticmethod + def check_lower(value): + return _UniffiConverterString.check_lower(value) + + @staticmethod + def lower(value): + return _UniffiConverterString.lower(value) + + +class _UniffiConverterTypeNodeId: + @staticmethod + def write(value, buf): + _UniffiConverterString.write(value, buf) + + @staticmethod + def read(buf): + return _UniffiConverterString.read(buf) + + @staticmethod + def lift(value): + return _UniffiConverterString.lift(value) + + @staticmethod + def check_lower(value): + return _UniffiConverterString.check_lower(value) + + @staticmethod + def lower(value): + return _UniffiConverterString.lower(value) + + +class _UniffiConverterTypeOfferId: + @staticmethod + def write(value, buf): + _UniffiConverterString.write(value, buf) + + @staticmethod + def read(buf): + return _UniffiConverterString.read(buf) + + @staticmethod + def lift(value): + return _UniffiConverterString.lift(value) + + @staticmethod + def check_lower(value): + return _UniffiConverterString.check_lower(value) + + @staticmethod + def lower(value): + return _UniffiConverterString.lower(value) + + +class _UniffiConverterTypePaymentHash: + @staticmethod + def write(value, buf): + _UniffiConverterString.write(value, buf) + + @staticmethod + def read(buf): + return _UniffiConverterString.read(buf) + + @staticmethod + def lift(value): + return _UniffiConverterString.lift(value) + + @staticmethod + def check_lower(value): + return _UniffiConverterString.check_lower(value) + + @staticmethod + def lower(value): + return _UniffiConverterString.lower(value) + + +class _UniffiConverterTypePaymentId: + @staticmethod + def write(value, buf): + _UniffiConverterString.write(value, buf) + + @staticmethod + def read(buf): + return _UniffiConverterString.read(buf) + + @staticmethod + def lift(value): + return _UniffiConverterString.lift(value) + + @staticmethod + def check_lower(value): + return _UniffiConverterString.check_lower(value) + + @staticmethod + def lower(value): + return _UniffiConverterString.lower(value) + + +class _UniffiConverterTypePaymentPreimage: + @staticmethod + def write(value, buf): + _UniffiConverterString.write(value, buf) + + @staticmethod + def read(buf): + return _UniffiConverterString.read(buf) + + @staticmethod + def lift(value): + return _UniffiConverterString.lift(value) + + @staticmethod + def check_lower(value): + return _UniffiConverterString.check_lower(value) + + @staticmethod + def lower(value): + return _UniffiConverterString.lower(value) + + +class _UniffiConverterTypePaymentSecret: + @staticmethod + def write(value, buf): + _UniffiConverterString.write(value, buf) + + @staticmethod + def read(buf): + return _UniffiConverterString.read(buf) + + @staticmethod + def lift(value): + return _UniffiConverterString.lift(value) + + @staticmethod + def check_lower(value): + return _UniffiConverterString.check_lower(value) + + @staticmethod + def lower(value): + return _UniffiConverterString.lower(value) + + +class _UniffiConverterTypePublicKey: + @staticmethod + def write(value, buf): + _UniffiConverterString.write(value, buf) + + @staticmethod + def read(buf): + return _UniffiConverterString.read(buf) + + @staticmethod + def lift(value): + return _UniffiConverterString.lift(value) + + @staticmethod + def check_lower(value): + return _UniffiConverterString.check_lower(value) + + @staticmethod + def lower(value): + return _UniffiConverterString.lower(value) + + +class _UniffiConverterTypeSocketAddress: + @staticmethod + def write(value, buf): + _UniffiConverterString.write(value, buf) + + @staticmethod + def read(buf): + return _UniffiConverterString.read(buf) + + @staticmethod + def lift(value): + return _UniffiConverterString.lift(value) + + @staticmethod + def check_lower(value): + return _UniffiConverterString.check_lower(value) + + @staticmethod + def lower(value): + return _UniffiConverterString.lower(value) + + +class _UniffiConverterTypeTxid: + @staticmethod + def write(value, buf): + _UniffiConverterString.write(value, buf) + + @staticmethod + def read(buf): + return _UniffiConverterString.read(buf) + + @staticmethod + def lift(value): + return _UniffiConverterString.lift(value) + + @staticmethod + def check_lower(value): + return _UniffiConverterString.check_lower(value) + + @staticmethod + def lower(value): + return _UniffiConverterString.lower(value) + + +class _UniffiConverterTypeUntrustedString: + @staticmethod + def write(value, buf): + _UniffiConverterString.write(value, buf) + + @staticmethod + def read(buf): + return _UniffiConverterString.read(buf) + + @staticmethod + def lift(value): + return _UniffiConverterString.lift(value) + + @staticmethod + def check_lower(value): + return _UniffiConverterString.check_lower(value) + + @staticmethod + def lower(value): + return _UniffiConverterString.lower(value) + + +class _UniffiConverterTypeUserChannelId: + @staticmethod + def write(value, buf): + _UniffiConverterString.write(value, buf) + + @staticmethod + def read(buf): + return _UniffiConverterString.read(buf) + + @staticmethod + def lift(value): + return _UniffiConverterString.lift(value) + + @staticmethod + def check_lower(value): + return _UniffiConverterString.check_lower(value) + + @staticmethod + def lower(value): + return _UniffiConverterString.lower(value) +Address = str +BlockHash = str +ChannelId = str +Lsps1OrderId = str +LspsDateTime = str +Mnemonic = str +NodeAlias = str +NodeId = str +OfferId = str +PaymentHash = str +PaymentId = str +PaymentPreimage = str +PaymentSecret = str +PublicKey = str +SocketAddress = str +Txid = str +UntrustedString = str +UserChannelId = str + +# Async support# RustFuturePoll values +_UNIFFI_RUST_FUTURE_POLL_READY = 0 +_UNIFFI_RUST_FUTURE_POLL_MAYBE_READY = 1 + +# Stores futures for _uniffi_continuation_callback +_UniffiContinuationHandleMap = _UniffiHandleMap() + +_UNIFFI_GLOBAL_EVENT_LOOP = None + +""" +Set the event loop to use for async functions + +This is needed if some async functions run outside of the eventloop, for example: + - A non-eventloop thread is spawned, maybe from `EventLoop.run_in_executor` or maybe from the + Rust code spawning its own thread. + - The Rust code calls an async callback method from a sync callback function, using something + like `pollster` to block on the async call. + +In this case, we need an event loop to run the Python async function, but there's no eventloop set +for the thread. Use `uniffi_set_event_loop` to force an eventloop to be used in this case. +""" +def uniffi_set_event_loop(eventloop: asyncio.BaseEventLoop): + global _UNIFFI_GLOBAL_EVENT_LOOP + _UNIFFI_GLOBAL_EVENT_LOOP = eventloop + +def _uniffi_get_event_loop(): + if _UNIFFI_GLOBAL_EVENT_LOOP is not None: + return _UNIFFI_GLOBAL_EVENT_LOOP + else: + return asyncio.get_running_loop() + +# Continuation callback for async functions +# lift the return value or error and resolve the future, causing the async function to resume. +@_UNIFFI_RUST_FUTURE_CONTINUATION_CALLBACK +def _uniffi_continuation_callback(future_ptr, poll_code): + (eventloop, future) = _UniffiContinuationHandleMap.remove(future_ptr) + eventloop.call_soon_threadsafe(_uniffi_set_future_result, future, poll_code) + +def _uniffi_set_future_result(future, poll_code): + if not future.cancelled(): + future.set_result(poll_code) + +async def _uniffi_rust_call_async(rust_future, ffi_poll, ffi_complete, ffi_free, lift_func, error_ffi_converter): + try: + eventloop = _uniffi_get_event_loop() + + # Loop and poll until we see a _UNIFFI_RUST_FUTURE_POLL_READY value + while True: + future = eventloop.create_future() + ffi_poll( + rust_future, + _uniffi_continuation_callback, + _UniffiContinuationHandleMap.insert((eventloop, future)), + ) + poll_code = await future + if poll_code == _UNIFFI_RUST_FUTURE_POLL_READY: + break + + return lift_func( + _uniffi_rust_call_with_error(error_ffi_converter, ffi_complete, rust_future) + ) + finally: + ffi_free(rust_future) + +def battery_saving_sync_intervals() -> "RuntimeSyncIntervals": + return _UniffiConverterTypeRuntimeSyncIntervals.lift(_uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_func_battery_saving_sync_intervals,)) + + +def default_config() -> "Config": + return _UniffiConverterTypeConfig.lift(_uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_func_default_config,)) + + +def derive_node_secret_from_mnemonic(mnemonic: "str",passphrase: "typing.Optional[str]") -> "typing.List[int]": + _UniffiConverterString.check_lower(mnemonic) + + _UniffiConverterOptionalString.check_lower(passphrase) + + return _UniffiConverterSequenceUInt8.lift(_uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_func_derive_node_secret_from_mnemonic, + _UniffiConverterString.lower(mnemonic), + _UniffiConverterOptionalString.lower(passphrase))) + + +def generate_entropy_mnemonic(word_count: "typing.Optional[WordCount]") -> "Mnemonic": + _UniffiConverterOptionalTypeWordCount.check_lower(word_count) + + return _UniffiConverterTypeMnemonic.lift(_uniffi_rust_call(_UniffiLib.uniffi_ldk_node_fn_func_generate_entropy_mnemonic, + _UniffiConverterOptionalTypeWordCount.lower(word_count))) + + +__all__ = [ + "InternalError", + "AddressType", + "AsyncPaymentsRole", + "BalanceSource", + "Bolt11InvoiceDescription", + "BuildError", + "ClosureReason", + "CoinSelectionAlgorithm", + "ConfirmationStatus", + "Currency", + "Event", + "KeychainKind", + "LightningBalance", + "LogLevel", + "Lsps1PaymentState", + "MaxDustHtlcExposure", + "Network", + "NodeError", + "OfferAmount", + "PaymentDirection", + "PaymentFailureReason", + "PaymentKind", + "PaymentStatus", + "PendingSweepBalance", + "QrPaymentResult", + "SyncType", + "VssHeaderProviderError", + "WordCount", + "AddressInfo", + "AddressTypeBalance", + "AnchorChannelsConfig", + "BackgroundSyncConfig", + "BalanceDetails", + "BestBlock", + "ChannelConfig", + "ChannelDataMigration", + "ChannelDetails", + "ChannelInfo", + "ChannelUpdateInfo", + "Config", + "CustomTlvRecord", + "ElectrumSyncConfig", + "EsploraSyncConfig", + "LogRecord", + "LspFeeLimits", + "Lsps1Bolt11PaymentInfo", + "Lsps1ChannelInfo", + "Lsps1OnchainPaymentInfo", + "Lsps1OrderParams", + "Lsps1OrderStatus", + "Lsps1PaymentInfo", + "Lsps2ServiceConfig", + "NodeAnnouncementInfo", + "NodeInfo", + "NodeStatus", + "OnchainWalletAccount", + "OnchainWalletAccountConfig", + "OutPoint", + "PaymentDetails", + "PeerDetails", + "ProbeHandle", + "RouteHintHop", + "RouteParametersConfig", + "RoutingFees", + "RuntimeSyncIntervals", + "ScoringDecayParameters", + "ScoringFeeParameters", + "SpendableUtxo", + "TransactionDetails", + "TxInput", + "TxOutput", + "battery_saving_sync_intervals", + "default_config", + "derive_node_secret_from_mnemonic", + "generate_entropy_mnemonic", + "Bolt11Invoice", + "Bolt11Payment", + "Bolt12Invoice", + "Bolt12Payment", + "Builder", + "FeeRate", + "Lsps1Liquidity", + "LogWriter", + "NetworkGraph", + "Node", + "Offer", + "OnchainPayment", + "Refund", + "SpontaneousPayment", + "UnifiedQrPayment", + "VssHeaderProvider", +] diff --git a/bindings/swift/Sources/LDKNode/LDKNode.swift b/bindings/swift/Sources/LDKNode/LDKNode.swift index 20ad658d7b..c58b0d716a 100644 --- a/bindings/swift/Sources/LDKNode/LDKNode.swift +++ b/bindings/swift/Sources/LDKNode/LDKNode.swift @@ -9,11 +9,11 @@ import Foundation // might be in a separate module, or it might be compiled inline into // this module. This is a bit of light hackery to work with both. #if canImport(LDKNodeFFI) -import LDKNodeFFI + import LDKNodeFFI #endif -fileprivate extension RustBuffer { - // Allocate a new buffer, copying the contents of a `UInt8` array. +private extension RustBuffer { + /// Allocate a new buffer, copying the contents of a `UInt8` array. init(bytes: [UInt8]) { let rbuf = bytes.withUnsafeBufferPointer { ptr in RustBuffer.from(ptr) @@ -22,21 +22,21 @@ fileprivate extension RustBuffer { } static func empty() -> RustBuffer { - RustBuffer(capacity: 0, len:0, data: nil) + RustBuffer(capacity: 0, len: 0, data: nil) } static func from(_ ptr: UnsafeBufferPointer) -> RustBuffer { try! rustCall { ffi_ldk_node_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) } } - // Frees the buffer in place. - // The buffer must not be used after this is called. + /// Frees the buffer in place. + /// The buffer must not be used after this is called. func deallocate() { try! rustCall { ffi_ldk_node_rustbuffer_free(self, $0) } } } -fileprivate extension ForeignBytes { +private extension ForeignBytes { init(bufferPointer: UnsafeBufferPointer) { self.init(len: Int32(bufferPointer.count), data: bufferPointer.baseAddress) } @@ -49,11 +49,13 @@ fileprivate extension ForeignBytes { // Helper classes/extensions that don't change. // Someday, this will be in a library of its own. -fileprivate extension Data { +private extension Data { init(rustBuffer: RustBuffer) { - // TODO: This copies the buffer. Can we read directly from a - // Rust buffer? - self.init(bytes: rustBuffer.data!, count: Int(rustBuffer.len)) + self.init( + bytesNoCopy: rustBuffer.data!, + count: Int(rustBuffer.len), + deallocator: .none + ) } } @@ -71,15 +73,15 @@ fileprivate extension Data { // // Instead, the read() method and these helper functions input a tuple of data -fileprivate func createReader(data: Data) -> (data: Data, offset: Data.Index) { +private func createReader(data: Data) -> (data: Data, offset: Data.Index) { (data: data, offset: 0) } -// Reads an integer at the current offset, in big-endian order, and advances -// the offset on success. Throws if reading the integer would move the -// offset past the end of the buffer. -fileprivate func readInt(_ reader: inout (data: Data, offset: Data.Index)) throws -> T { - let range = reader.offset...size +/// Reads an integer at the current offset, in big-endian order, and advances +/// the offset on success. Throws if reading the integer would move the +/// offset past the end of the buffer. +private func readInt(_ reader: inout (data: Data, offset: Data.Index)) throws -> T { + let range = reader.offset ..< reader.offset + MemoryLayout.size guard reader.data.count >= range.upperBound else { throw UniffiInternalError.bufferOverflow } @@ -89,38 +91,38 @@ fileprivate func readInt(_ reader: inout (data: Data, offs return value as! T } var value: T = 0 - let _ = withUnsafeMutableBytes(of: &value, { reader.data.copyBytes(to: $0, from: range)}) + let _ = withUnsafeMutableBytes(of: &value) { reader.data.copyBytes(to: $0, from: range) } reader.offset = range.upperBound return value.bigEndian } -// Reads an arbitrary number of bytes, to be used to read -// raw bytes, this is useful when lifting strings -fileprivate func readBytes(_ reader: inout (data: Data, offset: Data.Index), count: Int) throws -> Array { - let range = reader.offset..<(reader.offset+count) +/// Reads an arbitrary number of bytes, to be used to read +/// raw bytes, this is useful when lifting strings +private func readBytes(_ reader: inout (data: Data, offset: Data.Index), count: Int) throws -> [UInt8] { + let range = reader.offset ..< (reader.offset + count) guard reader.data.count >= range.upperBound else { throw UniffiInternalError.bufferOverflow } var value = [UInt8](repeating: 0, count: count) - value.withUnsafeMutableBufferPointer({ buffer in + value.withUnsafeMutableBufferPointer { buffer in reader.data.copyBytes(to: buffer, from: range) - }) + } reader.offset = range.upperBound return value } -// Reads a float at the current offset. -fileprivate func readFloat(_ reader: inout (data: Data, offset: Data.Index)) throws -> Float { - return Float(bitPattern: try readInt(&reader)) +/// Reads a float at the current offset. +private func readFloat(_ reader: inout (data: Data, offset: Data.Index)) throws -> Float { + return try Float(bitPattern: readInt(&reader)) } -// Reads a float at the current offset. -fileprivate func readDouble(_ reader: inout (data: Data, offset: Data.Index)) throws -> Double { - return Double(bitPattern: try readInt(&reader)) +/// Reads a float at the current offset. +private func readDouble(_ reader: inout (data: Data, offset: Data.Index)) throws -> Double { + return try Double(bitPattern: readInt(&reader)) } -// Indicates if the offset has reached the end of the buffer. -fileprivate func hasRemaining(_ reader: (data: Data, offset: Data.Index)) -> Bool { +/// Indicates if the offset has reached the end of the buffer. +private func hasRemaining(_ reader: (data: Data, offset: Data.Index)) -> Bool { return reader.offset < reader.data.count } @@ -128,34 +130,34 @@ fileprivate func hasRemaining(_ reader: (data: Data, offset: Data.Index)) -> Boo // struct, but we use standalone functions instead in order to make external // types work. See the above discussion on Readers for details. -fileprivate func createWriter() -> [UInt8] { +private func createWriter() -> [UInt8] { return [] } -fileprivate func writeBytes(_ writer: inout [UInt8], _ byteArr: S) where S: Sequence, S.Element == UInt8 { +private func writeBytes(_ writer: inout [UInt8], _ byteArr: S) where S.Element == UInt8 { writer.append(contentsOf: byteArr) } -// Writes an integer in big-endian order. -// -// Warning: make sure what you are trying to write -// is in the correct type! -fileprivate func writeInt(_ writer: inout [UInt8], _ value: T) { +/// Writes an integer in big-endian order. +/// +/// Warning: make sure what you are trying to write +/// is in the correct type! +private func writeInt(_ writer: inout [UInt8], _ value: T) { var value = value.bigEndian withUnsafeBytes(of: &value) { writer.append(contentsOf: $0) } } -fileprivate func writeFloat(_ writer: inout [UInt8], _ value: Float) { +private func writeFloat(_ writer: inout [UInt8], _ value: Float) { writeInt(&writer, value.bitPattern) } -fileprivate func writeDouble(_ writer: inout [UInt8], _ value: Double) { +private func writeDouble(_ writer: inout [UInt8], _ value: Double) { writeInt(&writer, value.bitPattern) } -// Protocol for types that transfer other types across the FFI. This is -// analogous go the Rust trait of the same name. -fileprivate protocol FfiConverter { +/// Protocol for types that transfer other types across the FFI. This is +/// analogous to the Rust trait of the same name. +private protocol FfiConverter { associatedtype FfiType associatedtype SwiftType @@ -165,24 +167,33 @@ fileprivate protocol FfiConverter { static func write(_ value: SwiftType, into buf: inout [UInt8]) } -// Types conforming to `Primitive` pass themselves directly over the FFI. -fileprivate protocol FfiConverterPrimitive: FfiConverter where FfiType == SwiftType { } +/// Types conforming to `Primitive` pass themselves directly over the FFI. +private protocol FfiConverterPrimitive: FfiConverter where FfiType == SwiftType {} extension FfiConverterPrimitive { + #if swift(>=5.8) + @_documentation(visibility: private) + #endif public static func lift(_ value: FfiType) throws -> SwiftType { return value } + #if swift(>=5.8) + @_documentation(visibility: private) + #endif public static func lower(_ value: SwiftType) -> FfiType { return value } } -// Types conforming to `FfiConverterRustBuffer` lift and lower into a `RustBuffer`. -// Used for complex types where it's hard to write a custom lift/lower. -fileprivate protocol FfiConverterRustBuffer: FfiConverter where FfiType == RustBuffer {} +/// Types conforming to `FfiConverterRustBuffer` lift and lower into a `RustBuffer`. +/// Used for complex types where it's hard to write a custom lift/lower. +private protocol FfiConverterRustBuffer: FfiConverter where FfiType == RustBuffer {} extension FfiConverterRustBuffer { + #if swift(>=5.8) + @_documentation(visibility: private) + #endif public static func lift(_ buf: RustBuffer) throws -> SwiftType { var reader = createReader(data: Data(rustBuffer: buf)) let value = try read(from: &reader) @@ -193,15 +204,19 @@ extension FfiConverterRustBuffer { return value } + #if swift(>=5.8) + @_documentation(visibility: private) + #endif public static func lower(_ value: SwiftType) -> RustBuffer { - var writer = createWriter() - write(value, into: &writer) - return RustBuffer(bytes: writer) + var writer = createWriter() + write(value, into: &writer) + return RustBuffer(bytes: writer) } } -// An error type for FFI errors. These errors occur at the UniFFI level, not -// the library level. -fileprivate enum UniffiInternalError: LocalizedError { + +/// An error type for FFI errors. These errors occur at the UniFFI level, not +/// the library level. +private enum UniffiInternalError: LocalizedError { case bufferOverflow case incompleteData case unexpectedOptionalTag @@ -212,7 +227,7 @@ fileprivate enum UniffiInternalError: LocalizedError { case unexpectedStaleHandle case rustPanic(_ message: String) - public var errorDescription: String? { + var errorDescription: String? { switch self { case .bufferOverflow: return "Reading the requested value would read past the end of the buffer" case .incompleteData: return "The buffer still has data after lifting its containing value" @@ -227,24 +242,24 @@ fileprivate enum UniffiInternalError: LocalizedError { } } -fileprivate extension NSLock { +private extension NSLock { func withLock(f: () throws -> T) rethrows -> T { - self.lock() + lock() defer { self.unlock() } return try f() } } -fileprivate let CALL_SUCCESS: Int8 = 0 -fileprivate let CALL_ERROR: Int8 = 1 -fileprivate let CALL_UNEXPECTED_ERROR: Int8 = 2 -fileprivate let CALL_CANCELLED: Int8 = 3 +private let CALL_SUCCESS: Int8 = 0 +private let CALL_ERROR: Int8 = 1 +private let CALL_UNEXPECTED_ERROR: Int8 = 2 +private let CALL_CANCELLED: Int8 = 3 -fileprivate extension RustCallStatus { +private extension RustCallStatus { init() { self.init( code: CALL_SUCCESS, - errorBuf: RustBuffer.init( + errorBuf: RustBuffer( capacity: 0, len: 0, data: nil @@ -254,69 +269,71 @@ fileprivate extension RustCallStatus { } private func rustCall(_ callback: (UnsafeMutablePointer) -> T) throws -> T { - try makeRustCall(callback, errorHandler: nil) + let neverThrow: ((RustBuffer) throws -> Never)? = nil + return try makeRustCall(callback, errorHandler: neverThrow) } -private func rustCallWithError( - _ errorHandler: @escaping (RustBuffer) throws -> Error, - _ callback: (UnsafeMutablePointer) -> T) throws -> T { +private func rustCallWithError( + _ errorHandler: @escaping (RustBuffer) throws -> E, + _ callback: (UnsafeMutablePointer) -> T +) throws -> T { try makeRustCall(callback, errorHandler: errorHandler) } -private func makeRustCall( +private func makeRustCall( _ callback: (UnsafeMutablePointer) -> T, - errorHandler: ((RustBuffer) throws -> Error)? + errorHandler: ((RustBuffer) throws -> E)? ) throws -> T { uniffiEnsureInitialized() - var callStatus = RustCallStatus.init() + var callStatus = RustCallStatus() let returnedVal = callback(&callStatus) try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: errorHandler) return returnedVal } -private func uniffiCheckCallStatus( +private func uniffiCheckCallStatus( callStatus: RustCallStatus, - errorHandler: ((RustBuffer) throws -> Error)? + errorHandler: ((RustBuffer) throws -> E)? ) throws { switch callStatus.code { - case CALL_SUCCESS: - return + case CALL_SUCCESS: + return - case CALL_ERROR: - if let errorHandler = errorHandler { - throw try errorHandler(callStatus.errorBuf) - } else { - callStatus.errorBuf.deallocate() - throw UniffiInternalError.unexpectedRustCallError - } + case CALL_ERROR: + if let errorHandler = errorHandler { + throw try errorHandler(callStatus.errorBuf) + } else { + callStatus.errorBuf.deallocate() + throw UniffiInternalError.unexpectedRustCallError + } - case CALL_UNEXPECTED_ERROR: - // When the rust code sees a panic, it tries to construct a RustBuffer - // with the message. But if that code panics, then it just sends back - // an empty buffer. - if callStatus.errorBuf.len > 0 { - throw UniffiInternalError.rustPanic(try FfiConverterString.lift(callStatus.errorBuf)) - } else { - callStatus.errorBuf.deallocate() - throw UniffiInternalError.rustPanic("Rust panic") - } + case CALL_UNEXPECTED_ERROR: + // When the rust code sees a panic, it tries to construct a RustBuffer + // with the message. But if that code panics, then it just sends back + // an empty buffer. + if callStatus.errorBuf.len > 0 { + throw try UniffiInternalError.rustPanic(FfiConverterString.lift(callStatus.errorBuf)) + } else { + callStatus.errorBuf.deallocate() + throw UniffiInternalError.rustPanic("Rust panic") + } - case CALL_CANCELLED: - fatalError("Cancellation not supported yet") + case CALL_CANCELLED: + fatalError("Cancellation not supported yet") - default: - throw UniffiInternalError.unexpectedRustCallStatusCode + default: + throw UniffiInternalError.unexpectedRustCallStatusCode } } private func uniffiTraitInterfaceCall( callStatus: UnsafeMutablePointer, makeCall: () throws -> T, - writeReturn: (T) -> () + writeReturn: (T) -> Void ) { do { try writeReturn(makeCall()) - } catch let error { + } catch { callStatus.pointee.code = CALL_UNEXPECTED_ERROR callStatus.pointee.errorBuf = FfiConverterString.lower(String(describing: error)) } @@ -325,7 +342,7 @@ private func uniffiTraitInterfaceCall( private func uniffiTraitInterfaceCallWithError( callStatus: UnsafeMutablePointer, makeCall: () throws -> T, - writeReturn: (T) -> (), + writeReturn: (T) -> Void, lowerError: (E) -> RustBuffer ) { do { @@ -338,7 +355,8 @@ private func uniffiTraitInterfaceCallWithError( callStatus.pointee.errorBuf = FfiConverterString.lower(String(describing: error)) } } -fileprivate class UniffiHandleMap { + +private class UniffiHandleMap { private var map: [UInt64: T] = [:] private let lock = NSLock() private var currentHandle: UInt64 = 1 @@ -352,7 +370,7 @@ fileprivate class UniffiHandleMap { } } - func get(handle: UInt64) throws -> T { + func get(handle: UInt64) throws -> T { try lock.withLock { guard let obj = map[handle] else { throw UniffiInternalError.unexpectedStaleHandle @@ -372,94 +390,124 @@ fileprivate class UniffiHandleMap { } var count: Int { - get { - map.count - } + map.count } } - // Public interface members begin here. - -fileprivate struct FfiConverterUInt8: FfiConverterPrimitive { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterUInt8: FfiConverterPrimitive { typealias FfiType = UInt8 typealias SwiftType = UInt8 - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt8 { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt8 { return try lift(readInt(&buf)) } - public static func write(_ value: UInt8, into buf: inout [UInt8]) { + static func write(_ value: UInt8, into buf: inout [UInt8]) { writeInt(&buf, lower(value)) } } -fileprivate struct FfiConverterUInt16: FfiConverterPrimitive { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterUInt16: FfiConverterPrimitive { typealias FfiType = UInt16 typealias SwiftType = UInt16 - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt16 { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt16 { return try lift(readInt(&buf)) } - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { writeInt(&buf, lower(value)) } } -fileprivate struct FfiConverterUInt32: FfiConverterPrimitive { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterUInt32: FfiConverterPrimitive { typealias FfiType = UInt32 typealias SwiftType = UInt32 - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt32 { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt32 { return try lift(readInt(&buf)) } - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { writeInt(&buf, lower(value)) } } -fileprivate struct FfiConverterUInt64: FfiConverterPrimitive { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterUInt64: FfiConverterPrimitive { typealias FfiType = UInt64 typealias SwiftType = UInt64 - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt64 { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt64 { + return try lift(readInt(&buf)) + } + + static func write(_ value: SwiftType, into buf: inout [UInt8]) { + writeInt(&buf, lower(value)) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterInt64: FfiConverterPrimitive { + typealias FfiType = Int64 + typealias SwiftType = Int64 + + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Int64 { return try lift(readInt(&buf)) } - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: Int64, into buf: inout [UInt8]) { writeInt(&buf, lower(value)) } } -fileprivate struct FfiConverterBool : FfiConverter { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterBool: FfiConverter { typealias FfiType = Int8 typealias SwiftType = Bool - public static func lift(_ value: Int8) throws -> Bool { + static func lift(_ value: Int8) throws -> Bool { return value != 0 } - public static func lower(_ value: Bool) -> Int8 { + static func lower(_ value: Bool) -> Int8 { return value ? 1 : 0 } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Bool { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Bool { return try lift(readInt(&buf)) } - public static func write(_ value: Bool, into buf: inout [UInt8]) { + static func write(_ value: Bool, into buf: inout [UInt8]) { writeInt(&buf, lower(value)) } } -fileprivate struct FfiConverterString: FfiConverter { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterString: FfiConverter { typealias SwiftType = String typealias FfiType = RustBuffer - public static func lift(_ value: RustBuffer) throws -> String { + static func lift(_ value: RustBuffer) throws -> String { defer { value.deallocate() } @@ -470,7 +518,7 @@ fileprivate struct FfiConverterString: FfiConverter { return String(bytes: bytes, encoding: String.Encoding.utf8)! } - public static func lower(_ value: String) -> RustBuffer { + static func lower(_ value: String) -> RustBuffer { return value.utf8CString.withUnsafeBufferPointer { ptr in // The swift string gives us int8_t, we want uint8_t. ptr.withMemoryRebound(to: UInt8.self) { ptr in @@ -481,80 +529,82 @@ fileprivate struct FfiConverterString: FfiConverter { } } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> String { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> String { let len: Int32 = try readInt(&buf) - return String(bytes: try readBytes(&buf, count: Int(len)), encoding: String.Encoding.utf8)! + return try String(bytes: readBytes(&buf, count: Int(len)), encoding: String.Encoding.utf8)! } - public static func write(_ value: String, into buf: inout [UInt8]) { + static func write(_ value: String, into buf: inout [UInt8]) { let len = Int32(value.utf8.count) writeInt(&buf, len) writeBytes(&buf, value.utf8) } } -fileprivate struct FfiConverterData: FfiConverterRustBuffer { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterData: FfiConverterRustBuffer { typealias SwiftType = Data - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Data { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Data { let len: Int32 = try readInt(&buf) - return Data(try readBytes(&buf, count: Int(len))) + return try Data(readBytes(&buf, count: Int(len))) } - public static func write(_ value: Data, into buf: inout [UInt8]) { + static func write(_ value: Data, into buf: inout [UInt8]) { let len = Int32(value.count) writeInt(&buf, len) writeBytes(&buf, value) } } +public protocol Bolt11InvoiceProtocol: AnyObject { + func amountMilliSatoshis() -> UInt64? + + func currency() -> Currency + + func expiryTimeSeconds() -> UInt64 + + func fallbackAddresses() -> [Address] + + func invoiceDescription() -> Bolt11InvoiceDescription + + func isExpired() -> Bool + func minFinalCltvExpiryDelta() -> UInt64 + func network() -> Network -public protocol Bolt11InvoiceProtocol : AnyObject { - - func amountMilliSatoshis() -> UInt64? - - func currency() -> Currency - - func expiryTimeSeconds() -> UInt64 - - func fallbackAddresses() -> [Address] - - func invoiceDescription() -> Bolt11InvoiceDescription - - func isExpired() -> Bool - - func minFinalCltvExpiryDelta() -> UInt64 - - func network() -> Network - - func paymentHash() -> PaymentHash - - func paymentSecret() -> PaymentSecret - - func recoverPayeePubKey() -> PublicKey - - func routeHints() -> [[RouteHintHop]] - - func secondsSinceEpoch() -> UInt64 - - func secondsUntilExpiry() -> UInt64 - - func signableHash() -> [UInt8] - - func wouldExpire(atTimeSeconds: UInt64) -> Bool - + func paymentHash() -> PaymentHash + + func paymentSecret() -> PaymentSecret + + func recoverPayeePubKey() -> PublicKey + + func routeHints() -> [[RouteHintHop]] + + func secondsSinceEpoch() -> UInt64 + + func secondsUntilExpiry() -> UInt64 + + func signableHash() -> [UInt8] + + func wouldExpire(atTimeSeconds: UInt64) -> Bool } open class Bolt11Invoice: CustomDebugStringConvertible, CustomStringConvertible, Equatable, - Bolt11InvoiceProtocol { + Bolt11InvoiceProtocol +{ fileprivate let pointer: UnsafeMutableRawPointer! - /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif public struct NoPointer { public init() {} } @@ -562,22 +612,29 @@ open class Bolt11Invoice: // TODO: We'd like this to be `private` but for Swifty reasons, // we can't implement `FfiConverter` without making this `required` and we can't // make it `required` without making it `public`. - required public init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + public required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { self.pointer = pointer } - /// This constructor can be used to instantiate a fake object. - /// - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. - /// - /// - Warning: - /// Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. - public init(noPointer: NoPointer) { - self.pointer = nil + // This constructor can be used to instantiate a fake object. + // - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. + // + // - Warning: + // Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public init(noPointer _: NoPointer) { + pointer = nil } + #if swift(>=5.8) + @_documentation(visibility: private) + #endif public func uniffiClonePointer() -> UnsafeMutableRawPointer { return try! rustCall { uniffi_ldk_node_fn_clone_bolt11invoice(self.pointer, $0) } } + // No primary constructor declared for this class. deinit { @@ -588,160 +645,141 @@ open class Bolt11Invoice: try! rustCall { uniffi_ldk_node_fn_free_bolt11invoice(pointer, $0) } } - -public static func fromStr(invoiceStr: String)throws -> Bolt11Invoice { - return try FfiConverterTypeBolt11Invoice.lift(try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_constructor_bolt11invoice_from_str( - FfiConverterString.lower(invoiceStr),$0 - ) -}) -} - + public static func fromStr(invoiceStr: String) throws -> Bolt11Invoice { + return try FfiConverterTypeBolt11Invoice.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_constructor_bolt11invoice_from_str( + FfiConverterString.lower(invoiceStr), $0 + ) + }) + } + + open func amountMilliSatoshis() -> UInt64? { + return try! FfiConverterOptionUInt64.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt11invoice_amount_milli_satoshis(self.uniffiClonePointer(), $0) + }) + } + + open func currency() -> Currency { + return try! FfiConverterTypeCurrency.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt11invoice_currency(self.uniffiClonePointer(), $0) + }) + } + + open func expiryTimeSeconds() -> UInt64 { + return try! FfiConverterUInt64.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt11invoice_expiry_time_seconds(self.uniffiClonePointer(), $0) + }) + } + + open func fallbackAddresses() -> [Address] { + return try! FfiConverterSequenceTypeAddress.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt11invoice_fallback_addresses(self.uniffiClonePointer(), $0) + }) + } + + open func invoiceDescription() -> Bolt11InvoiceDescription { + return try! FfiConverterTypeBolt11InvoiceDescription.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt11invoice_invoice_description(self.uniffiClonePointer(), $0) + }) + } + + open func isExpired() -> Bool { + return try! FfiConverterBool.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt11invoice_is_expired(self.uniffiClonePointer(), $0) + }) + } + + open func minFinalCltvExpiryDelta() -> UInt64 { + return try! FfiConverterUInt64.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt11invoice_min_final_cltv_expiry_delta(self.uniffiClonePointer(), $0) + }) + } + + open func network() -> Network { + return try! FfiConverterTypeNetwork.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt11invoice_network(self.uniffiClonePointer(), $0) + }) + } + + open func paymentHash() -> PaymentHash { + return try! FfiConverterTypePaymentHash.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt11invoice_payment_hash(self.uniffiClonePointer(), $0) + }) + } + + open func paymentSecret() -> PaymentSecret { + return try! FfiConverterTypePaymentSecret.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt11invoice_payment_secret(self.uniffiClonePointer(), $0) + }) + } + + open func recoverPayeePubKey() -> PublicKey { + return try! FfiConverterTypePublicKey.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt11invoice_recover_payee_pub_key(self.uniffiClonePointer(), $0) + }) + } + + open func routeHints() -> [[RouteHintHop]] { + return try! FfiConverterSequenceSequenceTypeRouteHintHop.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt11invoice_route_hints(self.uniffiClonePointer(), $0) + }) + } + + open func secondsSinceEpoch() -> UInt64 { + return try! FfiConverterUInt64.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt11invoice_seconds_since_epoch(self.uniffiClonePointer(), $0) + }) + } + + open func secondsUntilExpiry() -> UInt64 { + return try! FfiConverterUInt64.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt11invoice_seconds_until_expiry(self.uniffiClonePointer(), $0) + }) + } + + open func signableHash() -> [UInt8] { + return try! FfiConverterSequenceUInt8.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt11invoice_signable_hash(self.uniffiClonePointer(), $0) + }) + } + + open func wouldExpire(atTimeSeconds: UInt64) -> Bool { + return try! FfiConverterBool.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt11invoice_would_expire(self.uniffiClonePointer(), + FfiConverterUInt64.lower(atTimeSeconds), $0) + }) + } - -open func amountMilliSatoshis() -> UInt64? { - return try! FfiConverterOptionUInt64.lift(try! rustCall() { - uniffi_ldk_node_fn_method_bolt11invoice_amount_milli_satoshis(self.uniffiClonePointer(),$0 - ) -}) -} - -open func currency() -> Currency { - return try! FfiConverterTypeCurrency.lift(try! rustCall() { - uniffi_ldk_node_fn_method_bolt11invoice_currency(self.uniffiClonePointer(),$0 - ) -}) -} - -open func expiryTimeSeconds() -> UInt64 { - return try! FfiConverterUInt64.lift(try! rustCall() { - uniffi_ldk_node_fn_method_bolt11invoice_expiry_time_seconds(self.uniffiClonePointer(),$0 - ) -}) -} - -open func fallbackAddresses() -> [Address] { - return try! FfiConverterSequenceTypeAddress.lift(try! rustCall() { - uniffi_ldk_node_fn_method_bolt11invoice_fallback_addresses(self.uniffiClonePointer(),$0 - ) -}) -} - -open func invoiceDescription() -> Bolt11InvoiceDescription { - return try! FfiConverterTypeBolt11InvoiceDescription.lift(try! rustCall() { - uniffi_ldk_node_fn_method_bolt11invoice_invoice_description(self.uniffiClonePointer(),$0 - ) -}) -} - -open func isExpired() -> Bool { - return try! FfiConverterBool.lift(try! rustCall() { - uniffi_ldk_node_fn_method_bolt11invoice_is_expired(self.uniffiClonePointer(),$0 - ) -}) -} - -open func minFinalCltvExpiryDelta() -> UInt64 { - return try! FfiConverterUInt64.lift(try! rustCall() { - uniffi_ldk_node_fn_method_bolt11invoice_min_final_cltv_expiry_delta(self.uniffiClonePointer(),$0 - ) -}) -} - -open func network() -> Network { - return try! FfiConverterTypeNetwork.lift(try! rustCall() { - uniffi_ldk_node_fn_method_bolt11invoice_network(self.uniffiClonePointer(),$0 - ) -}) -} - -open func paymentHash() -> PaymentHash { - return try! FfiConverterTypePaymentHash.lift(try! rustCall() { - uniffi_ldk_node_fn_method_bolt11invoice_payment_hash(self.uniffiClonePointer(),$0 - ) -}) -} - -open func paymentSecret() -> PaymentSecret { - return try! FfiConverterTypePaymentSecret.lift(try! rustCall() { - uniffi_ldk_node_fn_method_bolt11invoice_payment_secret(self.uniffiClonePointer(),$0 - ) -}) -} - -open func recoverPayeePubKey() -> PublicKey { - return try! FfiConverterTypePublicKey.lift(try! rustCall() { - uniffi_ldk_node_fn_method_bolt11invoice_recover_payee_pub_key(self.uniffiClonePointer(),$0 - ) -}) -} - -open func routeHints() -> [[RouteHintHop]] { - return try! FfiConverterSequenceSequenceTypeRouteHintHop.lift(try! rustCall() { - uniffi_ldk_node_fn_method_bolt11invoice_route_hints(self.uniffiClonePointer(),$0 - ) -}) -} - -open func secondsSinceEpoch() -> UInt64 { - return try! FfiConverterUInt64.lift(try! rustCall() { - uniffi_ldk_node_fn_method_bolt11invoice_seconds_since_epoch(self.uniffiClonePointer(),$0 - ) -}) -} - -open func secondsUntilExpiry() -> UInt64 { - return try! FfiConverterUInt64.lift(try! rustCall() { - uniffi_ldk_node_fn_method_bolt11invoice_seconds_until_expiry(self.uniffiClonePointer(),$0 - ) -}) -} - -open func signableHash() -> [UInt8] { - return try! FfiConverterSequenceUInt8.lift(try! rustCall() { - uniffi_ldk_node_fn_method_bolt11invoice_signable_hash(self.uniffiClonePointer(),$0 - ) -}) -} - -open func wouldExpire(atTimeSeconds: UInt64) -> Bool { - return try! FfiConverterBool.lift(try! rustCall() { - uniffi_ldk_node_fn_method_bolt11invoice_would_expire(self.uniffiClonePointer(), - FfiConverterUInt64.lower(atTimeSeconds),$0 - ) -}) -} - open var debugDescription: String { - return try! FfiConverterString.lift( - try! rustCall() { - uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_debug(self.uniffiClonePointer(),$0 - ) -} + return try! FfiConverterString.lift( + try! rustCall { + uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_debug(self.uniffiClonePointer(), $0) + } ) } + open var description: String { - return try! FfiConverterString.lift( - try! rustCall() { - uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_display(self.uniffiClonePointer(),$0 - ) -} + return try! FfiConverterString.lift( + try! rustCall { + uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_display(self.uniffiClonePointer(), $0) + } ) } + public static func == (self: Bolt11Invoice, other: Bolt11Invoice) -> Bool { - return try! FfiConverterBool.lift( - try! rustCall() { - uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_eq_eq(self.uniffiClonePointer(), - FfiConverterTypeBolt11Invoice.lower(other),$0 - ) -} + return try! FfiConverterBool.lift( + try! rustCall { + uniffi_ldk_node_fn_method_bolt11invoice_uniffi_trait_eq_eq(self.uniffiClonePointer(), + FfiConverterTypeBolt11Invoice.lower(other), $0) + } ) } - } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypeBolt11Invoice: FfiConverter { - typealias FfiType = UnsafeMutableRawPointer typealias SwiftType = Bolt11Invoice @@ -758,7 +796,7 @@ public struct FfiConverterTypeBolt11Invoice: FfiConverter { // The Rust code won't compile if a pointer won't fit in a UInt64. // We have to go via `UInt` because that's the thing that's the size of a pointer. let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { + if ptr == nil { throw UniffiInternalError.unexpectedNullPointer } return try lift(ptr!) @@ -771,53 +809,63 @@ public struct FfiConverterTypeBolt11Invoice: FfiConverter { } } - - - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeBolt11Invoice_lift(_ pointer: UnsafeMutableRawPointer) throws -> Bolt11Invoice { return try FfiConverterTypeBolt11Invoice.lift(pointer) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeBolt11Invoice_lower(_ value: Bolt11Invoice) -> UnsafeMutableRawPointer { return FfiConverterTypeBolt11Invoice.lower(value) } +public protocol Bolt11PaymentProtocol: AnyObject { + func claimForHash(paymentHash: PaymentHash, claimableAmountMsat: UInt64, preimage: PaymentPreimage) throws + + func estimateRoutingFees(invoice: Bolt11Invoice) throws -> UInt64 + + func estimateRoutingFeesUsingAmount(invoice: Bolt11Invoice, amountMsat: UInt64) throws -> UInt64 + + func failForHash(paymentHash: PaymentHash) throws + + func receive(amountMsat: UInt64, description: Bolt11InvoiceDescription, expirySecs: UInt32) throws -> Bolt11Invoice + + func receiveForHash(amountMsat: UInt64, description: Bolt11InvoiceDescription, expirySecs: UInt32, paymentHash: PaymentHash) throws -> Bolt11Invoice + + func receiveVariableAmount(description: Bolt11InvoiceDescription, expirySecs: UInt32) throws -> Bolt11Invoice + + func receiveVariableAmountForHash(description: Bolt11InvoiceDescription, expirySecs: UInt32, paymentHash: PaymentHash) throws -> Bolt11Invoice + + func receiveVariableAmountViaJitChannel(description: Bolt11InvoiceDescription, expirySecs: UInt32, maxProportionalLspFeeLimitPpmMsat: UInt64?) throws -> Bolt11Invoice + + func receiveVariableAmountViaJitChannelForHash(description: Bolt11InvoiceDescription, expirySecs: UInt32, maxProportionalLspFeeLimitPpmMsat: UInt64?, paymentHash: PaymentHash) throws -> Bolt11Invoice + func receiveViaJitChannel(amountMsat: UInt64, description: Bolt11InvoiceDescription, expirySecs: UInt32, maxLspFeeLimitMsat: UInt64?) throws -> Bolt11Invoice + func receiveViaJitChannelForHash(amountMsat: UInt64, description: Bolt11InvoiceDescription, expirySecs: UInt32, maxLspFeeLimitMsat: UInt64?, paymentHash: PaymentHash) throws -> Bolt11Invoice -public protocol Bolt11PaymentProtocol : AnyObject { - - func claimForHash(paymentHash: PaymentHash, claimableAmountMsat: UInt64, preimage: PaymentPreimage) throws - - func failForHash(paymentHash: PaymentHash) throws - - func receive(amountMsat: UInt64, description: Bolt11InvoiceDescription, expirySecs: UInt32) throws -> Bolt11Invoice - - func receiveForHash(amountMsat: UInt64, description: Bolt11InvoiceDescription, expirySecs: UInt32, paymentHash: PaymentHash) throws -> Bolt11Invoice - - func receiveVariableAmount(description: Bolt11InvoiceDescription, expirySecs: UInt32) throws -> Bolt11Invoice - - func receiveVariableAmountForHash(description: Bolt11InvoiceDescription, expirySecs: UInt32, paymentHash: PaymentHash) throws -> Bolt11Invoice - - func receiveVariableAmountViaJitChannel(description: Bolt11InvoiceDescription, expirySecs: UInt32, maxProportionalLspFeeLimitPpmMsat: UInt64?) throws -> Bolt11Invoice - - func receiveViaJitChannel(amountMsat: UInt64, description: Bolt11InvoiceDescription, expirySecs: UInt32, maxLspFeeLimitMsat: UInt64?) throws -> Bolt11Invoice - - func send(invoice: Bolt11Invoice, sendingParameters: SendingParameters?) throws -> PaymentId - - func sendProbes(invoice: Bolt11Invoice) throws - - func sendProbesUsingAmount(invoice: Bolt11Invoice, amountMsat: UInt64) throws - - func sendUsingAmount(invoice: Bolt11Invoice, amountMsat: UInt64, sendingParameters: SendingParameters?) throws -> PaymentId - + func send(invoice: Bolt11Invoice, routeParameters: RouteParametersConfig?) throws -> PaymentId + + func sendProbes(invoice: Bolt11Invoice, routeParameters: RouteParametersConfig?) throws -> [ProbeHandle] + + func sendProbesUsingAmount(invoice: Bolt11Invoice, amountMsat: UInt64, routeParameters: RouteParametersConfig?) throws -> [ProbeHandle] + + func sendUsingAmount(invoice: Bolt11Invoice, amountMsat: UInt64, routeParameters: RouteParametersConfig?) throws -> PaymentId } open class Bolt11Payment: - Bolt11PaymentProtocol { + Bolt11PaymentProtocol +{ fileprivate let pointer: UnsafeMutableRawPointer! - /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif public struct NoPointer { public init() {} } @@ -825,22 +873,29 @@ open class Bolt11Payment: // TODO: We'd like this to be `private` but for Swifty reasons, // we can't implement `FfiConverter` without making this `required` and we can't // make it `required` without making it `public`. - required public init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + public required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { self.pointer = pointer } - /// This constructor can be used to instantiate a fake object. - /// - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. - /// - /// - Warning: - /// Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. - public init(noPointer: NoPointer) { - self.pointer = nil + // This constructor can be used to instantiate a fake object. + // - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. + // + // - Warning: + // Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public init(noPointer _: NoPointer) { + pointer = nil } + #if swift(>=5.8) + @_documentation(visibility: private) + #endif public func uniffiClonePointer() -> UnsafeMutableRawPointer { return try! rustCall { uniffi_ldk_node_fn_clone_bolt11payment(self.pointer, $0) } } + // No primary constructor declared for this class. deinit { @@ -851,125 +906,152 @@ open class Bolt11Payment: try! rustCall { uniffi_ldk_node_fn_free_bolt11payment(pointer, $0) } } - + open func claimForHash(paymentHash: PaymentHash, claimableAmountMsat: UInt64, preimage: PaymentPreimage) throws { + try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt11payment_claim_for_hash(self.uniffiClonePointer(), + FfiConverterTypePaymentHash.lower(paymentHash), + FfiConverterUInt64.lower(claimableAmountMsat), + FfiConverterTypePaymentPreimage.lower(preimage), $0) + } + } - -open func claimForHash(paymentHash: PaymentHash, claimableAmountMsat: UInt64, preimage: PaymentPreimage)throws {try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_bolt11payment_claim_for_hash(self.uniffiClonePointer(), - FfiConverterTypePaymentHash.lower(paymentHash), - FfiConverterUInt64.lower(claimableAmountMsat), - FfiConverterTypePaymentPreimage.lower(preimage),$0 - ) -} -} - -open func failForHash(paymentHash: PaymentHash)throws {try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_bolt11payment_fail_for_hash(self.uniffiClonePointer(), - FfiConverterTypePaymentHash.lower(paymentHash),$0 - ) -} -} - -open func receive(amountMsat: UInt64, description: Bolt11InvoiceDescription, expirySecs: UInt32)throws -> Bolt11Invoice { - return try FfiConverterTypeBolt11Invoice.lift(try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_bolt11payment_receive(self.uniffiClonePointer(), - FfiConverterUInt64.lower(amountMsat), - FfiConverterTypeBolt11InvoiceDescription.lower(description), - FfiConverterUInt32.lower(expirySecs),$0 - ) -}) -} - -open func receiveForHash(amountMsat: UInt64, description: Bolt11InvoiceDescription, expirySecs: UInt32, paymentHash: PaymentHash)throws -> Bolt11Invoice { - return try FfiConverterTypeBolt11Invoice.lift(try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_bolt11payment_receive_for_hash(self.uniffiClonePointer(), - FfiConverterUInt64.lower(amountMsat), - FfiConverterTypeBolt11InvoiceDescription.lower(description), - FfiConverterUInt32.lower(expirySecs), - FfiConverterTypePaymentHash.lower(paymentHash),$0 - ) -}) -} - -open func receiveVariableAmount(description: Bolt11InvoiceDescription, expirySecs: UInt32)throws -> Bolt11Invoice { - return try FfiConverterTypeBolt11Invoice.lift(try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount(self.uniffiClonePointer(), - FfiConverterTypeBolt11InvoiceDescription.lower(description), - FfiConverterUInt32.lower(expirySecs),$0 - ) -}) -} - -open func receiveVariableAmountForHash(description: Bolt11InvoiceDescription, expirySecs: UInt32, paymentHash: PaymentHash)throws -> Bolt11Invoice { - return try FfiConverterTypeBolt11Invoice.lift(try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount_for_hash(self.uniffiClonePointer(), - FfiConverterTypeBolt11InvoiceDescription.lower(description), - FfiConverterUInt32.lower(expirySecs), - FfiConverterTypePaymentHash.lower(paymentHash),$0 - ) -}) -} - -open func receiveVariableAmountViaJitChannel(description: Bolt11InvoiceDescription, expirySecs: UInt32, maxProportionalLspFeeLimitPpmMsat: UInt64?)throws -> Bolt11Invoice { - return try FfiConverterTypeBolt11Invoice.lift(try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount_via_jit_channel(self.uniffiClonePointer(), - FfiConverterTypeBolt11InvoiceDescription.lower(description), - FfiConverterUInt32.lower(expirySecs), - FfiConverterOptionUInt64.lower(maxProportionalLspFeeLimitPpmMsat),$0 - ) -}) -} - -open func receiveViaJitChannel(amountMsat: UInt64, description: Bolt11InvoiceDescription, expirySecs: UInt32, maxLspFeeLimitMsat: UInt64?)throws -> Bolt11Invoice { - return try FfiConverterTypeBolt11Invoice.lift(try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_bolt11payment_receive_via_jit_channel(self.uniffiClonePointer(), - FfiConverterUInt64.lower(amountMsat), - FfiConverterTypeBolt11InvoiceDescription.lower(description), - FfiConverterUInt32.lower(expirySecs), - FfiConverterOptionUInt64.lower(maxLspFeeLimitMsat),$0 - ) -}) -} - -open func send(invoice: Bolt11Invoice, sendingParameters: SendingParameters?)throws -> PaymentId { - return try FfiConverterTypePaymentId.lift(try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_bolt11payment_send(self.uniffiClonePointer(), - FfiConverterTypeBolt11Invoice.lower(invoice), - FfiConverterOptionTypeSendingParameters.lower(sendingParameters),$0 - ) -}) -} - -open func sendProbes(invoice: Bolt11Invoice)throws {try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_bolt11payment_send_probes(self.uniffiClonePointer(), - FfiConverterTypeBolt11Invoice.lower(invoice),$0 - ) -} -} - -open func sendProbesUsingAmount(invoice: Bolt11Invoice, amountMsat: UInt64)throws {try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_bolt11payment_send_probes_using_amount(self.uniffiClonePointer(), - FfiConverterTypeBolt11Invoice.lower(invoice), - FfiConverterUInt64.lower(amountMsat),$0 - ) -} -} - -open func sendUsingAmount(invoice: Bolt11Invoice, amountMsat: UInt64, sendingParameters: SendingParameters?)throws -> PaymentId { - return try FfiConverterTypePaymentId.lift(try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_bolt11payment_send_using_amount(self.uniffiClonePointer(), - FfiConverterTypeBolt11Invoice.lower(invoice), - FfiConverterUInt64.lower(amountMsat), - FfiConverterOptionTypeSendingParameters.lower(sendingParameters),$0 - ) -}) -} - + open func estimateRoutingFees(invoice: Bolt11Invoice) throws -> UInt64 { + return try FfiConverterUInt64.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt11payment_estimate_routing_fees(self.uniffiClonePointer(), + FfiConverterTypeBolt11Invoice.lower(invoice), $0) + }) + } -} + open func estimateRoutingFeesUsingAmount(invoice: Bolt11Invoice, amountMsat: UInt64) throws -> UInt64 { + return try FfiConverterUInt64.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt11payment_estimate_routing_fees_using_amount(self.uniffiClonePointer(), + FfiConverterTypeBolt11Invoice.lower(invoice), + FfiConverterUInt64.lower(amountMsat), $0) + }) + } -public struct FfiConverterTypeBolt11Payment: FfiConverter { + open func failForHash(paymentHash: PaymentHash) throws { + try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt11payment_fail_for_hash(self.uniffiClonePointer(), + FfiConverterTypePaymentHash.lower(paymentHash), $0) + } + } + + open func receive(amountMsat: UInt64, description: Bolt11InvoiceDescription, expirySecs: UInt32) throws -> Bolt11Invoice { + return try FfiConverterTypeBolt11Invoice.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt11payment_receive(self.uniffiClonePointer(), + FfiConverterUInt64.lower(amountMsat), + FfiConverterTypeBolt11InvoiceDescription.lower(description), + FfiConverterUInt32.lower(expirySecs), $0) + }) + } + + open func receiveForHash(amountMsat: UInt64, description: Bolt11InvoiceDescription, expirySecs: UInt32, paymentHash: PaymentHash) throws -> Bolt11Invoice { + return try FfiConverterTypeBolt11Invoice.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt11payment_receive_for_hash(self.uniffiClonePointer(), + FfiConverterUInt64.lower(amountMsat), + FfiConverterTypeBolt11InvoiceDescription.lower(description), + FfiConverterUInt32.lower(expirySecs), + FfiConverterTypePaymentHash.lower(paymentHash), $0) + }) + } + + open func receiveVariableAmount(description: Bolt11InvoiceDescription, expirySecs: UInt32) throws -> Bolt11Invoice { + return try FfiConverterTypeBolt11Invoice.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount(self.uniffiClonePointer(), + FfiConverterTypeBolt11InvoiceDescription.lower(description), + FfiConverterUInt32.lower(expirySecs), $0) + }) + } + + open func receiveVariableAmountForHash(description: Bolt11InvoiceDescription, expirySecs: UInt32, paymentHash: PaymentHash) throws -> Bolt11Invoice { + return try FfiConverterTypeBolt11Invoice.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount_for_hash(self.uniffiClonePointer(), + FfiConverterTypeBolt11InvoiceDescription.lower(description), + FfiConverterUInt32.lower(expirySecs), + FfiConverterTypePaymentHash.lower(paymentHash), $0) + }) + } + + open func receiveVariableAmountViaJitChannel(description: Bolt11InvoiceDescription, expirySecs: UInt32, maxProportionalLspFeeLimitPpmMsat: UInt64?) throws -> Bolt11Invoice { + return try FfiConverterTypeBolt11Invoice.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount_via_jit_channel(self.uniffiClonePointer(), + FfiConverterTypeBolt11InvoiceDescription.lower(description), + FfiConverterUInt32.lower(expirySecs), + FfiConverterOptionUInt64.lower(maxProportionalLspFeeLimitPpmMsat), $0) + }) + } + + open func receiveVariableAmountViaJitChannelForHash(description: Bolt11InvoiceDescription, expirySecs: UInt32, maxProportionalLspFeeLimitPpmMsat: UInt64?, paymentHash: PaymentHash) throws -> Bolt11Invoice { + return try FfiConverterTypeBolt11Invoice.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt11payment_receive_variable_amount_via_jit_channel_for_hash(self.uniffiClonePointer(), + FfiConverterTypeBolt11InvoiceDescription.lower(description), + FfiConverterUInt32.lower(expirySecs), + FfiConverterOptionUInt64.lower(maxProportionalLspFeeLimitPpmMsat), + FfiConverterTypePaymentHash.lower(paymentHash), $0) + }) + } + + open func receiveViaJitChannel(amountMsat: UInt64, description: Bolt11InvoiceDescription, expirySecs: UInt32, maxLspFeeLimitMsat: UInt64?) throws -> Bolt11Invoice { + return try FfiConverterTypeBolt11Invoice.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt11payment_receive_via_jit_channel(self.uniffiClonePointer(), + FfiConverterUInt64.lower(amountMsat), + FfiConverterTypeBolt11InvoiceDescription.lower(description), + FfiConverterUInt32.lower(expirySecs), + FfiConverterOptionUInt64.lower(maxLspFeeLimitMsat), $0) + }) + } + + open func receiveViaJitChannelForHash(amountMsat: UInt64, description: Bolt11InvoiceDescription, expirySecs: UInt32, maxLspFeeLimitMsat: UInt64?, paymentHash: PaymentHash) throws -> Bolt11Invoice { + return try FfiConverterTypeBolt11Invoice.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt11payment_receive_via_jit_channel_for_hash(self.uniffiClonePointer(), + FfiConverterUInt64.lower(amountMsat), + FfiConverterTypeBolt11InvoiceDescription.lower(description), + FfiConverterUInt32.lower(expirySecs), + FfiConverterOptionUInt64.lower(maxLspFeeLimitMsat), + FfiConverterTypePaymentHash.lower(paymentHash), $0) + }) + } + open func send(invoice: Bolt11Invoice, routeParameters: RouteParametersConfig?) throws -> PaymentId { + return try FfiConverterTypePaymentId.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt11payment_send(self.uniffiClonePointer(), + FfiConverterTypeBolt11Invoice.lower(invoice), + FfiConverterOptionTypeRouteParametersConfig.lower(routeParameters), $0) + }) + } + + open func sendProbes(invoice: Bolt11Invoice, routeParameters: RouteParametersConfig?) throws -> [ProbeHandle] { + return try FfiConverterSequenceTypeProbeHandle.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt11payment_send_probes(self.uniffiClonePointer(), + FfiConverterTypeBolt11Invoice.lower(invoice), + FfiConverterOptionTypeRouteParametersConfig.lower(routeParameters), $0) + }) + } + + open func sendProbesUsingAmount(invoice: Bolt11Invoice, amountMsat: UInt64, routeParameters: RouteParametersConfig?) throws -> [ProbeHandle] { + return try FfiConverterSequenceTypeProbeHandle.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt11payment_send_probes_using_amount(self.uniffiClonePointer(), + FfiConverterTypeBolt11Invoice.lower(invoice), + FfiConverterUInt64.lower(amountMsat), + FfiConverterOptionTypeRouteParametersConfig.lower(routeParameters), $0) + }) + } + + open func sendUsingAmount(invoice: Bolt11Invoice, amountMsat: UInt64, routeParameters: RouteParametersConfig?) throws -> PaymentId { + return try FfiConverterTypePaymentId.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt11payment_send_using_amount(self.uniffiClonePointer(), + FfiConverterTypeBolt11Invoice.lower(invoice), + FfiConverterUInt64.lower(amountMsat), + FfiConverterOptionTypeRouteParametersConfig.lower(routeParameters), $0) + }) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeBolt11Payment: FfiConverter { typealias FfiType = UnsafeMutableRawPointer typealias SwiftType = Bolt11Payment @@ -986,7 +1068,7 @@ public struct FfiConverterTypeBolt11Payment: FfiConverter { // The Rust code won't compile if a pointer won't fit in a UInt64. // We have to go via `UInt` because that's the thing that's the size of a pointer. let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { + if ptr == nil { throw UniffiInternalError.unexpectedNullPointer } return try lift(ptr!) @@ -999,41 +1081,71 @@ public struct FfiConverterTypeBolt11Payment: FfiConverter { } } - - - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeBolt11Payment_lift(_ pointer: UnsafeMutableRawPointer) throws -> Bolt11Payment { return try FfiConverterTypeBolt11Payment.lift(pointer) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeBolt11Payment_lower(_ value: Bolt11Payment) -> UnsafeMutableRawPointer { return FfiConverterTypeBolt11Payment.lower(value) } +public protocol Bolt12InvoiceProtocol: AnyObject { + func absoluteExpirySeconds() -> UInt64? + + func amount() -> OfferAmount? + + func amountMsats() -> UInt64 + + func chain() -> [UInt8] + + func createdAt() -> UInt64 + + func encode() -> [UInt8] + func fallbackAddresses() -> [Address] + func invoiceDescription() -> String? -public protocol Bolt12PaymentProtocol : AnyObject { - - func initiateRefund(amountMsat: UInt64, expirySecs: UInt32, quantity: UInt64?, payerNote: String?) throws -> Refund - - func receive(amountMsat: UInt64, description: String, expirySecs: UInt32?, quantity: UInt64?) throws -> Offer - - func receiveVariableAmount(description: String, expirySecs: UInt32?) throws -> Offer - - func requestRefundPayment(refund: Refund) throws -> Bolt12Invoice - - func send(offer: Offer, quantity: UInt64?, payerNote: String?) throws -> PaymentId - - func sendUsingAmount(offer: Offer, amountMsat: UInt64, quantity: UInt64?, payerNote: String?) throws -> PaymentId - + func isExpired() -> Bool + + func issuer() -> String? + + func issuerSigningPubkey() -> PublicKey? + + func metadata() -> [UInt8]? + + func offerChains() -> [[UInt8]]? + + func payerNote() -> String? + + func payerSigningPubkey() -> PublicKey + + func paymentHash() -> PaymentHash + + func quantity() -> UInt64? + + func relativeExpiry() -> UInt64 + + func signableHash() -> [UInt8] + + func signingPubkey() -> PublicKey } -open class Bolt12Payment: - Bolt12PaymentProtocol { +open class Bolt12Invoice: + Bolt12InvoiceProtocol +{ fileprivate let pointer: UnsafeMutableRawPointer! - /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif public struct NoPointer { public init() {} } @@ -1041,22 +1153,29 @@ open class Bolt12Payment: // TODO: We'd like this to be `private` but for Swifty reasons, // we can't implement `FfiConverter` without making this `required` and we can't // make it `required` without making it `public`. - required public init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + public required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { self.pointer = pointer } - /// This constructor can be used to instantiate a fake object. - /// - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. - /// - /// - Warning: - /// Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. - public init(noPointer: NoPointer) { - self.pointer = nil + // This constructor can be used to instantiate a fake object. + // - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. + // + // - Warning: + // Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public init(noPointer _: NoPointer) { + pointer = nil } + #if swift(>=5.8) + @_documentation(visibility: private) + #endif public func uniffiClonePointer() -> UnsafeMutableRawPointer { - return try! rustCall { uniffi_ldk_node_fn_clone_bolt12payment(self.pointer, $0) } + return try! rustCall { uniffi_ldk_node_fn_clone_bolt12invoice(self.pointer, $0) } } + // No primary constructor declared for this class. deinit { @@ -1064,469 +1183,214 @@ open class Bolt12Payment: return } - try! rustCall { uniffi_ldk_node_fn_free_bolt12payment(pointer, $0) } + try! rustCall { uniffi_ldk_node_fn_free_bolt12invoice(pointer, $0) } } - + public static func fromStr(invoiceStr: String) throws -> Bolt12Invoice { + return try FfiConverterTypeBolt12Invoice.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_constructor_bolt12invoice_from_str( + FfiConverterString.lower(invoiceStr), $0 + ) + }) + } - -open func initiateRefund(amountMsat: UInt64, expirySecs: UInt32, quantity: UInt64?, payerNote: String?)throws -> Refund { - return try FfiConverterTypeRefund.lift(try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_bolt12payment_initiate_refund(self.uniffiClonePointer(), - FfiConverterUInt64.lower(amountMsat), - FfiConverterUInt32.lower(expirySecs), - FfiConverterOptionUInt64.lower(quantity), - FfiConverterOptionString.lower(payerNote),$0 - ) -}) -} - -open func receive(amountMsat: UInt64, description: String, expirySecs: UInt32?, quantity: UInt64?)throws -> Offer { - return try FfiConverterTypeOffer.lift(try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_bolt12payment_receive(self.uniffiClonePointer(), - FfiConverterUInt64.lower(amountMsat), - FfiConverterString.lower(description), - FfiConverterOptionUInt32.lower(expirySecs), - FfiConverterOptionUInt64.lower(quantity),$0 - ) -}) -} - -open func receiveVariableAmount(description: String, expirySecs: UInt32?)throws -> Offer { - return try FfiConverterTypeOffer.lift(try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_bolt12payment_receive_variable_amount(self.uniffiClonePointer(), - FfiConverterString.lower(description), - FfiConverterOptionUInt32.lower(expirySecs),$0 - ) -}) -} - -open func requestRefundPayment(refund: Refund)throws -> Bolt12Invoice { - return try FfiConverterTypeBolt12Invoice.lift(try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_bolt12payment_request_refund_payment(self.uniffiClonePointer(), - FfiConverterTypeRefund.lower(refund),$0 - ) -}) -} - -open func send(offer: Offer, quantity: UInt64?, payerNote: String?)throws -> PaymentId { - return try FfiConverterTypePaymentId.lift(try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_bolt12payment_send(self.uniffiClonePointer(), - FfiConverterTypeOffer.lower(offer), - FfiConverterOptionUInt64.lower(quantity), - FfiConverterOptionString.lower(payerNote),$0 - ) -}) -} - -open func sendUsingAmount(offer: Offer, amountMsat: UInt64, quantity: UInt64?, payerNote: String?)throws -> PaymentId { - return try FfiConverterTypePaymentId.lift(try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_bolt12payment_send_using_amount(self.uniffiClonePointer(), - FfiConverterTypeOffer.lower(offer), - FfiConverterUInt64.lower(amountMsat), - FfiConverterOptionUInt64.lower(quantity), - FfiConverterOptionString.lower(payerNote),$0 - ) -}) -} - + open func absoluteExpirySeconds() -> UInt64? { + return try! FfiConverterOptionUInt64.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt12invoice_absolute_expiry_seconds(self.uniffiClonePointer(), $0) + }) + } -} + open func amount() -> OfferAmount? { + return try! FfiConverterOptionTypeOfferAmount.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt12invoice_amount(self.uniffiClonePointer(), $0) + }) + } -public struct FfiConverterTypeBolt12Payment: FfiConverter { + open func amountMsats() -> UInt64 { + return try! FfiConverterUInt64.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt12invoice_amount_msats(self.uniffiClonePointer(), $0) + }) + } - typealias FfiType = UnsafeMutableRawPointer - typealias SwiftType = Bolt12Payment + open func chain() -> [UInt8] { + return try! FfiConverterSequenceUInt8.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt12invoice_chain(self.uniffiClonePointer(), $0) + }) + } - public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Bolt12Payment { - return Bolt12Payment(unsafeFromRawPointer: pointer) + open func createdAt() -> UInt64 { + return try! FfiConverterUInt64.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt12invoice_created_at(self.uniffiClonePointer(), $0) + }) } - public static func lower(_ value: Bolt12Payment) -> UnsafeMutableRawPointer { - return value.uniffiClonePointer() + open func encode() -> [UInt8] { + return try! FfiConverterSequenceUInt8.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt12invoice_encode(self.uniffiClonePointer(), $0) + }) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Bolt12Payment { - let v: UInt64 = try readInt(&buf) - // The Rust code won't compile if a pointer won't fit in a UInt64. - // We have to go via `UInt` because that's the thing that's the size of a pointer. - let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { - throw UniffiInternalError.unexpectedNullPointer - } - return try lift(ptr!) + open func fallbackAddresses() -> [Address] { + return try! FfiConverterSequenceTypeAddress.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt12invoice_fallback_addresses(self.uniffiClonePointer(), $0) + }) } - public static func write(_ value: Bolt12Payment, into buf: inout [UInt8]) { - // This fiddling is because `Int` is the thing that's the same size as a pointer. - // The Rust code won't compile if a pointer won't fit in a `UInt64`. - writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + open func invoiceDescription() -> String? { + return try! FfiConverterOptionString.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt12invoice_invoice_description(self.uniffiClonePointer(), $0) + }) } -} - - - - -public func FfiConverterTypeBolt12Payment_lift(_ pointer: UnsafeMutableRawPointer) throws -> Bolt12Payment { - return try FfiConverterTypeBolt12Payment.lift(pointer) -} - -public func FfiConverterTypeBolt12Payment_lower(_ value: Bolt12Payment) -> UnsafeMutableRawPointer { - return FfiConverterTypeBolt12Payment.lower(value) -} - - + open func isExpired() -> Bool { + return try! FfiConverterBool.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt12invoice_is_expired(self.uniffiClonePointer(), $0) + }) + } -public protocol BuilderProtocol : AnyObject { - - func build() throws -> Node - - func buildWithFsStore() throws -> Node - - func buildWithVssStore(vssUrl: String, storeId: String, lnurlAuthServerUrl: String, fixedHeaders: [String: String]) throws -> Node - - func buildWithVssStoreAndFixedHeaders(vssUrl: String, storeId: String, fixedHeaders: [String: String]) throws -> Node - - func buildWithVssStoreAndHeaderProvider(vssUrl: String, storeId: String, headerProvider: VssHeaderProvider) throws -> Node - - func setAnnouncementAddresses(announcementAddresses: [SocketAddress]) throws - - func setChainSourceBitcoindRpc(rpcHost: String, rpcPort: UInt16, rpcUser: String, rpcPassword: String) - - func setChainSourceElectrum(serverUrl: String, config: ElectrumSyncConfig?) - - func setChainSourceEsplora(serverUrl: String, config: EsploraSyncConfig?) - - func setCustomLogger(logWriter: LogWriter) - - func setEntropyBip39Mnemonic(mnemonic: Mnemonic, passphrase: String?) - - func setEntropySeedBytes(seedBytes: [UInt8]) throws - - func setEntropySeedPath(seedPath: String) - - func setFilesystemLogger(logFilePath: String?, maxLogLevel: LogLevel?) - - func setGossipSourceP2p() - - func setGossipSourceRgs(rgsServerUrl: String) - - func setLiquiditySourceLsps1(nodeId: PublicKey, address: SocketAddress, token: String?) - - func setLiquiditySourceLsps2(nodeId: PublicKey, address: SocketAddress, token: String?) - - func setListeningAddresses(listeningAddresses: [SocketAddress]) throws - - func setLogFacadeLogger() - - func setNetwork(network: Network) - - func setNodeAlias(nodeAlias: String) throws - - func setStorageDirPath(storageDirPath: String) - -} + open func issuer() -> String? { + return try! FfiConverterOptionString.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt12invoice_issuer(self.uniffiClonePointer(), $0) + }) + } -open class Builder: - BuilderProtocol { - fileprivate let pointer: UnsafeMutableRawPointer! + open func issuerSigningPubkey() -> PublicKey? { + return try! FfiConverterOptionTypePublicKey.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt12invoice_issuer_signing_pubkey(self.uniffiClonePointer(), $0) + }) + } - /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. - public struct NoPointer { - public init() {} + open func metadata() -> [UInt8]? { + return try! FfiConverterOptionSequenceUInt8.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt12invoice_metadata(self.uniffiClonePointer(), $0) + }) } - // TODO: We'd like this to be `private` but for Swifty reasons, - // we can't implement `FfiConverter` without making this `required` and we can't - // make it `required` without making it `public`. - required public init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { - self.pointer = pointer + open func offerChains() -> [[UInt8]]? { + return try! FfiConverterOptionSequenceSequenceUInt8.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt12invoice_offer_chains(self.uniffiClonePointer(), $0) + }) } - /// This constructor can be used to instantiate a fake object. - /// - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. - /// - /// - Warning: - /// Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. - public init(noPointer: NoPointer) { - self.pointer = nil + open func payerNote() -> String? { + return try! FfiConverterOptionString.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt12invoice_payer_note(self.uniffiClonePointer(), $0) + }) } - public func uniffiClonePointer() -> UnsafeMutableRawPointer { - return try! rustCall { uniffi_ldk_node_fn_clone_builder(self.pointer, $0) } + open func payerSigningPubkey() -> PublicKey { + return try! FfiConverterTypePublicKey.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt12invoice_payer_signing_pubkey(self.uniffiClonePointer(), $0) + }) } -public convenience init() { - let pointer = - try! rustCall() { - uniffi_ldk_node_fn_constructor_builder_new($0 - ) -} - self.init(unsafeFromRawPointer: pointer) -} - deinit { - guard let pointer = pointer else { - return - } + open func paymentHash() -> PaymentHash { + return try! FfiConverterTypePaymentHash.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt12invoice_payment_hash(self.uniffiClonePointer(), $0) + }) + } - try! rustCall { uniffi_ldk_node_fn_free_builder(pointer, $0) } + open func quantity() -> UInt64? { + return try! FfiConverterOptionUInt64.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt12invoice_quantity(self.uniffiClonePointer(), $0) + }) } - -public static func fromConfig(config: Config) -> Builder { - return try! FfiConverterTypeBuilder.lift(try! rustCall() { - uniffi_ldk_node_fn_constructor_builder_from_config( - FfiConverterTypeConfig.lower(config),$0 - ) -}) -} - + open func relativeExpiry() -> UInt64 { + return try! FfiConverterUInt64.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt12invoice_relative_expiry(self.uniffiClonePointer(), $0) + }) + } - -open func build()throws -> Node { - return try FfiConverterTypeNode.lift(try rustCallWithError(FfiConverterTypeBuildError.lift) { - uniffi_ldk_node_fn_method_builder_build(self.uniffiClonePointer(),$0 - ) -}) -} - -open func buildWithFsStore()throws -> Node { - return try FfiConverterTypeNode.lift(try rustCallWithError(FfiConverterTypeBuildError.lift) { - uniffi_ldk_node_fn_method_builder_build_with_fs_store(self.uniffiClonePointer(),$0 - ) -}) -} - -open func buildWithVssStore(vssUrl: String, storeId: String, lnurlAuthServerUrl: String, fixedHeaders: [String: String])throws -> Node { - return try FfiConverterTypeNode.lift(try rustCallWithError(FfiConverterTypeBuildError.lift) { - uniffi_ldk_node_fn_method_builder_build_with_vss_store(self.uniffiClonePointer(), - FfiConverterString.lower(vssUrl), - FfiConverterString.lower(storeId), - FfiConverterString.lower(lnurlAuthServerUrl), - FfiConverterDictionaryStringString.lower(fixedHeaders),$0 - ) -}) -} - -open func buildWithVssStoreAndFixedHeaders(vssUrl: String, storeId: String, fixedHeaders: [String: String])throws -> Node { - return try FfiConverterTypeNode.lift(try rustCallWithError(FfiConverterTypeBuildError.lift) { - uniffi_ldk_node_fn_method_builder_build_with_vss_store_and_fixed_headers(self.uniffiClonePointer(), - FfiConverterString.lower(vssUrl), - FfiConverterString.lower(storeId), - FfiConverterDictionaryStringString.lower(fixedHeaders),$0 - ) -}) -} - -open func buildWithVssStoreAndHeaderProvider(vssUrl: String, storeId: String, headerProvider: VssHeaderProvider)throws -> Node { - return try FfiConverterTypeNode.lift(try rustCallWithError(FfiConverterTypeBuildError.lift) { - uniffi_ldk_node_fn_method_builder_build_with_vss_store_and_header_provider(self.uniffiClonePointer(), - FfiConverterString.lower(vssUrl), - FfiConverterString.lower(storeId), - FfiConverterTypeVssHeaderProvider.lower(headerProvider),$0 - ) -}) -} - -open func setAnnouncementAddresses(announcementAddresses: [SocketAddress])throws {try rustCallWithError(FfiConverterTypeBuildError.lift) { - uniffi_ldk_node_fn_method_builder_set_announcement_addresses(self.uniffiClonePointer(), - FfiConverterSequenceTypeSocketAddress.lower(announcementAddresses),$0 - ) -} -} - -open func setChainSourceBitcoindRpc(rpcHost: String, rpcPort: UInt16, rpcUser: String, rpcPassword: String) {try! rustCall() { - uniffi_ldk_node_fn_method_builder_set_chain_source_bitcoind_rpc(self.uniffiClonePointer(), - FfiConverterString.lower(rpcHost), - FfiConverterUInt16.lower(rpcPort), - FfiConverterString.lower(rpcUser), - FfiConverterString.lower(rpcPassword),$0 - ) -} -} - -open func setChainSourceElectrum(serverUrl: String, config: ElectrumSyncConfig?) {try! rustCall() { - uniffi_ldk_node_fn_method_builder_set_chain_source_electrum(self.uniffiClonePointer(), - FfiConverterString.lower(serverUrl), - FfiConverterOptionTypeElectrumSyncConfig.lower(config),$0 - ) -} -} - -open func setChainSourceEsplora(serverUrl: String, config: EsploraSyncConfig?) {try! rustCall() { - uniffi_ldk_node_fn_method_builder_set_chain_source_esplora(self.uniffiClonePointer(), - FfiConverterString.lower(serverUrl), - FfiConverterOptionTypeEsploraSyncConfig.lower(config),$0 - ) -} -} - -open func setCustomLogger(logWriter: LogWriter) {try! rustCall() { - uniffi_ldk_node_fn_method_builder_set_custom_logger(self.uniffiClonePointer(), - FfiConverterTypeLogWriter.lower(logWriter),$0 - ) -} -} - -open func setEntropyBip39Mnemonic(mnemonic: Mnemonic, passphrase: String?) {try! rustCall() { - uniffi_ldk_node_fn_method_builder_set_entropy_bip39_mnemonic(self.uniffiClonePointer(), - FfiConverterTypeMnemonic.lower(mnemonic), - FfiConverterOptionString.lower(passphrase),$0 - ) -} -} - -open func setEntropySeedBytes(seedBytes: [UInt8])throws {try rustCallWithError(FfiConverterTypeBuildError.lift) { - uniffi_ldk_node_fn_method_builder_set_entropy_seed_bytes(self.uniffiClonePointer(), - FfiConverterSequenceUInt8.lower(seedBytes),$0 - ) -} -} - -open func setEntropySeedPath(seedPath: String) {try! rustCall() { - uniffi_ldk_node_fn_method_builder_set_entropy_seed_path(self.uniffiClonePointer(), - FfiConverterString.lower(seedPath),$0 - ) -} -} - -open func setFilesystemLogger(logFilePath: String?, maxLogLevel: LogLevel?) {try! rustCall() { - uniffi_ldk_node_fn_method_builder_set_filesystem_logger(self.uniffiClonePointer(), - FfiConverterOptionString.lower(logFilePath), - FfiConverterOptionTypeLogLevel.lower(maxLogLevel),$0 - ) -} -} - -open func setGossipSourceP2p() {try! rustCall() { - uniffi_ldk_node_fn_method_builder_set_gossip_source_p2p(self.uniffiClonePointer(),$0 - ) -} -} - -open func setGossipSourceRgs(rgsServerUrl: String) {try! rustCall() { - uniffi_ldk_node_fn_method_builder_set_gossip_source_rgs(self.uniffiClonePointer(), - FfiConverterString.lower(rgsServerUrl),$0 - ) -} -} - -open func setLiquiditySourceLsps1(nodeId: PublicKey, address: SocketAddress, token: String?) {try! rustCall() { - uniffi_ldk_node_fn_method_builder_set_liquidity_source_lsps1(self.uniffiClonePointer(), - FfiConverterTypePublicKey.lower(nodeId), - FfiConverterTypeSocketAddress.lower(address), - FfiConverterOptionString.lower(token),$0 - ) -} -} - -open func setLiquiditySourceLsps2(nodeId: PublicKey, address: SocketAddress, token: String?) {try! rustCall() { - uniffi_ldk_node_fn_method_builder_set_liquidity_source_lsps2(self.uniffiClonePointer(), - FfiConverterTypePublicKey.lower(nodeId), - FfiConverterTypeSocketAddress.lower(address), - FfiConverterOptionString.lower(token),$0 - ) -} -} - -open func setListeningAddresses(listeningAddresses: [SocketAddress])throws {try rustCallWithError(FfiConverterTypeBuildError.lift) { - uniffi_ldk_node_fn_method_builder_set_listening_addresses(self.uniffiClonePointer(), - FfiConverterSequenceTypeSocketAddress.lower(listeningAddresses),$0 - ) -} -} - -open func setLogFacadeLogger() {try! rustCall() { - uniffi_ldk_node_fn_method_builder_set_log_facade_logger(self.uniffiClonePointer(),$0 - ) -} -} - -open func setNetwork(network: Network) {try! rustCall() { - uniffi_ldk_node_fn_method_builder_set_network(self.uniffiClonePointer(), - FfiConverterTypeNetwork.lower(network),$0 - ) -} -} - -open func setNodeAlias(nodeAlias: String)throws {try rustCallWithError(FfiConverterTypeBuildError.lift) { - uniffi_ldk_node_fn_method_builder_set_node_alias(self.uniffiClonePointer(), - FfiConverterString.lower(nodeAlias),$0 - ) -} -} - -open func setStorageDirPath(storageDirPath: String) {try! rustCall() { - uniffi_ldk_node_fn_method_builder_set_storage_dir_path(self.uniffiClonePointer(), - FfiConverterString.lower(storageDirPath),$0 - ) -} -} - + open func signableHash() -> [UInt8] { + return try! FfiConverterSequenceUInt8.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt12invoice_signable_hash(self.uniffiClonePointer(), $0) + }) + } + open func signingPubkey() -> PublicKey { + return try! FfiConverterTypePublicKey.lift(try! rustCall { + uniffi_ldk_node_fn_method_bolt12invoice_signing_pubkey(self.uniffiClonePointer(), $0) + }) + } } -public struct FfiConverterTypeBuilder: FfiConverter { - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeBolt12Invoice: FfiConverter { typealias FfiType = UnsafeMutableRawPointer - typealias SwiftType = Builder + typealias SwiftType = Bolt12Invoice - public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Builder { - return Builder(unsafeFromRawPointer: pointer) + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Bolt12Invoice { + return Bolt12Invoice(unsafeFromRawPointer: pointer) } - public static func lower(_ value: Builder) -> UnsafeMutableRawPointer { + public static func lower(_ value: Bolt12Invoice) -> UnsafeMutableRawPointer { return value.uniffiClonePointer() } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Builder { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Bolt12Invoice { let v: UInt64 = try readInt(&buf) // The Rust code won't compile if a pointer won't fit in a UInt64. // We have to go via `UInt` because that's the thing that's the size of a pointer. let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { + if ptr == nil { throw UniffiInternalError.unexpectedNullPointer } return try lift(ptr!) } - public static func write(_ value: Builder, into buf: inout [UInt8]) { + public static func write(_ value: Bolt12Invoice, into buf: inout [UInt8]) { // This fiddling is because `Int` is the thing that's the same size as a pointer. // The Rust code won't compile if a pointer won't fit in a `UInt64`. writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) } } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeBolt12Invoice_lift(_ pointer: UnsafeMutableRawPointer) throws -> Bolt12Invoice { + return try FfiConverterTypeBolt12Invoice.lift(pointer) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeBolt12Invoice_lower(_ value: Bolt12Invoice) -> UnsafeMutableRawPointer { + return FfiConverterTypeBolt12Invoice.lower(value) +} +public protocol Bolt12PaymentProtocol: AnyObject { + func blindedPathsForAsyncRecipient(recipientId: Data) throws -> Data + func initiateRefund(amountMsat: UInt64, expirySecs: UInt32, quantity: UInt64?, payerNote: String?, routeParameters: RouteParametersConfig?) throws -> Refund -public func FfiConverterTypeBuilder_lift(_ pointer: UnsafeMutableRawPointer) throws -> Builder { - return try FfiConverterTypeBuilder.lift(pointer) -} + func receive(amountMsat: UInt64, description: String, expirySecs: UInt32?, quantity: UInt64?) throws -> Offer -public func FfiConverterTypeBuilder_lower(_ value: Builder) -> UnsafeMutableRawPointer { - return FfiConverterTypeBuilder.lower(value) -} + func receiveAsync() throws -> Offer + func receiveVariableAmount(description: String, expirySecs: UInt32?) throws -> Offer + func requestRefundPayment(refund: Refund) throws -> Bolt12Invoice + func send(offer: Offer, quantity: UInt64?, payerNote: String?, routeParameters: RouteParametersConfig?) throws -> PaymentId -public protocol FeeRateProtocol : AnyObject { - - func toSatPerKwu() -> UInt64 - - func toSatPerVbCeil() -> UInt64 - - func toSatPerVbFloor() -> UInt64 - + func sendUsingAmount(offer: Offer, amountMsat: UInt64, quantity: UInt64?, payerNote: String?, routeParameters: RouteParametersConfig?) throws -> PaymentId + + func setPathsToStaticInvoiceServer(paths: Data) throws } -open class FeeRate: - FeeRateProtocol { +open class Bolt12Payment: + Bolt12PaymentProtocol +{ fileprivate let pointer: UnsafeMutableRawPointer! - /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif public struct NoPointer { public init() {} } @@ -1534,22 +1398,29 @@ open class FeeRate: // TODO: We'd like this to be `private` but for Swifty reasons, // we can't implement `FfiConverter` without making this `required` and we can't // make it `required` without making it `public`. - required public init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + public required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { self.pointer = pointer } - /// This constructor can be used to instantiate a fake object. - /// - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. - /// - /// - Warning: - /// Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. - public init(noPointer: NoPointer) { - self.pointer = nil + // This constructor can be used to instantiate a fake object. + // - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. + // + // - Warning: + // Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public init(noPointer _: NoPointer) { + pointer = nil } + #if swift(>=5.8) + @_documentation(visibility: private) + #endif public func uniffiClonePointer() -> UnsafeMutableRawPointer { - return try! rustCall { uniffi_ldk_node_fn_clone_feerate(self.pointer, $0) } + return try! rustCall { uniffi_ldk_node_fn_clone_bolt12payment(self.pointer, $0) } } + // No primary constructor declared for this class. deinit { @@ -1557,224 +1428,207 @@ open class FeeRate: return } - try! rustCall { uniffi_ldk_node_fn_free_feerate(pointer, $0) } + try! rustCall { uniffi_ldk_node_fn_free_bolt12payment(pointer, $0) } } - -public static func fromSatPerKwu(satKwu: UInt64) -> FeeRate { - return try! FfiConverterTypeFeeRate.lift(try! rustCall() { - uniffi_ldk_node_fn_constructor_feerate_from_sat_per_kwu( - FfiConverterUInt64.lower(satKwu),$0 - ) -}) -} - -public static func fromSatPerVbUnchecked(satVb: UInt64) -> FeeRate { - return try! FfiConverterTypeFeeRate.lift(try! rustCall() { - uniffi_ldk_node_fn_constructor_feerate_from_sat_per_vb_unchecked( - FfiConverterUInt64.lower(satVb),$0 - ) -}) -} - + open func blindedPathsForAsyncRecipient(recipientId: Data) throws -> Data { + return try FfiConverterData.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt12payment_blinded_paths_for_async_recipient(self.uniffiClonePointer(), + FfiConverterData.lower(recipientId), $0) + }) + } - -open func toSatPerKwu() -> UInt64 { - return try! FfiConverterUInt64.lift(try! rustCall() { - uniffi_ldk_node_fn_method_feerate_to_sat_per_kwu(self.uniffiClonePointer(),$0 - ) -}) -} - -open func toSatPerVbCeil() -> UInt64 { - return try! FfiConverterUInt64.lift(try! rustCall() { - uniffi_ldk_node_fn_method_feerate_to_sat_per_vb_ceil(self.uniffiClonePointer(),$0 - ) -}) -} - -open func toSatPerVbFloor() -> UInt64 { - return try! FfiConverterUInt64.lift(try! rustCall() { - uniffi_ldk_node_fn_method_feerate_to_sat_per_vb_floor(self.uniffiClonePointer(),$0 - ) -}) -} - + open func initiateRefund(amountMsat: UInt64, expirySecs: UInt32, quantity: UInt64?, payerNote: String?, routeParameters: RouteParametersConfig?) throws -> Refund { + return try FfiConverterTypeRefund.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt12payment_initiate_refund(self.uniffiClonePointer(), + FfiConverterUInt64.lower(amountMsat), + FfiConverterUInt32.lower(expirySecs), + FfiConverterOptionUInt64.lower(quantity), + FfiConverterOptionString.lower(payerNote), + FfiConverterOptionTypeRouteParametersConfig.lower(routeParameters), $0) + }) + } -} + open func receive(amountMsat: UInt64, description: String, expirySecs: UInt32?, quantity: UInt64?) throws -> Offer { + return try FfiConverterTypeOffer.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt12payment_receive(self.uniffiClonePointer(), + FfiConverterUInt64.lower(amountMsat), + FfiConverterString.lower(description), + FfiConverterOptionUInt32.lower(expirySecs), + FfiConverterOptionUInt64.lower(quantity), $0) + }) + } -public struct FfiConverterTypeFeeRate: FfiConverter { + open func receiveAsync() throws -> Offer { + return try FfiConverterTypeOffer.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt12payment_receive_async(self.uniffiClonePointer(), $0) + }) + } + + open func receiveVariableAmount(description: String, expirySecs: UInt32?) throws -> Offer { + return try FfiConverterTypeOffer.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt12payment_receive_variable_amount(self.uniffiClonePointer(), + FfiConverterString.lower(description), + FfiConverterOptionUInt32.lower(expirySecs), $0) + }) + } + + open func requestRefundPayment(refund: Refund) throws -> Bolt12Invoice { + return try FfiConverterTypeBolt12Invoice.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt12payment_request_refund_payment(self.uniffiClonePointer(), + FfiConverterTypeRefund.lower(refund), $0) + }) + } + + open func send(offer: Offer, quantity: UInt64?, payerNote: String?, routeParameters: RouteParametersConfig?) throws -> PaymentId { + return try FfiConverterTypePaymentId.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt12payment_send(self.uniffiClonePointer(), + FfiConverterTypeOffer.lower(offer), + FfiConverterOptionUInt64.lower(quantity), + FfiConverterOptionString.lower(payerNote), + FfiConverterOptionTypeRouteParametersConfig.lower(routeParameters), $0) + }) + } + + open func sendUsingAmount(offer: Offer, amountMsat: UInt64, quantity: UInt64?, payerNote: String?, routeParameters: RouteParametersConfig?) throws -> PaymentId { + return try FfiConverterTypePaymentId.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt12payment_send_using_amount(self.uniffiClonePointer(), + FfiConverterTypeOffer.lower(offer), + FfiConverterUInt64.lower(amountMsat), + FfiConverterOptionUInt64.lower(quantity), + FfiConverterOptionString.lower(payerNote), + FfiConverterOptionTypeRouteParametersConfig.lower(routeParameters), $0) + }) + } + open func setPathsToStaticInvoiceServer(paths: Data) throws { + try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_bolt12payment_set_paths_to_static_invoice_server(self.uniffiClonePointer(), + FfiConverterData.lower(paths), $0) + } + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeBolt12Payment: FfiConverter { typealias FfiType = UnsafeMutableRawPointer - typealias SwiftType = FeeRate + typealias SwiftType = Bolt12Payment - public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> FeeRate { - return FeeRate(unsafeFromRawPointer: pointer) + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Bolt12Payment { + return Bolt12Payment(unsafeFromRawPointer: pointer) } - public static func lower(_ value: FeeRate) -> UnsafeMutableRawPointer { + public static func lower(_ value: Bolt12Payment) -> UnsafeMutableRawPointer { return value.uniffiClonePointer() } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> FeeRate { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Bolt12Payment { let v: UInt64 = try readInt(&buf) // The Rust code won't compile if a pointer won't fit in a UInt64. // We have to go via `UInt` because that's the thing that's the size of a pointer. let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { + if ptr == nil { throw UniffiInternalError.unexpectedNullPointer } return try lift(ptr!) } - public static func write(_ value: FeeRate, into buf: inout [UInt8]) { + public static func write(_ value: Bolt12Payment, into buf: inout [UInt8]) { // This fiddling is because `Int` is the thing that's the same size as a pointer. // The Rust code won't compile if a pointer won't fit in a `UInt64`. writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) } } - - - -public func FfiConverterTypeFeeRate_lift(_ pointer: UnsafeMutableRawPointer) throws -> FeeRate { - return try FfiConverterTypeFeeRate.lift(pointer) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeBolt12Payment_lift(_ pointer: UnsafeMutableRawPointer) throws -> Bolt12Payment { + return try FfiConverterTypeBolt12Payment.lift(pointer) } -public func FfiConverterTypeFeeRate_lower(_ value: FeeRate) -> UnsafeMutableRawPointer { - return FfiConverterTypeFeeRate.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeBolt12Payment_lower(_ value: Bolt12Payment) -> UnsafeMutableRawPointer { + return FfiConverterTypeBolt12Payment.lower(value) } +public protocol BuilderProtocol: AnyObject { + func build() throws -> Node + func buildWithFsStore() throws -> Node + func buildWithVssStore(vssUrl: String, storeId: String, lnurlAuthServerUrl: String, fixedHeaders: [String: String]) throws -> Node -public protocol Lsps1LiquidityProtocol : AnyObject { - - func checkOrderStatus(orderId: OrderId) throws -> Lsps1OrderStatus - - func requestChannel(lspBalanceSat: UInt64, clientBalanceSat: UInt64, channelExpiryBlocks: UInt32, announceChannel: Bool) throws -> Lsps1OrderStatus - -} + func buildWithVssStoreAndFixedHeaders(vssUrl: String, storeId: String, fixedHeaders: [String: String]) throws -> Node -open class Lsps1Liquidity: - Lsps1LiquidityProtocol { - fileprivate let pointer: UnsafeMutableRawPointer! + func buildWithVssStoreAndHeaderProvider(vssUrl: String, storeId: String, headerProvider: VssHeaderProvider) throws -> Node - /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. - public struct NoPointer { - public init() {} - } + func setAddressType(addressType: AddressType) - // TODO: We'd like this to be `private` but for Swifty reasons, - // we can't implement `FfiConverter` without making this `required` and we can't - // make it `required` without making it `public`. - required public init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { - self.pointer = pointer - } + func setAddressTypesToMonitor(addressTypesToMonitor: [AddressType]) - /// This constructor can be used to instantiate a fake object. - /// - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. - /// - /// - Warning: - /// Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. - public init(noPointer: NoPointer) { - self.pointer = nil - } + func setAnnouncementAddresses(announcementAddresses: [SocketAddress]) throws - public func uniffiClonePointer() -> UnsafeMutableRawPointer { - return try! rustCall { uniffi_ldk_node_fn_clone_lsps1liquidity(self.pointer, $0) } - } - // No primary constructor declared for this class. + func setAsyncPaymentsRole(role: AsyncPaymentsRole?) throws - deinit { - guard let pointer = pointer else { - return - } + func setChainSourceBitcoindRest(restHost: String, restPort: UInt16, rpcHost: String, rpcPort: UInt16, rpcUser: String, rpcPassword: String) - try! rustCall { uniffi_ldk_node_fn_free_lsps1liquidity(pointer, $0) } - } + func setChainSourceBitcoindRpc(rpcHost: String, rpcPort: UInt16, rpcUser: String, rpcPassword: String) - + func setChainSourceElectrum(serverUrl: String, config: ElectrumSyncConfig?) - -open func checkOrderStatus(orderId: OrderId)throws -> Lsps1OrderStatus { - return try FfiConverterTypeLSPS1OrderStatus.lift(try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_lsps1liquidity_check_order_status(self.uniffiClonePointer(), - FfiConverterTypeOrderId.lower(orderId),$0 - ) -}) -} - -open func requestChannel(lspBalanceSat: UInt64, clientBalanceSat: UInt64, channelExpiryBlocks: UInt32, announceChannel: Bool)throws -> Lsps1OrderStatus { - return try FfiConverterTypeLSPS1OrderStatus.lift(try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_lsps1liquidity_request_channel(self.uniffiClonePointer(), - FfiConverterUInt64.lower(lspBalanceSat), - FfiConverterUInt64.lower(clientBalanceSat), - FfiConverterUInt32.lower(channelExpiryBlocks), - FfiConverterBool.lower(announceChannel),$0 - ) -}) -} - + func setChainSourceEsplora(serverUrl: String, config: EsploraSyncConfig?) -} + func setChannelDataMigration(migration: ChannelDataMigration) -public struct FfiConverterTypeLSPS1Liquidity: FfiConverter { + func setCustomLogger(logWriter: LogWriter) - typealias FfiType = UnsafeMutableRawPointer - typealias SwiftType = Lsps1Liquidity + func setEntropyBip39Mnemonic(mnemonic: Mnemonic, passphrase: String?) - public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Lsps1Liquidity { - return Lsps1Liquidity(unsafeFromRawPointer: pointer) - } + func setEntropySeedBytes(seedBytes: [UInt8]) throws - public static func lower(_ value: Lsps1Liquidity) -> UnsafeMutableRawPointer { - return value.uniffiClonePointer() - } + func setEntropySeedPath(seedPath: String) - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Lsps1Liquidity { - let v: UInt64 = try readInt(&buf) - // The Rust code won't compile if a pointer won't fit in a UInt64. - // We have to go via `UInt` because that's the thing that's the size of a pointer. - let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { - throw UniffiInternalError.unexpectedNullPointer - } - return try lift(ptr!) - } + func setFilesystemLogger(logFilePath: String?, maxLogLevel: LogLevel?) - public static func write(_ value: Lsps1Liquidity, into buf: inout [UInt8]) { - // This fiddling is because `Int` is the thing that's the same size as a pointer. - // The Rust code won't compile if a pointer won't fit in a `UInt64`. - writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) - } -} + func setGossipSourceP2p() + func setGossipSourceRgs(rgsServerUrl: String) + func setLiquiditySourceLsps1(nodeId: PublicKey, address: SocketAddress, token: String?) + func setLiquiditySourceLsps2(nodeId: PublicKey, address: SocketAddress, token: String?) -public func FfiConverterTypeLSPS1Liquidity_lift(_ pointer: UnsafeMutableRawPointer) throws -> Lsps1Liquidity { - return try FfiConverterTypeLSPS1Liquidity.lift(pointer) -} + func setListeningAddresses(listeningAddresses: [SocketAddress]) throws -public func FfiConverterTypeLSPS1Liquidity_lower(_ value: Lsps1Liquidity) -> UnsafeMutableRawPointer { - return FfiConverterTypeLSPS1Liquidity.lower(value) -} + func setLogFacadeLogger() + + func setNetwork(network: Network) + func setNodeAlias(nodeAlias: String) throws + func setPathfindingScoresSource(url: String) + func setScoringDecayParams(params: ScoringDecayParameters) -public protocol LogWriter : AnyObject { - - func log(record: LogRecord) - + func setScoringFeeParams(params: ScoringFeeParameters) + + func setStorageDirPath(storageDirPath: String) } -open class LogWriterImpl: - LogWriter { +open class Builder: + BuilderProtocol +{ fileprivate let pointer: UnsafeMutableRawPointer! - /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif public struct NoPointer { public init() {} } @@ -1782,161 +1636,354 @@ open class LogWriterImpl: // TODO: We'd like this to be `private` but for Swifty reasons, // we can't implement `FfiConverter` without making this `required` and we can't // make it `required` without making it `public`. - required public init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + public required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { self.pointer = pointer } - /// This constructor can be used to instantiate a fake object. - /// - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. - /// - /// - Warning: - /// Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. - public init(noPointer: NoPointer) { - self.pointer = nil + // This constructor can be used to instantiate a fake object. + // - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. + // + // - Warning: + // Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public init(noPointer _: NoPointer) { + pointer = nil } + #if swift(>=5.8) + @_documentation(visibility: private) + #endif public func uniffiClonePointer() -> UnsafeMutableRawPointer { - return try! rustCall { uniffi_ldk_node_fn_clone_logwriter(self.pointer, $0) } + return try! rustCall { uniffi_ldk_node_fn_clone_builder(self.pointer, $0) } } - // No primary constructor declared for this class. - deinit { - guard let pointer = pointer else { + public convenience init() { + let pointer = + try! rustCall { + uniffi_ldk_node_fn_constructor_builder_new($0) + } + self.init(unsafeFromRawPointer: pointer) + } + + deinit { + guard let pointer = pointer else { return } - try! rustCall { uniffi_ldk_node_fn_free_logwriter(pointer, $0) } + try! rustCall { uniffi_ldk_node_fn_free_builder(pointer, $0) } } - + public static func fromConfig(config: Config) -> Builder { + return try! FfiConverterTypeBuilder.lift(try! rustCall { + uniffi_ldk_node_fn_constructor_builder_from_config( + FfiConverterTypeConfig.lower(config), $0 + ) + }) + } - -open func log(record: LogRecord) {try! rustCall() { - uniffi_ldk_node_fn_method_logwriter_log(self.uniffiClonePointer(), - FfiConverterTypeLogRecord.lower(record),$0 - ) -} -} - + open func build() throws -> Node { + return try FfiConverterTypeNode.lift(rustCallWithError(FfiConverterTypeBuildError.lift) { + uniffi_ldk_node_fn_method_builder_build(self.uniffiClonePointer(), $0) + }) + } -} -// Magic number for the Rust proxy to call using the same mechanism as every other method, -// to free the callback once it's dropped by Rust. -private let IDX_CALLBACK_FREE: Int32 = 0 -// Callback return codes -private let UNIFFI_CALLBACK_SUCCESS: Int32 = 0 -private let UNIFFI_CALLBACK_ERROR: Int32 = 1 -private let UNIFFI_CALLBACK_UNEXPECTED_ERROR: Int32 = 2 + open func buildWithFsStore() throws -> Node { + return try FfiConverterTypeNode.lift(rustCallWithError(FfiConverterTypeBuildError.lift) { + uniffi_ldk_node_fn_method_builder_build_with_fs_store(self.uniffiClonePointer(), $0) + }) + } -// Put the implementation in a struct so we don't pollute the top-level namespace -fileprivate struct UniffiCallbackInterfaceLogWriter { + open func buildWithVssStore(vssUrl: String, storeId: String, lnurlAuthServerUrl: String, fixedHeaders: [String: String]) throws -> Node { + return try FfiConverterTypeNode.lift(rustCallWithError(FfiConverterTypeBuildError.lift) { + uniffi_ldk_node_fn_method_builder_build_with_vss_store(self.uniffiClonePointer(), + FfiConverterString.lower(vssUrl), + FfiConverterString.lower(storeId), + FfiConverterString.lower(lnurlAuthServerUrl), + FfiConverterDictionaryStringString.lower(fixedHeaders), $0) + }) + } - // Create the VTable using a series of closures. - // Swift automatically converts these into C callback functions. - static var vtable: UniffiVTableCallbackInterfaceLogWriter = UniffiVTableCallbackInterfaceLogWriter( - log: { ( - uniffiHandle: UInt64, - record: RustBuffer, - uniffiOutReturn: UnsafeMutableRawPointer, - uniffiCallStatus: UnsafeMutablePointer - ) in - let makeCall = { - () throws -> () in - guard let uniffiObj = try? FfiConverterTypeLogWriter.handleMap.get(handle: uniffiHandle) else { - throw UniffiInternalError.unexpectedStaleHandle - } - return uniffiObj.log( - record: try FfiConverterTypeLogRecord.lift(record) - ) - } + open func buildWithVssStoreAndFixedHeaders(vssUrl: String, storeId: String, fixedHeaders: [String: String]) throws -> Node { + return try FfiConverterTypeNode.lift(rustCallWithError(FfiConverterTypeBuildError.lift) { + uniffi_ldk_node_fn_method_builder_build_with_vss_store_and_fixed_headers(self.uniffiClonePointer(), + FfiConverterString.lower(vssUrl), + FfiConverterString.lower(storeId), + FfiConverterDictionaryStringString.lower(fixedHeaders), $0) + }) + } - - let writeReturn = { () } - uniffiTraitInterfaceCall( - callStatus: uniffiCallStatus, - makeCall: makeCall, - writeReturn: writeReturn - ) - }, - uniffiFree: { (uniffiHandle: UInt64) -> () in - let result = try? FfiConverterTypeLogWriter.handleMap.remove(handle: uniffiHandle) - if result == nil { - print("Uniffi callback interface LogWriter: handle missing in uniffiFree") - } + open func buildWithVssStoreAndHeaderProvider(vssUrl: String, storeId: String, headerProvider: VssHeaderProvider) throws -> Node { + return try FfiConverterTypeNode.lift(rustCallWithError(FfiConverterTypeBuildError.lift) { + uniffi_ldk_node_fn_method_builder_build_with_vss_store_and_header_provider(self.uniffiClonePointer(), + FfiConverterString.lower(vssUrl), + FfiConverterString.lower(storeId), + FfiConverterTypeVssHeaderProvider.lower(headerProvider), $0) + }) + } + + open func setAddressType(addressType: AddressType) { + try! rustCall { + uniffi_ldk_node_fn_method_builder_set_address_type(self.uniffiClonePointer(), + FfiConverterTypeAddressType.lower(addressType), $0) } - ) -} + } -private func uniffiCallbackInitLogWriter() { - uniffi_ldk_node_fn_init_callback_vtable_logwriter(&UniffiCallbackInterfaceLogWriter.vtable) -} + open func setAddressTypesToMonitor(addressTypesToMonitor: [AddressType]) { + try! rustCall { + uniffi_ldk_node_fn_method_builder_set_address_types_to_monitor(self.uniffiClonePointer(), + FfiConverterSequenceTypeAddressType.lower(addressTypesToMonitor), $0) + } + } -public struct FfiConverterTypeLogWriter: FfiConverter { - fileprivate static var handleMap = UniffiHandleMap() + open func setAnnouncementAddresses(announcementAddresses: [SocketAddress]) throws { + try rustCallWithError(FfiConverterTypeBuildError.lift) { + uniffi_ldk_node_fn_method_builder_set_announcement_addresses(self.uniffiClonePointer(), + FfiConverterSequenceTypeSocketAddress.lower(announcementAddresses), $0) + } + } - typealias FfiType = UnsafeMutableRawPointer - typealias SwiftType = LogWriter + open func setAsyncPaymentsRole(role: AsyncPaymentsRole?) throws { + try rustCallWithError(FfiConverterTypeBuildError.lift) { + uniffi_ldk_node_fn_method_builder_set_async_payments_role(self.uniffiClonePointer(), + FfiConverterOptionTypeAsyncPaymentsRole.lower(role), $0) + } + } - public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> LogWriter { - return LogWriterImpl(unsafeFromRawPointer: pointer) + open func setChainSourceBitcoindRest(restHost: String, restPort: UInt16, rpcHost: String, rpcPort: UInt16, rpcUser: String, rpcPassword: String) { + try! rustCall { + uniffi_ldk_node_fn_method_builder_set_chain_source_bitcoind_rest(self.uniffiClonePointer(), + FfiConverterString.lower(restHost), + FfiConverterUInt16.lower(restPort), + FfiConverterString.lower(rpcHost), + FfiConverterUInt16.lower(rpcPort), + FfiConverterString.lower(rpcUser), + FfiConverterString.lower(rpcPassword), $0) + } } - public static func lower(_ value: LogWriter) -> UnsafeMutableRawPointer { - guard let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: handleMap.insert(obj: value))) else { - fatalError("Cast to UnsafeMutableRawPointer failed") + open func setChainSourceBitcoindRpc(rpcHost: String, rpcPort: UInt16, rpcUser: String, rpcPassword: String) { + try! rustCall { + uniffi_ldk_node_fn_method_builder_set_chain_source_bitcoind_rpc(self.uniffiClonePointer(), + FfiConverterString.lower(rpcHost), + FfiConverterUInt16.lower(rpcPort), + FfiConverterString.lower(rpcUser), + FfiConverterString.lower(rpcPassword), $0) } - return ptr } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> LogWriter { + open func setChainSourceElectrum(serverUrl: String, config: ElectrumSyncConfig?) { + try! rustCall { + uniffi_ldk_node_fn_method_builder_set_chain_source_electrum(self.uniffiClonePointer(), + FfiConverterString.lower(serverUrl), + FfiConverterOptionTypeElectrumSyncConfig.lower(config), $0) + } + } + + open func setChainSourceEsplora(serverUrl: String, config: EsploraSyncConfig?) { + try! rustCall { + uniffi_ldk_node_fn_method_builder_set_chain_source_esplora(self.uniffiClonePointer(), + FfiConverterString.lower(serverUrl), + FfiConverterOptionTypeEsploraSyncConfig.lower(config), $0) + } + } + + open func setChannelDataMigration(migration: ChannelDataMigration) { + try! rustCall { + uniffi_ldk_node_fn_method_builder_set_channel_data_migration(self.uniffiClonePointer(), + FfiConverterTypeChannelDataMigration.lower(migration), $0) + } + } + + open func setCustomLogger(logWriter: LogWriter) { + try! rustCall { + uniffi_ldk_node_fn_method_builder_set_custom_logger(self.uniffiClonePointer(), + FfiConverterTypeLogWriter.lower(logWriter), $0) + } + } + + open func setEntropyBip39Mnemonic(mnemonic: Mnemonic, passphrase: String?) { + try! rustCall { + uniffi_ldk_node_fn_method_builder_set_entropy_bip39_mnemonic(self.uniffiClonePointer(), + FfiConverterTypeMnemonic.lower(mnemonic), + FfiConverterOptionString.lower(passphrase), $0) + } + } + + open func setEntropySeedBytes(seedBytes: [UInt8]) throws { + try rustCallWithError(FfiConverterTypeBuildError.lift) { + uniffi_ldk_node_fn_method_builder_set_entropy_seed_bytes(self.uniffiClonePointer(), + FfiConverterSequenceUInt8.lower(seedBytes), $0) + } + } + + open func setEntropySeedPath(seedPath: String) { + try! rustCall { + uniffi_ldk_node_fn_method_builder_set_entropy_seed_path(self.uniffiClonePointer(), + FfiConverterString.lower(seedPath), $0) + } + } + + open func setFilesystemLogger(logFilePath: String?, maxLogLevel: LogLevel?) { + try! rustCall { + uniffi_ldk_node_fn_method_builder_set_filesystem_logger(self.uniffiClonePointer(), + FfiConverterOptionString.lower(logFilePath), + FfiConverterOptionTypeLogLevel.lower(maxLogLevel), $0) + } + } + + open func setGossipSourceP2p() { + try! rustCall { + uniffi_ldk_node_fn_method_builder_set_gossip_source_p2p(self.uniffiClonePointer(), $0) + } + } + + open func setGossipSourceRgs(rgsServerUrl: String) { + try! rustCall { + uniffi_ldk_node_fn_method_builder_set_gossip_source_rgs(self.uniffiClonePointer(), + FfiConverterString.lower(rgsServerUrl), $0) + } + } + + open func setLiquiditySourceLsps1(nodeId: PublicKey, address: SocketAddress, token: String?) { + try! rustCall { + uniffi_ldk_node_fn_method_builder_set_liquidity_source_lsps1(self.uniffiClonePointer(), + FfiConverterTypePublicKey.lower(nodeId), + FfiConverterTypeSocketAddress.lower(address), + FfiConverterOptionString.lower(token), $0) + } + } + + open func setLiquiditySourceLsps2(nodeId: PublicKey, address: SocketAddress, token: String?) { + try! rustCall { + uniffi_ldk_node_fn_method_builder_set_liquidity_source_lsps2(self.uniffiClonePointer(), + FfiConverterTypePublicKey.lower(nodeId), + FfiConverterTypeSocketAddress.lower(address), + FfiConverterOptionString.lower(token), $0) + } + } + + open func setListeningAddresses(listeningAddresses: [SocketAddress]) throws { + try rustCallWithError(FfiConverterTypeBuildError.lift) { + uniffi_ldk_node_fn_method_builder_set_listening_addresses(self.uniffiClonePointer(), + FfiConverterSequenceTypeSocketAddress.lower(listeningAddresses), $0) + } + } + + open func setLogFacadeLogger() { + try! rustCall { + uniffi_ldk_node_fn_method_builder_set_log_facade_logger(self.uniffiClonePointer(), $0) + } + } + + open func setNetwork(network: Network) { + try! rustCall { + uniffi_ldk_node_fn_method_builder_set_network(self.uniffiClonePointer(), + FfiConverterTypeNetwork.lower(network), $0) + } + } + + open func setNodeAlias(nodeAlias: String) throws { + try rustCallWithError(FfiConverterTypeBuildError.lift) { + uniffi_ldk_node_fn_method_builder_set_node_alias(self.uniffiClonePointer(), + FfiConverterString.lower(nodeAlias), $0) + } + } + + open func setPathfindingScoresSource(url: String) { + try! rustCall { + uniffi_ldk_node_fn_method_builder_set_pathfinding_scores_source(self.uniffiClonePointer(), + FfiConverterString.lower(url), $0) + } + } + + open func setScoringDecayParams(params: ScoringDecayParameters) { + try! rustCall { + uniffi_ldk_node_fn_method_builder_set_scoring_decay_params(self.uniffiClonePointer(), + FfiConverterTypeScoringDecayParameters.lower(params), $0) + } + } + + open func setScoringFeeParams(params: ScoringFeeParameters) { + try! rustCall { + uniffi_ldk_node_fn_method_builder_set_scoring_fee_params(self.uniffiClonePointer(), + FfiConverterTypeScoringFeeParameters.lower(params), $0) + } + } + + open func setStorageDirPath(storageDirPath: String) { + try! rustCall { + uniffi_ldk_node_fn_method_builder_set_storage_dir_path(self.uniffiClonePointer(), + FfiConverterString.lower(storageDirPath), $0) + } + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeBuilder: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = Builder + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Builder { + return Builder(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: Builder) -> UnsafeMutableRawPointer { + return value.uniffiClonePointer() + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Builder { let v: UInt64 = try readInt(&buf) // The Rust code won't compile if a pointer won't fit in a UInt64. // We have to go via `UInt` because that's the thing that's the size of a pointer. let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { + if ptr == nil { throw UniffiInternalError.unexpectedNullPointer } return try lift(ptr!) } - public static func write(_ value: LogWriter, into buf: inout [UInt8]) { + public static func write(_ value: Builder, into buf: inout [UInt8]) { // This fiddling is because `Int` is the thing that's the same size as a pointer. // The Rust code won't compile if a pointer won't fit in a `UInt64`. writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) } } - - - -public func FfiConverterTypeLogWriter_lift(_ pointer: UnsafeMutableRawPointer) throws -> LogWriter { - return try FfiConverterTypeLogWriter.lift(pointer) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeBuilder_lift(_ pointer: UnsafeMutableRawPointer) throws -> Builder { + return try FfiConverterTypeBuilder.lift(pointer) } -public func FfiConverterTypeLogWriter_lower(_ value: LogWriter) -> UnsafeMutableRawPointer { - return FfiConverterTypeLogWriter.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeBuilder_lower(_ value: Builder) -> UnsafeMutableRawPointer { + return FfiConverterTypeBuilder.lower(value) } +public protocol FeeRateProtocol: AnyObject { + func toSatPerKwu() -> UInt64 + func toSatPerVbCeil() -> UInt64 - -public protocol NetworkGraphProtocol : AnyObject { - - func channel(shortChannelId: UInt64) -> ChannelInfo? - - func listChannels() -> [UInt64] - - func listNodes() -> [NodeId] - - func node(nodeId: NodeId) -> NodeInfo? - + func toSatPerVbFloor() -> UInt64 } -open class NetworkGraph: - NetworkGraphProtocol { +open class FeeRate: + FeeRateProtocol +{ fileprivate let pointer: UnsafeMutableRawPointer! - /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif public struct NoPointer { public init() {} } @@ -1944,22 +1991,29 @@ open class NetworkGraph: // TODO: We'd like this to be `private` but for Swifty reasons, // we can't implement `FfiConverter` without making this `required` and we can't // make it `required` without making it `public`. - required public init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + public required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { self.pointer = pointer } - /// This constructor can be used to instantiate a fake object. - /// - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. - /// - /// - Warning: - /// Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. - public init(noPointer: NoPointer) { - self.pointer = nil + // This constructor can be used to instantiate a fake object. + // - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. + // + // - Warning: + // Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public init(noPointer _: NoPointer) { + pointer = nil } + #if swift(>=5.8) + @_documentation(visibility: private) + #endif public func uniffiClonePointer() -> UnsafeMutableRawPointer { - return try! rustCall { uniffi_ldk_node_fn_clone_networkgraph(self.pointer, $0) } + return try! rustCall { uniffi_ldk_node_fn_clone_feerate(self.pointer, $0) } } + // No primary constructor declared for this class. deinit { @@ -1967,171 +2021,106 @@ open class NetworkGraph: return } - try! rustCall { uniffi_ldk_node_fn_free_networkgraph(pointer, $0) } + try! rustCall { uniffi_ldk_node_fn_free_feerate(pointer, $0) } } - + public static func fromSatPerKwu(satKwu: UInt64) -> FeeRate { + return try! FfiConverterTypeFeeRate.lift(try! rustCall { + uniffi_ldk_node_fn_constructor_feerate_from_sat_per_kwu( + FfiConverterUInt64.lower(satKwu), $0 + ) + }) + } - -open func channel(shortChannelId: UInt64) -> ChannelInfo? { - return try! FfiConverterOptionTypeChannelInfo.lift(try! rustCall() { - uniffi_ldk_node_fn_method_networkgraph_channel(self.uniffiClonePointer(), - FfiConverterUInt64.lower(shortChannelId),$0 - ) -}) -} - -open func listChannels() -> [UInt64] { - return try! FfiConverterSequenceUInt64.lift(try! rustCall() { - uniffi_ldk_node_fn_method_networkgraph_list_channels(self.uniffiClonePointer(),$0 - ) -}) -} - -open func listNodes() -> [NodeId] { - return try! FfiConverterSequenceTypeNodeId.lift(try! rustCall() { - uniffi_ldk_node_fn_method_networkgraph_list_nodes(self.uniffiClonePointer(),$0 - ) -}) -} - -open func node(nodeId: NodeId) -> NodeInfo? { - return try! FfiConverterOptionTypeNodeInfo.lift(try! rustCall() { - uniffi_ldk_node_fn_method_networkgraph_node(self.uniffiClonePointer(), - FfiConverterTypeNodeId.lower(nodeId),$0 - ) -}) -} - + public static func fromSatPerVbUnchecked(satVb: UInt64) -> FeeRate { + return try! FfiConverterTypeFeeRate.lift(try! rustCall { + uniffi_ldk_node_fn_constructor_feerate_from_sat_per_vb_unchecked( + FfiConverterUInt64.lower(satVb), $0 + ) + }) + } -} + open func toSatPerKwu() -> UInt64 { + return try! FfiConverterUInt64.lift(try! rustCall { + uniffi_ldk_node_fn_method_feerate_to_sat_per_kwu(self.uniffiClonePointer(), $0) + }) + } -public struct FfiConverterTypeNetworkGraph: FfiConverter { + open func toSatPerVbCeil() -> UInt64 { + return try! FfiConverterUInt64.lift(try! rustCall { + uniffi_ldk_node_fn_method_feerate_to_sat_per_vb_ceil(self.uniffiClonePointer(), $0) + }) + } + open func toSatPerVbFloor() -> UInt64 { + return try! FfiConverterUInt64.lift(try! rustCall { + uniffi_ldk_node_fn_method_feerate_to_sat_per_vb_floor(self.uniffiClonePointer(), $0) + }) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeFeeRate: FfiConverter { typealias FfiType = UnsafeMutableRawPointer - typealias SwiftType = NetworkGraph + typealias SwiftType = FeeRate - public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> NetworkGraph { - return NetworkGraph(unsafeFromRawPointer: pointer) + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> FeeRate { + return FeeRate(unsafeFromRawPointer: pointer) } - public static func lower(_ value: NetworkGraph) -> UnsafeMutableRawPointer { + public static func lower(_ value: FeeRate) -> UnsafeMutableRawPointer { return value.uniffiClonePointer() } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> NetworkGraph { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> FeeRate { let v: UInt64 = try readInt(&buf) // The Rust code won't compile if a pointer won't fit in a UInt64. // We have to go via `UInt` because that's the thing that's the size of a pointer. let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { + if ptr == nil { throw UniffiInternalError.unexpectedNullPointer } return try lift(ptr!) } - public static func write(_ value: NetworkGraph, into buf: inout [UInt8]) { + public static func write(_ value: FeeRate, into buf: inout [UInt8]) { // This fiddling is because `Int` is the thing that's the same size as a pointer. // The Rust code won't compile if a pointer won't fit in a `UInt64`. writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) } } - - - -public func FfiConverterTypeNetworkGraph_lift(_ pointer: UnsafeMutableRawPointer) throws -> NetworkGraph { - return try FfiConverterTypeNetworkGraph.lift(pointer) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeFeeRate_lift(_ pointer: UnsafeMutableRawPointer) throws -> FeeRate { + return try FfiConverterTypeFeeRate.lift(pointer) } -public func FfiConverterTypeNetworkGraph_lower(_ value: NetworkGraph) -> UnsafeMutableRawPointer { - return FfiConverterTypeNetworkGraph.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeFeeRate_lower(_ value: FeeRate) -> UnsafeMutableRawPointer { + return FfiConverterTypeFeeRate.lower(value) } +public protocol Lsps1LiquidityProtocol: AnyObject { + func checkOrderStatus(orderId: Lsps1OrderId) throws -> Lsps1OrderStatus - - -public protocol NodeProtocol : AnyObject { - - func announcementAddresses() -> [SocketAddress]? - - func bolt11Payment() -> Bolt11Payment - - func bolt12Payment() -> Bolt12Payment - - func closeChannel(userChannelId: UserChannelId, counterpartyNodeId: PublicKey) throws - - func config() -> Config - - func connect(nodeId: PublicKey, address: SocketAddress, persist: Bool) throws - - func disconnect(nodeId: PublicKey) throws - - func eventHandled() throws - - func exportPathfindingScores() throws -> Data - - func forceCloseChannel(userChannelId: UserChannelId, counterpartyNodeId: PublicKey, reason: String?) throws - - func listBalances() -> BalanceDetails - - func listChannels() -> [ChannelDetails] - - func listPayments() -> [PaymentDetails] - - func listPeers() -> [PeerDetails] - - func listeningAddresses() -> [SocketAddress]? - - func lsps1Liquidity() -> Lsps1Liquidity - - func networkGraph() -> NetworkGraph - - func nextEvent() -> Event? - - func nextEventAsync() async -> Event - - func nodeAlias() -> NodeAlias? - - func nodeId() -> PublicKey - - func onchainPayment() -> OnchainPayment - - func openAnnouncedChannel(nodeId: PublicKey, address: SocketAddress, channelAmountSats: UInt64, pushToCounterpartyMsat: UInt64?, channelConfig: ChannelConfig?) throws -> UserChannelId - - func openChannel(nodeId: PublicKey, address: SocketAddress, channelAmountSats: UInt64, pushToCounterpartyMsat: UInt64?, channelConfig: ChannelConfig?) throws -> UserChannelId - - func payment(paymentId: PaymentId) -> PaymentDetails? - - func removePayment(paymentId: PaymentId) throws - - func signMessage(msg: [UInt8]) -> String - - func spontaneousPayment() -> SpontaneousPayment - - func start() throws - - func status() -> NodeStatus - - func stop() throws - - func syncWallets() throws - - func unifiedQrPayment() -> UnifiedQrPayment - - func updateChannelConfig(userChannelId: UserChannelId, counterpartyNodeId: PublicKey, channelConfig: ChannelConfig) throws - - func verifySignature(msg: [UInt8], sig: String, pkey: PublicKey) -> Bool - - func waitNextEvent() -> Event - + func requestChannel(lspBalanceSat: UInt64, clientBalanceSat: UInt64, channelExpiryBlocks: UInt32, announceChannel: Bool) throws -> Lsps1OrderStatus } -open class Node: - NodeProtocol { +open class Lsps1Liquidity: + Lsps1LiquidityProtocol +{ fileprivate let pointer: UnsafeMutableRawPointer! - /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif public struct NoPointer { public init() {} } @@ -2139,22 +2128,29 @@ open class Node: // TODO: We'd like this to be `private` but for Swifty reasons, // we can't implement `FfiConverter` without making this `required` and we can't // make it `required` without making it `public`. - required public init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + public required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { self.pointer = pointer } - /// This constructor can be used to instantiate a fake object. - /// - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. - /// - /// - Warning: - /// Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. - public init(noPointer: NoPointer) { - self.pointer = nil + // This constructor can be used to instantiate a fake object. + // - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. + // + // - Warning: + // Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public init(noPointer _: NoPointer) { + pointer = nil } + #if swift(>=5.8) + @_documentation(visibility: private) + #endif public func uniffiClonePointer() -> UnsafeMutableRawPointer { - return try! rustCall { uniffi_ldk_node_fn_clone_node(self.pointer, $0) } + return try! rustCall { uniffi_ldk_node_fn_clone_lsps1liquidity(self.pointer, $0) } } + // No primary constructor declared for this class. deinit { @@ -2162,356 +2158,87 @@ open class Node: return } - try! rustCall { uniffi_ldk_node_fn_free_node(pointer, $0) } + try! rustCall { uniffi_ldk_node_fn_free_lsps1liquidity(pointer, $0) } } - + open func checkOrderStatus(orderId: Lsps1OrderId) throws -> Lsps1OrderStatus { + return try FfiConverterTypeLSPS1OrderStatus.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_lsps1liquidity_check_order_status(self.uniffiClonePointer(), + FfiConverterTypeLSPS1OrderId.lower(orderId), $0) + }) + } - -open func announcementAddresses() -> [SocketAddress]? { - return try! FfiConverterOptionSequenceTypeSocketAddress.lift(try! rustCall() { - uniffi_ldk_node_fn_method_node_announcement_addresses(self.uniffiClonePointer(),$0 - ) -}) + open func requestChannel(lspBalanceSat: UInt64, clientBalanceSat: UInt64, channelExpiryBlocks: UInt32, announceChannel: Bool) throws -> Lsps1OrderStatus { + return try FfiConverterTypeLSPS1OrderStatus.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_lsps1liquidity_request_channel(self.uniffiClonePointer(), + FfiConverterUInt64.lower(lspBalanceSat), + FfiConverterUInt64.lower(clientBalanceSat), + FfiConverterUInt32.lower(channelExpiryBlocks), + FfiConverterBool.lower(announceChannel), $0) + }) + } } - -open func bolt11Payment() -> Bolt11Payment { - return try! FfiConverterTypeBolt11Payment.lift(try! rustCall() { - uniffi_ldk_node_fn_method_node_bolt11_payment(self.uniffiClonePointer(),$0 - ) -}) + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeLSPS1Liquidity: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = Lsps1Liquidity + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Lsps1Liquidity { + return Lsps1Liquidity(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: Lsps1Liquidity) -> UnsafeMutableRawPointer { + return value.uniffiClonePointer() + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Lsps1Liquidity { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if ptr == nil { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: Lsps1Liquidity, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } } - -open func bolt12Payment() -> Bolt12Payment { - return try! FfiConverterTypeBolt12Payment.lift(try! rustCall() { - uniffi_ldk_node_fn_method_node_bolt12_payment(self.uniffiClonePointer(),$0 - ) -}) -} - -open func closeChannel(userChannelId: UserChannelId, counterpartyNodeId: PublicKey)throws {try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_close_channel(self.uniffiClonePointer(), - FfiConverterTypeUserChannelId.lower(userChannelId), - FfiConverterTypePublicKey.lower(counterpartyNodeId),$0 - ) -} -} - -open func config() -> Config { - return try! FfiConverterTypeConfig.lift(try! rustCall() { - uniffi_ldk_node_fn_method_node_config(self.uniffiClonePointer(),$0 - ) -}) -} - -open func connect(nodeId: PublicKey, address: SocketAddress, persist: Bool)throws {try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_connect(self.uniffiClonePointer(), - FfiConverterTypePublicKey.lower(nodeId), - FfiConverterTypeSocketAddress.lower(address), - FfiConverterBool.lower(persist),$0 - ) -} -} - -open func disconnect(nodeId: PublicKey)throws {try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_disconnect(self.uniffiClonePointer(), - FfiConverterTypePublicKey.lower(nodeId),$0 - ) -} -} - -open func eventHandled()throws {try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_event_handled(self.uniffiClonePointer(),$0 - ) -} -} - -open func exportPathfindingScores()throws -> Data { - return try FfiConverterData.lift(try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_export_pathfinding_scores(self.uniffiClonePointer(),$0 - ) -}) -} - -open func forceCloseChannel(userChannelId: UserChannelId, counterpartyNodeId: PublicKey, reason: String?)throws {try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_force_close_channel(self.uniffiClonePointer(), - FfiConverterTypeUserChannelId.lower(userChannelId), - FfiConverterTypePublicKey.lower(counterpartyNodeId), - FfiConverterOptionString.lower(reason),$0 - ) -} -} - -open func listBalances() -> BalanceDetails { - return try! FfiConverterTypeBalanceDetails.lift(try! rustCall() { - uniffi_ldk_node_fn_method_node_list_balances(self.uniffiClonePointer(),$0 - ) -}) -} - -open func listChannels() -> [ChannelDetails] { - return try! FfiConverterSequenceTypeChannelDetails.lift(try! rustCall() { - uniffi_ldk_node_fn_method_node_list_channels(self.uniffiClonePointer(),$0 - ) -}) -} - -open func listPayments() -> [PaymentDetails] { - return try! FfiConverterSequenceTypePaymentDetails.lift(try! rustCall() { - uniffi_ldk_node_fn_method_node_list_payments(self.uniffiClonePointer(),$0 - ) -}) -} - -open func listPeers() -> [PeerDetails] { - return try! FfiConverterSequenceTypePeerDetails.lift(try! rustCall() { - uniffi_ldk_node_fn_method_node_list_peers(self.uniffiClonePointer(),$0 - ) -}) -} - -open func listeningAddresses() -> [SocketAddress]? { - return try! FfiConverterOptionSequenceTypeSocketAddress.lift(try! rustCall() { - uniffi_ldk_node_fn_method_node_listening_addresses(self.uniffiClonePointer(),$0 - ) -}) -} - -open func lsps1Liquidity() -> Lsps1Liquidity { - return try! FfiConverterTypeLSPS1Liquidity.lift(try! rustCall() { - uniffi_ldk_node_fn_method_node_lsps1_liquidity(self.uniffiClonePointer(),$0 - ) -}) -} - -open func networkGraph() -> NetworkGraph { - return try! FfiConverterTypeNetworkGraph.lift(try! rustCall() { - uniffi_ldk_node_fn_method_node_network_graph(self.uniffiClonePointer(),$0 - ) -}) -} - -open func nextEvent() -> Event? { - return try! FfiConverterOptionTypeEvent.lift(try! rustCall() { - uniffi_ldk_node_fn_method_node_next_event(self.uniffiClonePointer(),$0 - ) -}) -} - -open func nextEventAsync()async -> Event { - return - try! await uniffiRustCallAsync( - rustFutureFunc: { - uniffi_ldk_node_fn_method_node_next_event_async( - self.uniffiClonePointer() - - ) - }, - pollFunc: ffi_ldk_node_rust_future_poll_rust_buffer, - completeFunc: ffi_ldk_node_rust_future_complete_rust_buffer, - freeFunc: ffi_ldk_node_rust_future_free_rust_buffer, - liftFunc: FfiConverterTypeEvent.lift, - errorHandler: nil - - ) -} - -open func nodeAlias() -> NodeAlias? { - return try! FfiConverterOptionTypeNodeAlias.lift(try! rustCall() { - uniffi_ldk_node_fn_method_node_node_alias(self.uniffiClonePointer(),$0 - ) -}) -} - -open func nodeId() -> PublicKey { - return try! FfiConverterTypePublicKey.lift(try! rustCall() { - uniffi_ldk_node_fn_method_node_node_id(self.uniffiClonePointer(),$0 - ) -}) -} - -open func onchainPayment() -> OnchainPayment { - return try! FfiConverterTypeOnchainPayment.lift(try! rustCall() { - uniffi_ldk_node_fn_method_node_onchain_payment(self.uniffiClonePointer(),$0 - ) -}) -} - -open func openAnnouncedChannel(nodeId: PublicKey, address: SocketAddress, channelAmountSats: UInt64, pushToCounterpartyMsat: UInt64?, channelConfig: ChannelConfig?)throws -> UserChannelId { - return try FfiConverterTypeUserChannelId.lift(try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_open_announced_channel(self.uniffiClonePointer(), - FfiConverterTypePublicKey.lower(nodeId), - FfiConverterTypeSocketAddress.lower(address), - FfiConverterUInt64.lower(channelAmountSats), - FfiConverterOptionUInt64.lower(pushToCounterpartyMsat), - FfiConverterOptionTypeChannelConfig.lower(channelConfig),$0 - ) -}) -} - -open func openChannel(nodeId: PublicKey, address: SocketAddress, channelAmountSats: UInt64, pushToCounterpartyMsat: UInt64?, channelConfig: ChannelConfig?)throws -> UserChannelId { - return try FfiConverterTypeUserChannelId.lift(try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_open_channel(self.uniffiClonePointer(), - FfiConverterTypePublicKey.lower(nodeId), - FfiConverterTypeSocketAddress.lower(address), - FfiConverterUInt64.lower(channelAmountSats), - FfiConverterOptionUInt64.lower(pushToCounterpartyMsat), - FfiConverterOptionTypeChannelConfig.lower(channelConfig),$0 - ) -}) -} - -open func payment(paymentId: PaymentId) -> PaymentDetails? { - return try! FfiConverterOptionTypePaymentDetails.lift(try! rustCall() { - uniffi_ldk_node_fn_method_node_payment(self.uniffiClonePointer(), - FfiConverterTypePaymentId.lower(paymentId),$0 - ) -}) -} - -open func removePayment(paymentId: PaymentId)throws {try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_remove_payment(self.uniffiClonePointer(), - FfiConverterTypePaymentId.lower(paymentId),$0 - ) -} -} - -open func signMessage(msg: [UInt8]) -> String { - return try! FfiConverterString.lift(try! rustCall() { - uniffi_ldk_node_fn_method_node_sign_message(self.uniffiClonePointer(), - FfiConverterSequenceUInt8.lower(msg),$0 - ) -}) -} - -open func spontaneousPayment() -> SpontaneousPayment { - return try! FfiConverterTypeSpontaneousPayment.lift(try! rustCall() { - uniffi_ldk_node_fn_method_node_spontaneous_payment(self.uniffiClonePointer(),$0 - ) -}) -} - -open func start()throws {try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_start(self.uniffiClonePointer(),$0 - ) -} -} - -open func status() -> NodeStatus { - return try! FfiConverterTypeNodeStatus.lift(try! rustCall() { - uniffi_ldk_node_fn_method_node_status(self.uniffiClonePointer(),$0 - ) -}) -} - -open func stop()throws {try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_stop(self.uniffiClonePointer(),$0 - ) -} -} - -open func syncWallets()throws {try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_sync_wallets(self.uniffiClonePointer(),$0 - ) -} -} - -open func unifiedQrPayment() -> UnifiedQrPayment { - return try! FfiConverterTypeUnifiedQrPayment.lift(try! rustCall() { - uniffi_ldk_node_fn_method_node_unified_qr_payment(self.uniffiClonePointer(),$0 - ) -}) -} - -open func updateChannelConfig(userChannelId: UserChannelId, counterpartyNodeId: PublicKey, channelConfig: ChannelConfig)throws {try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_node_update_channel_config(self.uniffiClonePointer(), - FfiConverterTypeUserChannelId.lower(userChannelId), - FfiConverterTypePublicKey.lower(counterpartyNodeId), - FfiConverterTypeChannelConfig.lower(channelConfig),$0 - ) -} -} - -open func verifySignature(msg: [UInt8], sig: String, pkey: PublicKey) -> Bool { - return try! FfiConverterBool.lift(try! rustCall() { - uniffi_ldk_node_fn_method_node_verify_signature(self.uniffiClonePointer(), - FfiConverterSequenceUInt8.lower(msg), - FfiConverterString.lower(sig), - FfiConverterTypePublicKey.lower(pkey),$0 - ) -}) -} - -open func waitNextEvent() -> Event { - return try! FfiConverterTypeEvent.lift(try! rustCall() { - uniffi_ldk_node_fn_method_node_wait_next_event(self.uniffiClonePointer(),$0 - ) -}) -} - - -} - -public struct FfiConverterTypeNode: FfiConverter { - - typealias FfiType = UnsafeMutableRawPointer - typealias SwiftType = Node - - public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Node { - return Node(unsafeFromRawPointer: pointer) - } - - public static func lower(_ value: Node) -> UnsafeMutableRawPointer { - return value.uniffiClonePointer() - } - - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Node { - let v: UInt64 = try readInt(&buf) - // The Rust code won't compile if a pointer won't fit in a UInt64. - // We have to go via `UInt` because that's the thing that's the size of a pointer. - let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { - throw UniffiInternalError.unexpectedNullPointer - } - return try lift(ptr!) - } - - public static func write(_ value: Node, into buf: inout [UInt8]) { - // This fiddling is because `Int` is the thing that's the same size as a pointer. - // The Rust code won't compile if a pointer won't fit in a `UInt64`. - writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) - } -} - - - -public func FfiConverterTypeNode_lift(_ pointer: UnsafeMutableRawPointer) throws -> Node { - return try FfiConverterTypeNode.lift(pointer) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeLSPS1Liquidity_lift(_ pointer: UnsafeMutableRawPointer) throws -> Lsps1Liquidity { + return try FfiConverterTypeLSPS1Liquidity.lift(pointer) } -public func FfiConverterTypeNode_lower(_ value: Node) -> UnsafeMutableRawPointer { - return FfiConverterTypeNode.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeLSPS1Liquidity_lower(_ value: Lsps1Liquidity) -> UnsafeMutableRawPointer { + return FfiConverterTypeLSPS1Liquidity.lower(value) } - - - -public protocol OnchainPaymentProtocol : AnyObject { - - func newAddress() throws -> Address - - func sendAllToAddress(address: Address, retainReserve: Bool, feeRate: FeeRate?) throws -> Txid - - func sendToAddress(address: Address, amountSats: UInt64, feeRate: FeeRate?) throws -> Txid - +public protocol LogWriter: AnyObject { + func log(record: LogRecord) } -open class OnchainPayment: - OnchainPaymentProtocol { +open class LogWriterImpl: + LogWriter +{ fileprivate let pointer: UnsafeMutableRawPointer! - /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif public struct NoPointer { public init() {} } @@ -2519,22 +2246,29 @@ open class OnchainPayment: // TODO: We'd like this to be `private` but for Swifty reasons, // we can't implement `FfiConverter` without making this `required` and we can't // make it `required` without making it `public`. - required public init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + public required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { self.pointer = pointer } - /// This constructor can be used to instantiate a fake object. - /// - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. - /// - /// - Warning: - /// Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. - public init(noPointer: NoPointer) { - self.pointer = nil + // This constructor can be used to instantiate a fake object. + // - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. + // + // - Warning: + // Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public init(noPointer _: NoPointer) { + pointer = nil } + #if swift(>=5.8) + @_documentation(visibility: private) + #endif public func uniffiClonePointer() -> UnsafeMutableRawPointer { - return try! rustCall { uniffi_ldk_node_fn_clone_onchainpayment(self.pointer, $0) } + return try! rustCall { uniffi_ldk_node_fn_clone_logwriter(self.pointer, $0) } } + // No primary constructor declared for this class. deinit { @@ -2542,102 +2276,137 @@ open class OnchainPayment: return } - try! rustCall { uniffi_ldk_node_fn_free_onchainpayment(pointer, $0) } + try! rustCall { uniffi_ldk_node_fn_free_logwriter(pointer, $0) } } - + open func log(record: LogRecord) { + try! rustCall { + uniffi_ldk_node_fn_method_logwriter_log(self.uniffiClonePointer(), + FfiConverterTypeLogRecord.lower(record), $0) + } + } +} - -open func newAddress()throws -> Address { - return try FfiConverterTypeAddress.lift(try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_onchainpayment_new_address(self.uniffiClonePointer(),$0 - ) -}) -} - -open func sendAllToAddress(address: Address, retainReserve: Bool, feeRate: FeeRate?)throws -> Txid { - return try FfiConverterTypeTxid.lift(try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_onchainpayment_send_all_to_address(self.uniffiClonePointer(), - FfiConverterTypeAddress.lower(address), - FfiConverterBool.lower(retainReserve), - FfiConverterOptionTypeFeeRate.lower(feeRate),$0 - ) -}) -} - -open func sendToAddress(address: Address, amountSats: UInt64, feeRate: FeeRate?)throws -> Txid { - return try FfiConverterTypeTxid.lift(try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_onchainpayment_send_to_address(self.uniffiClonePointer(), - FfiConverterTypeAddress.lower(address), - FfiConverterUInt64.lower(amountSats), - FfiConverterOptionTypeFeeRate.lower(feeRate),$0 +/// Magic number for the Rust proxy to call using the same mechanism as every other method, +/// to free the callback once it's dropped by Rust. +private let IDX_CALLBACK_FREE: Int32 = 0 +// Callback return codes +private let UNIFFI_CALLBACK_SUCCESS: Int32 = 0 +private let UNIFFI_CALLBACK_ERROR: Int32 = 1 +private let UNIFFI_CALLBACK_UNEXPECTED_ERROR: Int32 = 2 + +/// Put the implementation in a struct so we don't pollute the top-level namespace +private enum UniffiCallbackInterfaceLogWriter { + /// Create the VTable using a series of closures. + /// Swift automatically converts these into C callback functions. + static var vtable: UniffiVTableCallbackInterfaceLogWriter = .init( + log: { ( + uniffiHandle: UInt64, + record: RustBuffer, + _: UnsafeMutableRawPointer, + uniffiCallStatus: UnsafeMutablePointer + ) in + let makeCall = { + () throws in + guard let uniffiObj = try? FfiConverterTypeLogWriter.handleMap.get(handle: uniffiHandle) else { + throw UniffiInternalError.unexpectedStaleHandle + } + return try uniffiObj.log( + record: FfiConverterTypeLogRecord.lift(record) + ) + } + + let writeReturn = { () } + uniffiTraitInterfaceCall( + callStatus: uniffiCallStatus, + makeCall: makeCall, + writeReturn: writeReturn + ) + }, + uniffiFree: { (uniffiHandle: UInt64) in + let result = try? FfiConverterTypeLogWriter.handleMap.remove(handle: uniffiHandle) + if result == nil { + print("Uniffi callback interface LogWriter: handle missing in uniffiFree") + } + } ) -}) } - +private func uniffiCallbackInitLogWriter() { + uniffi_ldk_node_fn_init_callback_vtable_logwriter(&UniffiCallbackInterfaceLogWriter.vtable) } -public struct FfiConverterTypeOnchainPayment: FfiConverter { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeLogWriter: FfiConverter { + fileprivate static var handleMap = UniffiHandleMap() typealias FfiType = UnsafeMutableRawPointer - typealias SwiftType = OnchainPayment + typealias SwiftType = LogWriter - public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> OnchainPayment { - return OnchainPayment(unsafeFromRawPointer: pointer) + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> LogWriter { + return LogWriterImpl(unsafeFromRawPointer: pointer) } - public static func lower(_ value: OnchainPayment) -> UnsafeMutableRawPointer { - return value.uniffiClonePointer() + public static func lower(_ value: LogWriter) -> UnsafeMutableRawPointer { + guard let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: handleMap.insert(obj: value))) else { + fatalError("Cast to UnsafeMutableRawPointer failed") + } + return ptr } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> OnchainPayment { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> LogWriter { let v: UInt64 = try readInt(&buf) // The Rust code won't compile if a pointer won't fit in a UInt64. // We have to go via `UInt` because that's the thing that's the size of a pointer. let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { + if ptr == nil { throw UniffiInternalError.unexpectedNullPointer } return try lift(ptr!) } - public static func write(_ value: OnchainPayment, into buf: inout [UInt8]) { + public static func write(_ value: LogWriter, into buf: inout [UInt8]) { // This fiddling is because `Int` is the thing that's the same size as a pointer. // The Rust code won't compile if a pointer won't fit in a `UInt64`. writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) } } - - - -public func FfiConverterTypeOnchainPayment_lift(_ pointer: UnsafeMutableRawPointer) throws -> OnchainPayment { - return try FfiConverterTypeOnchainPayment.lift(pointer) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeLogWriter_lift(_ pointer: UnsafeMutableRawPointer) throws -> LogWriter { + return try FfiConverterTypeLogWriter.lift(pointer) } -public func FfiConverterTypeOnchainPayment_lower(_ value: OnchainPayment) -> UnsafeMutableRawPointer { - return FfiConverterTypeOnchainPayment.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeLogWriter_lower(_ value: LogWriter) -> UnsafeMutableRawPointer { + return FfiConverterTypeLogWriter.lower(value) } +public protocol NetworkGraphProtocol: AnyObject { + func channel(shortChannelId: UInt64) -> ChannelInfo? + func listChannels() -> [UInt64] + func listNodes() -> [NodeId] -public protocol SpontaneousPaymentProtocol : AnyObject { - - func send(amountMsat: UInt64, nodeId: PublicKey, sendingParameters: SendingParameters?) throws -> PaymentId - - func sendProbes(amountMsat: UInt64, nodeId: PublicKey) throws - - func sendWithCustomTlvs(amountMsat: UInt64, nodeId: PublicKey, sendingParameters: SendingParameters?, customTlvs: [CustomTlvRecord]) throws -> PaymentId - + func node(nodeId: NodeId) -> NodeInfo? } -open class SpontaneousPayment: - SpontaneousPaymentProtocol { +open class NetworkGraph: + NetworkGraphProtocol +{ fileprivate let pointer: UnsafeMutableRawPointer! - /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif public struct NoPointer { public init() {} } @@ -2645,22 +2414,29 @@ open class SpontaneousPayment: // TODO: We'd like this to be `private` but for Swifty reasons, // we can't implement `FfiConverter` without making this `required` and we can't // make it `required` without making it `public`. - required public init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + public required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { self.pointer = pointer } - /// This constructor can be used to instantiate a fake object. - /// - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. - /// - /// - Warning: - /// Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. - public init(noPointer: NoPointer) { - self.pointer = nil + // This constructor can be used to instantiate a fake object. + // - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. + // + // - Warning: + // Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public init(noPointer _: NoPointer) { + pointer = nil } + #if swift(>=5.8) + @_documentation(visibility: private) + #endif public func uniffiClonePointer() -> UnsafeMutableRawPointer { - return try! rustCall { uniffi_ldk_node_fn_clone_spontaneouspayment(self.pointer, $0) } + return try! rustCall { uniffi_ldk_node_fn_clone_networkgraph(self.pointer, $0) } } + // No primary constructor declared for this class. deinit { @@ -2668,215 +2444,202 @@ open class SpontaneousPayment: return } - try! rustCall { uniffi_ldk_node_fn_free_spontaneouspayment(pointer, $0) } + try! rustCall { uniffi_ldk_node_fn_free_networkgraph(pointer, $0) } } - + open func channel(shortChannelId: UInt64) -> ChannelInfo? { + return try! FfiConverterOptionTypeChannelInfo.lift(try! rustCall { + uniffi_ldk_node_fn_method_networkgraph_channel(self.uniffiClonePointer(), + FfiConverterUInt64.lower(shortChannelId), $0) + }) + } - -open func send(amountMsat: UInt64, nodeId: PublicKey, sendingParameters: SendingParameters?)throws -> PaymentId { - return try FfiConverterTypePaymentId.lift(try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_spontaneouspayment_send(self.uniffiClonePointer(), - FfiConverterUInt64.lower(amountMsat), - FfiConverterTypePublicKey.lower(nodeId), - FfiConverterOptionTypeSendingParameters.lower(sendingParameters),$0 - ) -}) -} - -open func sendProbes(amountMsat: UInt64, nodeId: PublicKey)throws {try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_spontaneouspayment_send_probes(self.uniffiClonePointer(), - FfiConverterUInt64.lower(amountMsat), - FfiConverterTypePublicKey.lower(nodeId),$0 - ) -} -} - -open func sendWithCustomTlvs(amountMsat: UInt64, nodeId: PublicKey, sendingParameters: SendingParameters?, customTlvs: [CustomTlvRecord])throws -> PaymentId { - return try FfiConverterTypePaymentId.lift(try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_spontaneouspayment_send_with_custom_tlvs(self.uniffiClonePointer(), - FfiConverterUInt64.lower(amountMsat), - FfiConverterTypePublicKey.lower(nodeId), - FfiConverterOptionTypeSendingParameters.lower(sendingParameters), - FfiConverterSequenceTypeCustomTlvRecord.lower(customTlvs),$0 - ) -}) -} - + open func listChannels() -> [UInt64] { + return try! FfiConverterSequenceUInt64.lift(try! rustCall { + uniffi_ldk_node_fn_method_networkgraph_list_channels(self.uniffiClonePointer(), $0) + }) + } -} + open func listNodes() -> [NodeId] { + return try! FfiConverterSequenceTypeNodeId.lift(try! rustCall { + uniffi_ldk_node_fn_method_networkgraph_list_nodes(self.uniffiClonePointer(), $0) + }) + } -public struct FfiConverterTypeSpontaneousPayment: FfiConverter { + open func node(nodeId: NodeId) -> NodeInfo? { + return try! FfiConverterOptionTypeNodeInfo.lift(try! rustCall { + uniffi_ldk_node_fn_method_networkgraph_node(self.uniffiClonePointer(), + FfiConverterTypeNodeId.lower(nodeId), $0) + }) + } +} +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeNetworkGraph: FfiConverter { typealias FfiType = UnsafeMutableRawPointer - typealias SwiftType = SpontaneousPayment + typealias SwiftType = NetworkGraph - public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> SpontaneousPayment { - return SpontaneousPayment(unsafeFromRawPointer: pointer) + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> NetworkGraph { + return NetworkGraph(unsafeFromRawPointer: pointer) } - public static func lower(_ value: SpontaneousPayment) -> UnsafeMutableRawPointer { + public static func lower(_ value: NetworkGraph) -> UnsafeMutableRawPointer { return value.uniffiClonePointer() } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SpontaneousPayment { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> NetworkGraph { let v: UInt64 = try readInt(&buf) // The Rust code won't compile if a pointer won't fit in a UInt64. // We have to go via `UInt` because that's the thing that's the size of a pointer. let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { + if ptr == nil { throw UniffiInternalError.unexpectedNullPointer } return try lift(ptr!) } - public static func write(_ value: SpontaneousPayment, into buf: inout [UInt8]) { + public static func write(_ value: NetworkGraph, into buf: inout [UInt8]) { // This fiddling is because `Int` is the thing that's the same size as a pointer. // The Rust code won't compile if a pointer won't fit in a `UInt64`. writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) } } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeNetworkGraph_lift(_ pointer: UnsafeMutableRawPointer) throws -> NetworkGraph { + return try FfiConverterTypeNetworkGraph.lift(pointer) +} +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeNetworkGraph_lower(_ value: NetworkGraph) -> UnsafeMutableRawPointer { + return FfiConverterTypeNetworkGraph.lower(value) +} +public protocol NodeProtocol: AnyObject { + func addAddressTypeToMonitor(addressType: AddressType, seedBytes: [UInt8]) throws -public func FfiConverterTypeSpontaneousPayment_lift(_ pointer: UnsafeMutableRawPointer) throws -> SpontaneousPayment { - return try FfiConverterTypeSpontaneousPayment.lift(pointer) -} + func addAddressTypeToMonitorWithMnemonic(addressType: AddressType, mnemonic: Mnemonic, passphrase: String?) throws -public func FfiConverterTypeSpontaneousPayment_lower(_ value: SpontaneousPayment) -> UnsafeMutableRawPointer { - return FfiConverterTypeSpontaneousPayment.lower(value) -} + func addOnchainWalletAccount(addressType: AddressType, accountIndex: UInt32, xpub: String) throws + func announcementAddresses() -> [SocketAddress]? + func bolt11Payment() -> Bolt11Payment + func bolt12Payment() -> Bolt12Payment -public protocol UnifiedQrPaymentProtocol : AnyObject { - - func receive(amountSats: UInt64, message: String, expirySec: UInt32) throws -> String - - func send(uriStr: String) throws -> QrPaymentResult - -} + func closeChannel(userChannelId: UserChannelId, counterpartyNodeId: PublicKey) throws -open class UnifiedQrPayment: - UnifiedQrPaymentProtocol { - fileprivate let pointer: UnsafeMutableRawPointer! + func config() -> Config - /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. - public struct NoPointer { - public init() {} - } + func connect(nodeId: PublicKey, address: SocketAddress, persist: Bool) throws - // TODO: We'd like this to be `private` but for Swifty reasons, - // we can't implement `FfiConverter` without making this `required` and we can't - // make it `required` without making it `public`. - required public init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { - self.pointer = pointer - } + func currentSyncIntervals() -> RuntimeSyncIntervals - /// This constructor can be used to instantiate a fake object. - /// - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. - /// - /// - Warning: - /// Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. - public init(noPointer: NoPointer) { - self.pointer = nil - } + func disconnect(nodeId: PublicKey) throws - public func uniffiClonePointer() -> UnsafeMutableRawPointer { - return try! rustCall { uniffi_ldk_node_fn_clone_unifiedqrpayment(self.pointer, $0) } - } - // No primary constructor declared for this class. + func eventHandled() throws - deinit { - guard let pointer = pointer else { - return - } + func exportOnchainWalletAccountXpub(addressType: AddressType, accountIndex: UInt32) throws -> String - try! rustCall { uniffi_ldk_node_fn_free_unifiedqrpayment(pointer, $0) } - } + func exportPathfindingScores() throws -> Data - + func forceCloseChannel(userChannelId: UserChannelId, counterpartyNodeId: PublicKey, reason: String?) throws - -open func receive(amountSats: UInt64, message: String, expirySec: UInt32)throws -> String { - return try FfiConverterString.lift(try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_unifiedqrpayment_receive(self.uniffiClonePointer(), - FfiConverterUInt64.lower(amountSats), - FfiConverterString.lower(message), - FfiConverterUInt32.lower(expirySec),$0 - ) -}) -} - -open func send(uriStr: String)throws -> QrPaymentResult { - return try FfiConverterTypeQrPaymentResult.lift(try rustCallWithError(FfiConverterTypeNodeError.lift) { - uniffi_ldk_node_fn_method_unifiedqrpayment_send(self.uniffiClonePointer(), - FfiConverterString.lower(uriStr),$0 - ) -}) -} - + func getAddressBalance(addressStr: String) throws -> UInt64 -} + func getBalanceForAddressType(addressType: AddressType) throws -> AddressTypeBalance -public struct FfiConverterTypeUnifiedQrPayment: FfiConverter { + func getBalanceForOnchainWalletAccount(addressType: AddressType, accountIndex: UInt32) throws -> AddressTypeBalance - typealias FfiType = UnsafeMutableRawPointer - typealias SwiftType = UnifiedQrPayment + func getTransactionDetails(txid: Txid) -> TransactionDetails? - public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> UnifiedQrPayment { - return UnifiedQrPayment(unsafeFromRawPointer: pointer) - } + func listBalances() -> BalanceDetails - public static func lower(_ value: UnifiedQrPayment) -> UnsafeMutableRawPointer { - return value.uniffiClonePointer() - } + func listChannels() -> [ChannelDetails] - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UnifiedQrPayment { - let v: UInt64 = try readInt(&buf) - // The Rust code won't compile if a pointer won't fit in a UInt64. - // We have to go via `UInt` because that's the thing that's the size of a pointer. - let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { - throw UniffiInternalError.unexpectedNullPointer - } - return try lift(ptr!) - } + func listMonitoredAddressTypes() -> [AddressType] - public static func write(_ value: UnifiedQrPayment, into buf: inout [UInt8]) { - // This fiddling is because `Int` is the thing that's the same size as a pointer. - // The Rust code won't compile if a pointer won't fit in a `UInt64`. - writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) - } -} + func listOnchainWalletAccounts() -> [OnchainWalletAccount] + func listPayments() -> [PaymentDetails] + func listPeers() -> [PeerDetails] + func listeningAddresses() -> [SocketAddress]? -public func FfiConverterTypeUnifiedQrPayment_lift(_ pointer: UnsafeMutableRawPointer) throws -> UnifiedQrPayment { - return try FfiConverterTypeUnifiedQrPayment.lift(pointer) -} + func lsps1Liquidity() -> Lsps1Liquidity -public func FfiConverterTypeUnifiedQrPayment_lower(_ value: UnifiedQrPayment) -> UnsafeMutableRawPointer { - return FfiConverterTypeUnifiedQrPayment.lower(value) -} + func networkGraph() -> NetworkGraph + + func nextEvent() -> Event? + + func nextEventAsync() async -> Event + + func nodeAlias() -> NodeAlias? + + func nodeId() -> PublicKey + + func onchainPayment() -> OnchainPayment + + func openAnnouncedChannel(nodeId: PublicKey, address: SocketAddress, channelAmountSats: UInt64, pushToCounterpartyMsat: UInt64?, channelConfig: ChannelConfig?) throws -> UserChannelId + + func openChannel(nodeId: PublicKey, address: SocketAddress, channelAmountSats: UInt64, pushToCounterpartyMsat: UInt64?, channelConfig: ChannelConfig?) throws -> UserChannelId + + func payment(paymentId: PaymentId) -> PaymentDetails? + + func removeAddressTypeFromMonitor(addressType: AddressType) throws + + func removeOnchainWalletAccount(addressType: AddressType, accountIndex: UInt32) throws + + func removePayment(paymentId: PaymentId) throws + + func setPrimaryAddressType(addressType: AddressType, seedBytes: [UInt8]) throws + + func setPrimaryAddressTypeWithMnemonic(addressType: AddressType, mnemonic: Mnemonic, passphrase: String?) throws + + func signMessage(msg: [UInt8]) -> String + + func spliceIn(userChannelId: UserChannelId, counterpartyNodeId: PublicKey, spliceAmountSats: UInt64) throws + func spliceOut(userChannelId: UserChannelId, counterpartyNodeId: PublicKey, address: Address, spliceAmountSats: UInt64) throws + func spontaneousPayment() -> SpontaneousPayment + func start() throws -public protocol VssHeaderProviderProtocol : AnyObject { - - func getHeaders(request: [UInt8]) async throws -> [String: String] - + func status() -> NodeStatus + + func stop() throws + + func syncWallets() throws + + func unifiedQrPayment() -> UnifiedQrPayment + + func updateChannelConfig(userChannelId: UserChannelId, counterpartyNodeId: PublicKey, channelConfig: ChannelConfig) throws + + func updateSyncIntervals(intervals: RuntimeSyncIntervals) throws + + func verifySignature(msg: [UInt8], sig: String, pkey: PublicKey) -> Bool + + func waitNextEvent() -> Event } -open class VssHeaderProvider: - VssHeaderProviderProtocol { +open class Node: + NodeProtocol +{ fileprivate let pointer: UnsafeMutableRawPointer! - /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif public struct NoPointer { public init() {} } @@ -2884,22 +2647,29 @@ open class VssHeaderProvider: // TODO: We'd like this to be `private` but for Swifty reasons, // we can't implement `FfiConverter` without making this `required` and we can't // make it `required` without making it `public`. - required public init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + public required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { self.pointer = pointer } - /// This constructor can be used to instantiate a fake object. - /// - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. - /// - /// - Warning: - /// Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. - public init(noPointer: NoPointer) { - self.pointer = nil + // This constructor can be used to instantiate a fake object. + // - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. + // + // - Warning: + // Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public init(noPointer _: NoPointer) { + pointer = nil } + #if swift(>=5.8) + @_documentation(visibility: private) + #endif public func uniffiClonePointer() -> UnsafeMutableRawPointer { - return try! rustCall { uniffi_ldk_node_fn_clone_vssheaderprovider(self.pointer, $0) } + return try! rustCall { uniffi_ldk_node_fn_clone_node(self.pointer, $0) } } + // No primary constructor declared for this class. deinit { @@ -2907,482 +2677,2179 @@ open class VssHeaderProvider: return } - try! rustCall { uniffi_ldk_node_fn_free_vssheaderprovider(pointer, $0) } + try! rustCall { uniffi_ldk_node_fn_free_node(pointer, $0) } } - + open func addAddressTypeToMonitor(addressType: AddressType, seedBytes: [UInt8]) throws { + try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_add_address_type_to_monitor(self.uniffiClonePointer(), + FfiConverterTypeAddressType.lower(addressType), + FfiConverterSequenceUInt8.lower(seedBytes), $0) + } + } - -open func getHeaders(request: [UInt8])async throws -> [String: String] { - return - try await uniffiRustCallAsync( - rustFutureFunc: { - uniffi_ldk_node_fn_method_vssheaderprovider_get_headers( - self.uniffiClonePointer(), - FfiConverterSequenceUInt8.lower(request) - ) - }, - pollFunc: ffi_ldk_node_rust_future_poll_rust_buffer, - completeFunc: ffi_ldk_node_rust_future_complete_rust_buffer, - freeFunc: ffi_ldk_node_rust_future_free_rust_buffer, - liftFunc: FfiConverterDictionaryStringString.lift, - errorHandler: FfiConverterTypeVssHeaderProviderError.lift - ) -} - + open func addAddressTypeToMonitorWithMnemonic(addressType: AddressType, mnemonic: Mnemonic, passphrase: String?) throws { + try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_add_address_type_to_monitor_with_mnemonic(self.uniffiClonePointer(), + FfiConverterTypeAddressType.lower(addressType), + FfiConverterTypeMnemonic.lower(mnemonic), + FfiConverterOptionString.lower(passphrase), $0) + } + } -} + open func addOnchainWalletAccount(addressType: AddressType, accountIndex: UInt32, xpub: String) throws { + try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_add_onchain_wallet_account(self.uniffiClonePointer(), + FfiConverterTypeAddressType.lower(addressType), + FfiConverterUInt32.lower(accountIndex), + FfiConverterString.lower(xpub), $0) + } + } -public struct FfiConverterTypeVssHeaderProvider: FfiConverter { + open func announcementAddresses() -> [SocketAddress]? { + return try! FfiConverterOptionSequenceTypeSocketAddress.lift(try! rustCall { + uniffi_ldk_node_fn_method_node_announcement_addresses(self.uniffiClonePointer(), $0) + }) + } - typealias FfiType = UnsafeMutableRawPointer - typealias SwiftType = VssHeaderProvider + open func bolt11Payment() -> Bolt11Payment { + return try! FfiConverterTypeBolt11Payment.lift(try! rustCall { + uniffi_ldk_node_fn_method_node_bolt11_payment(self.uniffiClonePointer(), $0) + }) + } - public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> VssHeaderProvider { - return VssHeaderProvider(unsafeFromRawPointer: pointer) + open func bolt12Payment() -> Bolt12Payment { + return try! FfiConverterTypeBolt12Payment.lift(try! rustCall { + uniffi_ldk_node_fn_method_node_bolt12_payment(self.uniffiClonePointer(), $0) + }) } - public static func lower(_ value: VssHeaderProvider) -> UnsafeMutableRawPointer { - return value.uniffiClonePointer() + open func closeChannel(userChannelId: UserChannelId, counterpartyNodeId: PublicKey) throws { + try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_close_channel(self.uniffiClonePointer(), + FfiConverterTypeUserChannelId.lower(userChannelId), + FfiConverterTypePublicKey.lower(counterpartyNodeId), $0) + } } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> VssHeaderProvider { - let v: UInt64 = try readInt(&buf) - // The Rust code won't compile if a pointer won't fit in a UInt64. - // We have to go via `UInt` because that's the thing that's the size of a pointer. - let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { - throw UniffiInternalError.unexpectedNullPointer + open func config() -> Config { + return try! FfiConverterTypeConfig.lift(try! rustCall { + uniffi_ldk_node_fn_method_node_config(self.uniffiClonePointer(), $0) + }) + } + + open func connect(nodeId: PublicKey, address: SocketAddress, persist: Bool) throws { + try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_connect(self.uniffiClonePointer(), + FfiConverterTypePublicKey.lower(nodeId), + FfiConverterTypeSocketAddress.lower(address), + FfiConverterBool.lower(persist), $0) } - return try lift(ptr!) } - public static func write(_ value: VssHeaderProvider, into buf: inout [UInt8]) { - // This fiddling is because `Int` is the thing that's the same size as a pointer. - // The Rust code won't compile if a pointer won't fit in a `UInt64`. - writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + open func currentSyncIntervals() -> RuntimeSyncIntervals { + return try! FfiConverterTypeRuntimeSyncIntervals.lift(try! rustCall { + uniffi_ldk_node_fn_method_node_current_sync_intervals(self.uniffiClonePointer(), $0) + }) } -} + open func disconnect(nodeId: PublicKey) throws { + try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_disconnect(self.uniffiClonePointer(), + FfiConverterTypePublicKey.lower(nodeId), $0) + } + } + open func eventHandled() throws { + try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_event_handled(self.uniffiClonePointer(), $0) + } + } + open func exportOnchainWalletAccountXpub(addressType: AddressType, accountIndex: UInt32) throws -> String { + return try FfiConverterString.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_export_onchain_wallet_account_xpub(self.uniffiClonePointer(), + FfiConverterTypeAddressType.lower(addressType), + FfiConverterUInt32.lower(accountIndex), $0) + }) + } -public func FfiConverterTypeVssHeaderProvider_lift(_ pointer: UnsafeMutableRawPointer) throws -> VssHeaderProvider { - return try FfiConverterTypeVssHeaderProvider.lift(pointer) -} + open func exportPathfindingScores() throws -> Data { + return try FfiConverterData.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_export_pathfinding_scores(self.uniffiClonePointer(), $0) + }) + } -public func FfiConverterTypeVssHeaderProvider_lower(_ value: VssHeaderProvider) -> UnsafeMutableRawPointer { - return FfiConverterTypeVssHeaderProvider.lower(value) -} + open func forceCloseChannel(userChannelId: UserChannelId, counterpartyNodeId: PublicKey, reason: String?) throws { + try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_force_close_channel(self.uniffiClonePointer(), + FfiConverterTypeUserChannelId.lower(userChannelId), + FfiConverterTypePublicKey.lower(counterpartyNodeId), + FfiConverterOptionString.lower(reason), $0) + } + } + open func getAddressBalance(addressStr: String) throws -> UInt64 { + return try FfiConverterUInt64.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_get_address_balance(self.uniffiClonePointer(), + FfiConverterString.lower(addressStr), $0) + }) + } -public struct AnchorChannelsConfig { - public var trustedPeersNoReserve: [PublicKey] - public var perChannelReserveSats: UInt64 + open func getBalanceForAddressType(addressType: AddressType) throws -> AddressTypeBalance { + return try FfiConverterTypeAddressTypeBalance.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_get_balance_for_address_type(self.uniffiClonePointer(), + FfiConverterTypeAddressType.lower(addressType), $0) + }) + } - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(trustedPeersNoReserve: [PublicKey], perChannelReserveSats: UInt64) { - self.trustedPeersNoReserve = trustedPeersNoReserve - self.perChannelReserveSats = perChannelReserveSats + open func getBalanceForOnchainWalletAccount(addressType: AddressType, accountIndex: UInt32) throws -> AddressTypeBalance { + return try FfiConverterTypeAddressTypeBalance.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_get_balance_for_onchain_wallet_account(self.uniffiClonePointer(), + FfiConverterTypeAddressType.lower(addressType), + FfiConverterUInt32.lower(accountIndex), $0) + }) } -} + open func getTransactionDetails(txid: Txid) -> TransactionDetails? { + return try! FfiConverterOptionTypeTransactionDetails.lift(try! rustCall { + uniffi_ldk_node_fn_method_node_get_transaction_details(self.uniffiClonePointer(), + FfiConverterTypeTxid.lower(txid), $0) + }) + } + open func listBalances() -> BalanceDetails { + return try! FfiConverterTypeBalanceDetails.lift(try! rustCall { + uniffi_ldk_node_fn_method_node_list_balances(self.uniffiClonePointer(), $0) + }) + } -extension AnchorChannelsConfig: Equatable, Hashable { - public static func ==(lhs: AnchorChannelsConfig, rhs: AnchorChannelsConfig) -> Bool { - if lhs.trustedPeersNoReserve != rhs.trustedPeersNoReserve { - return false - } - if lhs.perChannelReserveSats != rhs.perChannelReserveSats { - return false - } - return true + open func listChannels() -> [ChannelDetails] { + return try! FfiConverterSequenceTypeChannelDetails.lift(try! rustCall { + uniffi_ldk_node_fn_method_node_list_channels(self.uniffiClonePointer(), $0) + }) } - public func hash(into hasher: inout Hasher) { - hasher.combine(trustedPeersNoReserve) - hasher.combine(perChannelReserveSats) + open func listMonitoredAddressTypes() -> [AddressType] { + return try! FfiConverterSequenceTypeAddressType.lift(try! rustCall { + uniffi_ldk_node_fn_method_node_list_monitored_address_types(self.uniffiClonePointer(), $0) + }) } -} + open func listOnchainWalletAccounts() -> [OnchainWalletAccount] { + return try! FfiConverterSequenceTypeOnchainWalletAccount.lift(try! rustCall { + uniffi_ldk_node_fn_method_node_list_onchain_wallet_accounts(self.uniffiClonePointer(), $0) + }) + } -public struct FfiConverterTypeAnchorChannelsConfig: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AnchorChannelsConfig { - return - try AnchorChannelsConfig( - trustedPeersNoReserve: FfiConverterSequenceTypePublicKey.read(from: &buf), - perChannelReserveSats: FfiConverterUInt64.read(from: &buf) - ) + open func listPayments() -> [PaymentDetails] { + return try! FfiConverterSequenceTypePaymentDetails.lift(try! rustCall { + uniffi_ldk_node_fn_method_node_list_payments(self.uniffiClonePointer(), $0) + }) } - public static func write(_ value: AnchorChannelsConfig, into buf: inout [UInt8]) { - FfiConverterSequenceTypePublicKey.write(value.trustedPeersNoReserve, into: &buf) - FfiConverterUInt64.write(value.perChannelReserveSats, into: &buf) + open func listPeers() -> [PeerDetails] { + return try! FfiConverterSequenceTypePeerDetails.lift(try! rustCall { + uniffi_ldk_node_fn_method_node_list_peers(self.uniffiClonePointer(), $0) + }) } -} + open func listeningAddresses() -> [SocketAddress]? { + return try! FfiConverterOptionSequenceTypeSocketAddress.lift(try! rustCall { + uniffi_ldk_node_fn_method_node_listening_addresses(self.uniffiClonePointer(), $0) + }) + } -public func FfiConverterTypeAnchorChannelsConfig_lift(_ buf: RustBuffer) throws -> AnchorChannelsConfig { - return try FfiConverterTypeAnchorChannelsConfig.lift(buf) -} + open func lsps1Liquidity() -> Lsps1Liquidity { + return try! FfiConverterTypeLSPS1Liquidity.lift(try! rustCall { + uniffi_ldk_node_fn_method_node_lsps1_liquidity(self.uniffiClonePointer(), $0) + }) + } -public func FfiConverterTypeAnchorChannelsConfig_lower(_ value: AnchorChannelsConfig) -> RustBuffer { - return FfiConverterTypeAnchorChannelsConfig.lower(value) -} + open func networkGraph() -> NetworkGraph { + return try! FfiConverterTypeNetworkGraph.lift(try! rustCall { + uniffi_ldk_node_fn_method_node_network_graph(self.uniffiClonePointer(), $0) + }) + } + open func nextEvent() -> Event? { + return try! FfiConverterOptionTypeEvent.lift(try! rustCall { + uniffi_ldk_node_fn_method_node_next_event(self.uniffiClonePointer(), $0) + }) + } -public struct BackgroundSyncConfig { - public var onchainWalletSyncIntervalSecs: UInt64 - public var lightningWalletSyncIntervalSecs: UInt64 - public var feeRateCacheUpdateIntervalSecs: UInt64 + open func nextEventAsync() async -> Event { + return + try! await uniffiRustCallAsync( + rustFutureFunc: { + uniffi_ldk_node_fn_method_node_next_event_async( + self.uniffiClonePointer() + ) + }, + pollFunc: ffi_ldk_node_rust_future_poll_rust_buffer, + completeFunc: ffi_ldk_node_rust_future_complete_rust_buffer, + freeFunc: ffi_ldk_node_rust_future_free_rust_buffer, + liftFunc: FfiConverterTypeEvent.lift, + errorHandler: nil + ) + } - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(onchainWalletSyncIntervalSecs: UInt64, lightningWalletSyncIntervalSecs: UInt64, feeRateCacheUpdateIntervalSecs: UInt64) { - self.onchainWalletSyncIntervalSecs = onchainWalletSyncIntervalSecs - self.lightningWalletSyncIntervalSecs = lightningWalletSyncIntervalSecs - self.feeRateCacheUpdateIntervalSecs = feeRateCacheUpdateIntervalSecs + open func nodeAlias() -> NodeAlias? { + return try! FfiConverterOptionTypeNodeAlias.lift(try! rustCall { + uniffi_ldk_node_fn_method_node_node_alias(self.uniffiClonePointer(), $0) + }) + } + + open func nodeId() -> PublicKey { + return try! FfiConverterTypePublicKey.lift(try! rustCall { + uniffi_ldk_node_fn_method_node_node_id(self.uniffiClonePointer(), $0) + }) } -} + open func onchainPayment() -> OnchainPayment { + return try! FfiConverterTypeOnchainPayment.lift(try! rustCall { + uniffi_ldk_node_fn_method_node_onchain_payment(self.uniffiClonePointer(), $0) + }) + } + open func openAnnouncedChannel(nodeId: PublicKey, address: SocketAddress, channelAmountSats: UInt64, pushToCounterpartyMsat: UInt64?, channelConfig: ChannelConfig?) throws -> UserChannelId { + return try FfiConverterTypeUserChannelId.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_open_announced_channel(self.uniffiClonePointer(), + FfiConverterTypePublicKey.lower(nodeId), + FfiConverterTypeSocketAddress.lower(address), + FfiConverterUInt64.lower(channelAmountSats), + FfiConverterOptionUInt64.lower(pushToCounterpartyMsat), + FfiConverterOptionTypeChannelConfig.lower(channelConfig), $0) + }) + } -extension BackgroundSyncConfig: Equatable, Hashable { - public static func ==(lhs: BackgroundSyncConfig, rhs: BackgroundSyncConfig) -> Bool { - if lhs.onchainWalletSyncIntervalSecs != rhs.onchainWalletSyncIntervalSecs { - return false + open func openChannel(nodeId: PublicKey, address: SocketAddress, channelAmountSats: UInt64, pushToCounterpartyMsat: UInt64?, channelConfig: ChannelConfig?) throws -> UserChannelId { + return try FfiConverterTypeUserChannelId.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_open_channel(self.uniffiClonePointer(), + FfiConverterTypePublicKey.lower(nodeId), + FfiConverterTypeSocketAddress.lower(address), + FfiConverterUInt64.lower(channelAmountSats), + FfiConverterOptionUInt64.lower(pushToCounterpartyMsat), + FfiConverterOptionTypeChannelConfig.lower(channelConfig), $0) + }) + } + + open func payment(paymentId: PaymentId) -> PaymentDetails? { + return try! FfiConverterOptionTypePaymentDetails.lift(try! rustCall { + uniffi_ldk_node_fn_method_node_payment(self.uniffiClonePointer(), + FfiConverterTypePaymentId.lower(paymentId), $0) + }) + } + + open func removeAddressTypeFromMonitor(addressType: AddressType) throws { + try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_remove_address_type_from_monitor(self.uniffiClonePointer(), + FfiConverterTypeAddressType.lower(addressType), $0) } - if lhs.lightningWalletSyncIntervalSecs != rhs.lightningWalletSyncIntervalSecs { - return false + } + + open func removeOnchainWalletAccount(addressType: AddressType, accountIndex: UInt32) throws { + try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_remove_onchain_wallet_account(self.uniffiClonePointer(), + FfiConverterTypeAddressType.lower(addressType), + FfiConverterUInt32.lower(accountIndex), $0) } - if lhs.feeRateCacheUpdateIntervalSecs != rhs.feeRateCacheUpdateIntervalSecs { - return false + } + + open func removePayment(paymentId: PaymentId) throws { + try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_remove_payment(self.uniffiClonePointer(), + FfiConverterTypePaymentId.lower(paymentId), $0) } - return true } - public func hash(into hasher: inout Hasher) { - hasher.combine(onchainWalletSyncIntervalSecs) - hasher.combine(lightningWalletSyncIntervalSecs) - hasher.combine(feeRateCacheUpdateIntervalSecs) + open func setPrimaryAddressType(addressType: AddressType, seedBytes: [UInt8]) throws { + try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_set_primary_address_type(self.uniffiClonePointer(), + FfiConverterTypeAddressType.lower(addressType), + FfiConverterSequenceUInt8.lower(seedBytes), $0) + } } -} + open func setPrimaryAddressTypeWithMnemonic(addressType: AddressType, mnemonic: Mnemonic, passphrase: String?) throws { + try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_set_primary_address_type_with_mnemonic(self.uniffiClonePointer(), + FfiConverterTypeAddressType.lower(addressType), + FfiConverterTypeMnemonic.lower(mnemonic), + FfiConverterOptionString.lower(passphrase), $0) + } + } -public struct FfiConverterTypeBackgroundSyncConfig: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> BackgroundSyncConfig { - return - try BackgroundSyncConfig( - onchainWalletSyncIntervalSecs: FfiConverterUInt64.read(from: &buf), - lightningWalletSyncIntervalSecs: FfiConverterUInt64.read(from: &buf), - feeRateCacheUpdateIntervalSecs: FfiConverterUInt64.read(from: &buf) - ) + open func signMessage(msg: [UInt8]) -> String { + return try! FfiConverterString.lift(try! rustCall { + uniffi_ldk_node_fn_method_node_sign_message(self.uniffiClonePointer(), + FfiConverterSequenceUInt8.lower(msg), $0) + }) } - public static func write(_ value: BackgroundSyncConfig, into buf: inout [UInt8]) { - FfiConverterUInt64.write(value.onchainWalletSyncIntervalSecs, into: &buf) - FfiConverterUInt64.write(value.lightningWalletSyncIntervalSecs, into: &buf) - FfiConverterUInt64.write(value.feeRateCacheUpdateIntervalSecs, into: &buf) + open func spliceIn(userChannelId: UserChannelId, counterpartyNodeId: PublicKey, spliceAmountSats: UInt64) throws { + try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_splice_in(self.uniffiClonePointer(), + FfiConverterTypeUserChannelId.lower(userChannelId), + FfiConverterTypePublicKey.lower(counterpartyNodeId), + FfiConverterUInt64.lower(spliceAmountSats), $0) + } } -} + open func spliceOut(userChannelId: UserChannelId, counterpartyNodeId: PublicKey, address: Address, spliceAmountSats: UInt64) throws { + try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_splice_out(self.uniffiClonePointer(), + FfiConverterTypeUserChannelId.lower(userChannelId), + FfiConverterTypePublicKey.lower(counterpartyNodeId), + FfiConverterTypeAddress.lower(address), + FfiConverterUInt64.lower(spliceAmountSats), $0) + } + } -public func FfiConverterTypeBackgroundSyncConfig_lift(_ buf: RustBuffer) throws -> BackgroundSyncConfig { - return try FfiConverterTypeBackgroundSyncConfig.lift(buf) -} + open func spontaneousPayment() -> SpontaneousPayment { + return try! FfiConverterTypeSpontaneousPayment.lift(try! rustCall { + uniffi_ldk_node_fn_method_node_spontaneous_payment(self.uniffiClonePointer(), $0) + }) + } -public func FfiConverterTypeBackgroundSyncConfig_lower(_ value: BackgroundSyncConfig) -> RustBuffer { - return FfiConverterTypeBackgroundSyncConfig.lower(value) -} + open func start() throws { + try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_start(self.uniffiClonePointer(), $0) + } + } + open func status() -> NodeStatus { + return try! FfiConverterTypeNodeStatus.lift(try! rustCall { + uniffi_ldk_node_fn_method_node_status(self.uniffiClonePointer(), $0) + }) + } -public struct BalanceDetails { - public var totalOnchainBalanceSats: UInt64 - public var spendableOnchainBalanceSats: UInt64 - public var totalAnchorChannelsReserveSats: UInt64 - public var totalLightningBalanceSats: UInt64 - public var lightningBalances: [LightningBalance] - public var pendingBalancesFromChannelClosures: [PendingSweepBalance] + open func stop() throws { + try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_stop(self.uniffiClonePointer(), $0) + } + } - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(totalOnchainBalanceSats: UInt64, spendableOnchainBalanceSats: UInt64, totalAnchorChannelsReserveSats: UInt64, totalLightningBalanceSats: UInt64, lightningBalances: [LightningBalance], pendingBalancesFromChannelClosures: [PendingSweepBalance]) { - self.totalOnchainBalanceSats = totalOnchainBalanceSats - self.spendableOnchainBalanceSats = spendableOnchainBalanceSats - self.totalAnchorChannelsReserveSats = totalAnchorChannelsReserveSats - self.totalLightningBalanceSats = totalLightningBalanceSats - self.lightningBalances = lightningBalances - self.pendingBalancesFromChannelClosures = pendingBalancesFromChannelClosures + open func syncWallets() throws { + try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_sync_wallets(self.uniffiClonePointer(), $0) + } } -} + open func unifiedQrPayment() -> UnifiedQrPayment { + return try! FfiConverterTypeUnifiedQrPayment.lift(try! rustCall { + uniffi_ldk_node_fn_method_node_unified_qr_payment(self.uniffiClonePointer(), $0) + }) + } + open func updateChannelConfig(userChannelId: UserChannelId, counterpartyNodeId: PublicKey, channelConfig: ChannelConfig) throws { + try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_update_channel_config(self.uniffiClonePointer(), + FfiConverterTypeUserChannelId.lower(userChannelId), + FfiConverterTypePublicKey.lower(counterpartyNodeId), + FfiConverterTypeChannelConfig.lower(channelConfig), $0) + } + } -extension BalanceDetails: Equatable, Hashable { - public static func ==(lhs: BalanceDetails, rhs: BalanceDetails) -> Bool { - if lhs.totalOnchainBalanceSats != rhs.totalOnchainBalanceSats { - return false - } - if lhs.spendableOnchainBalanceSats != rhs.spendableOnchainBalanceSats { - return false - } - if lhs.totalAnchorChannelsReserveSats != rhs.totalAnchorChannelsReserveSats { - return false - } - if lhs.totalLightningBalanceSats != rhs.totalLightningBalanceSats { - return false - } - if lhs.lightningBalances != rhs.lightningBalances { - return false - } - if lhs.pendingBalancesFromChannelClosures != rhs.pendingBalancesFromChannelClosures { - return false + open func updateSyncIntervals(intervals: RuntimeSyncIntervals) throws { + try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_node_update_sync_intervals(self.uniffiClonePointer(), + FfiConverterTypeRuntimeSyncIntervals.lower(intervals), $0) } - return true } - public func hash(into hasher: inout Hasher) { - hasher.combine(totalOnchainBalanceSats) - hasher.combine(spendableOnchainBalanceSats) - hasher.combine(totalAnchorChannelsReserveSats) - hasher.combine(totalLightningBalanceSats) - hasher.combine(lightningBalances) - hasher.combine(pendingBalancesFromChannelClosures) + open func verifySignature(msg: [UInt8], sig: String, pkey: PublicKey) -> Bool { + return try! FfiConverterBool.lift(try! rustCall { + uniffi_ldk_node_fn_method_node_verify_signature(self.uniffiClonePointer(), + FfiConverterSequenceUInt8.lower(msg), + FfiConverterString.lower(sig), + FfiConverterTypePublicKey.lower(pkey), $0) + }) + } + + open func waitNextEvent() -> Event { + return try! FfiConverterTypeEvent.lift(try! rustCall { + uniffi_ldk_node_fn_method_node_wait_next_event(self.uniffiClonePointer(), $0) + }) } } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeNode: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = Node -public struct FfiConverterTypeBalanceDetails: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> BalanceDetails { - return - try BalanceDetails( - totalOnchainBalanceSats: FfiConverterUInt64.read(from: &buf), - spendableOnchainBalanceSats: FfiConverterUInt64.read(from: &buf), - totalAnchorChannelsReserveSats: FfiConverterUInt64.read(from: &buf), - totalLightningBalanceSats: FfiConverterUInt64.read(from: &buf), - lightningBalances: FfiConverterSequenceTypeLightningBalance.read(from: &buf), - pendingBalancesFromChannelClosures: FfiConverterSequenceTypePendingSweepBalance.read(from: &buf) - ) + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Node { + return Node(unsafeFromRawPointer: pointer) } - public static func write(_ value: BalanceDetails, into buf: inout [UInt8]) { - FfiConverterUInt64.write(value.totalOnchainBalanceSats, into: &buf) - FfiConverterUInt64.write(value.spendableOnchainBalanceSats, into: &buf) - FfiConverterUInt64.write(value.totalAnchorChannelsReserveSats, into: &buf) - FfiConverterUInt64.write(value.totalLightningBalanceSats, into: &buf) - FfiConverterSequenceTypeLightningBalance.write(value.lightningBalances, into: &buf) - FfiConverterSequenceTypePendingSweepBalance.write(value.pendingBalancesFromChannelClosures, into: &buf) + public static func lower(_ value: Node) -> UnsafeMutableRawPointer { + return value.uniffiClonePointer() } -} + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Node { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if ptr == nil { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } -public func FfiConverterTypeBalanceDetails_lift(_ buf: RustBuffer) throws -> BalanceDetails { - return try FfiConverterTypeBalanceDetails.lift(buf) + public static func write(_ value: Node, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } } -public func FfiConverterTypeBalanceDetails_lower(_ value: BalanceDetails) -> RustBuffer { - return FfiConverterTypeBalanceDetails.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeNode_lift(_ pointer: UnsafeMutableRawPointer) throws -> Node { + return try FfiConverterTypeNode.lift(pointer) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeNode_lower(_ value: Node) -> UnsafeMutableRawPointer { + return FfiConverterTypeNode.lower(value) +} -public struct BestBlock { - public var blockHash: BlockHash - public var height: UInt32 +public protocol OfferProtocol: AnyObject { + func absoluteExpirySeconds() -> UInt64? - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(blockHash: BlockHash, height: UInt32) { - self.blockHash = blockHash - self.height = height - } -} + func amount() -> OfferAmount? + func chains() -> [Network] + func expectsQuantity() -> Bool -extension BestBlock: Equatable, Hashable { - public static func ==(lhs: BestBlock, rhs: BestBlock) -> Bool { - if lhs.blockHash != rhs.blockHash { - return false - } - if lhs.height != rhs.height { - return false - } - return true - } + func id() -> OfferId - public func hash(into hasher: inout Hasher) { - hasher.combine(blockHash) - hasher.combine(height) - } + func isExpired() -> Bool + + func isValidQuantity(quantity: UInt64) -> Bool + + func issuer() -> String? + + func issuerSigningPubkey() -> PublicKey? + + func metadata() -> [UInt8]? + + func offerDescription() -> String? + + func supportsChain(chain: Network) -> Bool } +open class Offer: + CustomDebugStringConvertible, + CustomStringConvertible, + Equatable, + OfferProtocol +{ + fileprivate let pointer: UnsafeMutableRawPointer! -public struct FfiConverterTypeBestBlock: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> BestBlock { - return - try BestBlock( - blockHash: FfiConverterTypeBlockHash.read(from: &buf), - height: FfiConverterUInt32.read(from: &buf) - ) + // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public struct NoPointer { + public init() {} } - public static func write(_ value: BestBlock, into buf: inout [UInt8]) { - FfiConverterTypeBlockHash.write(value.blockHash, into: &buf) - FfiConverterUInt32.write(value.height, into: &buf) + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + public required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer } -} + // This constructor can be used to instantiate a fake object. + // - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. + // + // - Warning: + // Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public init(noPointer _: NoPointer) { + pointer = nil + } -public func FfiConverterTypeBestBlock_lift(_ buf: RustBuffer) throws -> BestBlock { - return try FfiConverterTypeBestBlock.lift(buf) -} + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public func uniffiClonePointer() -> UnsafeMutableRawPointer { + return try! rustCall { uniffi_ldk_node_fn_clone_offer(self.pointer, $0) } + } -public func FfiConverterTypeBestBlock_lower(_ value: BestBlock) -> RustBuffer { - return FfiConverterTypeBestBlock.lower(value) -} + // No primary constructor declared for this class. + deinit { + guard let pointer = pointer else { + return + } -public struct Bolt11PaymentInfo { - public var state: PaymentState - public var expiresAt: DateTime - public var feeTotalSat: UInt64 - public var orderTotalSat: UInt64 - public var invoice: Bolt11Invoice + try! rustCall { uniffi_ldk_node_fn_free_offer(pointer, $0) } + } - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(state: PaymentState, expiresAt: DateTime, feeTotalSat: UInt64, orderTotalSat: UInt64, invoice: Bolt11Invoice) { - self.state = state - self.expiresAt = expiresAt - self.feeTotalSat = feeTotalSat - self.orderTotalSat = orderTotalSat - self.invoice = invoice + public static func fromStr(offerStr: String) throws -> Offer { + return try FfiConverterTypeOffer.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_constructor_offer_from_str( + FfiConverterString.lower(offerStr), $0 + ) + }) } -} + open func absoluteExpirySeconds() -> UInt64? { + return try! FfiConverterOptionUInt64.lift(try! rustCall { + uniffi_ldk_node_fn_method_offer_absolute_expiry_seconds(self.uniffiClonePointer(), $0) + }) + } + open func amount() -> OfferAmount? { + return try! FfiConverterOptionTypeOfferAmount.lift(try! rustCall { + uniffi_ldk_node_fn_method_offer_amount(self.uniffiClonePointer(), $0) + }) + } -public struct FfiConverterTypeBolt11PaymentInfo: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Bolt11PaymentInfo { - return - try Bolt11PaymentInfo( - state: FfiConverterTypePaymentState.read(from: &buf), - expiresAt: FfiConverterTypeDateTime.read(from: &buf), - feeTotalSat: FfiConverterUInt64.read(from: &buf), - orderTotalSat: FfiConverterUInt64.read(from: &buf), - invoice: FfiConverterTypeBolt11Invoice.read(from: &buf) - ) + open func chains() -> [Network] { + return try! FfiConverterSequenceTypeNetwork.lift(try! rustCall { + uniffi_ldk_node_fn_method_offer_chains(self.uniffiClonePointer(), $0) + }) } - public static func write(_ value: Bolt11PaymentInfo, into buf: inout [UInt8]) { - FfiConverterTypePaymentState.write(value.state, into: &buf) - FfiConverterTypeDateTime.write(value.expiresAt, into: &buf) - FfiConverterUInt64.write(value.feeTotalSat, into: &buf) - FfiConverterUInt64.write(value.orderTotalSat, into: &buf) - FfiConverterTypeBolt11Invoice.write(value.invoice, into: &buf) + open func expectsQuantity() -> Bool { + return try! FfiConverterBool.lift(try! rustCall { + uniffi_ldk_node_fn_method_offer_expects_quantity(self.uniffiClonePointer(), $0) + }) } -} + open func id() -> OfferId { + return try! FfiConverterTypeOfferId.lift(try! rustCall { + uniffi_ldk_node_fn_method_offer_id(self.uniffiClonePointer(), $0) + }) + } -public func FfiConverterTypeBolt11PaymentInfo_lift(_ buf: RustBuffer) throws -> Bolt11PaymentInfo { - return try FfiConverterTypeBolt11PaymentInfo.lift(buf) -} + open func isExpired() -> Bool { + return try! FfiConverterBool.lift(try! rustCall { + uniffi_ldk_node_fn_method_offer_is_expired(self.uniffiClonePointer(), $0) + }) + } -public func FfiConverterTypeBolt11PaymentInfo_lower(_ value: Bolt11PaymentInfo) -> RustBuffer { - return FfiConverterTypeBolt11PaymentInfo.lower(value) -} + open func isValidQuantity(quantity: UInt64) -> Bool { + return try! FfiConverterBool.lift(try! rustCall { + uniffi_ldk_node_fn_method_offer_is_valid_quantity(self.uniffiClonePointer(), + FfiConverterUInt64.lower(quantity), $0) + }) + } + open func issuer() -> String? { + return try! FfiConverterOptionString.lift(try! rustCall { + uniffi_ldk_node_fn_method_offer_issuer(self.uniffiClonePointer(), $0) + }) + } -public struct ChannelConfig { - public var forwardingFeeProportionalMillionths: UInt32 - public var forwardingFeeBaseMsat: UInt32 - public var cltvExpiryDelta: UInt16 - public var maxDustHtlcExposure: MaxDustHtlcExposure - public var forceCloseAvoidanceMaxFeeSatoshis: UInt64 - public var acceptUnderpayingHtlcs: Bool + open func issuerSigningPubkey() -> PublicKey? { + return try! FfiConverterOptionTypePublicKey.lift(try! rustCall { + uniffi_ldk_node_fn_method_offer_issuer_signing_pubkey(self.uniffiClonePointer(), $0) + }) + } - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(forwardingFeeProportionalMillionths: UInt32, forwardingFeeBaseMsat: UInt32, cltvExpiryDelta: UInt16, maxDustHtlcExposure: MaxDustHtlcExposure, forceCloseAvoidanceMaxFeeSatoshis: UInt64, acceptUnderpayingHtlcs: Bool) { - self.forwardingFeeProportionalMillionths = forwardingFeeProportionalMillionths - self.forwardingFeeBaseMsat = forwardingFeeBaseMsat - self.cltvExpiryDelta = cltvExpiryDelta - self.maxDustHtlcExposure = maxDustHtlcExposure - self.forceCloseAvoidanceMaxFeeSatoshis = forceCloseAvoidanceMaxFeeSatoshis - self.acceptUnderpayingHtlcs = acceptUnderpayingHtlcs + open func metadata() -> [UInt8]? { + return try! FfiConverterOptionSequenceUInt8.lift(try! rustCall { + uniffi_ldk_node_fn_method_offer_metadata(self.uniffiClonePointer(), $0) + }) } -} + open func offerDescription() -> String? { + return try! FfiConverterOptionString.lift(try! rustCall { + uniffi_ldk_node_fn_method_offer_offer_description(self.uniffiClonePointer(), $0) + }) + } + open func supportsChain(chain: Network) -> Bool { + return try! FfiConverterBool.lift(try! rustCall { + uniffi_ldk_node_fn_method_offer_supports_chain(self.uniffiClonePointer(), + FfiConverterTypeNetwork.lower(chain), $0) + }) + } -extension ChannelConfig: Equatable, Hashable { - public static func ==(lhs: ChannelConfig, rhs: ChannelConfig) -> Bool { - if lhs.forwardingFeeProportionalMillionths != rhs.forwardingFeeProportionalMillionths { - return false - } - if lhs.forwardingFeeBaseMsat != rhs.forwardingFeeBaseMsat { - return false - } - if lhs.cltvExpiryDelta != rhs.cltvExpiryDelta { - return false - } - if lhs.maxDustHtlcExposure != rhs.maxDustHtlcExposure { - return false - } - if lhs.forceCloseAvoidanceMaxFeeSatoshis != rhs.forceCloseAvoidanceMaxFeeSatoshis { - return false - } - if lhs.acceptUnderpayingHtlcs != rhs.acceptUnderpayingHtlcs { - return false - } - return true + open var debugDescription: String { + return try! FfiConverterString.lift( + try! rustCall { + uniffi_ldk_node_fn_method_offer_uniffi_trait_debug(self.uniffiClonePointer(), $0) + } + ) } - public func hash(into hasher: inout Hasher) { - hasher.combine(forwardingFeeProportionalMillionths) - hasher.combine(forwardingFeeBaseMsat) - hasher.combine(cltvExpiryDelta) - hasher.combine(maxDustHtlcExposure) - hasher.combine(forceCloseAvoidanceMaxFeeSatoshis) - hasher.combine(acceptUnderpayingHtlcs) + open var description: String { + return try! FfiConverterString.lift( + try! rustCall { + uniffi_ldk_node_fn_method_offer_uniffi_trait_display(self.uniffiClonePointer(), $0) + } + ) + } + + public static func == (self: Offer, other: Offer) -> Bool { + return try! FfiConverterBool.lift( + try! rustCall { + uniffi_ldk_node_fn_method_offer_uniffi_trait_eq_eq(self.uniffiClonePointer(), + FfiConverterTypeOffer.lower(other), $0) + } + ) } } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeOffer: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = Offer -public struct FfiConverterTypeChannelConfig: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ChannelConfig { - return - try ChannelConfig( - forwardingFeeProportionalMillionths: FfiConverterUInt32.read(from: &buf), - forwardingFeeBaseMsat: FfiConverterUInt32.read(from: &buf), - cltvExpiryDelta: FfiConverterUInt16.read(from: &buf), - maxDustHtlcExposure: FfiConverterTypeMaxDustHTLCExposure.read(from: &buf), - forceCloseAvoidanceMaxFeeSatoshis: FfiConverterUInt64.read(from: &buf), - acceptUnderpayingHtlcs: FfiConverterBool.read(from: &buf) - ) + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Offer { + return Offer(unsafeFromRawPointer: pointer) } - public static func write(_ value: ChannelConfig, into buf: inout [UInt8]) { - FfiConverterUInt32.write(value.forwardingFeeProportionalMillionths, into: &buf) - FfiConverterUInt32.write(value.forwardingFeeBaseMsat, into: &buf) - FfiConverterUInt16.write(value.cltvExpiryDelta, into: &buf) - FfiConverterTypeMaxDustHTLCExposure.write(value.maxDustHtlcExposure, into: &buf) - FfiConverterUInt64.write(value.forceCloseAvoidanceMaxFeeSatoshis, into: &buf) - FfiConverterBool.write(value.acceptUnderpayingHtlcs, into: &buf) + public static func lower(_ value: Offer) -> UnsafeMutableRawPointer { + return value.uniffiClonePointer() } -} + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Offer { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if ptr == nil { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } -public func FfiConverterTypeChannelConfig_lift(_ buf: RustBuffer) throws -> ChannelConfig { - return try FfiConverterTypeChannelConfig.lift(buf) + public static func write(_ value: Offer, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } } -public func FfiConverterTypeChannelConfig_lower(_ value: ChannelConfig) -> RustBuffer { - return FfiConverterTypeChannelConfig.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeOffer_lift(_ pointer: UnsafeMutableRawPointer) throws -> Offer { + return try FfiConverterTypeOffer.lift(pointer) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeOffer_lower(_ value: Offer) -> UnsafeMutableRawPointer { + return FfiConverterTypeOffer.lower(value) +} + +public protocol OnchainPaymentProtocol: AnyObject { + func accelerateByCpfp(txid: Txid, feeRate: FeeRate?, destinationAddress: Address?) throws -> Txid + + func addressInfoForAccountAtIndex(addressType: AddressType, accountIndex: UInt32, keychain: KeychainKind, index: UInt32) throws -> AddressInfo + + func addressInfoForTypeAtIndex(addressType: AddressType, keychain: KeychainKind, index: UInt32) throws -> AddressInfo + + func addressInfosForAccount(addressType: AddressType, accountIndex: UInt32, keychain: KeychainKind, startIndex: UInt32, count: UInt32) throws -> [AddressInfo] + + func addressInfosForType(addressType: AddressType, keychain: KeychainKind, startIndex: UInt32, count: UInt32) throws -> [AddressInfo] + + func bumpFeeByRbf(txid: Txid, feeRate: FeeRate) throws -> Txid + + func calculateCpfpFeeRate(parentTxid: Txid, urgent: Bool) throws -> FeeRate + + func calculateSendAllFee(address: Address, retainReserves: Bool, feeRate: FeeRate?) throws -> UInt64 + + func calculateTotalFee(address: Address, amountSats: UInt64, feeRate: FeeRate?, utxosToSpend: [SpendableUtxo]?) throws -> UInt64 + + func listSpendableOutputs() throws -> [SpendableUtxo] + + func newAddress() throws -> Address + + func newAddressForAccount(addressType: AddressType, accountIndex: UInt32) throws -> Address + + func newAddressForType(addressType: AddressType) throws -> Address + + func newAddressInfo() throws -> AddressInfo + + func newAddressInfoForAccount(addressType: AddressType, accountIndex: UInt32) throws -> AddressInfo + + func newAddressInfoForType(addressType: AddressType) throws -> AddressInfo + + func revealReceiveAddressesTo(addressType: AddressType, index: UInt32) throws + + func revealReceiveAddressesToAccount(addressType: AddressType, accountIndex: UInt32, index: UInt32) throws + + func selectUtxosWithAlgorithm(targetAmountSats: UInt64, feeRate: FeeRate?, algorithm: CoinSelectionAlgorithm, utxos: [SpendableUtxo]?) throws -> [SpendableUtxo] + + func sendAllToAddress(address: Address, retainReserve: Bool, feeRate: FeeRate?) throws -> Txid + + func sendToAddress(address: Address, amountSats: UInt64, feeRate: FeeRate?, utxosToSpend: [SpendableUtxo]?) throws -> Txid +} + +open class OnchainPayment: + OnchainPaymentProtocol +{ + fileprivate let pointer: UnsafeMutableRawPointer! + + // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public struct NoPointer { + public init() {} + } + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + public required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + + // This constructor can be used to instantiate a fake object. + // - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. + // + // - Warning: + // Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public init(noPointer _: NoPointer) { + pointer = nil + } + + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public func uniffiClonePointer() -> UnsafeMutableRawPointer { + return try! rustCall { uniffi_ldk_node_fn_clone_onchainpayment(self.pointer, $0) } + } + + // No primary constructor declared for this class. + + deinit { + guard let pointer = pointer else { + return + } + + try! rustCall { uniffi_ldk_node_fn_free_onchainpayment(pointer, $0) } + } + + open func accelerateByCpfp(txid: Txid, feeRate: FeeRate?, destinationAddress: Address?) throws -> Txid { + return try FfiConverterTypeTxid.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_onchainpayment_accelerate_by_cpfp(self.uniffiClonePointer(), + FfiConverterTypeTxid.lower(txid), + FfiConverterOptionTypeFeeRate.lower(feeRate), + FfiConverterOptionTypeAddress.lower(destinationAddress), $0) + }) + } + + open func addressInfoForAccountAtIndex(addressType: AddressType, accountIndex: UInt32, keychain: KeychainKind, index: UInt32) throws -> AddressInfo { + return try FfiConverterTypeAddressInfo.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_onchainpayment_address_info_for_account_at_index(self.uniffiClonePointer(), + FfiConverterTypeAddressType.lower(addressType), + FfiConverterUInt32.lower(accountIndex), + FfiConverterTypeKeychainKind.lower(keychain), + FfiConverterUInt32.lower(index), $0) + }) + } + + open func addressInfoForTypeAtIndex(addressType: AddressType, keychain: KeychainKind, index: UInt32) throws -> AddressInfo { + return try FfiConverterTypeAddressInfo.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_onchainpayment_address_info_for_type_at_index(self.uniffiClonePointer(), + FfiConverterTypeAddressType.lower(addressType), + FfiConverterTypeKeychainKind.lower(keychain), + FfiConverterUInt32.lower(index), $0) + }) + } + + open func addressInfosForAccount(addressType: AddressType, accountIndex: UInt32, keychain: KeychainKind, startIndex: UInt32, count: UInt32) throws -> [AddressInfo] { + return try FfiConverterSequenceTypeAddressInfo.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_onchainpayment_address_infos_for_account(self.uniffiClonePointer(), + FfiConverterTypeAddressType.lower(addressType), + FfiConverterUInt32.lower(accountIndex), + FfiConverterTypeKeychainKind.lower(keychain), + FfiConverterUInt32.lower(startIndex), + FfiConverterUInt32.lower(count), $0) + }) + } + + open func addressInfosForType(addressType: AddressType, keychain: KeychainKind, startIndex: UInt32, count: UInt32) throws -> [AddressInfo] { + return try FfiConverterSequenceTypeAddressInfo.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_onchainpayment_address_infos_for_type(self.uniffiClonePointer(), + FfiConverterTypeAddressType.lower(addressType), + FfiConverterTypeKeychainKind.lower(keychain), + FfiConverterUInt32.lower(startIndex), + FfiConverterUInt32.lower(count), $0) + }) + } + + open func bumpFeeByRbf(txid: Txid, feeRate: FeeRate) throws -> Txid { + return try FfiConverterTypeTxid.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_onchainpayment_bump_fee_by_rbf(self.uniffiClonePointer(), + FfiConverterTypeTxid.lower(txid), + FfiConverterTypeFeeRate.lower(feeRate), $0) + }) + } + + open func calculateCpfpFeeRate(parentTxid: Txid, urgent: Bool) throws -> FeeRate { + return try FfiConverterTypeFeeRate.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_onchainpayment_calculate_cpfp_fee_rate(self.uniffiClonePointer(), + FfiConverterTypeTxid.lower(parentTxid), + FfiConverterBool.lower(urgent), $0) + }) + } + + open func calculateSendAllFee(address: Address, retainReserves: Bool, feeRate: FeeRate?) throws -> UInt64 { + return try FfiConverterUInt64.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_onchainpayment_calculate_send_all_fee(self.uniffiClonePointer(), + FfiConverterTypeAddress.lower(address), + FfiConverterBool.lower(retainReserves), + FfiConverterOptionTypeFeeRate.lower(feeRate), $0) + }) + } + + open func calculateTotalFee(address: Address, amountSats: UInt64, feeRate: FeeRate?, utxosToSpend: [SpendableUtxo]?) throws -> UInt64 { + return try FfiConverterUInt64.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_onchainpayment_calculate_total_fee(self.uniffiClonePointer(), + FfiConverterTypeAddress.lower(address), + FfiConverterUInt64.lower(amountSats), + FfiConverterOptionTypeFeeRate.lower(feeRate), + FfiConverterOptionSequenceTypeSpendableUtxo.lower(utxosToSpend), $0) + }) + } + + open func listSpendableOutputs() throws -> [SpendableUtxo] { + return try FfiConverterSequenceTypeSpendableUtxo.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_onchainpayment_list_spendable_outputs(self.uniffiClonePointer(), $0) + }) + } + + open func newAddress() throws -> Address { + return try FfiConverterTypeAddress.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_onchainpayment_new_address(self.uniffiClonePointer(), $0) + }) + } + + open func newAddressForAccount(addressType: AddressType, accountIndex: UInt32) throws -> Address { + return try FfiConverterTypeAddress.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_onchainpayment_new_address_for_account(self.uniffiClonePointer(), + FfiConverterTypeAddressType.lower(addressType), + FfiConverterUInt32.lower(accountIndex), $0) + }) + } + + open func newAddressForType(addressType: AddressType) throws -> Address { + return try FfiConverterTypeAddress.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_onchainpayment_new_address_for_type(self.uniffiClonePointer(), + FfiConverterTypeAddressType.lower(addressType), $0) + }) + } + + open func newAddressInfo() throws -> AddressInfo { + return try FfiConverterTypeAddressInfo.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_onchainpayment_new_address_info(self.uniffiClonePointer(), $0) + }) + } + + open func newAddressInfoForAccount(addressType: AddressType, accountIndex: UInt32) throws -> AddressInfo { + return try FfiConverterTypeAddressInfo.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_onchainpayment_new_address_info_for_account(self.uniffiClonePointer(), + FfiConverterTypeAddressType.lower(addressType), + FfiConverterUInt32.lower(accountIndex), $0) + }) + } + + open func newAddressInfoForType(addressType: AddressType) throws -> AddressInfo { + return try FfiConverterTypeAddressInfo.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_onchainpayment_new_address_info_for_type(self.uniffiClonePointer(), + FfiConverterTypeAddressType.lower(addressType), $0) + }) + } + + open func revealReceiveAddressesTo(addressType: AddressType, index: UInt32) throws { + try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_onchainpayment_reveal_receive_addresses_to(self.uniffiClonePointer(), + FfiConverterTypeAddressType.lower(addressType), + FfiConverterUInt32.lower(index), $0) + } + } + + open func revealReceiveAddressesToAccount(addressType: AddressType, accountIndex: UInt32, index: UInt32) throws { + try rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_onchainpayment_reveal_receive_addresses_to_account(self.uniffiClonePointer(), + FfiConverterTypeAddressType.lower(addressType), + FfiConverterUInt32.lower(accountIndex), + FfiConverterUInt32.lower(index), $0) + } + } + + open func selectUtxosWithAlgorithm(targetAmountSats: UInt64, feeRate: FeeRate?, algorithm: CoinSelectionAlgorithm, utxos: [SpendableUtxo]?) throws -> [SpendableUtxo] { + return try FfiConverterSequenceTypeSpendableUtxo.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_onchainpayment_select_utxos_with_algorithm(self.uniffiClonePointer(), + FfiConverterUInt64.lower(targetAmountSats), + FfiConverterOptionTypeFeeRate.lower(feeRate), + FfiConverterTypeCoinSelectionAlgorithm.lower(algorithm), + FfiConverterOptionSequenceTypeSpendableUtxo.lower(utxos), $0) + }) + } + + open func sendAllToAddress(address: Address, retainReserve: Bool, feeRate: FeeRate?) throws -> Txid { + return try FfiConverterTypeTxid.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_onchainpayment_send_all_to_address(self.uniffiClonePointer(), + FfiConverterTypeAddress.lower(address), + FfiConverterBool.lower(retainReserve), + FfiConverterOptionTypeFeeRate.lower(feeRate), $0) + }) + } + + open func sendToAddress(address: Address, amountSats: UInt64, feeRate: FeeRate?, utxosToSpend: [SpendableUtxo]?) throws -> Txid { + return try FfiConverterTypeTxid.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_onchainpayment_send_to_address(self.uniffiClonePointer(), + FfiConverterTypeAddress.lower(address), + FfiConverterUInt64.lower(amountSats), + FfiConverterOptionTypeFeeRate.lower(feeRate), + FfiConverterOptionSequenceTypeSpendableUtxo.lower(utxosToSpend), $0) + }) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeOnchainPayment: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = OnchainPayment + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> OnchainPayment { + return OnchainPayment(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: OnchainPayment) -> UnsafeMutableRawPointer { + return value.uniffiClonePointer() + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> OnchainPayment { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if ptr == nil { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: OnchainPayment, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeOnchainPayment_lift(_ pointer: UnsafeMutableRawPointer) throws -> OnchainPayment { + return try FfiConverterTypeOnchainPayment.lift(pointer) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeOnchainPayment_lower(_ value: OnchainPayment) -> UnsafeMutableRawPointer { + return FfiConverterTypeOnchainPayment.lower(value) +} + +public protocol RefundProtocol: AnyObject { + func absoluteExpirySeconds() -> UInt64? + + func amountMsats() -> UInt64 + + func chain() -> Network? + + func isExpired() -> Bool + + func issuer() -> String? + + func payerMetadata() -> [UInt8] + + func payerNote() -> String? + + func payerSigningPubkey() -> PublicKey + + func quantity() -> UInt64? + + func refundDescription() -> String +} + +open class Refund: + CustomDebugStringConvertible, + CustomStringConvertible, + Equatable, + RefundProtocol +{ + fileprivate let pointer: UnsafeMutableRawPointer! + + // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public struct NoPointer { + public init() {} + } + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + public required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + + // This constructor can be used to instantiate a fake object. + // - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. + // + // - Warning: + // Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public init(noPointer _: NoPointer) { + pointer = nil + } + + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public func uniffiClonePointer() -> UnsafeMutableRawPointer { + return try! rustCall { uniffi_ldk_node_fn_clone_refund(self.pointer, $0) } + } + + // No primary constructor declared for this class. + + deinit { + guard let pointer = pointer else { + return + } + + try! rustCall { uniffi_ldk_node_fn_free_refund(pointer, $0) } + } + + public static func fromStr(refundStr: String) throws -> Refund { + return try FfiConverterTypeRefund.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_constructor_refund_from_str( + FfiConverterString.lower(refundStr), $0 + ) + }) + } + + open func absoluteExpirySeconds() -> UInt64? { + return try! FfiConverterOptionUInt64.lift(try! rustCall { + uniffi_ldk_node_fn_method_refund_absolute_expiry_seconds(self.uniffiClonePointer(), $0) + }) + } + + open func amountMsats() -> UInt64 { + return try! FfiConverterUInt64.lift(try! rustCall { + uniffi_ldk_node_fn_method_refund_amount_msats(self.uniffiClonePointer(), $0) + }) + } + + open func chain() -> Network? { + return try! FfiConverterOptionTypeNetwork.lift(try! rustCall { + uniffi_ldk_node_fn_method_refund_chain(self.uniffiClonePointer(), $0) + }) + } + + open func isExpired() -> Bool { + return try! FfiConverterBool.lift(try! rustCall { + uniffi_ldk_node_fn_method_refund_is_expired(self.uniffiClonePointer(), $0) + }) + } + + open func issuer() -> String? { + return try! FfiConverterOptionString.lift(try! rustCall { + uniffi_ldk_node_fn_method_refund_issuer(self.uniffiClonePointer(), $0) + }) + } + + open func payerMetadata() -> [UInt8] { + return try! FfiConverterSequenceUInt8.lift(try! rustCall { + uniffi_ldk_node_fn_method_refund_payer_metadata(self.uniffiClonePointer(), $0) + }) + } + + open func payerNote() -> String? { + return try! FfiConverterOptionString.lift(try! rustCall { + uniffi_ldk_node_fn_method_refund_payer_note(self.uniffiClonePointer(), $0) + }) + } + + open func payerSigningPubkey() -> PublicKey { + return try! FfiConverterTypePublicKey.lift(try! rustCall { + uniffi_ldk_node_fn_method_refund_payer_signing_pubkey(self.uniffiClonePointer(), $0) + }) + } + + open func quantity() -> UInt64? { + return try! FfiConverterOptionUInt64.lift(try! rustCall { + uniffi_ldk_node_fn_method_refund_quantity(self.uniffiClonePointer(), $0) + }) + } + + open func refundDescription() -> String { + return try! FfiConverterString.lift(try! rustCall { + uniffi_ldk_node_fn_method_refund_refund_description(self.uniffiClonePointer(), $0) + }) + } + + open var debugDescription: String { + return try! FfiConverterString.lift( + try! rustCall { + uniffi_ldk_node_fn_method_refund_uniffi_trait_debug(self.uniffiClonePointer(), $0) + } + ) + } + + open var description: String { + return try! FfiConverterString.lift( + try! rustCall { + uniffi_ldk_node_fn_method_refund_uniffi_trait_display(self.uniffiClonePointer(), $0) + } + ) + } + + public static func == (self: Refund, other: Refund) -> Bool { + return try! FfiConverterBool.lift( + try! rustCall { + uniffi_ldk_node_fn_method_refund_uniffi_trait_eq_eq(self.uniffiClonePointer(), + FfiConverterTypeRefund.lower(other), $0) + } + ) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeRefund: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = Refund + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> Refund { + return Refund(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: Refund) -> UnsafeMutableRawPointer { + return value.uniffiClonePointer() + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Refund { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if ptr == nil { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: Refund, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeRefund_lift(_ pointer: UnsafeMutableRawPointer) throws -> Refund { + return try FfiConverterTypeRefund.lift(pointer) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeRefund_lower(_ value: Refund) -> UnsafeMutableRawPointer { + return FfiConverterTypeRefund.lower(value) +} + +public protocol SpontaneousPaymentProtocol: AnyObject { + func send(amountMsat: UInt64, nodeId: PublicKey, routeParameters: RouteParametersConfig?) throws -> PaymentId + + func sendProbes(amountMsat: UInt64, nodeId: PublicKey) throws -> [ProbeHandle] + + func sendWithCustomTlvs(amountMsat: UInt64, nodeId: PublicKey, routeParameters: RouteParametersConfig?, customTlvs: [CustomTlvRecord]) throws -> PaymentId + + func sendWithPreimage(amountMsat: UInt64, nodeId: PublicKey, preimage: PaymentPreimage, routeParameters: RouteParametersConfig?) throws -> PaymentId + + func sendWithPreimageAndCustomTlvs(amountMsat: UInt64, nodeId: PublicKey, customTlvs: [CustomTlvRecord], preimage: PaymentPreimage, routeParameters: RouteParametersConfig?) throws -> PaymentId +} + +open class SpontaneousPayment: + SpontaneousPaymentProtocol +{ + fileprivate let pointer: UnsafeMutableRawPointer! + + // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public struct NoPointer { + public init() {} + } + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + public required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + + // This constructor can be used to instantiate a fake object. + // - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. + // + // - Warning: + // Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public init(noPointer _: NoPointer) { + pointer = nil + } + + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public func uniffiClonePointer() -> UnsafeMutableRawPointer { + return try! rustCall { uniffi_ldk_node_fn_clone_spontaneouspayment(self.pointer, $0) } + } + + // No primary constructor declared for this class. + + deinit { + guard let pointer = pointer else { + return + } + + try! rustCall { uniffi_ldk_node_fn_free_spontaneouspayment(pointer, $0) } + } + + open func send(amountMsat: UInt64, nodeId: PublicKey, routeParameters: RouteParametersConfig?) throws -> PaymentId { + return try FfiConverterTypePaymentId.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_spontaneouspayment_send(self.uniffiClonePointer(), + FfiConverterUInt64.lower(amountMsat), + FfiConverterTypePublicKey.lower(nodeId), + FfiConverterOptionTypeRouteParametersConfig.lower(routeParameters), $0) + }) + } + + open func sendProbes(amountMsat: UInt64, nodeId: PublicKey) throws -> [ProbeHandle] { + return try FfiConverterSequenceTypeProbeHandle.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_spontaneouspayment_send_probes(self.uniffiClonePointer(), + FfiConverterUInt64.lower(amountMsat), + FfiConverterTypePublicKey.lower(nodeId), $0) + }) + } + + open func sendWithCustomTlvs(amountMsat: UInt64, nodeId: PublicKey, routeParameters: RouteParametersConfig?, customTlvs: [CustomTlvRecord]) throws -> PaymentId { + return try FfiConverterTypePaymentId.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_spontaneouspayment_send_with_custom_tlvs(self.uniffiClonePointer(), + FfiConverterUInt64.lower(amountMsat), + FfiConverterTypePublicKey.lower(nodeId), + FfiConverterOptionTypeRouteParametersConfig.lower(routeParameters), + FfiConverterSequenceTypeCustomTlvRecord.lower(customTlvs), $0) + }) + } + + open func sendWithPreimage(amountMsat: UInt64, nodeId: PublicKey, preimage: PaymentPreimage, routeParameters: RouteParametersConfig?) throws -> PaymentId { + return try FfiConverterTypePaymentId.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_spontaneouspayment_send_with_preimage(self.uniffiClonePointer(), + FfiConverterUInt64.lower(amountMsat), + FfiConverterTypePublicKey.lower(nodeId), + FfiConverterTypePaymentPreimage.lower(preimage), + FfiConverterOptionTypeRouteParametersConfig.lower(routeParameters), $0) + }) + } + + open func sendWithPreimageAndCustomTlvs(amountMsat: UInt64, nodeId: PublicKey, customTlvs: [CustomTlvRecord], preimage: PaymentPreimage, routeParameters: RouteParametersConfig?) throws -> PaymentId { + return try FfiConverterTypePaymentId.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_spontaneouspayment_send_with_preimage_and_custom_tlvs(self.uniffiClonePointer(), + FfiConverterUInt64.lower(amountMsat), + FfiConverterTypePublicKey.lower(nodeId), + FfiConverterSequenceTypeCustomTlvRecord.lower(customTlvs), + FfiConverterTypePaymentPreimage.lower(preimage), + FfiConverterOptionTypeRouteParametersConfig.lower(routeParameters), $0) + }) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeSpontaneousPayment: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = SpontaneousPayment + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> SpontaneousPayment { + return SpontaneousPayment(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: SpontaneousPayment) -> UnsafeMutableRawPointer { + return value.uniffiClonePointer() + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SpontaneousPayment { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if ptr == nil { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: SpontaneousPayment, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeSpontaneousPayment_lift(_ pointer: UnsafeMutableRawPointer) throws -> SpontaneousPayment { + return try FfiConverterTypeSpontaneousPayment.lift(pointer) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeSpontaneousPayment_lower(_ value: SpontaneousPayment) -> UnsafeMutableRawPointer { + return FfiConverterTypeSpontaneousPayment.lower(value) +} + +public protocol UnifiedQrPaymentProtocol: AnyObject { + func receive(amountSats: UInt64, message: String, expirySec: UInt32) throws -> String + + func send(uriStr: String, routeParameters: RouteParametersConfig?) throws -> QrPaymentResult +} + +open class UnifiedQrPayment: + UnifiedQrPaymentProtocol +{ + fileprivate let pointer: UnsafeMutableRawPointer! + + // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public struct NoPointer { + public init() {} + } + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + public required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + + // This constructor can be used to instantiate a fake object. + // - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. + // + // - Warning: + // Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public init(noPointer _: NoPointer) { + pointer = nil + } + + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public func uniffiClonePointer() -> UnsafeMutableRawPointer { + return try! rustCall { uniffi_ldk_node_fn_clone_unifiedqrpayment(self.pointer, $0) } + } + + // No primary constructor declared for this class. + + deinit { + guard let pointer = pointer else { + return + } + + try! rustCall { uniffi_ldk_node_fn_free_unifiedqrpayment(pointer, $0) } + } + + open func receive(amountSats: UInt64, message: String, expirySec: UInt32) throws -> String { + return try FfiConverterString.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_unifiedqrpayment_receive(self.uniffiClonePointer(), + FfiConverterUInt64.lower(amountSats), + FfiConverterString.lower(message), + FfiConverterUInt32.lower(expirySec), $0) + }) + } + + open func send(uriStr: String, routeParameters: RouteParametersConfig?) throws -> QrPaymentResult { + return try FfiConverterTypeQrPaymentResult.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_method_unifiedqrpayment_send(self.uniffiClonePointer(), + FfiConverterString.lower(uriStr), + FfiConverterOptionTypeRouteParametersConfig.lower(routeParameters), $0) + }) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeUnifiedQrPayment: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = UnifiedQrPayment + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> UnifiedQrPayment { + return UnifiedQrPayment(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: UnifiedQrPayment) -> UnsafeMutableRawPointer { + return value.uniffiClonePointer() + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UnifiedQrPayment { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if ptr == nil { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: UnifiedQrPayment, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeUnifiedQrPayment_lift(_ pointer: UnsafeMutableRawPointer) throws -> UnifiedQrPayment { + return try FfiConverterTypeUnifiedQrPayment.lift(pointer) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeUnifiedQrPayment_lower(_ value: UnifiedQrPayment) -> UnsafeMutableRawPointer { + return FfiConverterTypeUnifiedQrPayment.lower(value) +} + +public protocol VssHeaderProviderProtocol: AnyObject { + func getHeaders(request: [UInt8]) async throws -> [String: String] +} + +open class VssHeaderProvider: + VssHeaderProviderProtocol +{ + fileprivate let pointer: UnsafeMutableRawPointer! + + // Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public struct NoPointer { + public init() {} + } + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + public required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + + // This constructor can be used to instantiate a fake object. + // - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. + // + // - Warning: + // Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public init(noPointer _: NoPointer) { + pointer = nil + } + + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public func uniffiClonePointer() -> UnsafeMutableRawPointer { + return try! rustCall { uniffi_ldk_node_fn_clone_vssheaderprovider(self.pointer, $0) } + } + + // No primary constructor declared for this class. + + deinit { + guard let pointer = pointer else { + return + } + + try! rustCall { uniffi_ldk_node_fn_free_vssheaderprovider(pointer, $0) } + } + + open func getHeaders(request: [UInt8]) async throws -> [String: String] { + return + try await uniffiRustCallAsync( + rustFutureFunc: { + uniffi_ldk_node_fn_method_vssheaderprovider_get_headers( + self.uniffiClonePointer(), + FfiConverterSequenceUInt8.lower(request) + ) + }, + pollFunc: ffi_ldk_node_rust_future_poll_rust_buffer, + completeFunc: ffi_ldk_node_rust_future_complete_rust_buffer, + freeFunc: ffi_ldk_node_rust_future_free_rust_buffer, + liftFunc: FfiConverterDictionaryStringString.lift, + errorHandler: FfiConverterTypeVssHeaderProviderError.lift + ) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeVssHeaderProvider: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = VssHeaderProvider + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> VssHeaderProvider { + return VssHeaderProvider(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: VssHeaderProvider) -> UnsafeMutableRawPointer { + return value.uniffiClonePointer() + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> VssHeaderProvider { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if ptr == nil { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: VssHeaderProvider, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeVssHeaderProvider_lift(_ pointer: UnsafeMutableRawPointer) throws -> VssHeaderProvider { + return try FfiConverterTypeVssHeaderProvider.lift(pointer) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeVssHeaderProvider_lower(_ value: VssHeaderProvider) -> UnsafeMutableRawPointer { + return FfiConverterTypeVssHeaderProvider.lower(value) +} + +public struct AddressInfo { + public var index: UInt32 + public var address: Address + public var keychain: KeychainKind + + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(index: UInt32, address: Address, keychain: KeychainKind) { + self.index = index + self.address = address + self.keychain = keychain + } +} + +extension AddressInfo: Equatable, Hashable { + public static func == (lhs: AddressInfo, rhs: AddressInfo) -> Bool { + if lhs.index != rhs.index { + return false + } + if lhs.address != rhs.address { + return false + } + if lhs.keychain != rhs.keychain { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(index) + hasher.combine(address) + hasher.combine(keychain) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeAddressInfo: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AddressInfo { + return + try AddressInfo( + index: FfiConverterUInt32.read(from: &buf), + address: FfiConverterTypeAddress.read(from: &buf), + keychain: FfiConverterTypeKeychainKind.read(from: &buf) + ) + } + + public static func write(_ value: AddressInfo, into buf: inout [UInt8]) { + FfiConverterUInt32.write(value.index, into: &buf) + FfiConverterTypeAddress.write(value.address, into: &buf) + FfiConverterTypeKeychainKind.write(value.keychain, into: &buf) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeAddressInfo_lift(_ buf: RustBuffer) throws -> AddressInfo { + return try FfiConverterTypeAddressInfo.lift(buf) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeAddressInfo_lower(_ value: AddressInfo) -> RustBuffer { + return FfiConverterTypeAddressInfo.lower(value) +} + +public struct AddressTypeBalance { + public var totalSats: UInt64 + public var spendableSats: UInt64 + + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(totalSats: UInt64, spendableSats: UInt64) { + self.totalSats = totalSats + self.spendableSats = spendableSats + } +} + +extension AddressTypeBalance: Equatable, Hashable { + public static func == (lhs: AddressTypeBalance, rhs: AddressTypeBalance) -> Bool { + if lhs.totalSats != rhs.totalSats { + return false + } + if lhs.spendableSats != rhs.spendableSats { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(totalSats) + hasher.combine(spendableSats) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeAddressTypeBalance: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AddressTypeBalance { + return + try AddressTypeBalance( + totalSats: FfiConverterUInt64.read(from: &buf), + spendableSats: FfiConverterUInt64.read(from: &buf) + ) + } + + public static func write(_ value: AddressTypeBalance, into buf: inout [UInt8]) { + FfiConverterUInt64.write(value.totalSats, into: &buf) + FfiConverterUInt64.write(value.spendableSats, into: &buf) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeAddressTypeBalance_lift(_ buf: RustBuffer) throws -> AddressTypeBalance { + return try FfiConverterTypeAddressTypeBalance.lift(buf) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeAddressTypeBalance_lower(_ value: AddressTypeBalance) -> RustBuffer { + return FfiConverterTypeAddressTypeBalance.lower(value) +} + +public struct AnchorChannelsConfig { + public var trustedPeersNoReserve: [PublicKey] + public var perChannelReserveSats: UInt64 + + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(trustedPeersNoReserve: [PublicKey], perChannelReserveSats: UInt64) { + self.trustedPeersNoReserve = trustedPeersNoReserve + self.perChannelReserveSats = perChannelReserveSats + } +} + +extension AnchorChannelsConfig: Equatable, Hashable { + public static func == (lhs: AnchorChannelsConfig, rhs: AnchorChannelsConfig) -> Bool { + if lhs.trustedPeersNoReserve != rhs.trustedPeersNoReserve { + return false + } + if lhs.perChannelReserveSats != rhs.perChannelReserveSats { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(trustedPeersNoReserve) + hasher.combine(perChannelReserveSats) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeAnchorChannelsConfig: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AnchorChannelsConfig { + return + try AnchorChannelsConfig( + trustedPeersNoReserve: FfiConverterSequenceTypePublicKey.read(from: &buf), + perChannelReserveSats: FfiConverterUInt64.read(from: &buf) + ) + } + + public static func write(_ value: AnchorChannelsConfig, into buf: inout [UInt8]) { + FfiConverterSequenceTypePublicKey.write(value.trustedPeersNoReserve, into: &buf) + FfiConverterUInt64.write(value.perChannelReserveSats, into: &buf) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeAnchorChannelsConfig_lift(_ buf: RustBuffer) throws -> AnchorChannelsConfig { + return try FfiConverterTypeAnchorChannelsConfig.lift(buf) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeAnchorChannelsConfig_lower(_ value: AnchorChannelsConfig) -> RustBuffer { + return FfiConverterTypeAnchorChannelsConfig.lower(value) +} + +public struct BackgroundSyncConfig { + public var onchainWalletSyncIntervalSecs: UInt64 + public var lightningWalletSyncIntervalSecs: UInt64 + public var feeRateCacheUpdateIntervalSecs: UInt64 + + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(onchainWalletSyncIntervalSecs: UInt64, lightningWalletSyncIntervalSecs: UInt64, feeRateCacheUpdateIntervalSecs: UInt64) { + self.onchainWalletSyncIntervalSecs = onchainWalletSyncIntervalSecs + self.lightningWalletSyncIntervalSecs = lightningWalletSyncIntervalSecs + self.feeRateCacheUpdateIntervalSecs = feeRateCacheUpdateIntervalSecs + } +} + +extension BackgroundSyncConfig: Equatable, Hashable { + public static func == (lhs: BackgroundSyncConfig, rhs: BackgroundSyncConfig) -> Bool { + if lhs.onchainWalletSyncIntervalSecs != rhs.onchainWalletSyncIntervalSecs { + return false + } + if lhs.lightningWalletSyncIntervalSecs != rhs.lightningWalletSyncIntervalSecs { + return false + } + if lhs.feeRateCacheUpdateIntervalSecs != rhs.feeRateCacheUpdateIntervalSecs { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(onchainWalletSyncIntervalSecs) + hasher.combine(lightningWalletSyncIntervalSecs) + hasher.combine(feeRateCacheUpdateIntervalSecs) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeBackgroundSyncConfig: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> BackgroundSyncConfig { + return + try BackgroundSyncConfig( + onchainWalletSyncIntervalSecs: FfiConverterUInt64.read(from: &buf), + lightningWalletSyncIntervalSecs: FfiConverterUInt64.read(from: &buf), + feeRateCacheUpdateIntervalSecs: FfiConverterUInt64.read(from: &buf) + ) + } + + public static func write(_ value: BackgroundSyncConfig, into buf: inout [UInt8]) { + FfiConverterUInt64.write(value.onchainWalletSyncIntervalSecs, into: &buf) + FfiConverterUInt64.write(value.lightningWalletSyncIntervalSecs, into: &buf) + FfiConverterUInt64.write(value.feeRateCacheUpdateIntervalSecs, into: &buf) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeBackgroundSyncConfig_lift(_ buf: RustBuffer) throws -> BackgroundSyncConfig { + return try FfiConverterTypeBackgroundSyncConfig.lift(buf) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeBackgroundSyncConfig_lower(_ value: BackgroundSyncConfig) -> RustBuffer { + return FfiConverterTypeBackgroundSyncConfig.lower(value) +} + +public struct BalanceDetails { + public var totalOnchainBalanceSats: UInt64 + public var spendableOnchainBalanceSats: UInt64 + public var totalAnchorChannelsReserveSats: UInt64 + public var totalLightningBalanceSats: UInt64 + public var lightningBalances: [LightningBalance] + public var pendingBalancesFromChannelClosures: [PendingSweepBalance] + + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(totalOnchainBalanceSats: UInt64, spendableOnchainBalanceSats: UInt64, totalAnchorChannelsReserveSats: UInt64, totalLightningBalanceSats: UInt64, lightningBalances: [LightningBalance], pendingBalancesFromChannelClosures: [PendingSweepBalance]) { + self.totalOnchainBalanceSats = totalOnchainBalanceSats + self.spendableOnchainBalanceSats = spendableOnchainBalanceSats + self.totalAnchorChannelsReserveSats = totalAnchorChannelsReserveSats + self.totalLightningBalanceSats = totalLightningBalanceSats + self.lightningBalances = lightningBalances + self.pendingBalancesFromChannelClosures = pendingBalancesFromChannelClosures + } +} + +extension BalanceDetails: Equatable, Hashable { + public static func == (lhs: BalanceDetails, rhs: BalanceDetails) -> Bool { + if lhs.totalOnchainBalanceSats != rhs.totalOnchainBalanceSats { + return false + } + if lhs.spendableOnchainBalanceSats != rhs.spendableOnchainBalanceSats { + return false + } + if lhs.totalAnchorChannelsReserveSats != rhs.totalAnchorChannelsReserveSats { + return false + } + if lhs.totalLightningBalanceSats != rhs.totalLightningBalanceSats { + return false + } + if lhs.lightningBalances != rhs.lightningBalances { + return false + } + if lhs.pendingBalancesFromChannelClosures != rhs.pendingBalancesFromChannelClosures { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(totalOnchainBalanceSats) + hasher.combine(spendableOnchainBalanceSats) + hasher.combine(totalAnchorChannelsReserveSats) + hasher.combine(totalLightningBalanceSats) + hasher.combine(lightningBalances) + hasher.combine(pendingBalancesFromChannelClosures) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeBalanceDetails: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> BalanceDetails { + return + try BalanceDetails( + totalOnchainBalanceSats: FfiConverterUInt64.read(from: &buf), + spendableOnchainBalanceSats: FfiConverterUInt64.read(from: &buf), + totalAnchorChannelsReserveSats: FfiConverterUInt64.read(from: &buf), + totalLightningBalanceSats: FfiConverterUInt64.read(from: &buf), + lightningBalances: FfiConverterSequenceTypeLightningBalance.read(from: &buf), + pendingBalancesFromChannelClosures: FfiConverterSequenceTypePendingSweepBalance.read(from: &buf) + ) + } + + public static func write(_ value: BalanceDetails, into buf: inout [UInt8]) { + FfiConverterUInt64.write(value.totalOnchainBalanceSats, into: &buf) + FfiConverterUInt64.write(value.spendableOnchainBalanceSats, into: &buf) + FfiConverterUInt64.write(value.totalAnchorChannelsReserveSats, into: &buf) + FfiConverterUInt64.write(value.totalLightningBalanceSats, into: &buf) + FfiConverterSequenceTypeLightningBalance.write(value.lightningBalances, into: &buf) + FfiConverterSequenceTypePendingSweepBalance.write(value.pendingBalancesFromChannelClosures, into: &buf) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeBalanceDetails_lift(_ buf: RustBuffer) throws -> BalanceDetails { + return try FfiConverterTypeBalanceDetails.lift(buf) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeBalanceDetails_lower(_ value: BalanceDetails) -> RustBuffer { + return FfiConverterTypeBalanceDetails.lower(value) +} + +public struct BestBlock { + public var blockHash: BlockHash + public var height: UInt32 + + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(blockHash: BlockHash, height: UInt32) { + self.blockHash = blockHash + self.height = height + } +} + +extension BestBlock: Equatable, Hashable { + public static func == (lhs: BestBlock, rhs: BestBlock) -> Bool { + if lhs.blockHash != rhs.blockHash { + return false + } + if lhs.height != rhs.height { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(blockHash) + hasher.combine(height) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeBestBlock: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> BestBlock { + return + try BestBlock( + blockHash: FfiConverterTypeBlockHash.read(from: &buf), + height: FfiConverterUInt32.read(from: &buf) + ) + } + + public static func write(_ value: BestBlock, into buf: inout [UInt8]) { + FfiConverterTypeBlockHash.write(value.blockHash, into: &buf) + FfiConverterUInt32.write(value.height, into: &buf) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeBestBlock_lift(_ buf: RustBuffer) throws -> BestBlock { + return try FfiConverterTypeBestBlock.lift(buf) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeBestBlock_lower(_ value: BestBlock) -> RustBuffer { + return FfiConverterTypeBestBlock.lower(value) +} + +public struct ChannelConfig { + public var forwardingFeeProportionalMillionths: UInt32 + public var forwardingFeeBaseMsat: UInt32 + public var cltvExpiryDelta: UInt16 + public var maxDustHtlcExposure: MaxDustHtlcExposure + public var forceCloseAvoidanceMaxFeeSatoshis: UInt64 + public var acceptUnderpayingHtlcs: Bool + + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(forwardingFeeProportionalMillionths: UInt32, forwardingFeeBaseMsat: UInt32, cltvExpiryDelta: UInt16, maxDustHtlcExposure: MaxDustHtlcExposure, forceCloseAvoidanceMaxFeeSatoshis: UInt64, acceptUnderpayingHtlcs: Bool) { + self.forwardingFeeProportionalMillionths = forwardingFeeProportionalMillionths + self.forwardingFeeBaseMsat = forwardingFeeBaseMsat + self.cltvExpiryDelta = cltvExpiryDelta + self.maxDustHtlcExposure = maxDustHtlcExposure + self.forceCloseAvoidanceMaxFeeSatoshis = forceCloseAvoidanceMaxFeeSatoshis + self.acceptUnderpayingHtlcs = acceptUnderpayingHtlcs + } +} + +extension ChannelConfig: Equatable, Hashable { + public static func == (lhs: ChannelConfig, rhs: ChannelConfig) -> Bool { + if lhs.forwardingFeeProportionalMillionths != rhs.forwardingFeeProportionalMillionths { + return false + } + if lhs.forwardingFeeBaseMsat != rhs.forwardingFeeBaseMsat { + return false + } + if lhs.cltvExpiryDelta != rhs.cltvExpiryDelta { + return false + } + if lhs.maxDustHtlcExposure != rhs.maxDustHtlcExposure { + return false + } + if lhs.forceCloseAvoidanceMaxFeeSatoshis != rhs.forceCloseAvoidanceMaxFeeSatoshis { + return false + } + if lhs.acceptUnderpayingHtlcs != rhs.acceptUnderpayingHtlcs { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(forwardingFeeProportionalMillionths) + hasher.combine(forwardingFeeBaseMsat) + hasher.combine(cltvExpiryDelta) + hasher.combine(maxDustHtlcExposure) + hasher.combine(forceCloseAvoidanceMaxFeeSatoshis) + hasher.combine(acceptUnderpayingHtlcs) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeChannelConfig: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ChannelConfig { + return + try ChannelConfig( + forwardingFeeProportionalMillionths: FfiConverterUInt32.read(from: &buf), + forwardingFeeBaseMsat: FfiConverterUInt32.read(from: &buf), + cltvExpiryDelta: FfiConverterUInt16.read(from: &buf), + maxDustHtlcExposure: FfiConverterTypeMaxDustHTLCExposure.read(from: &buf), + forceCloseAvoidanceMaxFeeSatoshis: FfiConverterUInt64.read(from: &buf), + acceptUnderpayingHtlcs: FfiConverterBool.read(from: &buf) + ) + } + + public static func write(_ value: ChannelConfig, into buf: inout [UInt8]) { + FfiConverterUInt32.write(value.forwardingFeeProportionalMillionths, into: &buf) + FfiConverterUInt32.write(value.forwardingFeeBaseMsat, into: &buf) + FfiConverterUInt16.write(value.cltvExpiryDelta, into: &buf) + FfiConverterTypeMaxDustHTLCExposure.write(value.maxDustHtlcExposure, into: &buf) + FfiConverterUInt64.write(value.forceCloseAvoidanceMaxFeeSatoshis, into: &buf) + FfiConverterBool.write(value.acceptUnderpayingHtlcs, into: &buf) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeChannelConfig_lift(_ buf: RustBuffer) throws -> ChannelConfig { + return try FfiConverterTypeChannelConfig.lift(buf) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeChannelConfig_lower(_ value: ChannelConfig) -> RustBuffer { + return FfiConverterTypeChannelConfig.lower(value) +} + +public struct ChannelDataMigration { + public var channelManager: [UInt8]? + public var channelMonitors: [[UInt8]] + + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(channelManager: [UInt8]?, channelMonitors: [[UInt8]]) { + self.channelManager = channelManager + self.channelMonitors = channelMonitors + } +} + +extension ChannelDataMigration: Equatable, Hashable { + public static func == (lhs: ChannelDataMigration, rhs: ChannelDataMigration) -> Bool { + if lhs.channelManager != rhs.channelManager { + return false + } + if lhs.channelMonitors != rhs.channelMonitors { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(channelManager) + hasher.combine(channelMonitors) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeChannelDataMigration: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ChannelDataMigration { + return + try ChannelDataMigration( + channelManager: FfiConverterOptionSequenceUInt8.read(from: &buf), + channelMonitors: FfiConverterSequenceSequenceUInt8.read(from: &buf) + ) + } + + public static func write(_ value: ChannelDataMigration, into buf: inout [UInt8]) { + FfiConverterOptionSequenceUInt8.write(value.channelManager, into: &buf) + FfiConverterSequenceSequenceUInt8.write(value.channelMonitors, into: &buf) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeChannelDataMigration_lift(_ buf: RustBuffer) throws -> ChannelDataMigration { + return try FfiConverterTypeChannelDataMigration.lift(buf) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeChannelDataMigration_lower(_ value: ChannelDataMigration) -> RustBuffer { + return FfiConverterTypeChannelDataMigration.lower(value) +} public struct ChannelDetails { public var channelId: ChannelId @@ -3416,10 +4883,11 @@ public struct ChannelDetails { public var inboundHtlcMinimumMsat: UInt64 public var inboundHtlcMaximumMsat: UInt64? public var config: ChannelConfig + public var claimableOnCloseSats: UInt64? - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(channelId: ChannelId, counterpartyNodeId: PublicKey, fundingTxo: OutPoint?, shortChannelId: UInt64?, outboundScidAlias: UInt64?, inboundScidAlias: UInt64?, channelValueSats: UInt64, unspendablePunishmentReserve: UInt64?, userChannelId: UserChannelId, feerateSatPer1000Weight: UInt32, outboundCapacityMsat: UInt64, inboundCapacityMsat: UInt64, confirmationsRequired: UInt32?, confirmations: UInt32?, isOutbound: Bool, isChannelReady: Bool, isUsable: Bool, isAnnounced: Bool, cltvExpiryDelta: UInt16?, counterpartyUnspendablePunishmentReserve: UInt64, counterpartyOutboundHtlcMinimumMsat: UInt64?, counterpartyOutboundHtlcMaximumMsat: UInt64?, counterpartyForwardingInfoFeeBaseMsat: UInt32?, counterpartyForwardingInfoFeeProportionalMillionths: UInt32?, counterpartyForwardingInfoCltvExpiryDelta: UInt16?, nextOutboundHtlcLimitMsat: UInt64, nextOutboundHtlcMinimumMsat: UInt64, forceCloseSpendDelay: UInt16?, inboundHtlcMinimumMsat: UInt64, inboundHtlcMaximumMsat: UInt64?, config: ChannelConfig) { + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(channelId: ChannelId, counterpartyNodeId: PublicKey, fundingTxo: OutPoint?, shortChannelId: UInt64?, outboundScidAlias: UInt64?, inboundScidAlias: UInt64?, channelValueSats: UInt64, unspendablePunishmentReserve: UInt64?, userChannelId: UserChannelId, feerateSatPer1000Weight: UInt32, outboundCapacityMsat: UInt64, inboundCapacityMsat: UInt64, confirmationsRequired: UInt32?, confirmations: UInt32?, isOutbound: Bool, isChannelReady: Bool, isUsable: Bool, isAnnounced: Bool, cltvExpiryDelta: UInt16?, counterpartyUnspendablePunishmentReserve: UInt64, counterpartyOutboundHtlcMinimumMsat: UInt64?, counterpartyOutboundHtlcMaximumMsat: UInt64?, counterpartyForwardingInfoFeeBaseMsat: UInt32?, counterpartyForwardingInfoFeeProportionalMillionths: UInt32?, counterpartyForwardingInfoCltvExpiryDelta: UInt16?, nextOutboundHtlcLimitMsat: UInt64, nextOutboundHtlcMinimumMsat: UInt64, forceCloseSpendDelay: UInt16?, inboundHtlcMinimumMsat: UInt64, inboundHtlcMaximumMsat: UInt64?, config: ChannelConfig, claimableOnCloseSats: UInt64?) { self.channelId = channelId self.counterpartyNodeId = counterpartyNodeId self.fundingTxo = fundingTxo @@ -3451,2132 +4919,3235 @@ public struct ChannelDetails { self.inboundHtlcMinimumMsat = inboundHtlcMinimumMsat self.inboundHtlcMaximumMsat = inboundHtlcMaximumMsat self.config = config + self.claimableOnCloseSats = claimableOnCloseSats + } +} + +extension ChannelDetails: Equatable, Hashable { + public static func == (lhs: ChannelDetails, rhs: ChannelDetails) -> Bool { + if lhs.channelId != rhs.channelId { + return false + } + if lhs.counterpartyNodeId != rhs.counterpartyNodeId { + return false + } + if lhs.fundingTxo != rhs.fundingTxo { + return false + } + if lhs.shortChannelId != rhs.shortChannelId { + return false + } + if lhs.outboundScidAlias != rhs.outboundScidAlias { + return false + } + if lhs.inboundScidAlias != rhs.inboundScidAlias { + return false + } + if lhs.channelValueSats != rhs.channelValueSats { + return false + } + if lhs.unspendablePunishmentReserve != rhs.unspendablePunishmentReserve { + return false + } + if lhs.userChannelId != rhs.userChannelId { + return false + } + if lhs.feerateSatPer1000Weight != rhs.feerateSatPer1000Weight { + return false + } + if lhs.outboundCapacityMsat != rhs.outboundCapacityMsat { + return false + } + if lhs.inboundCapacityMsat != rhs.inboundCapacityMsat { + return false + } + if lhs.confirmationsRequired != rhs.confirmationsRequired { + return false + } + if lhs.confirmations != rhs.confirmations { + return false + } + if lhs.isOutbound != rhs.isOutbound { + return false + } + if lhs.isChannelReady != rhs.isChannelReady { + return false + } + if lhs.isUsable != rhs.isUsable { + return false + } + if lhs.isAnnounced != rhs.isAnnounced { + return false + } + if lhs.cltvExpiryDelta != rhs.cltvExpiryDelta { + return false + } + if lhs.counterpartyUnspendablePunishmentReserve != rhs.counterpartyUnspendablePunishmentReserve { + return false + } + if lhs.counterpartyOutboundHtlcMinimumMsat != rhs.counterpartyOutboundHtlcMinimumMsat { + return false + } + if lhs.counterpartyOutboundHtlcMaximumMsat != rhs.counterpartyOutboundHtlcMaximumMsat { + return false + } + if lhs.counterpartyForwardingInfoFeeBaseMsat != rhs.counterpartyForwardingInfoFeeBaseMsat { + return false + } + if lhs.counterpartyForwardingInfoFeeProportionalMillionths != rhs.counterpartyForwardingInfoFeeProportionalMillionths { + return false + } + if lhs.counterpartyForwardingInfoCltvExpiryDelta != rhs.counterpartyForwardingInfoCltvExpiryDelta { + return false + } + if lhs.nextOutboundHtlcLimitMsat != rhs.nextOutboundHtlcLimitMsat { + return false + } + if lhs.nextOutboundHtlcMinimumMsat != rhs.nextOutboundHtlcMinimumMsat { + return false + } + if lhs.forceCloseSpendDelay != rhs.forceCloseSpendDelay { + return false + } + if lhs.inboundHtlcMinimumMsat != rhs.inboundHtlcMinimumMsat { + return false + } + if lhs.inboundHtlcMaximumMsat != rhs.inboundHtlcMaximumMsat { + return false + } + if lhs.config != rhs.config { + return false + } + if lhs.claimableOnCloseSats != rhs.claimableOnCloseSats { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(channelId) + hasher.combine(counterpartyNodeId) + hasher.combine(fundingTxo) + hasher.combine(shortChannelId) + hasher.combine(outboundScidAlias) + hasher.combine(inboundScidAlias) + hasher.combine(channelValueSats) + hasher.combine(unspendablePunishmentReserve) + hasher.combine(userChannelId) + hasher.combine(feerateSatPer1000Weight) + hasher.combine(outboundCapacityMsat) + hasher.combine(inboundCapacityMsat) + hasher.combine(confirmationsRequired) + hasher.combine(confirmations) + hasher.combine(isOutbound) + hasher.combine(isChannelReady) + hasher.combine(isUsable) + hasher.combine(isAnnounced) + hasher.combine(cltvExpiryDelta) + hasher.combine(counterpartyUnspendablePunishmentReserve) + hasher.combine(counterpartyOutboundHtlcMinimumMsat) + hasher.combine(counterpartyOutboundHtlcMaximumMsat) + hasher.combine(counterpartyForwardingInfoFeeBaseMsat) + hasher.combine(counterpartyForwardingInfoFeeProportionalMillionths) + hasher.combine(counterpartyForwardingInfoCltvExpiryDelta) + hasher.combine(nextOutboundHtlcLimitMsat) + hasher.combine(nextOutboundHtlcMinimumMsat) + hasher.combine(forceCloseSpendDelay) + hasher.combine(inboundHtlcMinimumMsat) + hasher.combine(inboundHtlcMaximumMsat) + hasher.combine(config) + hasher.combine(claimableOnCloseSats) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeChannelDetails: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ChannelDetails { + return + try ChannelDetails( + channelId: FfiConverterTypeChannelId.read(from: &buf), + counterpartyNodeId: FfiConverterTypePublicKey.read(from: &buf), + fundingTxo: FfiConverterOptionTypeOutPoint.read(from: &buf), + shortChannelId: FfiConverterOptionUInt64.read(from: &buf), + outboundScidAlias: FfiConverterOptionUInt64.read(from: &buf), + inboundScidAlias: FfiConverterOptionUInt64.read(from: &buf), + channelValueSats: FfiConverterUInt64.read(from: &buf), + unspendablePunishmentReserve: FfiConverterOptionUInt64.read(from: &buf), + userChannelId: FfiConverterTypeUserChannelId.read(from: &buf), + feerateSatPer1000Weight: FfiConverterUInt32.read(from: &buf), + outboundCapacityMsat: FfiConverterUInt64.read(from: &buf), + inboundCapacityMsat: FfiConverterUInt64.read(from: &buf), + confirmationsRequired: FfiConverterOptionUInt32.read(from: &buf), + confirmations: FfiConverterOptionUInt32.read(from: &buf), + isOutbound: FfiConverterBool.read(from: &buf), + isChannelReady: FfiConverterBool.read(from: &buf), + isUsable: FfiConverterBool.read(from: &buf), + isAnnounced: FfiConverterBool.read(from: &buf), + cltvExpiryDelta: FfiConverterOptionUInt16.read(from: &buf), + counterpartyUnspendablePunishmentReserve: FfiConverterUInt64.read(from: &buf), + counterpartyOutboundHtlcMinimumMsat: FfiConverterOptionUInt64.read(from: &buf), + counterpartyOutboundHtlcMaximumMsat: FfiConverterOptionUInt64.read(from: &buf), + counterpartyForwardingInfoFeeBaseMsat: FfiConverterOptionUInt32.read(from: &buf), + counterpartyForwardingInfoFeeProportionalMillionths: FfiConverterOptionUInt32.read(from: &buf), + counterpartyForwardingInfoCltvExpiryDelta: FfiConverterOptionUInt16.read(from: &buf), + nextOutboundHtlcLimitMsat: FfiConverterUInt64.read(from: &buf), + nextOutboundHtlcMinimumMsat: FfiConverterUInt64.read(from: &buf), + forceCloseSpendDelay: FfiConverterOptionUInt16.read(from: &buf), + inboundHtlcMinimumMsat: FfiConverterUInt64.read(from: &buf), + inboundHtlcMaximumMsat: FfiConverterOptionUInt64.read(from: &buf), + config: FfiConverterTypeChannelConfig.read(from: &buf), + claimableOnCloseSats: FfiConverterOptionUInt64.read(from: &buf) + ) + } + + public static func write(_ value: ChannelDetails, into buf: inout [UInt8]) { + FfiConverterTypeChannelId.write(value.channelId, into: &buf) + FfiConverterTypePublicKey.write(value.counterpartyNodeId, into: &buf) + FfiConverterOptionTypeOutPoint.write(value.fundingTxo, into: &buf) + FfiConverterOptionUInt64.write(value.shortChannelId, into: &buf) + FfiConverterOptionUInt64.write(value.outboundScidAlias, into: &buf) + FfiConverterOptionUInt64.write(value.inboundScidAlias, into: &buf) + FfiConverterUInt64.write(value.channelValueSats, into: &buf) + FfiConverterOptionUInt64.write(value.unspendablePunishmentReserve, into: &buf) + FfiConverterTypeUserChannelId.write(value.userChannelId, into: &buf) + FfiConverterUInt32.write(value.feerateSatPer1000Weight, into: &buf) + FfiConverterUInt64.write(value.outboundCapacityMsat, into: &buf) + FfiConverterUInt64.write(value.inboundCapacityMsat, into: &buf) + FfiConverterOptionUInt32.write(value.confirmationsRequired, into: &buf) + FfiConverterOptionUInt32.write(value.confirmations, into: &buf) + FfiConverterBool.write(value.isOutbound, into: &buf) + FfiConverterBool.write(value.isChannelReady, into: &buf) + FfiConverterBool.write(value.isUsable, into: &buf) + FfiConverterBool.write(value.isAnnounced, into: &buf) + FfiConverterOptionUInt16.write(value.cltvExpiryDelta, into: &buf) + FfiConverterUInt64.write(value.counterpartyUnspendablePunishmentReserve, into: &buf) + FfiConverterOptionUInt64.write(value.counterpartyOutboundHtlcMinimumMsat, into: &buf) + FfiConverterOptionUInt64.write(value.counterpartyOutboundHtlcMaximumMsat, into: &buf) + FfiConverterOptionUInt32.write(value.counterpartyForwardingInfoFeeBaseMsat, into: &buf) + FfiConverterOptionUInt32.write(value.counterpartyForwardingInfoFeeProportionalMillionths, into: &buf) + FfiConverterOptionUInt16.write(value.counterpartyForwardingInfoCltvExpiryDelta, into: &buf) + FfiConverterUInt64.write(value.nextOutboundHtlcLimitMsat, into: &buf) + FfiConverterUInt64.write(value.nextOutboundHtlcMinimumMsat, into: &buf) + FfiConverterOptionUInt16.write(value.forceCloseSpendDelay, into: &buf) + FfiConverterUInt64.write(value.inboundHtlcMinimumMsat, into: &buf) + FfiConverterOptionUInt64.write(value.inboundHtlcMaximumMsat, into: &buf) + FfiConverterTypeChannelConfig.write(value.config, into: &buf) + FfiConverterOptionUInt64.write(value.claimableOnCloseSats, into: &buf) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeChannelDetails_lift(_ buf: RustBuffer) throws -> ChannelDetails { + return try FfiConverterTypeChannelDetails.lift(buf) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeChannelDetails_lower(_ value: ChannelDetails) -> RustBuffer { + return FfiConverterTypeChannelDetails.lower(value) +} + +public struct ChannelInfo { + public var nodeOne: NodeId + public var oneToTwo: ChannelUpdateInfo? + public var nodeTwo: NodeId + public var twoToOne: ChannelUpdateInfo? + public var capacitySats: UInt64? + + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(nodeOne: NodeId, oneToTwo: ChannelUpdateInfo?, nodeTwo: NodeId, twoToOne: ChannelUpdateInfo?, capacitySats: UInt64?) { + self.nodeOne = nodeOne + self.oneToTwo = oneToTwo + self.nodeTwo = nodeTwo + self.twoToOne = twoToOne + self.capacitySats = capacitySats + } +} + +extension ChannelInfo: Equatable, Hashable { + public static func == (lhs: ChannelInfo, rhs: ChannelInfo) -> Bool { + if lhs.nodeOne != rhs.nodeOne { + return false + } + if lhs.oneToTwo != rhs.oneToTwo { + return false + } + if lhs.nodeTwo != rhs.nodeTwo { + return false + } + if lhs.twoToOne != rhs.twoToOne { + return false + } + if lhs.capacitySats != rhs.capacitySats { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(nodeOne) + hasher.combine(oneToTwo) + hasher.combine(nodeTwo) + hasher.combine(twoToOne) + hasher.combine(capacitySats) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeChannelInfo: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ChannelInfo { + return + try ChannelInfo( + nodeOne: FfiConverterTypeNodeId.read(from: &buf), + oneToTwo: FfiConverterOptionTypeChannelUpdateInfo.read(from: &buf), + nodeTwo: FfiConverterTypeNodeId.read(from: &buf), + twoToOne: FfiConverterOptionTypeChannelUpdateInfo.read(from: &buf), + capacitySats: FfiConverterOptionUInt64.read(from: &buf) + ) + } + + public static func write(_ value: ChannelInfo, into buf: inout [UInt8]) { + FfiConverterTypeNodeId.write(value.nodeOne, into: &buf) + FfiConverterOptionTypeChannelUpdateInfo.write(value.oneToTwo, into: &buf) + FfiConverterTypeNodeId.write(value.nodeTwo, into: &buf) + FfiConverterOptionTypeChannelUpdateInfo.write(value.twoToOne, into: &buf) + FfiConverterOptionUInt64.write(value.capacitySats, into: &buf) } } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeChannelInfo_lift(_ buf: RustBuffer) throws -> ChannelInfo { + return try FfiConverterTypeChannelInfo.lift(buf) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeChannelInfo_lower(_ value: ChannelInfo) -> RustBuffer { + return FfiConverterTypeChannelInfo.lower(value) +} +public struct ChannelUpdateInfo { + public var lastUpdate: UInt32 + public var enabled: Bool + public var cltvExpiryDelta: UInt16 + public var htlcMinimumMsat: UInt64 + public var htlcMaximumMsat: UInt64 + public var fees: RoutingFees -extension ChannelDetails: Equatable, Hashable { - public static func ==(lhs: ChannelDetails, rhs: ChannelDetails) -> Bool { - if lhs.channelId != rhs.channelId { + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(lastUpdate: UInt32, enabled: Bool, cltvExpiryDelta: UInt16, htlcMinimumMsat: UInt64, htlcMaximumMsat: UInt64, fees: RoutingFees) { + self.lastUpdate = lastUpdate + self.enabled = enabled + self.cltvExpiryDelta = cltvExpiryDelta + self.htlcMinimumMsat = htlcMinimumMsat + self.htlcMaximumMsat = htlcMaximumMsat + self.fees = fees + } +} + +extension ChannelUpdateInfo: Equatable, Hashable { + public static func == (lhs: ChannelUpdateInfo, rhs: ChannelUpdateInfo) -> Bool { + if lhs.lastUpdate != rhs.lastUpdate { return false } - if lhs.counterpartyNodeId != rhs.counterpartyNodeId { + if lhs.enabled != rhs.enabled { return false } - if lhs.fundingTxo != rhs.fundingTxo { + if lhs.cltvExpiryDelta != rhs.cltvExpiryDelta { return false } - if lhs.shortChannelId != rhs.shortChannelId { + if lhs.htlcMinimumMsat != rhs.htlcMinimumMsat { return false } - if lhs.outboundScidAlias != rhs.outboundScidAlias { + if lhs.htlcMaximumMsat != rhs.htlcMaximumMsat { return false } - if lhs.inboundScidAlias != rhs.inboundScidAlias { + if lhs.fees != rhs.fees { return false } - if lhs.channelValueSats != rhs.channelValueSats { + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(lastUpdate) + hasher.combine(enabled) + hasher.combine(cltvExpiryDelta) + hasher.combine(htlcMinimumMsat) + hasher.combine(htlcMaximumMsat) + hasher.combine(fees) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeChannelUpdateInfo: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ChannelUpdateInfo { + return + try ChannelUpdateInfo( + lastUpdate: FfiConverterUInt32.read(from: &buf), + enabled: FfiConverterBool.read(from: &buf), + cltvExpiryDelta: FfiConverterUInt16.read(from: &buf), + htlcMinimumMsat: FfiConverterUInt64.read(from: &buf), + htlcMaximumMsat: FfiConverterUInt64.read(from: &buf), + fees: FfiConverterTypeRoutingFees.read(from: &buf) + ) + } + + public static func write(_ value: ChannelUpdateInfo, into buf: inout [UInt8]) { + FfiConverterUInt32.write(value.lastUpdate, into: &buf) + FfiConverterBool.write(value.enabled, into: &buf) + FfiConverterUInt16.write(value.cltvExpiryDelta, into: &buf) + FfiConverterUInt64.write(value.htlcMinimumMsat, into: &buf) + FfiConverterUInt64.write(value.htlcMaximumMsat, into: &buf) + FfiConverterTypeRoutingFees.write(value.fees, into: &buf) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeChannelUpdateInfo_lift(_ buf: RustBuffer) throws -> ChannelUpdateInfo { + return try FfiConverterTypeChannelUpdateInfo.lift(buf) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeChannelUpdateInfo_lower(_ value: ChannelUpdateInfo) -> RustBuffer { + return FfiConverterTypeChannelUpdateInfo.lower(value) +} + +public struct Config { + public var storageDirPath: String + public var network: Network + public var listeningAddresses: [SocketAddress]? + public var announcementAddresses: [SocketAddress]? + public var nodeAlias: NodeAlias? + public var trustedPeers0conf: [PublicKey] + public var probingLiquidityLimitMultiplier: UInt64 + public var anchorChannelsConfig: AnchorChannelsConfig? + public var routeParameters: RouteParametersConfig? + public var scoringFeeParams: ScoringFeeParameters? + public var scoringDecayParams: ScoringDecayParameters? + public var includeUntrustedPendingInSpendable: Bool + public var addressType: AddressType + public var addressTypesToMonitor: [AddressType] + public var onchainWalletAccounts: [OnchainWalletAccountConfig] + + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(storageDirPath: String, network: Network, listeningAddresses: [SocketAddress]?, announcementAddresses: [SocketAddress]?, nodeAlias: NodeAlias?, trustedPeers0conf: [PublicKey], probingLiquidityLimitMultiplier: UInt64, anchorChannelsConfig: AnchorChannelsConfig?, routeParameters: RouteParametersConfig?, scoringFeeParams: ScoringFeeParameters?, scoringDecayParams: ScoringDecayParameters?, includeUntrustedPendingInSpendable: Bool, addressType: AddressType, addressTypesToMonitor: [AddressType], onchainWalletAccounts: [OnchainWalletAccountConfig]) { + self.storageDirPath = storageDirPath + self.network = network + self.listeningAddresses = listeningAddresses + self.announcementAddresses = announcementAddresses + self.nodeAlias = nodeAlias + self.trustedPeers0conf = trustedPeers0conf + self.probingLiquidityLimitMultiplier = probingLiquidityLimitMultiplier + self.anchorChannelsConfig = anchorChannelsConfig + self.routeParameters = routeParameters + self.scoringFeeParams = scoringFeeParams + self.scoringDecayParams = scoringDecayParams + self.includeUntrustedPendingInSpendable = includeUntrustedPendingInSpendable + self.addressType = addressType + self.addressTypesToMonitor = addressTypesToMonitor + self.onchainWalletAccounts = onchainWalletAccounts + } +} + +extension Config: Equatable, Hashable { + public static func == (lhs: Config, rhs: Config) -> Bool { + if lhs.storageDirPath != rhs.storageDirPath { return false } - if lhs.unspendablePunishmentReserve != rhs.unspendablePunishmentReserve { + if lhs.network != rhs.network { return false } - if lhs.userChannelId != rhs.userChannelId { + if lhs.listeningAddresses != rhs.listeningAddresses { return false } - if lhs.feerateSatPer1000Weight != rhs.feerateSatPer1000Weight { + if lhs.announcementAddresses != rhs.announcementAddresses { return false } - if lhs.outboundCapacityMsat != rhs.outboundCapacityMsat { + if lhs.nodeAlias != rhs.nodeAlias { return false } - if lhs.inboundCapacityMsat != rhs.inboundCapacityMsat { + if lhs.trustedPeers0conf != rhs.trustedPeers0conf { return false } - if lhs.confirmationsRequired != rhs.confirmationsRequired { + if lhs.probingLiquidityLimitMultiplier != rhs.probingLiquidityLimitMultiplier { return false } - if lhs.confirmations != rhs.confirmations { + if lhs.anchorChannelsConfig != rhs.anchorChannelsConfig { return false } - if lhs.isOutbound != rhs.isOutbound { + if lhs.routeParameters != rhs.routeParameters { return false } - if lhs.isChannelReady != rhs.isChannelReady { + if lhs.scoringFeeParams != rhs.scoringFeeParams { return false } - if lhs.isUsable != rhs.isUsable { + if lhs.scoringDecayParams != rhs.scoringDecayParams { return false } - if lhs.isAnnounced != rhs.isAnnounced { + if lhs.includeUntrustedPendingInSpendable != rhs.includeUntrustedPendingInSpendable { return false } - if lhs.cltvExpiryDelta != rhs.cltvExpiryDelta { + if lhs.addressType != rhs.addressType { return false } - if lhs.counterpartyUnspendablePunishmentReserve != rhs.counterpartyUnspendablePunishmentReserve { + if lhs.addressTypesToMonitor != rhs.addressTypesToMonitor { return false } - if lhs.counterpartyOutboundHtlcMinimumMsat != rhs.counterpartyOutboundHtlcMinimumMsat { + if lhs.onchainWalletAccounts != rhs.onchainWalletAccounts { return false } - if lhs.counterpartyOutboundHtlcMaximumMsat != rhs.counterpartyOutboundHtlcMaximumMsat { + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(storageDirPath) + hasher.combine(network) + hasher.combine(listeningAddresses) + hasher.combine(announcementAddresses) + hasher.combine(nodeAlias) + hasher.combine(trustedPeers0conf) + hasher.combine(probingLiquidityLimitMultiplier) + hasher.combine(anchorChannelsConfig) + hasher.combine(routeParameters) + hasher.combine(scoringFeeParams) + hasher.combine(scoringDecayParams) + hasher.combine(includeUntrustedPendingInSpendable) + hasher.combine(addressType) + hasher.combine(addressTypesToMonitor) + hasher.combine(onchainWalletAccounts) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeConfig: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Config { + return + try Config( + storageDirPath: FfiConverterString.read(from: &buf), + network: FfiConverterTypeNetwork.read(from: &buf), + listeningAddresses: FfiConverterOptionSequenceTypeSocketAddress.read(from: &buf), + announcementAddresses: FfiConverterOptionSequenceTypeSocketAddress.read(from: &buf), + nodeAlias: FfiConverterOptionTypeNodeAlias.read(from: &buf), + trustedPeers0conf: FfiConverterSequenceTypePublicKey.read(from: &buf), + probingLiquidityLimitMultiplier: FfiConverterUInt64.read(from: &buf), + anchorChannelsConfig: FfiConverterOptionTypeAnchorChannelsConfig.read(from: &buf), + routeParameters: FfiConverterOptionTypeRouteParametersConfig.read(from: &buf), + scoringFeeParams: FfiConverterOptionTypeScoringFeeParameters.read(from: &buf), + scoringDecayParams: FfiConverterOptionTypeScoringDecayParameters.read(from: &buf), + includeUntrustedPendingInSpendable: FfiConverterBool.read(from: &buf), + addressType: FfiConverterTypeAddressType.read(from: &buf), + addressTypesToMonitor: FfiConverterSequenceTypeAddressType.read(from: &buf), + onchainWalletAccounts: FfiConverterSequenceTypeOnchainWalletAccountConfig.read(from: &buf) + ) + } + + public static func write(_ value: Config, into buf: inout [UInt8]) { + FfiConverterString.write(value.storageDirPath, into: &buf) + FfiConverterTypeNetwork.write(value.network, into: &buf) + FfiConverterOptionSequenceTypeSocketAddress.write(value.listeningAddresses, into: &buf) + FfiConverterOptionSequenceTypeSocketAddress.write(value.announcementAddresses, into: &buf) + FfiConverterOptionTypeNodeAlias.write(value.nodeAlias, into: &buf) + FfiConverterSequenceTypePublicKey.write(value.trustedPeers0conf, into: &buf) + FfiConverterUInt64.write(value.probingLiquidityLimitMultiplier, into: &buf) + FfiConverterOptionTypeAnchorChannelsConfig.write(value.anchorChannelsConfig, into: &buf) + FfiConverterOptionTypeRouteParametersConfig.write(value.routeParameters, into: &buf) + FfiConverterOptionTypeScoringFeeParameters.write(value.scoringFeeParams, into: &buf) + FfiConverterOptionTypeScoringDecayParameters.write(value.scoringDecayParams, into: &buf) + FfiConverterBool.write(value.includeUntrustedPendingInSpendable, into: &buf) + FfiConverterTypeAddressType.write(value.addressType, into: &buf) + FfiConverterSequenceTypeAddressType.write(value.addressTypesToMonitor, into: &buf) + FfiConverterSequenceTypeOnchainWalletAccountConfig.write(value.onchainWalletAccounts, into: &buf) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeConfig_lift(_ buf: RustBuffer) throws -> Config { + return try FfiConverterTypeConfig.lift(buf) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeConfig_lower(_ value: Config) -> RustBuffer { + return FfiConverterTypeConfig.lower(value) +} + +public struct CustomTlvRecord { + public var typeNum: UInt64 + public var value: [UInt8] + + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(typeNum: UInt64, value: [UInt8]) { + self.typeNum = typeNum + self.value = value + } +} + +extension CustomTlvRecord: Equatable, Hashable { + public static func == (lhs: CustomTlvRecord, rhs: CustomTlvRecord) -> Bool { + if lhs.typeNum != rhs.typeNum { return false } - if lhs.counterpartyForwardingInfoFeeBaseMsat != rhs.counterpartyForwardingInfoFeeBaseMsat { + if lhs.value != rhs.value { return false } - if lhs.counterpartyForwardingInfoFeeProportionalMillionths != rhs.counterpartyForwardingInfoFeeProportionalMillionths { + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(typeNum) + hasher.combine(value) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeCustomTlvRecord: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> CustomTlvRecord { + return + try CustomTlvRecord( + typeNum: FfiConverterUInt64.read(from: &buf), + value: FfiConverterSequenceUInt8.read(from: &buf) + ) + } + + public static func write(_ value: CustomTlvRecord, into buf: inout [UInt8]) { + FfiConverterUInt64.write(value.typeNum, into: &buf) + FfiConverterSequenceUInt8.write(value.value, into: &buf) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeCustomTlvRecord_lift(_ buf: RustBuffer) throws -> CustomTlvRecord { + return try FfiConverterTypeCustomTlvRecord.lift(buf) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeCustomTlvRecord_lower(_ value: CustomTlvRecord) -> RustBuffer { + return FfiConverterTypeCustomTlvRecord.lower(value) +} + +public struct ElectrumSyncConfig { + public var backgroundSyncConfig: BackgroundSyncConfig? + public var connectionTimeoutSecs: UInt64 + public var additionalWalletFullScanBatchSize: UInt32 + public var additionalWalletFullScanStopGap: UInt32 + + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(backgroundSyncConfig: BackgroundSyncConfig?, connectionTimeoutSecs: UInt64, additionalWalletFullScanBatchSize: UInt32, additionalWalletFullScanStopGap: UInt32) { + self.backgroundSyncConfig = backgroundSyncConfig + self.connectionTimeoutSecs = connectionTimeoutSecs + self.additionalWalletFullScanBatchSize = additionalWalletFullScanBatchSize + self.additionalWalletFullScanStopGap = additionalWalletFullScanStopGap + } +} + +extension ElectrumSyncConfig: Equatable, Hashable { + public static func == (lhs: ElectrumSyncConfig, rhs: ElectrumSyncConfig) -> Bool { + if lhs.backgroundSyncConfig != rhs.backgroundSyncConfig { return false } - if lhs.counterpartyForwardingInfoCltvExpiryDelta != rhs.counterpartyForwardingInfoCltvExpiryDelta { + if lhs.connectionTimeoutSecs != rhs.connectionTimeoutSecs { return false } - if lhs.nextOutboundHtlcLimitMsat != rhs.nextOutboundHtlcLimitMsat { + if lhs.additionalWalletFullScanBatchSize != rhs.additionalWalletFullScanBatchSize { + return false + } + if lhs.additionalWalletFullScanStopGap != rhs.additionalWalletFullScanStopGap { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(backgroundSyncConfig) + hasher.combine(connectionTimeoutSecs) + hasher.combine(additionalWalletFullScanBatchSize) + hasher.combine(additionalWalletFullScanStopGap) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeElectrumSyncConfig: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ElectrumSyncConfig { + return + try ElectrumSyncConfig( + backgroundSyncConfig: FfiConverterOptionTypeBackgroundSyncConfig.read(from: &buf), + connectionTimeoutSecs: FfiConverterUInt64.read(from: &buf), + additionalWalletFullScanBatchSize: FfiConverterUInt32.read(from: &buf), + additionalWalletFullScanStopGap: FfiConverterUInt32.read(from: &buf) + ) + } + + public static func write(_ value: ElectrumSyncConfig, into buf: inout [UInt8]) { + FfiConverterOptionTypeBackgroundSyncConfig.write(value.backgroundSyncConfig, into: &buf) + FfiConverterUInt64.write(value.connectionTimeoutSecs, into: &buf) + FfiConverterUInt32.write(value.additionalWalletFullScanBatchSize, into: &buf) + FfiConverterUInt32.write(value.additionalWalletFullScanStopGap, into: &buf) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeElectrumSyncConfig_lift(_ buf: RustBuffer) throws -> ElectrumSyncConfig { + return try FfiConverterTypeElectrumSyncConfig.lift(buf) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeElectrumSyncConfig_lower(_ value: ElectrumSyncConfig) -> RustBuffer { + return FfiConverterTypeElectrumSyncConfig.lower(value) +} + +public struct EsploraSyncConfig { + public var backgroundSyncConfig: BackgroundSyncConfig? + + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(backgroundSyncConfig: BackgroundSyncConfig?) { + self.backgroundSyncConfig = backgroundSyncConfig + } +} + +extension EsploraSyncConfig: Equatable, Hashable { + public static func == (lhs: EsploraSyncConfig, rhs: EsploraSyncConfig) -> Bool { + if lhs.backgroundSyncConfig != rhs.backgroundSyncConfig { return false } - if lhs.nextOutboundHtlcMinimumMsat != rhs.nextOutboundHtlcMinimumMsat { + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(backgroundSyncConfig) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeEsploraSyncConfig: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> EsploraSyncConfig { + return + try EsploraSyncConfig( + backgroundSyncConfig: FfiConverterOptionTypeBackgroundSyncConfig.read(from: &buf) + ) + } + + public static func write(_ value: EsploraSyncConfig, into buf: inout [UInt8]) { + FfiConverterOptionTypeBackgroundSyncConfig.write(value.backgroundSyncConfig, into: &buf) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeEsploraSyncConfig_lift(_ buf: RustBuffer) throws -> EsploraSyncConfig { + return try FfiConverterTypeEsploraSyncConfig.lift(buf) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeEsploraSyncConfig_lower(_ value: EsploraSyncConfig) -> RustBuffer { + return FfiConverterTypeEsploraSyncConfig.lower(value) +} + +public struct LspFeeLimits { + public var maxTotalOpeningFeeMsat: UInt64? + public var maxProportionalOpeningFeePpmMsat: UInt64? + + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(maxTotalOpeningFeeMsat: UInt64?, maxProportionalOpeningFeePpmMsat: UInt64?) { + self.maxTotalOpeningFeeMsat = maxTotalOpeningFeeMsat + self.maxProportionalOpeningFeePpmMsat = maxProportionalOpeningFeePpmMsat + } +} + +extension LspFeeLimits: Equatable, Hashable { + public static func == (lhs: LspFeeLimits, rhs: LspFeeLimits) -> Bool { + if lhs.maxTotalOpeningFeeMsat != rhs.maxTotalOpeningFeeMsat { return false } - if lhs.forceCloseSpendDelay != rhs.forceCloseSpendDelay { + if lhs.maxProportionalOpeningFeePpmMsat != rhs.maxProportionalOpeningFeePpmMsat { return false } - if lhs.inboundHtlcMinimumMsat != rhs.inboundHtlcMinimumMsat { + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(maxTotalOpeningFeeMsat) + hasher.combine(maxProportionalOpeningFeePpmMsat) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeLSPFeeLimits: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> LspFeeLimits { + return + try LspFeeLimits( + maxTotalOpeningFeeMsat: FfiConverterOptionUInt64.read(from: &buf), + maxProportionalOpeningFeePpmMsat: FfiConverterOptionUInt64.read(from: &buf) + ) + } + + public static func write(_ value: LspFeeLimits, into buf: inout [UInt8]) { + FfiConverterOptionUInt64.write(value.maxTotalOpeningFeeMsat, into: &buf) + FfiConverterOptionUInt64.write(value.maxProportionalOpeningFeePpmMsat, into: &buf) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeLSPFeeLimits_lift(_ buf: RustBuffer) throws -> LspFeeLimits { + return try FfiConverterTypeLSPFeeLimits.lift(buf) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeLSPFeeLimits_lower(_ value: LspFeeLimits) -> RustBuffer { + return FfiConverterTypeLSPFeeLimits.lower(value) +} + +public struct Lsps1Bolt11PaymentInfo { + public var state: Lsps1PaymentState + public var expiresAt: LspsDateTime + public var feeTotalSat: UInt64 + public var orderTotalSat: UInt64 + public var invoice: Bolt11Invoice + + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(state: Lsps1PaymentState, expiresAt: LspsDateTime, feeTotalSat: UInt64, orderTotalSat: UInt64, invoice: Bolt11Invoice) { + self.state = state + self.expiresAt = expiresAt + self.feeTotalSat = feeTotalSat + self.orderTotalSat = orderTotalSat + self.invoice = invoice + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeLSPS1Bolt11PaymentInfo: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Lsps1Bolt11PaymentInfo { + return + try Lsps1Bolt11PaymentInfo( + state: FfiConverterTypeLSPS1PaymentState.read(from: &buf), + expiresAt: FfiConverterTypeLSPSDateTime.read(from: &buf), + feeTotalSat: FfiConverterUInt64.read(from: &buf), + orderTotalSat: FfiConverterUInt64.read(from: &buf), + invoice: FfiConverterTypeBolt11Invoice.read(from: &buf) + ) + } + + public static func write(_ value: Lsps1Bolt11PaymentInfo, into buf: inout [UInt8]) { + FfiConverterTypeLSPS1PaymentState.write(value.state, into: &buf) + FfiConverterTypeLSPSDateTime.write(value.expiresAt, into: &buf) + FfiConverterUInt64.write(value.feeTotalSat, into: &buf) + FfiConverterUInt64.write(value.orderTotalSat, into: &buf) + FfiConverterTypeBolt11Invoice.write(value.invoice, into: &buf) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeLSPS1Bolt11PaymentInfo_lift(_ buf: RustBuffer) throws -> Lsps1Bolt11PaymentInfo { + return try FfiConverterTypeLSPS1Bolt11PaymentInfo.lift(buf) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeLSPS1Bolt11PaymentInfo_lower(_ value: Lsps1Bolt11PaymentInfo) -> RustBuffer { + return FfiConverterTypeLSPS1Bolt11PaymentInfo.lower(value) +} + +public struct Lsps1ChannelInfo { + public var fundedAt: LspsDateTime + public var fundingOutpoint: OutPoint + public var expiresAt: LspsDateTime + + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(fundedAt: LspsDateTime, fundingOutpoint: OutPoint, expiresAt: LspsDateTime) { + self.fundedAt = fundedAt + self.fundingOutpoint = fundingOutpoint + self.expiresAt = expiresAt + } +} + +extension Lsps1ChannelInfo: Equatable, Hashable { + public static func == (lhs: Lsps1ChannelInfo, rhs: Lsps1ChannelInfo) -> Bool { + if lhs.fundedAt != rhs.fundedAt { return false } - if lhs.inboundHtlcMaximumMsat != rhs.inboundHtlcMaximumMsat { + if lhs.fundingOutpoint != rhs.fundingOutpoint { return false } - if lhs.config != rhs.config { + if lhs.expiresAt != rhs.expiresAt { return false } return true } public func hash(into hasher: inout Hasher) { - hasher.combine(channelId) - hasher.combine(counterpartyNodeId) - hasher.combine(fundingTxo) - hasher.combine(shortChannelId) - hasher.combine(outboundScidAlias) - hasher.combine(inboundScidAlias) - hasher.combine(channelValueSats) - hasher.combine(unspendablePunishmentReserve) - hasher.combine(userChannelId) - hasher.combine(feerateSatPer1000Weight) - hasher.combine(outboundCapacityMsat) - hasher.combine(inboundCapacityMsat) - hasher.combine(confirmationsRequired) - hasher.combine(confirmations) - hasher.combine(isOutbound) - hasher.combine(isChannelReady) - hasher.combine(isUsable) - hasher.combine(isAnnounced) - hasher.combine(cltvExpiryDelta) - hasher.combine(counterpartyUnspendablePunishmentReserve) - hasher.combine(counterpartyOutboundHtlcMinimumMsat) - hasher.combine(counterpartyOutboundHtlcMaximumMsat) - hasher.combine(counterpartyForwardingInfoFeeBaseMsat) - hasher.combine(counterpartyForwardingInfoFeeProportionalMillionths) - hasher.combine(counterpartyForwardingInfoCltvExpiryDelta) - hasher.combine(nextOutboundHtlcLimitMsat) - hasher.combine(nextOutboundHtlcMinimumMsat) - hasher.combine(forceCloseSpendDelay) - hasher.combine(inboundHtlcMinimumMsat) - hasher.combine(inboundHtlcMaximumMsat) - hasher.combine(config) + hasher.combine(fundedAt) + hasher.combine(fundingOutpoint) + hasher.combine(expiresAt) } } - -public struct FfiConverterTypeChannelDetails: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ChannelDetails { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeLSPS1ChannelInfo: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Lsps1ChannelInfo { return - try ChannelDetails( - channelId: FfiConverterTypeChannelId.read(from: &buf), - counterpartyNodeId: FfiConverterTypePublicKey.read(from: &buf), - fundingTxo: FfiConverterOptionTypeOutPoint.read(from: &buf), - shortChannelId: FfiConverterOptionUInt64.read(from: &buf), - outboundScidAlias: FfiConverterOptionUInt64.read(from: &buf), - inboundScidAlias: FfiConverterOptionUInt64.read(from: &buf), - channelValueSats: FfiConverterUInt64.read(from: &buf), - unspendablePunishmentReserve: FfiConverterOptionUInt64.read(from: &buf), - userChannelId: FfiConverterTypeUserChannelId.read(from: &buf), - feerateSatPer1000Weight: FfiConverterUInt32.read(from: &buf), - outboundCapacityMsat: FfiConverterUInt64.read(from: &buf), - inboundCapacityMsat: FfiConverterUInt64.read(from: &buf), - confirmationsRequired: FfiConverterOptionUInt32.read(from: &buf), - confirmations: FfiConverterOptionUInt32.read(from: &buf), - isOutbound: FfiConverterBool.read(from: &buf), - isChannelReady: FfiConverterBool.read(from: &buf), - isUsable: FfiConverterBool.read(from: &buf), - isAnnounced: FfiConverterBool.read(from: &buf), - cltvExpiryDelta: FfiConverterOptionUInt16.read(from: &buf), - counterpartyUnspendablePunishmentReserve: FfiConverterUInt64.read(from: &buf), - counterpartyOutboundHtlcMinimumMsat: FfiConverterOptionUInt64.read(from: &buf), - counterpartyOutboundHtlcMaximumMsat: FfiConverterOptionUInt64.read(from: &buf), - counterpartyForwardingInfoFeeBaseMsat: FfiConverterOptionUInt32.read(from: &buf), - counterpartyForwardingInfoFeeProportionalMillionths: FfiConverterOptionUInt32.read(from: &buf), - counterpartyForwardingInfoCltvExpiryDelta: FfiConverterOptionUInt16.read(from: &buf), - nextOutboundHtlcLimitMsat: FfiConverterUInt64.read(from: &buf), - nextOutboundHtlcMinimumMsat: FfiConverterUInt64.read(from: &buf), - forceCloseSpendDelay: FfiConverterOptionUInt16.read(from: &buf), - inboundHtlcMinimumMsat: FfiConverterUInt64.read(from: &buf), - inboundHtlcMaximumMsat: FfiConverterOptionUInt64.read(from: &buf), - config: FfiConverterTypeChannelConfig.read(from: &buf) - ) + try Lsps1ChannelInfo( + fundedAt: FfiConverterTypeLSPSDateTime.read(from: &buf), + fundingOutpoint: FfiConverterTypeOutPoint.read(from: &buf), + expiresAt: FfiConverterTypeLSPSDateTime.read(from: &buf) + ) } - public static func write(_ value: ChannelDetails, into buf: inout [UInt8]) { - FfiConverterTypeChannelId.write(value.channelId, into: &buf) - FfiConverterTypePublicKey.write(value.counterpartyNodeId, into: &buf) - FfiConverterOptionTypeOutPoint.write(value.fundingTxo, into: &buf) - FfiConverterOptionUInt64.write(value.shortChannelId, into: &buf) - FfiConverterOptionUInt64.write(value.outboundScidAlias, into: &buf) - FfiConverterOptionUInt64.write(value.inboundScidAlias, into: &buf) - FfiConverterUInt64.write(value.channelValueSats, into: &buf) - FfiConverterOptionUInt64.write(value.unspendablePunishmentReserve, into: &buf) - FfiConverterTypeUserChannelId.write(value.userChannelId, into: &buf) - FfiConverterUInt32.write(value.feerateSatPer1000Weight, into: &buf) - FfiConverterUInt64.write(value.outboundCapacityMsat, into: &buf) - FfiConverterUInt64.write(value.inboundCapacityMsat, into: &buf) - FfiConverterOptionUInt32.write(value.confirmationsRequired, into: &buf) - FfiConverterOptionUInt32.write(value.confirmations, into: &buf) - FfiConverterBool.write(value.isOutbound, into: &buf) - FfiConverterBool.write(value.isChannelReady, into: &buf) - FfiConverterBool.write(value.isUsable, into: &buf) - FfiConverterBool.write(value.isAnnounced, into: &buf) - FfiConverterOptionUInt16.write(value.cltvExpiryDelta, into: &buf) - FfiConverterUInt64.write(value.counterpartyUnspendablePunishmentReserve, into: &buf) - FfiConverterOptionUInt64.write(value.counterpartyOutboundHtlcMinimumMsat, into: &buf) - FfiConverterOptionUInt64.write(value.counterpartyOutboundHtlcMaximumMsat, into: &buf) - FfiConverterOptionUInt32.write(value.counterpartyForwardingInfoFeeBaseMsat, into: &buf) - FfiConverterOptionUInt32.write(value.counterpartyForwardingInfoFeeProportionalMillionths, into: &buf) - FfiConverterOptionUInt16.write(value.counterpartyForwardingInfoCltvExpiryDelta, into: &buf) - FfiConverterUInt64.write(value.nextOutboundHtlcLimitMsat, into: &buf) - FfiConverterUInt64.write(value.nextOutboundHtlcMinimumMsat, into: &buf) - FfiConverterOptionUInt16.write(value.forceCloseSpendDelay, into: &buf) - FfiConverterUInt64.write(value.inboundHtlcMinimumMsat, into: &buf) - FfiConverterOptionUInt64.write(value.inboundHtlcMaximumMsat, into: &buf) - FfiConverterTypeChannelConfig.write(value.config, into: &buf) + public static func write(_ value: Lsps1ChannelInfo, into buf: inout [UInt8]) { + FfiConverterTypeLSPSDateTime.write(value.fundedAt, into: &buf) + FfiConverterTypeOutPoint.write(value.fundingOutpoint, into: &buf) + FfiConverterTypeLSPSDateTime.write(value.expiresAt, into: &buf) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeLSPS1ChannelInfo_lift(_ buf: RustBuffer) throws -> Lsps1ChannelInfo { + return try FfiConverterTypeLSPS1ChannelInfo.lift(buf) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeLSPS1ChannelInfo_lower(_ value: Lsps1ChannelInfo) -> RustBuffer { + return FfiConverterTypeLSPS1ChannelInfo.lower(value) +} + +public struct Lsps1OnchainPaymentInfo { + public var state: Lsps1PaymentState + public var expiresAt: LspsDateTime + public var feeTotalSat: UInt64 + public var orderTotalSat: UInt64 + public var address: Address + public var minOnchainPaymentConfirmations: UInt16? + public var minFeeFor0conf: FeeRate + public var refundOnchainAddress: Address? + + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(state: Lsps1PaymentState, expiresAt: LspsDateTime, feeTotalSat: UInt64, orderTotalSat: UInt64, address: Address, minOnchainPaymentConfirmations: UInt16?, minFeeFor0conf: FeeRate, refundOnchainAddress: Address?) { + self.state = state + self.expiresAt = expiresAt + self.feeTotalSat = feeTotalSat + self.orderTotalSat = orderTotalSat + self.address = address + self.minOnchainPaymentConfirmations = minOnchainPaymentConfirmations + self.minFeeFor0conf = minFeeFor0conf + self.refundOnchainAddress = refundOnchainAddress } } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeLSPS1OnchainPaymentInfo: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Lsps1OnchainPaymentInfo { + return + try Lsps1OnchainPaymentInfo( + state: FfiConverterTypeLSPS1PaymentState.read(from: &buf), + expiresAt: FfiConverterTypeLSPSDateTime.read(from: &buf), + feeTotalSat: FfiConverterUInt64.read(from: &buf), + orderTotalSat: FfiConverterUInt64.read(from: &buf), + address: FfiConverterTypeAddress.read(from: &buf), + minOnchainPaymentConfirmations: FfiConverterOptionUInt16.read(from: &buf), + minFeeFor0conf: FfiConverterTypeFeeRate.read(from: &buf), + refundOnchainAddress: FfiConverterOptionTypeAddress.read(from: &buf) + ) + } -public func FfiConverterTypeChannelDetails_lift(_ buf: RustBuffer) throws -> ChannelDetails { - return try FfiConverterTypeChannelDetails.lift(buf) + public static func write(_ value: Lsps1OnchainPaymentInfo, into buf: inout [UInt8]) { + FfiConverterTypeLSPS1PaymentState.write(value.state, into: &buf) + FfiConverterTypeLSPSDateTime.write(value.expiresAt, into: &buf) + FfiConverterUInt64.write(value.feeTotalSat, into: &buf) + FfiConverterUInt64.write(value.orderTotalSat, into: &buf) + FfiConverterTypeAddress.write(value.address, into: &buf) + FfiConverterOptionUInt16.write(value.minOnchainPaymentConfirmations, into: &buf) + FfiConverterTypeFeeRate.write(value.minFeeFor0conf, into: &buf) + FfiConverterOptionTypeAddress.write(value.refundOnchainAddress, into: &buf) + } } -public func FfiConverterTypeChannelDetails_lower(_ value: ChannelDetails) -> RustBuffer { - return FfiConverterTypeChannelDetails.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeLSPS1OnchainPaymentInfo_lift(_ buf: RustBuffer) throws -> Lsps1OnchainPaymentInfo { + return try FfiConverterTypeLSPS1OnchainPaymentInfo.lift(buf) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeLSPS1OnchainPaymentInfo_lower(_ value: Lsps1OnchainPaymentInfo) -> RustBuffer { + return FfiConverterTypeLSPS1OnchainPaymentInfo.lower(value) +} -public struct ChannelInfo { - public var nodeOne: NodeId - public var oneToTwo: ChannelUpdateInfo? - public var nodeTwo: NodeId - public var twoToOne: ChannelUpdateInfo? - public var capacitySats: UInt64? +public struct Lsps1OrderParams { + public var lspBalanceSat: UInt64 + public var clientBalanceSat: UInt64 + public var requiredChannelConfirmations: UInt16 + public var fundingConfirmsWithinBlocks: UInt16 + public var channelExpiryBlocks: UInt32 + public var token: String? + public var announceChannel: Bool - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(nodeOne: NodeId, oneToTwo: ChannelUpdateInfo?, nodeTwo: NodeId, twoToOne: ChannelUpdateInfo?, capacitySats: UInt64?) { - self.nodeOne = nodeOne - self.oneToTwo = oneToTwo - self.nodeTwo = nodeTwo - self.twoToOne = twoToOne - self.capacitySats = capacitySats + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(lspBalanceSat: UInt64, clientBalanceSat: UInt64, requiredChannelConfirmations: UInt16, fundingConfirmsWithinBlocks: UInt16, channelExpiryBlocks: UInt32, token: String?, announceChannel: Bool) { + self.lspBalanceSat = lspBalanceSat + self.clientBalanceSat = clientBalanceSat + self.requiredChannelConfirmations = requiredChannelConfirmations + self.fundingConfirmsWithinBlocks = fundingConfirmsWithinBlocks + self.channelExpiryBlocks = channelExpiryBlocks + self.token = token + self.announceChannel = announceChannel } } - - -extension ChannelInfo: Equatable, Hashable { - public static func ==(lhs: ChannelInfo, rhs: ChannelInfo) -> Bool { - if lhs.nodeOne != rhs.nodeOne { +extension Lsps1OrderParams: Equatable, Hashable { + public static func == (lhs: Lsps1OrderParams, rhs: Lsps1OrderParams) -> Bool { + if lhs.lspBalanceSat != rhs.lspBalanceSat { return false } - if lhs.oneToTwo != rhs.oneToTwo { + if lhs.clientBalanceSat != rhs.clientBalanceSat { return false } - if lhs.nodeTwo != rhs.nodeTwo { + if lhs.requiredChannelConfirmations != rhs.requiredChannelConfirmations { return false } - if lhs.twoToOne != rhs.twoToOne { + if lhs.fundingConfirmsWithinBlocks != rhs.fundingConfirmsWithinBlocks { return false } - if lhs.capacitySats != rhs.capacitySats { + if lhs.channelExpiryBlocks != rhs.channelExpiryBlocks { + return false + } + if lhs.token != rhs.token { + return false + } + if lhs.announceChannel != rhs.announceChannel { return false } return true } public func hash(into hasher: inout Hasher) { - hasher.combine(nodeOne) - hasher.combine(oneToTwo) - hasher.combine(nodeTwo) - hasher.combine(twoToOne) - hasher.combine(capacitySats) + hasher.combine(lspBalanceSat) + hasher.combine(clientBalanceSat) + hasher.combine(requiredChannelConfirmations) + hasher.combine(fundingConfirmsWithinBlocks) + hasher.combine(channelExpiryBlocks) + hasher.combine(token) + hasher.combine(announceChannel) } } - -public struct FfiConverterTypeChannelInfo: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ChannelInfo { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeLSPS1OrderParams: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Lsps1OrderParams { return - try ChannelInfo( - nodeOne: FfiConverterTypeNodeId.read(from: &buf), - oneToTwo: FfiConverterOptionTypeChannelUpdateInfo.read(from: &buf), - nodeTwo: FfiConverterTypeNodeId.read(from: &buf), - twoToOne: FfiConverterOptionTypeChannelUpdateInfo.read(from: &buf), - capacitySats: FfiConverterOptionUInt64.read(from: &buf) - ) + try Lsps1OrderParams( + lspBalanceSat: FfiConverterUInt64.read(from: &buf), + clientBalanceSat: FfiConverterUInt64.read(from: &buf), + requiredChannelConfirmations: FfiConverterUInt16.read(from: &buf), + fundingConfirmsWithinBlocks: FfiConverterUInt16.read(from: &buf), + channelExpiryBlocks: FfiConverterUInt32.read(from: &buf), + token: FfiConverterOptionString.read(from: &buf), + announceChannel: FfiConverterBool.read(from: &buf) + ) } - public static func write(_ value: ChannelInfo, into buf: inout [UInt8]) { - FfiConverterTypeNodeId.write(value.nodeOne, into: &buf) - FfiConverterOptionTypeChannelUpdateInfo.write(value.oneToTwo, into: &buf) - FfiConverterTypeNodeId.write(value.nodeTwo, into: &buf) - FfiConverterOptionTypeChannelUpdateInfo.write(value.twoToOne, into: &buf) - FfiConverterOptionUInt64.write(value.capacitySats, into: &buf) + public static func write(_ value: Lsps1OrderParams, into buf: inout [UInt8]) { + FfiConverterUInt64.write(value.lspBalanceSat, into: &buf) + FfiConverterUInt64.write(value.clientBalanceSat, into: &buf) + FfiConverterUInt16.write(value.requiredChannelConfirmations, into: &buf) + FfiConverterUInt16.write(value.fundingConfirmsWithinBlocks, into: &buf) + FfiConverterUInt32.write(value.channelExpiryBlocks, into: &buf) + FfiConverterOptionString.write(value.token, into: &buf) + FfiConverterBool.write(value.announceChannel, into: &buf) } } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeLSPS1OrderParams_lift(_ buf: RustBuffer) throws -> Lsps1OrderParams { + return try FfiConverterTypeLSPS1OrderParams.lift(buf) +} -public func FfiConverterTypeChannelInfo_lift(_ buf: RustBuffer) throws -> ChannelInfo { - return try FfiConverterTypeChannelInfo.lift(buf) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeLSPS1OrderParams_lower(_ value: Lsps1OrderParams) -> RustBuffer { + return FfiConverterTypeLSPS1OrderParams.lower(value) } -public func FfiConverterTypeChannelInfo_lower(_ value: ChannelInfo) -> RustBuffer { - return FfiConverterTypeChannelInfo.lower(value) +public struct Lsps1OrderStatus { + public var orderId: Lsps1OrderId + public var orderParams: Lsps1OrderParams + public var paymentOptions: Lsps1PaymentInfo + public var channelState: Lsps1ChannelInfo? + + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(orderId: Lsps1OrderId, orderParams: Lsps1OrderParams, paymentOptions: Lsps1PaymentInfo, channelState: Lsps1ChannelInfo?) { + self.orderId = orderId + self.orderParams = orderParams + self.paymentOptions = paymentOptions + self.channelState = channelState + } } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeLSPS1OrderStatus: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Lsps1OrderStatus { + return + try Lsps1OrderStatus( + orderId: FfiConverterTypeLSPS1OrderId.read(from: &buf), + orderParams: FfiConverterTypeLSPS1OrderParams.read(from: &buf), + paymentOptions: FfiConverterTypeLSPS1PaymentInfo.read(from: &buf), + channelState: FfiConverterOptionTypeLSPS1ChannelInfo.read(from: &buf) + ) + } -public struct ChannelOrderInfo { - public var fundedAt: DateTime - public var fundingOutpoint: OutPoint - public var expiresAt: DateTime + public static func write(_ value: Lsps1OrderStatus, into buf: inout [UInt8]) { + FfiConverterTypeLSPS1OrderId.write(value.orderId, into: &buf) + FfiConverterTypeLSPS1OrderParams.write(value.orderParams, into: &buf) + FfiConverterTypeLSPS1PaymentInfo.write(value.paymentOptions, into: &buf) + FfiConverterOptionTypeLSPS1ChannelInfo.write(value.channelState, into: &buf) + } +} - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(fundedAt: DateTime, fundingOutpoint: OutPoint, expiresAt: DateTime) { - self.fundedAt = fundedAt - self.fundingOutpoint = fundingOutpoint - self.expiresAt = expiresAt +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeLSPS1OrderStatus_lift(_ buf: RustBuffer) throws -> Lsps1OrderStatus { + return try FfiConverterTypeLSPS1OrderStatus.lift(buf) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeLSPS1OrderStatus_lower(_ value: Lsps1OrderStatus) -> RustBuffer { + return FfiConverterTypeLSPS1OrderStatus.lower(value) +} + +public struct Lsps1PaymentInfo { + public var bolt11: Lsps1Bolt11PaymentInfo? + public var onchain: Lsps1OnchainPaymentInfo? + + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(bolt11: Lsps1Bolt11PaymentInfo?, onchain: Lsps1OnchainPaymentInfo?) { + self.bolt11 = bolt11 + self.onchain = onchain + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeLSPS1PaymentInfo: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Lsps1PaymentInfo { + return + try Lsps1PaymentInfo( + bolt11: FfiConverterOptionTypeLSPS1Bolt11PaymentInfo.read(from: &buf), + onchain: FfiConverterOptionTypeLSPS1OnchainPaymentInfo.read(from: &buf) + ) + } + + public static func write(_ value: Lsps1PaymentInfo, into buf: inout [UInt8]) { + FfiConverterOptionTypeLSPS1Bolt11PaymentInfo.write(value.bolt11, into: &buf) + FfiConverterOptionTypeLSPS1OnchainPaymentInfo.write(value.onchain, into: &buf) } } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeLSPS1PaymentInfo_lift(_ buf: RustBuffer) throws -> Lsps1PaymentInfo { + return try FfiConverterTypeLSPS1PaymentInfo.lift(buf) +} +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeLSPS1PaymentInfo_lower(_ value: Lsps1PaymentInfo) -> RustBuffer { + return FfiConverterTypeLSPS1PaymentInfo.lower(value) +} -extension ChannelOrderInfo: Equatable, Hashable { - public static func ==(lhs: ChannelOrderInfo, rhs: ChannelOrderInfo) -> Bool { - if lhs.fundedAt != rhs.fundedAt { +public struct Lsps2ServiceConfig { + public var requireToken: String? + public var advertiseService: Bool + public var channelOpeningFeePpm: UInt32 + public var channelOverProvisioningPpm: UInt32 + public var minChannelOpeningFeeMsat: UInt64 + public var minChannelLifetime: UInt32 + public var maxClientToSelfDelay: UInt32 + public var minPaymentSizeMsat: UInt64 + public var maxPaymentSizeMsat: UInt64 + public var clientTrustsLsp: Bool + + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(requireToken: String?, advertiseService: Bool, channelOpeningFeePpm: UInt32, channelOverProvisioningPpm: UInt32, minChannelOpeningFeeMsat: UInt64, minChannelLifetime: UInt32, maxClientToSelfDelay: UInt32, minPaymentSizeMsat: UInt64, maxPaymentSizeMsat: UInt64, clientTrustsLsp: Bool) { + self.requireToken = requireToken + self.advertiseService = advertiseService + self.channelOpeningFeePpm = channelOpeningFeePpm + self.channelOverProvisioningPpm = channelOverProvisioningPpm + self.minChannelOpeningFeeMsat = minChannelOpeningFeeMsat + self.minChannelLifetime = minChannelLifetime + self.maxClientToSelfDelay = maxClientToSelfDelay + self.minPaymentSizeMsat = minPaymentSizeMsat + self.maxPaymentSizeMsat = maxPaymentSizeMsat + self.clientTrustsLsp = clientTrustsLsp + } +} + +extension Lsps2ServiceConfig: Equatable, Hashable { + public static func == (lhs: Lsps2ServiceConfig, rhs: Lsps2ServiceConfig) -> Bool { + if lhs.requireToken != rhs.requireToken { return false } - if lhs.fundingOutpoint != rhs.fundingOutpoint { + if lhs.advertiseService != rhs.advertiseService { return false } - if lhs.expiresAt != rhs.expiresAt { + if lhs.channelOpeningFeePpm != rhs.channelOpeningFeePpm { + return false + } + if lhs.channelOverProvisioningPpm != rhs.channelOverProvisioningPpm { + return false + } + if lhs.minChannelOpeningFeeMsat != rhs.minChannelOpeningFeeMsat { + return false + } + if lhs.minChannelLifetime != rhs.minChannelLifetime { + return false + } + if lhs.maxClientToSelfDelay != rhs.maxClientToSelfDelay { + return false + } + if lhs.minPaymentSizeMsat != rhs.minPaymentSizeMsat { + return false + } + if lhs.maxPaymentSizeMsat != rhs.maxPaymentSizeMsat { + return false + } + if lhs.clientTrustsLsp != rhs.clientTrustsLsp { return false } return true } public func hash(into hasher: inout Hasher) { - hasher.combine(fundedAt) - hasher.combine(fundingOutpoint) - hasher.combine(expiresAt) + hasher.combine(requireToken) + hasher.combine(advertiseService) + hasher.combine(channelOpeningFeePpm) + hasher.combine(channelOverProvisioningPpm) + hasher.combine(minChannelOpeningFeeMsat) + hasher.combine(minChannelLifetime) + hasher.combine(maxClientToSelfDelay) + hasher.combine(minPaymentSizeMsat) + hasher.combine(maxPaymentSizeMsat) + hasher.combine(clientTrustsLsp) } } - -public struct FfiConverterTypeChannelOrderInfo: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ChannelOrderInfo { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeLSPS2ServiceConfig: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Lsps2ServiceConfig { return - try ChannelOrderInfo( - fundedAt: FfiConverterTypeDateTime.read(from: &buf), - fundingOutpoint: FfiConverterTypeOutPoint.read(from: &buf), - expiresAt: FfiConverterTypeDateTime.read(from: &buf) - ) + try Lsps2ServiceConfig( + requireToken: FfiConverterOptionString.read(from: &buf), + advertiseService: FfiConverterBool.read(from: &buf), + channelOpeningFeePpm: FfiConverterUInt32.read(from: &buf), + channelOverProvisioningPpm: FfiConverterUInt32.read(from: &buf), + minChannelOpeningFeeMsat: FfiConverterUInt64.read(from: &buf), + minChannelLifetime: FfiConverterUInt32.read(from: &buf), + maxClientToSelfDelay: FfiConverterUInt32.read(from: &buf), + minPaymentSizeMsat: FfiConverterUInt64.read(from: &buf), + maxPaymentSizeMsat: FfiConverterUInt64.read(from: &buf), + clientTrustsLsp: FfiConverterBool.read(from: &buf) + ) } - public static func write(_ value: ChannelOrderInfo, into buf: inout [UInt8]) { - FfiConverterTypeDateTime.write(value.fundedAt, into: &buf) - FfiConverterTypeOutPoint.write(value.fundingOutpoint, into: &buf) - FfiConverterTypeDateTime.write(value.expiresAt, into: &buf) + public static func write(_ value: Lsps2ServiceConfig, into buf: inout [UInt8]) { + FfiConverterOptionString.write(value.requireToken, into: &buf) + FfiConverterBool.write(value.advertiseService, into: &buf) + FfiConverterUInt32.write(value.channelOpeningFeePpm, into: &buf) + FfiConverterUInt32.write(value.channelOverProvisioningPpm, into: &buf) + FfiConverterUInt64.write(value.minChannelOpeningFeeMsat, into: &buf) + FfiConverterUInt32.write(value.minChannelLifetime, into: &buf) + FfiConverterUInt32.write(value.maxClientToSelfDelay, into: &buf) + FfiConverterUInt64.write(value.minPaymentSizeMsat, into: &buf) + FfiConverterUInt64.write(value.maxPaymentSizeMsat, into: &buf) + FfiConverterBool.write(value.clientTrustsLsp, into: &buf) } } - -public func FfiConverterTypeChannelOrderInfo_lift(_ buf: RustBuffer) throws -> ChannelOrderInfo { - return try FfiConverterTypeChannelOrderInfo.lift(buf) -} - -public func FfiConverterTypeChannelOrderInfo_lower(_ value: ChannelOrderInfo) -> RustBuffer { - return FfiConverterTypeChannelOrderInfo.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeLSPS2ServiceConfig_lift(_ buf: RustBuffer) throws -> Lsps2ServiceConfig { + return try FfiConverterTypeLSPS2ServiceConfig.lift(buf) } - -public struct ChannelUpdateInfo { - public var lastUpdate: UInt32 - public var enabled: Bool - public var cltvExpiryDelta: UInt16 - public var htlcMinimumMsat: UInt64 - public var htlcMaximumMsat: UInt64 - public var fees: RoutingFees - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(lastUpdate: UInt32, enabled: Bool, cltvExpiryDelta: UInt16, htlcMinimumMsat: UInt64, htlcMaximumMsat: UInt64, fees: RoutingFees) { - self.lastUpdate = lastUpdate - self.enabled = enabled - self.cltvExpiryDelta = cltvExpiryDelta - self.htlcMinimumMsat = htlcMinimumMsat - self.htlcMaximumMsat = htlcMaximumMsat - self.fees = fees - } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeLSPS2ServiceConfig_lower(_ value: Lsps2ServiceConfig) -> RustBuffer { + return FfiConverterTypeLSPS2ServiceConfig.lower(value) } +public struct LogRecord { + public var level: LogLevel + public var args: String + public var modulePath: String + public var line: UInt32 + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(level: LogLevel, args: String, modulePath: String, line: UInt32) { + self.level = level + self.args = args + self.modulePath = modulePath + self.line = line + } +} -extension ChannelUpdateInfo: Equatable, Hashable { - public static func ==(lhs: ChannelUpdateInfo, rhs: ChannelUpdateInfo) -> Bool { - if lhs.lastUpdate != rhs.lastUpdate { - return false - } - if lhs.enabled != rhs.enabled { - return false - } - if lhs.cltvExpiryDelta != rhs.cltvExpiryDelta { +extension LogRecord: Equatable, Hashable { + public static func == (lhs: LogRecord, rhs: LogRecord) -> Bool { + if lhs.level != rhs.level { return false } - if lhs.htlcMinimumMsat != rhs.htlcMinimumMsat { + if lhs.args != rhs.args { return false } - if lhs.htlcMaximumMsat != rhs.htlcMaximumMsat { + if lhs.modulePath != rhs.modulePath { return false } - if lhs.fees != rhs.fees { + if lhs.line != rhs.line { return false } return true } public func hash(into hasher: inout Hasher) { - hasher.combine(lastUpdate) - hasher.combine(enabled) - hasher.combine(cltvExpiryDelta) - hasher.combine(htlcMinimumMsat) - hasher.combine(htlcMaximumMsat) - hasher.combine(fees) + hasher.combine(level) + hasher.combine(args) + hasher.combine(modulePath) + hasher.combine(line) } } - -public struct FfiConverterTypeChannelUpdateInfo: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ChannelUpdateInfo { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeLogRecord: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> LogRecord { return - try ChannelUpdateInfo( - lastUpdate: FfiConverterUInt32.read(from: &buf), - enabled: FfiConverterBool.read(from: &buf), - cltvExpiryDelta: FfiConverterUInt16.read(from: &buf), - htlcMinimumMsat: FfiConverterUInt64.read(from: &buf), - htlcMaximumMsat: FfiConverterUInt64.read(from: &buf), - fees: FfiConverterTypeRoutingFees.read(from: &buf) - ) + try LogRecord( + level: FfiConverterTypeLogLevel.read(from: &buf), + args: FfiConverterString.read(from: &buf), + modulePath: FfiConverterString.read(from: &buf), + line: FfiConverterUInt32.read(from: &buf) + ) } - public static func write(_ value: ChannelUpdateInfo, into buf: inout [UInt8]) { - FfiConverterUInt32.write(value.lastUpdate, into: &buf) - FfiConverterBool.write(value.enabled, into: &buf) - FfiConverterUInt16.write(value.cltvExpiryDelta, into: &buf) - FfiConverterUInt64.write(value.htlcMinimumMsat, into: &buf) - FfiConverterUInt64.write(value.htlcMaximumMsat, into: &buf) - FfiConverterTypeRoutingFees.write(value.fees, into: &buf) + public static func write(_ value: LogRecord, into buf: inout [UInt8]) { + FfiConverterTypeLogLevel.write(value.level, into: &buf) + FfiConverterString.write(value.args, into: &buf) + FfiConverterString.write(value.modulePath, into: &buf) + FfiConverterUInt32.write(value.line, into: &buf) } } - -public func FfiConverterTypeChannelUpdateInfo_lift(_ buf: RustBuffer) throws -> ChannelUpdateInfo { - return try FfiConverterTypeChannelUpdateInfo.lift(buf) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeLogRecord_lift(_ buf: RustBuffer) throws -> LogRecord { + return try FfiConverterTypeLogRecord.lift(buf) } -public func FfiConverterTypeChannelUpdateInfo_lower(_ value: ChannelUpdateInfo) -> RustBuffer { - return FfiConverterTypeChannelUpdateInfo.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeLogRecord_lower(_ value: LogRecord) -> RustBuffer { + return FfiConverterTypeLogRecord.lower(value) } +public struct NodeAnnouncementInfo { + public var lastUpdate: UInt32 + public var alias: String + public var addresses: [SocketAddress] -public struct Config { - public var storageDirPath: String - public var network: Network - public var listeningAddresses: [SocketAddress]? - public var announcementAddresses: [SocketAddress]? - public var nodeAlias: NodeAlias? - public var trustedPeers0conf: [PublicKey] - public var probingLiquidityLimitMultiplier: UInt64 - public var anchorChannelsConfig: AnchorChannelsConfig? - public var sendingParameters: SendingParameters? - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(storageDirPath: String, network: Network, listeningAddresses: [SocketAddress]?, announcementAddresses: [SocketAddress]?, nodeAlias: NodeAlias?, trustedPeers0conf: [PublicKey], probingLiquidityLimitMultiplier: UInt64, anchorChannelsConfig: AnchorChannelsConfig?, sendingParameters: SendingParameters?) { - self.storageDirPath = storageDirPath - self.network = network - self.listeningAddresses = listeningAddresses - self.announcementAddresses = announcementAddresses - self.nodeAlias = nodeAlias - self.trustedPeers0conf = trustedPeers0conf - self.probingLiquidityLimitMultiplier = probingLiquidityLimitMultiplier - self.anchorChannelsConfig = anchorChannelsConfig - self.sendingParameters = sendingParameters + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(lastUpdate: UInt32, alias: String, addresses: [SocketAddress]) { + self.lastUpdate = lastUpdate + self.alias = alias + self.addresses = addresses } } - - -extension Config: Equatable, Hashable { - public static func ==(lhs: Config, rhs: Config) -> Bool { - if lhs.storageDirPath != rhs.storageDirPath { - return false - } - if lhs.network != rhs.network { - return false - } - if lhs.listeningAddresses != rhs.listeningAddresses { - return false - } - if lhs.announcementAddresses != rhs.announcementAddresses { - return false - } - if lhs.nodeAlias != rhs.nodeAlias { - return false - } - if lhs.trustedPeers0conf != rhs.trustedPeers0conf { - return false - } - if lhs.probingLiquidityLimitMultiplier != rhs.probingLiquidityLimitMultiplier { +extension NodeAnnouncementInfo: Equatable, Hashable { + public static func == (lhs: NodeAnnouncementInfo, rhs: NodeAnnouncementInfo) -> Bool { + if lhs.lastUpdate != rhs.lastUpdate { return false } - if lhs.anchorChannelsConfig != rhs.anchorChannelsConfig { + if lhs.alias != rhs.alias { return false } - if lhs.sendingParameters != rhs.sendingParameters { + if lhs.addresses != rhs.addresses { return false } return true } public func hash(into hasher: inout Hasher) { - hasher.combine(storageDirPath) - hasher.combine(network) - hasher.combine(listeningAddresses) - hasher.combine(announcementAddresses) - hasher.combine(nodeAlias) - hasher.combine(trustedPeers0conf) - hasher.combine(probingLiquidityLimitMultiplier) - hasher.combine(anchorChannelsConfig) - hasher.combine(sendingParameters) + hasher.combine(lastUpdate) + hasher.combine(alias) + hasher.combine(addresses) } } - -public struct FfiConverterTypeConfig: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Config { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeNodeAnnouncementInfo: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> NodeAnnouncementInfo { return - try Config( - storageDirPath: FfiConverterString.read(from: &buf), - network: FfiConverterTypeNetwork.read(from: &buf), - listeningAddresses: FfiConverterOptionSequenceTypeSocketAddress.read(from: &buf), - announcementAddresses: FfiConverterOptionSequenceTypeSocketAddress.read(from: &buf), - nodeAlias: FfiConverterOptionTypeNodeAlias.read(from: &buf), - trustedPeers0conf: FfiConverterSequenceTypePublicKey.read(from: &buf), - probingLiquidityLimitMultiplier: FfiConverterUInt64.read(from: &buf), - anchorChannelsConfig: FfiConverterOptionTypeAnchorChannelsConfig.read(from: &buf), - sendingParameters: FfiConverterOptionTypeSendingParameters.read(from: &buf) - ) + try NodeAnnouncementInfo( + lastUpdate: FfiConverterUInt32.read(from: &buf), + alias: FfiConverterString.read(from: &buf), + addresses: FfiConverterSequenceTypeSocketAddress.read(from: &buf) + ) } - public static func write(_ value: Config, into buf: inout [UInt8]) { - FfiConverterString.write(value.storageDirPath, into: &buf) - FfiConverterTypeNetwork.write(value.network, into: &buf) - FfiConverterOptionSequenceTypeSocketAddress.write(value.listeningAddresses, into: &buf) - FfiConverterOptionSequenceTypeSocketAddress.write(value.announcementAddresses, into: &buf) - FfiConverterOptionTypeNodeAlias.write(value.nodeAlias, into: &buf) - FfiConverterSequenceTypePublicKey.write(value.trustedPeers0conf, into: &buf) - FfiConverterUInt64.write(value.probingLiquidityLimitMultiplier, into: &buf) - FfiConverterOptionTypeAnchorChannelsConfig.write(value.anchorChannelsConfig, into: &buf) - FfiConverterOptionTypeSendingParameters.write(value.sendingParameters, into: &buf) + public static func write(_ value: NodeAnnouncementInfo, into buf: inout [UInt8]) { + FfiConverterUInt32.write(value.lastUpdate, into: &buf) + FfiConverterString.write(value.alias, into: &buf) + FfiConverterSequenceTypeSocketAddress.write(value.addresses, into: &buf) } } - -public func FfiConverterTypeConfig_lift(_ buf: RustBuffer) throws -> Config { - return try FfiConverterTypeConfig.lift(buf) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeNodeAnnouncementInfo_lift(_ buf: RustBuffer) throws -> NodeAnnouncementInfo { + return try FfiConverterTypeNodeAnnouncementInfo.lift(buf) } -public func FfiConverterTypeConfig_lower(_ value: Config) -> RustBuffer { - return FfiConverterTypeConfig.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeNodeAnnouncementInfo_lower(_ value: NodeAnnouncementInfo) -> RustBuffer { + return FfiConverterTypeNodeAnnouncementInfo.lower(value) } +public struct NodeInfo { + public var channels: [UInt64] + public var announcementInfo: NodeAnnouncementInfo? -public struct CustomTlvRecord { - public var typeNum: UInt64 - public var value: [UInt8] - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(typeNum: UInt64, value: [UInt8]) { - self.typeNum = typeNum - self.value = value + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(channels: [UInt64], announcementInfo: NodeAnnouncementInfo?) { + self.channels = channels + self.announcementInfo = announcementInfo } } - - -extension CustomTlvRecord: Equatable, Hashable { - public static func ==(lhs: CustomTlvRecord, rhs: CustomTlvRecord) -> Bool { - if lhs.typeNum != rhs.typeNum { +extension NodeInfo: Equatable, Hashable { + public static func == (lhs: NodeInfo, rhs: NodeInfo) -> Bool { + if lhs.channels != rhs.channels { return false } - if lhs.value != rhs.value { + if lhs.announcementInfo != rhs.announcementInfo { return false } return true } public func hash(into hasher: inout Hasher) { - hasher.combine(typeNum) - hasher.combine(value) + hasher.combine(channels) + hasher.combine(announcementInfo) } } - -public struct FfiConverterTypeCustomTlvRecord: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> CustomTlvRecord { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeNodeInfo: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> NodeInfo { return - try CustomTlvRecord( - typeNum: FfiConverterUInt64.read(from: &buf), - value: FfiConverterSequenceUInt8.read(from: &buf) - ) + try NodeInfo( + channels: FfiConverterSequenceUInt64.read(from: &buf), + announcementInfo: FfiConverterOptionTypeNodeAnnouncementInfo.read(from: &buf) + ) } - public static func write(_ value: CustomTlvRecord, into buf: inout [UInt8]) { - FfiConverterUInt64.write(value.typeNum, into: &buf) - FfiConverterSequenceUInt8.write(value.value, into: &buf) + public static func write(_ value: NodeInfo, into buf: inout [UInt8]) { + FfiConverterSequenceUInt64.write(value.channels, into: &buf) + FfiConverterOptionTypeNodeAnnouncementInfo.write(value.announcementInfo, into: &buf) } } - -public func FfiConverterTypeCustomTlvRecord_lift(_ buf: RustBuffer) throws -> CustomTlvRecord { - return try FfiConverterTypeCustomTlvRecord.lift(buf) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeNodeInfo_lift(_ buf: RustBuffer) throws -> NodeInfo { + return try FfiConverterTypeNodeInfo.lift(buf) } -public func FfiConverterTypeCustomTlvRecord_lower(_ value: CustomTlvRecord) -> RustBuffer { - return FfiConverterTypeCustomTlvRecord.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeNodeInfo_lower(_ value: NodeInfo) -> RustBuffer { + return FfiConverterTypeNodeInfo.lower(value) } +public struct NodeStatus { + public var isRunning: Bool + public var currentBestBlock: BestBlock + public var latestLightningWalletSyncTimestamp: UInt64? + public var latestOnchainWalletSyncTimestamp: UInt64? + public var latestFeeRateCacheUpdateTimestamp: UInt64? + public var latestRgsSnapshotTimestamp: UInt64? + public var latestPathfindingScoresSyncTimestamp: UInt64? + public var latestNodeAnnouncementBroadcastTimestamp: UInt64? + public var latestChannelMonitorArchivalHeight: UInt32? -public struct ElectrumSyncConfig { - public var backgroundSyncConfig: BackgroundSyncConfig? - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(backgroundSyncConfig: BackgroundSyncConfig?) { - self.backgroundSyncConfig = backgroundSyncConfig + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(isRunning: Bool, currentBestBlock: BestBlock, latestLightningWalletSyncTimestamp: UInt64?, latestOnchainWalletSyncTimestamp: UInt64?, latestFeeRateCacheUpdateTimestamp: UInt64?, latestRgsSnapshotTimestamp: UInt64?, latestPathfindingScoresSyncTimestamp: UInt64?, latestNodeAnnouncementBroadcastTimestamp: UInt64?, latestChannelMonitorArchivalHeight: UInt32?) { + self.isRunning = isRunning + self.currentBestBlock = currentBestBlock + self.latestLightningWalletSyncTimestamp = latestLightningWalletSyncTimestamp + self.latestOnchainWalletSyncTimestamp = latestOnchainWalletSyncTimestamp + self.latestFeeRateCacheUpdateTimestamp = latestFeeRateCacheUpdateTimestamp + self.latestRgsSnapshotTimestamp = latestRgsSnapshotTimestamp + self.latestPathfindingScoresSyncTimestamp = latestPathfindingScoresSyncTimestamp + self.latestNodeAnnouncementBroadcastTimestamp = latestNodeAnnouncementBroadcastTimestamp + self.latestChannelMonitorArchivalHeight = latestChannelMonitorArchivalHeight } } - - -extension ElectrumSyncConfig: Equatable, Hashable { - public static func ==(lhs: ElectrumSyncConfig, rhs: ElectrumSyncConfig) -> Bool { - if lhs.backgroundSyncConfig != rhs.backgroundSyncConfig { +extension NodeStatus: Equatable, Hashable { + public static func == (lhs: NodeStatus, rhs: NodeStatus) -> Bool { + if lhs.isRunning != rhs.isRunning { + return false + } + if lhs.currentBestBlock != rhs.currentBestBlock { + return false + } + if lhs.latestLightningWalletSyncTimestamp != rhs.latestLightningWalletSyncTimestamp { + return false + } + if lhs.latestOnchainWalletSyncTimestamp != rhs.latestOnchainWalletSyncTimestamp { + return false + } + if lhs.latestFeeRateCacheUpdateTimestamp != rhs.latestFeeRateCacheUpdateTimestamp { + return false + } + if lhs.latestRgsSnapshotTimestamp != rhs.latestRgsSnapshotTimestamp { + return false + } + if lhs.latestPathfindingScoresSyncTimestamp != rhs.latestPathfindingScoresSyncTimestamp { + return false + } + if lhs.latestNodeAnnouncementBroadcastTimestamp != rhs.latestNodeAnnouncementBroadcastTimestamp { + return false + } + if lhs.latestChannelMonitorArchivalHeight != rhs.latestChannelMonitorArchivalHeight { return false } return true } public func hash(into hasher: inout Hasher) { - hasher.combine(backgroundSyncConfig) + hasher.combine(isRunning) + hasher.combine(currentBestBlock) + hasher.combine(latestLightningWalletSyncTimestamp) + hasher.combine(latestOnchainWalletSyncTimestamp) + hasher.combine(latestFeeRateCacheUpdateTimestamp) + hasher.combine(latestRgsSnapshotTimestamp) + hasher.combine(latestPathfindingScoresSyncTimestamp) + hasher.combine(latestNodeAnnouncementBroadcastTimestamp) + hasher.combine(latestChannelMonitorArchivalHeight) } } - -public struct FfiConverterTypeElectrumSyncConfig: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ElectrumSyncConfig { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeNodeStatus: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> NodeStatus { return - try ElectrumSyncConfig( - backgroundSyncConfig: FfiConverterOptionTypeBackgroundSyncConfig.read(from: &buf) - ) + try NodeStatus( + isRunning: FfiConverterBool.read(from: &buf), + currentBestBlock: FfiConverterTypeBestBlock.read(from: &buf), + latestLightningWalletSyncTimestamp: FfiConverterOptionUInt64.read(from: &buf), + latestOnchainWalletSyncTimestamp: FfiConverterOptionUInt64.read(from: &buf), + latestFeeRateCacheUpdateTimestamp: FfiConverterOptionUInt64.read(from: &buf), + latestRgsSnapshotTimestamp: FfiConverterOptionUInt64.read(from: &buf), + latestPathfindingScoresSyncTimestamp: FfiConverterOptionUInt64.read(from: &buf), + latestNodeAnnouncementBroadcastTimestamp: FfiConverterOptionUInt64.read(from: &buf), + latestChannelMonitorArchivalHeight: FfiConverterOptionUInt32.read(from: &buf) + ) } - public static func write(_ value: ElectrumSyncConfig, into buf: inout [UInt8]) { - FfiConverterOptionTypeBackgroundSyncConfig.write(value.backgroundSyncConfig, into: &buf) + public static func write(_ value: NodeStatus, into buf: inout [UInt8]) { + FfiConverterBool.write(value.isRunning, into: &buf) + FfiConverterTypeBestBlock.write(value.currentBestBlock, into: &buf) + FfiConverterOptionUInt64.write(value.latestLightningWalletSyncTimestamp, into: &buf) + FfiConverterOptionUInt64.write(value.latestOnchainWalletSyncTimestamp, into: &buf) + FfiConverterOptionUInt64.write(value.latestFeeRateCacheUpdateTimestamp, into: &buf) + FfiConverterOptionUInt64.write(value.latestRgsSnapshotTimestamp, into: &buf) + FfiConverterOptionUInt64.write(value.latestPathfindingScoresSyncTimestamp, into: &buf) + FfiConverterOptionUInt64.write(value.latestNodeAnnouncementBroadcastTimestamp, into: &buf) + FfiConverterOptionUInt32.write(value.latestChannelMonitorArchivalHeight, into: &buf) } } - -public func FfiConverterTypeElectrumSyncConfig_lift(_ buf: RustBuffer) throws -> ElectrumSyncConfig { - return try FfiConverterTypeElectrumSyncConfig.lift(buf) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeNodeStatus_lift(_ buf: RustBuffer) throws -> NodeStatus { + return try FfiConverterTypeNodeStatus.lift(buf) } -public func FfiConverterTypeElectrumSyncConfig_lower(_ value: ElectrumSyncConfig) -> RustBuffer { - return FfiConverterTypeElectrumSyncConfig.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeNodeStatus_lower(_ value: NodeStatus) -> RustBuffer { + return FfiConverterTypeNodeStatus.lower(value) } +public struct OnchainWalletAccount { + public var addressType: AddressType + public var accountIndex: UInt32 -public struct EsploraSyncConfig { - public var backgroundSyncConfig: BackgroundSyncConfig? - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(backgroundSyncConfig: BackgroundSyncConfig?) { - self.backgroundSyncConfig = backgroundSyncConfig + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(addressType: AddressType, accountIndex: UInt32) { + self.addressType = addressType + self.accountIndex = accountIndex } } - - -extension EsploraSyncConfig: Equatable, Hashable { - public static func ==(lhs: EsploraSyncConfig, rhs: EsploraSyncConfig) -> Bool { - if lhs.backgroundSyncConfig != rhs.backgroundSyncConfig { +extension OnchainWalletAccount: Equatable, Hashable { + public static func == (lhs: OnchainWalletAccount, rhs: OnchainWalletAccount) -> Bool { + if lhs.addressType != rhs.addressType { + return false + } + if lhs.accountIndex != rhs.accountIndex { return false } return true } public func hash(into hasher: inout Hasher) { - hasher.combine(backgroundSyncConfig) + hasher.combine(addressType) + hasher.combine(accountIndex) } } - -public struct FfiConverterTypeEsploraSyncConfig: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> EsploraSyncConfig { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeOnchainWalletAccount: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> OnchainWalletAccount { return - try EsploraSyncConfig( - backgroundSyncConfig: FfiConverterOptionTypeBackgroundSyncConfig.read(from: &buf) - ) + try OnchainWalletAccount( + addressType: FfiConverterTypeAddressType.read(from: &buf), + accountIndex: FfiConverterUInt32.read(from: &buf) + ) } - public static func write(_ value: EsploraSyncConfig, into buf: inout [UInt8]) { - FfiConverterOptionTypeBackgroundSyncConfig.write(value.backgroundSyncConfig, into: &buf) + public static func write(_ value: OnchainWalletAccount, into buf: inout [UInt8]) { + FfiConverterTypeAddressType.write(value.addressType, into: &buf) + FfiConverterUInt32.write(value.accountIndex, into: &buf) } } - -public func FfiConverterTypeEsploraSyncConfig_lift(_ buf: RustBuffer) throws -> EsploraSyncConfig { - return try FfiConverterTypeEsploraSyncConfig.lift(buf) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeOnchainWalletAccount_lift(_ buf: RustBuffer) throws -> OnchainWalletAccount { + return try FfiConverterTypeOnchainWalletAccount.lift(buf) } -public func FfiConverterTypeEsploraSyncConfig_lower(_ value: EsploraSyncConfig) -> RustBuffer { - return FfiConverterTypeEsploraSyncConfig.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeOnchainWalletAccount_lower(_ value: OnchainWalletAccount) -> RustBuffer { + return FfiConverterTypeOnchainWalletAccount.lower(value) } +public struct OnchainWalletAccountConfig { + public var addressType: AddressType + public var accountIndex: UInt32 + public var xpub: String -public struct LspFeeLimits { - public var maxTotalOpeningFeeMsat: UInt64? - public var maxProportionalOpeningFeePpmMsat: UInt64? - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(maxTotalOpeningFeeMsat: UInt64?, maxProportionalOpeningFeePpmMsat: UInt64?) { - self.maxTotalOpeningFeeMsat = maxTotalOpeningFeeMsat - self.maxProportionalOpeningFeePpmMsat = maxProportionalOpeningFeePpmMsat + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(addressType: AddressType, accountIndex: UInt32, xpub: String) { + self.addressType = addressType + self.accountIndex = accountIndex + self.xpub = xpub } } - - -extension LspFeeLimits: Equatable, Hashable { - public static func ==(lhs: LspFeeLimits, rhs: LspFeeLimits) -> Bool { - if lhs.maxTotalOpeningFeeMsat != rhs.maxTotalOpeningFeeMsat { +extension OnchainWalletAccountConfig: Equatable, Hashable { + public static func == (lhs: OnchainWalletAccountConfig, rhs: OnchainWalletAccountConfig) -> Bool { + if lhs.addressType != rhs.addressType { return false } - if lhs.maxProportionalOpeningFeePpmMsat != rhs.maxProportionalOpeningFeePpmMsat { + if lhs.accountIndex != rhs.accountIndex { + return false + } + if lhs.xpub != rhs.xpub { return false } return true } public func hash(into hasher: inout Hasher) { - hasher.combine(maxTotalOpeningFeeMsat) - hasher.combine(maxProportionalOpeningFeePpmMsat) + hasher.combine(addressType) + hasher.combine(accountIndex) + hasher.combine(xpub) } } - -public struct FfiConverterTypeLSPFeeLimits: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> LspFeeLimits { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeOnchainWalletAccountConfig: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> OnchainWalletAccountConfig { return - try LspFeeLimits( - maxTotalOpeningFeeMsat: FfiConverterOptionUInt64.read(from: &buf), - maxProportionalOpeningFeePpmMsat: FfiConverterOptionUInt64.read(from: &buf) - ) + try OnchainWalletAccountConfig( + addressType: FfiConverterTypeAddressType.read(from: &buf), + accountIndex: FfiConverterUInt32.read(from: &buf), + xpub: FfiConverterString.read(from: &buf) + ) } - public static func write(_ value: LspFeeLimits, into buf: inout [UInt8]) { - FfiConverterOptionUInt64.write(value.maxTotalOpeningFeeMsat, into: &buf) - FfiConverterOptionUInt64.write(value.maxProportionalOpeningFeePpmMsat, into: &buf) + public static func write(_ value: OnchainWalletAccountConfig, into buf: inout [UInt8]) { + FfiConverterTypeAddressType.write(value.addressType, into: &buf) + FfiConverterUInt32.write(value.accountIndex, into: &buf) + FfiConverterString.write(value.xpub, into: &buf) } } - -public func FfiConverterTypeLSPFeeLimits_lift(_ buf: RustBuffer) throws -> LspFeeLimits { - return try FfiConverterTypeLSPFeeLimits.lift(buf) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeOnchainWalletAccountConfig_lift(_ buf: RustBuffer) throws -> OnchainWalletAccountConfig { + return try FfiConverterTypeOnchainWalletAccountConfig.lift(buf) } -public func FfiConverterTypeLSPFeeLimits_lower(_ value: LspFeeLimits) -> RustBuffer { - return FfiConverterTypeLSPFeeLimits.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeOnchainWalletAccountConfig_lower(_ value: OnchainWalletAccountConfig) -> RustBuffer { + return FfiConverterTypeOnchainWalletAccountConfig.lower(value) } +public struct OutPoint { + public var txid: Txid + public var vout: UInt32 -public struct Lsps1OrderStatus { - public var orderId: OrderId - public var orderParams: OrderParameters - public var paymentOptions: PaymentInfo - public var channelState: ChannelOrderInfo? - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(orderId: OrderId, orderParams: OrderParameters, paymentOptions: PaymentInfo, channelState: ChannelOrderInfo?) { - self.orderId = orderId - self.orderParams = orderParams - self.paymentOptions = paymentOptions - self.channelState = channelState + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(txid: Txid, vout: UInt32) { + self.txid = txid + self.vout = vout } } +extension OutPoint: Equatable, Hashable { + public static func == (lhs: OutPoint, rhs: OutPoint) -> Bool { + if lhs.txid != rhs.txid { + return false + } + if lhs.vout != rhs.vout { + return false + } + return true + } + public func hash(into hasher: inout Hasher) { + hasher.combine(txid) + hasher.combine(vout) + } +} -public struct FfiConverterTypeLSPS1OrderStatus: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Lsps1OrderStatus { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeOutPoint: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> OutPoint { return - try Lsps1OrderStatus( - orderId: FfiConverterTypeOrderId.read(from: &buf), - orderParams: FfiConverterTypeOrderParameters.read(from: &buf), - paymentOptions: FfiConverterTypePaymentInfo.read(from: &buf), - channelState: FfiConverterOptionTypeChannelOrderInfo.read(from: &buf) - ) + try OutPoint( + txid: FfiConverterTypeTxid.read(from: &buf), + vout: FfiConverterUInt32.read(from: &buf) + ) } - public static func write(_ value: Lsps1OrderStatus, into buf: inout [UInt8]) { - FfiConverterTypeOrderId.write(value.orderId, into: &buf) - FfiConverterTypeOrderParameters.write(value.orderParams, into: &buf) - FfiConverterTypePaymentInfo.write(value.paymentOptions, into: &buf) - FfiConverterOptionTypeChannelOrderInfo.write(value.channelState, into: &buf) + public static func write(_ value: OutPoint, into buf: inout [UInt8]) { + FfiConverterTypeTxid.write(value.txid, into: &buf) + FfiConverterUInt32.write(value.vout, into: &buf) } } - -public func FfiConverterTypeLSPS1OrderStatus_lift(_ buf: RustBuffer) throws -> Lsps1OrderStatus { - return try FfiConverterTypeLSPS1OrderStatus.lift(buf) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeOutPoint_lift(_ buf: RustBuffer) throws -> OutPoint { + return try FfiConverterTypeOutPoint.lift(buf) } -public func FfiConverterTypeLSPS1OrderStatus_lower(_ value: Lsps1OrderStatus) -> RustBuffer { - return FfiConverterTypeLSPS1OrderStatus.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeOutPoint_lower(_ value: OutPoint) -> RustBuffer { + return FfiConverterTypeOutPoint.lower(value) } +public struct PaymentDetails { + public var id: PaymentId + public var kind: PaymentKind + public var amountMsat: UInt64? + public var feePaidMsat: UInt64? + public var direction: PaymentDirection + public var status: PaymentStatus + public var latestUpdateTimestamp: UInt64 -public struct Lsps2ServiceConfig { - public var requireToken: String? - public var advertiseService: Bool - public var channelOpeningFeePpm: UInt32 - public var channelOverProvisioningPpm: UInt32 - public var minChannelOpeningFeeMsat: UInt64 - public var minChannelLifetime: UInt32 - public var maxClientToSelfDelay: UInt32 - public var minPaymentSizeMsat: UInt64 - public var maxPaymentSizeMsat: UInt64 - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(requireToken: String?, advertiseService: Bool, channelOpeningFeePpm: UInt32, channelOverProvisioningPpm: UInt32, minChannelOpeningFeeMsat: UInt64, minChannelLifetime: UInt32, maxClientToSelfDelay: UInt32, minPaymentSizeMsat: UInt64, maxPaymentSizeMsat: UInt64) { - self.requireToken = requireToken - self.advertiseService = advertiseService - self.channelOpeningFeePpm = channelOpeningFeePpm - self.channelOverProvisioningPpm = channelOverProvisioningPpm - self.minChannelOpeningFeeMsat = minChannelOpeningFeeMsat - self.minChannelLifetime = minChannelLifetime - self.maxClientToSelfDelay = maxClientToSelfDelay - self.minPaymentSizeMsat = minPaymentSizeMsat - self.maxPaymentSizeMsat = maxPaymentSizeMsat + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(id: PaymentId, kind: PaymentKind, amountMsat: UInt64?, feePaidMsat: UInt64?, direction: PaymentDirection, status: PaymentStatus, latestUpdateTimestamp: UInt64) { + self.id = id + self.kind = kind + self.amountMsat = amountMsat + self.feePaidMsat = feePaidMsat + self.direction = direction + self.status = status + self.latestUpdateTimestamp = latestUpdateTimestamp } } - - -extension Lsps2ServiceConfig: Equatable, Hashable { - public static func ==(lhs: Lsps2ServiceConfig, rhs: Lsps2ServiceConfig) -> Bool { - if lhs.requireToken != rhs.requireToken { - return false - } - if lhs.advertiseService != rhs.advertiseService { - return false - } - if lhs.channelOpeningFeePpm != rhs.channelOpeningFeePpm { +extension PaymentDetails: Equatable, Hashable { + public static func == (lhs: PaymentDetails, rhs: PaymentDetails) -> Bool { + if lhs.id != rhs.id { return false } - if lhs.channelOverProvisioningPpm != rhs.channelOverProvisioningPpm { + if lhs.kind != rhs.kind { return false } - if lhs.minChannelOpeningFeeMsat != rhs.minChannelOpeningFeeMsat { + if lhs.amountMsat != rhs.amountMsat { return false } - if lhs.minChannelLifetime != rhs.minChannelLifetime { + if lhs.feePaidMsat != rhs.feePaidMsat { return false } - if lhs.maxClientToSelfDelay != rhs.maxClientToSelfDelay { + if lhs.direction != rhs.direction { return false } - if lhs.minPaymentSizeMsat != rhs.minPaymentSizeMsat { + if lhs.status != rhs.status { return false } - if lhs.maxPaymentSizeMsat != rhs.maxPaymentSizeMsat { + if lhs.latestUpdateTimestamp != rhs.latestUpdateTimestamp { return false } return true } public func hash(into hasher: inout Hasher) { - hasher.combine(requireToken) - hasher.combine(advertiseService) - hasher.combine(channelOpeningFeePpm) - hasher.combine(channelOverProvisioningPpm) - hasher.combine(minChannelOpeningFeeMsat) - hasher.combine(minChannelLifetime) - hasher.combine(maxClientToSelfDelay) - hasher.combine(minPaymentSizeMsat) - hasher.combine(maxPaymentSizeMsat) + hasher.combine(id) + hasher.combine(kind) + hasher.combine(amountMsat) + hasher.combine(feePaidMsat) + hasher.combine(direction) + hasher.combine(status) + hasher.combine(latestUpdateTimestamp) } } - -public struct FfiConverterTypeLSPS2ServiceConfig: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Lsps2ServiceConfig { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypePaymentDetails: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> PaymentDetails { return - try Lsps2ServiceConfig( - requireToken: FfiConverterOptionString.read(from: &buf), - advertiseService: FfiConverterBool.read(from: &buf), - channelOpeningFeePpm: FfiConverterUInt32.read(from: &buf), - channelOverProvisioningPpm: FfiConverterUInt32.read(from: &buf), - minChannelOpeningFeeMsat: FfiConverterUInt64.read(from: &buf), - minChannelLifetime: FfiConverterUInt32.read(from: &buf), - maxClientToSelfDelay: FfiConverterUInt32.read(from: &buf), - minPaymentSizeMsat: FfiConverterUInt64.read(from: &buf), - maxPaymentSizeMsat: FfiConverterUInt64.read(from: &buf) - ) + try PaymentDetails( + id: FfiConverterTypePaymentId.read(from: &buf), + kind: FfiConverterTypePaymentKind.read(from: &buf), + amountMsat: FfiConverterOptionUInt64.read(from: &buf), + feePaidMsat: FfiConverterOptionUInt64.read(from: &buf), + direction: FfiConverterTypePaymentDirection.read(from: &buf), + status: FfiConverterTypePaymentStatus.read(from: &buf), + latestUpdateTimestamp: FfiConverterUInt64.read(from: &buf) + ) } - public static func write(_ value: Lsps2ServiceConfig, into buf: inout [UInt8]) { - FfiConverterOptionString.write(value.requireToken, into: &buf) - FfiConverterBool.write(value.advertiseService, into: &buf) - FfiConverterUInt32.write(value.channelOpeningFeePpm, into: &buf) - FfiConverterUInt32.write(value.channelOverProvisioningPpm, into: &buf) - FfiConverterUInt64.write(value.minChannelOpeningFeeMsat, into: &buf) - FfiConverterUInt32.write(value.minChannelLifetime, into: &buf) - FfiConverterUInt32.write(value.maxClientToSelfDelay, into: &buf) - FfiConverterUInt64.write(value.minPaymentSizeMsat, into: &buf) - FfiConverterUInt64.write(value.maxPaymentSizeMsat, into: &buf) + public static func write(_ value: PaymentDetails, into buf: inout [UInt8]) { + FfiConverterTypePaymentId.write(value.id, into: &buf) + FfiConverterTypePaymentKind.write(value.kind, into: &buf) + FfiConverterOptionUInt64.write(value.amountMsat, into: &buf) + FfiConverterOptionUInt64.write(value.feePaidMsat, into: &buf) + FfiConverterTypePaymentDirection.write(value.direction, into: &buf) + FfiConverterTypePaymentStatus.write(value.status, into: &buf) + FfiConverterUInt64.write(value.latestUpdateTimestamp, into: &buf) } } - -public func FfiConverterTypeLSPS2ServiceConfig_lift(_ buf: RustBuffer) throws -> Lsps2ServiceConfig { - return try FfiConverterTypeLSPS2ServiceConfig.lift(buf) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypePaymentDetails_lift(_ buf: RustBuffer) throws -> PaymentDetails { + return try FfiConverterTypePaymentDetails.lift(buf) } -public func FfiConverterTypeLSPS2ServiceConfig_lower(_ value: Lsps2ServiceConfig) -> RustBuffer { - return FfiConverterTypeLSPS2ServiceConfig.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypePaymentDetails_lower(_ value: PaymentDetails) -> RustBuffer { + return FfiConverterTypePaymentDetails.lower(value) } +public struct PeerDetails { + public var nodeId: PublicKey + public var address: SocketAddress + public var isPersisted: Bool + public var isConnected: Bool -public struct LogRecord { - public var level: LogLevel - public var args: String - public var modulePath: String - public var line: UInt32 - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(level: LogLevel, args: String, modulePath: String, line: UInt32) { - self.level = level - self.args = args - self.modulePath = modulePath - self.line = line + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(nodeId: PublicKey, address: SocketAddress, isPersisted: Bool, isConnected: Bool) { + self.nodeId = nodeId + self.address = address + self.isPersisted = isPersisted + self.isConnected = isConnected } } - - -extension LogRecord: Equatable, Hashable { - public static func ==(lhs: LogRecord, rhs: LogRecord) -> Bool { - if lhs.level != rhs.level { +extension PeerDetails: Equatable, Hashable { + public static func == (lhs: PeerDetails, rhs: PeerDetails) -> Bool { + if lhs.nodeId != rhs.nodeId { return false } - if lhs.args != rhs.args { + if lhs.address != rhs.address { return false } - if lhs.modulePath != rhs.modulePath { + if lhs.isPersisted != rhs.isPersisted { return false } - if lhs.line != rhs.line { + if lhs.isConnected != rhs.isConnected { return false } return true } public func hash(into hasher: inout Hasher) { - hasher.combine(level) - hasher.combine(args) - hasher.combine(modulePath) - hasher.combine(line) + hasher.combine(nodeId) + hasher.combine(address) + hasher.combine(isPersisted) + hasher.combine(isConnected) } } - -public struct FfiConverterTypeLogRecord: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> LogRecord { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypePeerDetails: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> PeerDetails { return - try LogRecord( - level: FfiConverterTypeLogLevel.read(from: &buf), - args: FfiConverterString.read(from: &buf), - modulePath: FfiConverterString.read(from: &buf), - line: FfiConverterUInt32.read(from: &buf) - ) + try PeerDetails( + nodeId: FfiConverterTypePublicKey.read(from: &buf), + address: FfiConverterTypeSocketAddress.read(from: &buf), + isPersisted: FfiConverterBool.read(from: &buf), + isConnected: FfiConverterBool.read(from: &buf) + ) } - public static func write(_ value: LogRecord, into buf: inout [UInt8]) { - FfiConverterTypeLogLevel.write(value.level, into: &buf) - FfiConverterString.write(value.args, into: &buf) - FfiConverterString.write(value.modulePath, into: &buf) - FfiConverterUInt32.write(value.line, into: &buf) + public static func write(_ value: PeerDetails, into buf: inout [UInt8]) { + FfiConverterTypePublicKey.write(value.nodeId, into: &buf) + FfiConverterTypeSocketAddress.write(value.address, into: &buf) + FfiConverterBool.write(value.isPersisted, into: &buf) + FfiConverterBool.write(value.isConnected, into: &buf) } } - -public func FfiConverterTypeLogRecord_lift(_ buf: RustBuffer) throws -> LogRecord { - return try FfiConverterTypeLogRecord.lift(buf) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypePeerDetails_lift(_ buf: RustBuffer) throws -> PeerDetails { + return try FfiConverterTypePeerDetails.lift(buf) } -public func FfiConverterTypeLogRecord_lower(_ value: LogRecord) -> RustBuffer { - return FfiConverterTypeLogRecord.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypePeerDetails_lower(_ value: PeerDetails) -> RustBuffer { + return FfiConverterTypePeerDetails.lower(value) } +public struct ProbeHandle { + public var paymentHash: PaymentHash + public var paymentId: PaymentId -public struct NodeAnnouncementInfo { - public var lastUpdate: UInt32 - public var alias: String - public var addresses: [SocketAddress] - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(lastUpdate: UInt32, alias: String, addresses: [SocketAddress]) { - self.lastUpdate = lastUpdate - self.alias = alias - self.addresses = addresses + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(paymentHash: PaymentHash, paymentId: PaymentId) { + self.paymentHash = paymentHash + self.paymentId = paymentId } } - - -extension NodeAnnouncementInfo: Equatable, Hashable { - public static func ==(lhs: NodeAnnouncementInfo, rhs: NodeAnnouncementInfo) -> Bool { - if lhs.lastUpdate != rhs.lastUpdate { - return false - } - if lhs.alias != rhs.alias { +extension ProbeHandle: Equatable, Hashable { + public static func == (lhs: ProbeHandle, rhs: ProbeHandle) -> Bool { + if lhs.paymentHash != rhs.paymentHash { return false } - if lhs.addresses != rhs.addresses { + if lhs.paymentId != rhs.paymentId { return false } return true } public func hash(into hasher: inout Hasher) { - hasher.combine(lastUpdate) - hasher.combine(alias) - hasher.combine(addresses) + hasher.combine(paymentHash) + hasher.combine(paymentId) } } - -public struct FfiConverterTypeNodeAnnouncementInfo: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> NodeAnnouncementInfo { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeProbeHandle: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ProbeHandle { return - try NodeAnnouncementInfo( - lastUpdate: FfiConverterUInt32.read(from: &buf), - alias: FfiConverterString.read(from: &buf), - addresses: FfiConverterSequenceTypeSocketAddress.read(from: &buf) - ) + try ProbeHandle( + paymentHash: FfiConverterTypePaymentHash.read(from: &buf), + paymentId: FfiConverterTypePaymentId.read(from: &buf) + ) } - public static func write(_ value: NodeAnnouncementInfo, into buf: inout [UInt8]) { - FfiConverterUInt32.write(value.lastUpdate, into: &buf) - FfiConverterString.write(value.alias, into: &buf) - FfiConverterSequenceTypeSocketAddress.write(value.addresses, into: &buf) + public static func write(_ value: ProbeHandle, into buf: inout [UInt8]) { + FfiConverterTypePaymentHash.write(value.paymentHash, into: &buf) + FfiConverterTypePaymentId.write(value.paymentId, into: &buf) } } - -public func FfiConverterTypeNodeAnnouncementInfo_lift(_ buf: RustBuffer) throws -> NodeAnnouncementInfo { - return try FfiConverterTypeNodeAnnouncementInfo.lift(buf) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeProbeHandle_lift(_ buf: RustBuffer) throws -> ProbeHandle { + return try FfiConverterTypeProbeHandle.lift(buf) } -public func FfiConverterTypeNodeAnnouncementInfo_lower(_ value: NodeAnnouncementInfo) -> RustBuffer { - return FfiConverterTypeNodeAnnouncementInfo.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeProbeHandle_lower(_ value: ProbeHandle) -> RustBuffer { + return FfiConverterTypeProbeHandle.lower(value) } +public struct RouteHintHop { + public var srcNodeId: PublicKey + public var shortChannelId: UInt64 + public var cltvExpiryDelta: UInt16 + public var htlcMinimumMsat: UInt64? + public var htlcMaximumMsat: UInt64? + public var fees: RoutingFees -public struct NodeInfo { - public var channels: [UInt64] - public var announcementInfo: NodeAnnouncementInfo? - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(channels: [UInt64], announcementInfo: NodeAnnouncementInfo?) { - self.channels = channels - self.announcementInfo = announcementInfo + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(srcNodeId: PublicKey, shortChannelId: UInt64, cltvExpiryDelta: UInt16, htlcMinimumMsat: UInt64?, htlcMaximumMsat: UInt64?, fees: RoutingFees) { + self.srcNodeId = srcNodeId + self.shortChannelId = shortChannelId + self.cltvExpiryDelta = cltvExpiryDelta + self.htlcMinimumMsat = htlcMinimumMsat + self.htlcMaximumMsat = htlcMaximumMsat + self.fees = fees } } - - -extension NodeInfo: Equatable, Hashable { - public static func ==(lhs: NodeInfo, rhs: NodeInfo) -> Bool { - if lhs.channels != rhs.channels { +extension RouteHintHop: Equatable, Hashable { + public static func == (lhs: RouteHintHop, rhs: RouteHintHop) -> Bool { + if lhs.srcNodeId != rhs.srcNodeId { return false } - if lhs.announcementInfo != rhs.announcementInfo { + if lhs.shortChannelId != rhs.shortChannelId { + return false + } + if lhs.cltvExpiryDelta != rhs.cltvExpiryDelta { + return false + } + if lhs.htlcMinimumMsat != rhs.htlcMinimumMsat { + return false + } + if lhs.htlcMaximumMsat != rhs.htlcMaximumMsat { + return false + } + if lhs.fees != rhs.fees { return false } return true } public func hash(into hasher: inout Hasher) { - hasher.combine(channels) - hasher.combine(announcementInfo) + hasher.combine(srcNodeId) + hasher.combine(shortChannelId) + hasher.combine(cltvExpiryDelta) + hasher.combine(htlcMinimumMsat) + hasher.combine(htlcMaximumMsat) + hasher.combine(fees) } } - -public struct FfiConverterTypeNodeInfo: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> NodeInfo { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeRouteHintHop: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> RouteHintHop { return - try NodeInfo( - channels: FfiConverterSequenceUInt64.read(from: &buf), - announcementInfo: FfiConverterOptionTypeNodeAnnouncementInfo.read(from: &buf) - ) + try RouteHintHop( + srcNodeId: FfiConverterTypePublicKey.read(from: &buf), + shortChannelId: FfiConverterUInt64.read(from: &buf), + cltvExpiryDelta: FfiConverterUInt16.read(from: &buf), + htlcMinimumMsat: FfiConverterOptionUInt64.read(from: &buf), + htlcMaximumMsat: FfiConverterOptionUInt64.read(from: &buf), + fees: FfiConverterTypeRoutingFees.read(from: &buf) + ) } - public static func write(_ value: NodeInfo, into buf: inout [UInt8]) { - FfiConverterSequenceUInt64.write(value.channels, into: &buf) - FfiConverterOptionTypeNodeAnnouncementInfo.write(value.announcementInfo, into: &buf) + public static func write(_ value: RouteHintHop, into buf: inout [UInt8]) { + FfiConverterTypePublicKey.write(value.srcNodeId, into: &buf) + FfiConverterUInt64.write(value.shortChannelId, into: &buf) + FfiConverterUInt16.write(value.cltvExpiryDelta, into: &buf) + FfiConverterOptionUInt64.write(value.htlcMinimumMsat, into: &buf) + FfiConverterOptionUInt64.write(value.htlcMaximumMsat, into: &buf) + FfiConverterTypeRoutingFees.write(value.fees, into: &buf) } } - -public func FfiConverterTypeNodeInfo_lift(_ buf: RustBuffer) throws -> NodeInfo { - return try FfiConverterTypeNodeInfo.lift(buf) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeRouteHintHop_lift(_ buf: RustBuffer) throws -> RouteHintHop { + return try FfiConverterTypeRouteHintHop.lift(buf) } -public func FfiConverterTypeNodeInfo_lower(_ value: NodeInfo) -> RustBuffer { - return FfiConverterTypeNodeInfo.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeRouteHintHop_lower(_ value: RouteHintHop) -> RustBuffer { + return FfiConverterTypeRouteHintHop.lower(value) } +public struct RouteParametersConfig { + public var maxTotalRoutingFeeMsat: UInt64? + public var maxTotalCltvExpiryDelta: UInt32 + public var maxPathCount: UInt8 + public var maxChannelSaturationPowerOfHalf: UInt8 -public struct NodeStatus { - public var isRunning: Bool - public var isListening: Bool - public var currentBestBlock: BestBlock - public var latestLightningWalletSyncTimestamp: UInt64? - public var latestOnchainWalletSyncTimestamp: UInt64? - public var latestFeeRateCacheUpdateTimestamp: UInt64? - public var latestRgsSnapshotTimestamp: UInt64? - public var latestNodeAnnouncementBroadcastTimestamp: UInt64? - public var latestChannelMonitorArchivalHeight: UInt32? - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(isRunning: Bool, isListening: Bool, currentBestBlock: BestBlock, latestLightningWalletSyncTimestamp: UInt64?, latestOnchainWalletSyncTimestamp: UInt64?, latestFeeRateCacheUpdateTimestamp: UInt64?, latestRgsSnapshotTimestamp: UInt64?, latestNodeAnnouncementBroadcastTimestamp: UInt64?, latestChannelMonitorArchivalHeight: UInt32?) { - self.isRunning = isRunning - self.isListening = isListening - self.currentBestBlock = currentBestBlock - self.latestLightningWalletSyncTimestamp = latestLightningWalletSyncTimestamp - self.latestOnchainWalletSyncTimestamp = latestOnchainWalletSyncTimestamp - self.latestFeeRateCacheUpdateTimestamp = latestFeeRateCacheUpdateTimestamp - self.latestRgsSnapshotTimestamp = latestRgsSnapshotTimestamp - self.latestNodeAnnouncementBroadcastTimestamp = latestNodeAnnouncementBroadcastTimestamp - self.latestChannelMonitorArchivalHeight = latestChannelMonitorArchivalHeight + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(maxTotalRoutingFeeMsat: UInt64?, maxTotalCltvExpiryDelta: UInt32, maxPathCount: UInt8, maxChannelSaturationPowerOfHalf: UInt8) { + self.maxTotalRoutingFeeMsat = maxTotalRoutingFeeMsat + self.maxTotalCltvExpiryDelta = maxTotalCltvExpiryDelta + self.maxPathCount = maxPathCount + self.maxChannelSaturationPowerOfHalf = maxChannelSaturationPowerOfHalf } } - - -extension NodeStatus: Equatable, Hashable { - public static func ==(lhs: NodeStatus, rhs: NodeStatus) -> Bool { - if lhs.isRunning != rhs.isRunning { - return false - } - if lhs.isListening != rhs.isListening { - return false - } - if lhs.currentBestBlock != rhs.currentBestBlock { - return false - } - if lhs.latestLightningWalletSyncTimestamp != rhs.latestLightningWalletSyncTimestamp { - return false - } - if lhs.latestOnchainWalletSyncTimestamp != rhs.latestOnchainWalletSyncTimestamp { - return false - } - if lhs.latestFeeRateCacheUpdateTimestamp != rhs.latestFeeRateCacheUpdateTimestamp { +extension RouteParametersConfig: Equatable, Hashable { + public static func == (lhs: RouteParametersConfig, rhs: RouteParametersConfig) -> Bool { + if lhs.maxTotalRoutingFeeMsat != rhs.maxTotalRoutingFeeMsat { return false } - if lhs.latestRgsSnapshotTimestamp != rhs.latestRgsSnapshotTimestamp { + if lhs.maxTotalCltvExpiryDelta != rhs.maxTotalCltvExpiryDelta { return false } - if lhs.latestNodeAnnouncementBroadcastTimestamp != rhs.latestNodeAnnouncementBroadcastTimestamp { + if lhs.maxPathCount != rhs.maxPathCount { return false } - if lhs.latestChannelMonitorArchivalHeight != rhs.latestChannelMonitorArchivalHeight { + if lhs.maxChannelSaturationPowerOfHalf != rhs.maxChannelSaturationPowerOfHalf { return false } return true } public func hash(into hasher: inout Hasher) { - hasher.combine(isRunning) - hasher.combine(isListening) - hasher.combine(currentBestBlock) - hasher.combine(latestLightningWalletSyncTimestamp) - hasher.combine(latestOnchainWalletSyncTimestamp) - hasher.combine(latestFeeRateCacheUpdateTimestamp) - hasher.combine(latestRgsSnapshotTimestamp) - hasher.combine(latestNodeAnnouncementBroadcastTimestamp) - hasher.combine(latestChannelMonitorArchivalHeight) + hasher.combine(maxTotalRoutingFeeMsat) + hasher.combine(maxTotalCltvExpiryDelta) + hasher.combine(maxPathCount) + hasher.combine(maxChannelSaturationPowerOfHalf) } } - -public struct FfiConverterTypeNodeStatus: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> NodeStatus { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeRouteParametersConfig: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> RouteParametersConfig { return - try NodeStatus( - isRunning: FfiConverterBool.read(from: &buf), - isListening: FfiConverterBool.read(from: &buf), - currentBestBlock: FfiConverterTypeBestBlock.read(from: &buf), - latestLightningWalletSyncTimestamp: FfiConverterOptionUInt64.read(from: &buf), - latestOnchainWalletSyncTimestamp: FfiConverterOptionUInt64.read(from: &buf), - latestFeeRateCacheUpdateTimestamp: FfiConverterOptionUInt64.read(from: &buf), - latestRgsSnapshotTimestamp: FfiConverterOptionUInt64.read(from: &buf), - latestNodeAnnouncementBroadcastTimestamp: FfiConverterOptionUInt64.read(from: &buf), - latestChannelMonitorArchivalHeight: FfiConverterOptionUInt32.read(from: &buf) - ) + try RouteParametersConfig( + maxTotalRoutingFeeMsat: FfiConverterOptionUInt64.read(from: &buf), + maxTotalCltvExpiryDelta: FfiConverterUInt32.read(from: &buf), + maxPathCount: FfiConverterUInt8.read(from: &buf), + maxChannelSaturationPowerOfHalf: FfiConverterUInt8.read(from: &buf) + ) } - public static func write(_ value: NodeStatus, into buf: inout [UInt8]) { - FfiConverterBool.write(value.isRunning, into: &buf) - FfiConverterBool.write(value.isListening, into: &buf) - FfiConverterTypeBestBlock.write(value.currentBestBlock, into: &buf) - FfiConverterOptionUInt64.write(value.latestLightningWalletSyncTimestamp, into: &buf) - FfiConverterOptionUInt64.write(value.latestOnchainWalletSyncTimestamp, into: &buf) - FfiConverterOptionUInt64.write(value.latestFeeRateCacheUpdateTimestamp, into: &buf) - FfiConverterOptionUInt64.write(value.latestRgsSnapshotTimestamp, into: &buf) - FfiConverterOptionUInt64.write(value.latestNodeAnnouncementBroadcastTimestamp, into: &buf) - FfiConverterOptionUInt32.write(value.latestChannelMonitorArchivalHeight, into: &buf) + public static func write(_ value: RouteParametersConfig, into buf: inout [UInt8]) { + FfiConverterOptionUInt64.write(value.maxTotalRoutingFeeMsat, into: &buf) + FfiConverterUInt32.write(value.maxTotalCltvExpiryDelta, into: &buf) + FfiConverterUInt8.write(value.maxPathCount, into: &buf) + FfiConverterUInt8.write(value.maxChannelSaturationPowerOfHalf, into: &buf) } } - -public func FfiConverterTypeNodeStatus_lift(_ buf: RustBuffer) throws -> NodeStatus { - return try FfiConverterTypeNodeStatus.lift(buf) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeRouteParametersConfig_lift(_ buf: RustBuffer) throws -> RouteParametersConfig { + return try FfiConverterTypeRouteParametersConfig.lift(buf) } -public func FfiConverterTypeNodeStatus_lower(_ value: NodeStatus) -> RustBuffer { - return FfiConverterTypeNodeStatus.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeRouteParametersConfig_lower(_ value: RouteParametersConfig) -> RustBuffer { + return FfiConverterTypeRouteParametersConfig.lower(value) } +public struct RoutingFees { + public var baseMsat: UInt32 + public var proportionalMillionths: UInt32 -public struct OnchainPaymentInfo { - public var state: PaymentState - public var expiresAt: DateTime - public var feeTotalSat: UInt64 - public var orderTotalSat: UInt64 - public var address: Address - public var minOnchainPaymentConfirmations: UInt16? - public var minFeeFor0conf: FeeRate - public var refundOnchainAddress: Address? - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(state: PaymentState, expiresAt: DateTime, feeTotalSat: UInt64, orderTotalSat: UInt64, address: Address, minOnchainPaymentConfirmations: UInt16?, minFeeFor0conf: FeeRate, refundOnchainAddress: Address?) { - self.state = state - self.expiresAt = expiresAt - self.feeTotalSat = feeTotalSat - self.orderTotalSat = orderTotalSat - self.address = address - self.minOnchainPaymentConfirmations = minOnchainPaymentConfirmations - self.minFeeFor0conf = minFeeFor0conf - self.refundOnchainAddress = refundOnchainAddress + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(baseMsat: UInt32, proportionalMillionths: UInt32) { + self.baseMsat = baseMsat + self.proportionalMillionths = proportionalMillionths } } +extension RoutingFees: Equatable, Hashable { + public static func == (lhs: RoutingFees, rhs: RoutingFees) -> Bool { + if lhs.baseMsat != rhs.baseMsat { + return false + } + if lhs.proportionalMillionths != rhs.proportionalMillionths { + return false + } + return true + } + public func hash(into hasher: inout Hasher) { + hasher.combine(baseMsat) + hasher.combine(proportionalMillionths) + } +} -public struct FfiConverterTypeOnchainPaymentInfo: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> OnchainPaymentInfo { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeRoutingFees: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> RoutingFees { return - try OnchainPaymentInfo( - state: FfiConverterTypePaymentState.read(from: &buf), - expiresAt: FfiConverterTypeDateTime.read(from: &buf), - feeTotalSat: FfiConverterUInt64.read(from: &buf), - orderTotalSat: FfiConverterUInt64.read(from: &buf), - address: FfiConverterTypeAddress.read(from: &buf), - minOnchainPaymentConfirmations: FfiConverterOptionUInt16.read(from: &buf), - minFeeFor0conf: FfiConverterTypeFeeRate.read(from: &buf), - refundOnchainAddress: FfiConverterOptionTypeAddress.read(from: &buf) - ) + try RoutingFees( + baseMsat: FfiConverterUInt32.read(from: &buf), + proportionalMillionths: FfiConverterUInt32.read(from: &buf) + ) } - public static func write(_ value: OnchainPaymentInfo, into buf: inout [UInt8]) { - FfiConverterTypePaymentState.write(value.state, into: &buf) - FfiConverterTypeDateTime.write(value.expiresAt, into: &buf) - FfiConverterUInt64.write(value.feeTotalSat, into: &buf) - FfiConverterUInt64.write(value.orderTotalSat, into: &buf) - FfiConverterTypeAddress.write(value.address, into: &buf) - FfiConverterOptionUInt16.write(value.minOnchainPaymentConfirmations, into: &buf) - FfiConverterTypeFeeRate.write(value.minFeeFor0conf, into: &buf) - FfiConverterOptionTypeAddress.write(value.refundOnchainAddress, into: &buf) + public static func write(_ value: RoutingFees, into buf: inout [UInt8]) { + FfiConverterUInt32.write(value.baseMsat, into: &buf) + FfiConverterUInt32.write(value.proportionalMillionths, into: &buf) } } - -public func FfiConverterTypeOnchainPaymentInfo_lift(_ buf: RustBuffer) throws -> OnchainPaymentInfo { - return try FfiConverterTypeOnchainPaymentInfo.lift(buf) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeRoutingFees_lift(_ buf: RustBuffer) throws -> RoutingFees { + return try FfiConverterTypeRoutingFees.lift(buf) } -public func FfiConverterTypeOnchainPaymentInfo_lower(_ value: OnchainPaymentInfo) -> RustBuffer { - return FfiConverterTypeOnchainPaymentInfo.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeRoutingFees_lower(_ value: RoutingFees) -> RustBuffer { + return FfiConverterTypeRoutingFees.lower(value) } +public struct RuntimeSyncIntervals { + public var onchainWalletSyncIntervalSecs: UInt64 + public var lightningWalletSyncIntervalSecs: UInt64 + public var feeRateCacheUpdateIntervalSecs: UInt64 -public struct OrderParameters { - public var lspBalanceSat: UInt64 - public var clientBalanceSat: UInt64 - public var requiredChannelConfirmations: UInt16 - public var fundingConfirmsWithinBlocks: UInt16 - public var channelExpiryBlocks: UInt32 - public var token: String? - public var announceChannel: Bool - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(lspBalanceSat: UInt64, clientBalanceSat: UInt64, requiredChannelConfirmations: UInt16, fundingConfirmsWithinBlocks: UInt16, channelExpiryBlocks: UInt32, token: String?, announceChannel: Bool) { - self.lspBalanceSat = lspBalanceSat - self.clientBalanceSat = clientBalanceSat - self.requiredChannelConfirmations = requiredChannelConfirmations - self.fundingConfirmsWithinBlocks = fundingConfirmsWithinBlocks - self.channelExpiryBlocks = channelExpiryBlocks - self.token = token - self.announceChannel = announceChannel + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(onchainWalletSyncIntervalSecs: UInt64, lightningWalletSyncIntervalSecs: UInt64, feeRateCacheUpdateIntervalSecs: UInt64) { + self.onchainWalletSyncIntervalSecs = onchainWalletSyncIntervalSecs + self.lightningWalletSyncIntervalSecs = lightningWalletSyncIntervalSecs + self.feeRateCacheUpdateIntervalSecs = feeRateCacheUpdateIntervalSecs } } - - -extension OrderParameters: Equatable, Hashable { - public static func ==(lhs: OrderParameters, rhs: OrderParameters) -> Bool { - if lhs.lspBalanceSat != rhs.lspBalanceSat { - return false - } - if lhs.clientBalanceSat != rhs.clientBalanceSat { - return false - } - if lhs.requiredChannelConfirmations != rhs.requiredChannelConfirmations { - return false - } - if lhs.fundingConfirmsWithinBlocks != rhs.fundingConfirmsWithinBlocks { - return false - } - if lhs.channelExpiryBlocks != rhs.channelExpiryBlocks { +extension RuntimeSyncIntervals: Equatable, Hashable { + public static func == (lhs: RuntimeSyncIntervals, rhs: RuntimeSyncIntervals) -> Bool { + if lhs.onchainWalletSyncIntervalSecs != rhs.onchainWalletSyncIntervalSecs { return false } - if lhs.token != rhs.token { + if lhs.lightningWalletSyncIntervalSecs != rhs.lightningWalletSyncIntervalSecs { return false } - if lhs.announceChannel != rhs.announceChannel { + if lhs.feeRateCacheUpdateIntervalSecs != rhs.feeRateCacheUpdateIntervalSecs { return false } return true } public func hash(into hasher: inout Hasher) { - hasher.combine(lspBalanceSat) - hasher.combine(clientBalanceSat) - hasher.combine(requiredChannelConfirmations) - hasher.combine(fundingConfirmsWithinBlocks) - hasher.combine(channelExpiryBlocks) - hasher.combine(token) - hasher.combine(announceChannel) + hasher.combine(onchainWalletSyncIntervalSecs) + hasher.combine(lightningWalletSyncIntervalSecs) + hasher.combine(feeRateCacheUpdateIntervalSecs) } } - -public struct FfiConverterTypeOrderParameters: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> OrderParameters { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeRuntimeSyncIntervals: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> RuntimeSyncIntervals { return - try OrderParameters( - lspBalanceSat: FfiConverterUInt64.read(from: &buf), - clientBalanceSat: FfiConverterUInt64.read(from: &buf), - requiredChannelConfirmations: FfiConverterUInt16.read(from: &buf), - fundingConfirmsWithinBlocks: FfiConverterUInt16.read(from: &buf), - channelExpiryBlocks: FfiConverterUInt32.read(from: &buf), - token: FfiConverterOptionString.read(from: &buf), - announceChannel: FfiConverterBool.read(from: &buf) - ) + try RuntimeSyncIntervals( + onchainWalletSyncIntervalSecs: FfiConverterUInt64.read(from: &buf), + lightningWalletSyncIntervalSecs: FfiConverterUInt64.read(from: &buf), + feeRateCacheUpdateIntervalSecs: FfiConverterUInt64.read(from: &buf) + ) } - public static func write(_ value: OrderParameters, into buf: inout [UInt8]) { - FfiConverterUInt64.write(value.lspBalanceSat, into: &buf) - FfiConverterUInt64.write(value.clientBalanceSat, into: &buf) - FfiConverterUInt16.write(value.requiredChannelConfirmations, into: &buf) - FfiConverterUInt16.write(value.fundingConfirmsWithinBlocks, into: &buf) - FfiConverterUInt32.write(value.channelExpiryBlocks, into: &buf) - FfiConverterOptionString.write(value.token, into: &buf) - FfiConverterBool.write(value.announceChannel, into: &buf) + public static func write(_ value: RuntimeSyncIntervals, into buf: inout [UInt8]) { + FfiConverterUInt64.write(value.onchainWalletSyncIntervalSecs, into: &buf) + FfiConverterUInt64.write(value.lightningWalletSyncIntervalSecs, into: &buf) + FfiConverterUInt64.write(value.feeRateCacheUpdateIntervalSecs, into: &buf) } } - -public func FfiConverterTypeOrderParameters_lift(_ buf: RustBuffer) throws -> OrderParameters { - return try FfiConverterTypeOrderParameters.lift(buf) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeRuntimeSyncIntervals_lift(_ buf: RustBuffer) throws -> RuntimeSyncIntervals { + return try FfiConverterTypeRuntimeSyncIntervals.lift(buf) } -public func FfiConverterTypeOrderParameters_lower(_ value: OrderParameters) -> RustBuffer { - return FfiConverterTypeOrderParameters.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeRuntimeSyncIntervals_lower(_ value: RuntimeSyncIntervals) -> RustBuffer { + return FfiConverterTypeRuntimeSyncIntervals.lower(value) } +public struct ScoringDecayParameters { + public var historicalNoUpdatesHalfLifeSecs: UInt64 + public var liquidityOffsetHalfLifeSecs: UInt64 -public struct OutPoint { - public var txid: Txid - public var vout: UInt32 - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(txid: Txid, vout: UInt32) { - self.txid = txid - self.vout = vout + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(historicalNoUpdatesHalfLifeSecs: UInt64, liquidityOffsetHalfLifeSecs: UInt64) { + self.historicalNoUpdatesHalfLifeSecs = historicalNoUpdatesHalfLifeSecs + self.liquidityOffsetHalfLifeSecs = liquidityOffsetHalfLifeSecs } } - - -extension OutPoint: Equatable, Hashable { - public static func ==(lhs: OutPoint, rhs: OutPoint) -> Bool { - if lhs.txid != rhs.txid { +extension ScoringDecayParameters: Equatable, Hashable { + public static func == (lhs: ScoringDecayParameters, rhs: ScoringDecayParameters) -> Bool { + if lhs.historicalNoUpdatesHalfLifeSecs != rhs.historicalNoUpdatesHalfLifeSecs { return false } - if lhs.vout != rhs.vout { + if lhs.liquidityOffsetHalfLifeSecs != rhs.liquidityOffsetHalfLifeSecs { return false } return true } public func hash(into hasher: inout Hasher) { - hasher.combine(txid) - hasher.combine(vout) + hasher.combine(historicalNoUpdatesHalfLifeSecs) + hasher.combine(liquidityOffsetHalfLifeSecs) } } - -public struct FfiConverterTypeOutPoint: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> OutPoint { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeScoringDecayParameters: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ScoringDecayParameters { return - try OutPoint( - txid: FfiConverterTypeTxid.read(from: &buf), - vout: FfiConverterUInt32.read(from: &buf) - ) + try ScoringDecayParameters( + historicalNoUpdatesHalfLifeSecs: FfiConverterUInt64.read(from: &buf), + liquidityOffsetHalfLifeSecs: FfiConverterUInt64.read(from: &buf) + ) } - public static func write(_ value: OutPoint, into buf: inout [UInt8]) { - FfiConverterTypeTxid.write(value.txid, into: &buf) - FfiConverterUInt32.write(value.vout, into: &buf) + public static func write(_ value: ScoringDecayParameters, into buf: inout [UInt8]) { + FfiConverterUInt64.write(value.historicalNoUpdatesHalfLifeSecs, into: &buf) + FfiConverterUInt64.write(value.liquidityOffsetHalfLifeSecs, into: &buf) } } - -public func FfiConverterTypeOutPoint_lift(_ buf: RustBuffer) throws -> OutPoint { - return try FfiConverterTypeOutPoint.lift(buf) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeScoringDecayParameters_lift(_ buf: RustBuffer) throws -> ScoringDecayParameters { + return try FfiConverterTypeScoringDecayParameters.lift(buf) } -public func FfiConverterTypeOutPoint_lower(_ value: OutPoint) -> RustBuffer { - return FfiConverterTypeOutPoint.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeScoringDecayParameters_lower(_ value: ScoringDecayParameters) -> RustBuffer { + return FfiConverterTypeScoringDecayParameters.lower(value) } +public struct ScoringFeeParameters { + public var basePenaltyMsat: UInt64 + public var basePenaltyAmountMultiplierMsat: UInt64 + public var liquidityPenaltyMultiplierMsat: UInt64 + public var liquidityPenaltyAmountMultiplierMsat: UInt64 + public var historicalLiquidityPenaltyMultiplierMsat: UInt64 + public var historicalLiquidityPenaltyAmountMultiplierMsat: UInt64 + public var antiProbingPenaltyMsat: UInt64 + public var consideredImpossiblePenaltyMsat: UInt64 + public var linearSuccessProbability: Bool + public var probingDiversityPenaltyMsat: UInt64 -public struct PaymentDetails { - public var id: PaymentId - public var kind: PaymentKind - public var amountMsat: UInt64? - public var feePaidMsat: UInt64? - public var direction: PaymentDirection - public var status: PaymentStatus - public var latestUpdateTimestamp: UInt64 - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(id: PaymentId, kind: PaymentKind, amountMsat: UInt64?, feePaidMsat: UInt64?, direction: PaymentDirection, status: PaymentStatus, latestUpdateTimestamp: UInt64) { - self.id = id - self.kind = kind - self.amountMsat = amountMsat - self.feePaidMsat = feePaidMsat - self.direction = direction - self.status = status - self.latestUpdateTimestamp = latestUpdateTimestamp + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(basePenaltyMsat: UInt64, basePenaltyAmountMultiplierMsat: UInt64, liquidityPenaltyMultiplierMsat: UInt64, liquidityPenaltyAmountMultiplierMsat: UInt64, historicalLiquidityPenaltyMultiplierMsat: UInt64, historicalLiquidityPenaltyAmountMultiplierMsat: UInt64, antiProbingPenaltyMsat: UInt64, consideredImpossiblePenaltyMsat: UInt64, linearSuccessProbability: Bool, probingDiversityPenaltyMsat: UInt64) { + self.basePenaltyMsat = basePenaltyMsat + self.basePenaltyAmountMultiplierMsat = basePenaltyAmountMultiplierMsat + self.liquidityPenaltyMultiplierMsat = liquidityPenaltyMultiplierMsat + self.liquidityPenaltyAmountMultiplierMsat = liquidityPenaltyAmountMultiplierMsat + self.historicalLiquidityPenaltyMultiplierMsat = historicalLiquidityPenaltyMultiplierMsat + self.historicalLiquidityPenaltyAmountMultiplierMsat = historicalLiquidityPenaltyAmountMultiplierMsat + self.antiProbingPenaltyMsat = antiProbingPenaltyMsat + self.consideredImpossiblePenaltyMsat = consideredImpossiblePenaltyMsat + self.linearSuccessProbability = linearSuccessProbability + self.probingDiversityPenaltyMsat = probingDiversityPenaltyMsat } } - - -extension PaymentDetails: Equatable, Hashable { - public static func ==(lhs: PaymentDetails, rhs: PaymentDetails) -> Bool { - if lhs.id != rhs.id { +extension ScoringFeeParameters: Equatable, Hashable { + public static func == (lhs: ScoringFeeParameters, rhs: ScoringFeeParameters) -> Bool { + if lhs.basePenaltyMsat != rhs.basePenaltyMsat { return false } - if lhs.kind != rhs.kind { + if lhs.basePenaltyAmountMultiplierMsat != rhs.basePenaltyAmountMultiplierMsat { return false } - if lhs.amountMsat != rhs.amountMsat { + if lhs.liquidityPenaltyMultiplierMsat != rhs.liquidityPenaltyMultiplierMsat { return false } - if lhs.feePaidMsat != rhs.feePaidMsat { + if lhs.liquidityPenaltyAmountMultiplierMsat != rhs.liquidityPenaltyAmountMultiplierMsat { return false } - if lhs.direction != rhs.direction { + if lhs.historicalLiquidityPenaltyMultiplierMsat != rhs.historicalLiquidityPenaltyMultiplierMsat { return false } - if lhs.status != rhs.status { + if lhs.historicalLiquidityPenaltyAmountMultiplierMsat != rhs.historicalLiquidityPenaltyAmountMultiplierMsat { + return false + } + if lhs.antiProbingPenaltyMsat != rhs.antiProbingPenaltyMsat { + return false + } + if lhs.consideredImpossiblePenaltyMsat != rhs.consideredImpossiblePenaltyMsat { + return false + } + if lhs.linearSuccessProbability != rhs.linearSuccessProbability { return false } - if lhs.latestUpdateTimestamp != rhs.latestUpdateTimestamp { + if lhs.probingDiversityPenaltyMsat != rhs.probingDiversityPenaltyMsat { return false } return true } public func hash(into hasher: inout Hasher) { - hasher.combine(id) - hasher.combine(kind) - hasher.combine(amountMsat) - hasher.combine(feePaidMsat) - hasher.combine(direction) - hasher.combine(status) - hasher.combine(latestUpdateTimestamp) + hasher.combine(basePenaltyMsat) + hasher.combine(basePenaltyAmountMultiplierMsat) + hasher.combine(liquidityPenaltyMultiplierMsat) + hasher.combine(liquidityPenaltyAmountMultiplierMsat) + hasher.combine(historicalLiquidityPenaltyMultiplierMsat) + hasher.combine(historicalLiquidityPenaltyAmountMultiplierMsat) + hasher.combine(antiProbingPenaltyMsat) + hasher.combine(consideredImpossiblePenaltyMsat) + hasher.combine(linearSuccessProbability) + hasher.combine(probingDiversityPenaltyMsat) } } - -public struct FfiConverterTypePaymentDetails: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> PaymentDetails { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeScoringFeeParameters: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ScoringFeeParameters { return - try PaymentDetails( - id: FfiConverterTypePaymentId.read(from: &buf), - kind: FfiConverterTypePaymentKind.read(from: &buf), - amountMsat: FfiConverterOptionUInt64.read(from: &buf), - feePaidMsat: FfiConverterOptionUInt64.read(from: &buf), - direction: FfiConverterTypePaymentDirection.read(from: &buf), - status: FfiConverterTypePaymentStatus.read(from: &buf), - latestUpdateTimestamp: FfiConverterUInt64.read(from: &buf) - ) + try ScoringFeeParameters( + basePenaltyMsat: FfiConverterUInt64.read(from: &buf), + basePenaltyAmountMultiplierMsat: FfiConverterUInt64.read(from: &buf), + liquidityPenaltyMultiplierMsat: FfiConverterUInt64.read(from: &buf), + liquidityPenaltyAmountMultiplierMsat: FfiConverterUInt64.read(from: &buf), + historicalLiquidityPenaltyMultiplierMsat: FfiConverterUInt64.read(from: &buf), + historicalLiquidityPenaltyAmountMultiplierMsat: FfiConverterUInt64.read(from: &buf), + antiProbingPenaltyMsat: FfiConverterUInt64.read(from: &buf), + consideredImpossiblePenaltyMsat: FfiConverterUInt64.read(from: &buf), + linearSuccessProbability: FfiConverterBool.read(from: &buf), + probingDiversityPenaltyMsat: FfiConverterUInt64.read(from: &buf) + ) } - public static func write(_ value: PaymentDetails, into buf: inout [UInt8]) { - FfiConverterTypePaymentId.write(value.id, into: &buf) - FfiConverterTypePaymentKind.write(value.kind, into: &buf) - FfiConverterOptionUInt64.write(value.amountMsat, into: &buf) - FfiConverterOptionUInt64.write(value.feePaidMsat, into: &buf) - FfiConverterTypePaymentDirection.write(value.direction, into: &buf) - FfiConverterTypePaymentStatus.write(value.status, into: &buf) - FfiConverterUInt64.write(value.latestUpdateTimestamp, into: &buf) + public static func write(_ value: ScoringFeeParameters, into buf: inout [UInt8]) { + FfiConverterUInt64.write(value.basePenaltyMsat, into: &buf) + FfiConverterUInt64.write(value.basePenaltyAmountMultiplierMsat, into: &buf) + FfiConverterUInt64.write(value.liquidityPenaltyMultiplierMsat, into: &buf) + FfiConverterUInt64.write(value.liquidityPenaltyAmountMultiplierMsat, into: &buf) + FfiConverterUInt64.write(value.historicalLiquidityPenaltyMultiplierMsat, into: &buf) + FfiConverterUInt64.write(value.historicalLiquidityPenaltyAmountMultiplierMsat, into: &buf) + FfiConverterUInt64.write(value.antiProbingPenaltyMsat, into: &buf) + FfiConverterUInt64.write(value.consideredImpossiblePenaltyMsat, into: &buf) + FfiConverterBool.write(value.linearSuccessProbability, into: &buf) + FfiConverterUInt64.write(value.probingDiversityPenaltyMsat, into: &buf) } } - -public func FfiConverterTypePaymentDetails_lift(_ buf: RustBuffer) throws -> PaymentDetails { - return try FfiConverterTypePaymentDetails.lift(buf) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeScoringFeeParameters_lift(_ buf: RustBuffer) throws -> ScoringFeeParameters { + return try FfiConverterTypeScoringFeeParameters.lift(buf) } -public func FfiConverterTypePaymentDetails_lower(_ value: PaymentDetails) -> RustBuffer { - return FfiConverterTypePaymentDetails.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeScoringFeeParameters_lower(_ value: ScoringFeeParameters) -> RustBuffer { + return FfiConverterTypeScoringFeeParameters.lower(value) } +public struct SpendableUtxo { + public var outpoint: OutPoint + public var valueSats: UInt64 -public struct PaymentInfo { - public var bolt11: Bolt11PaymentInfo? - public var onchain: OnchainPaymentInfo? - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(bolt11: Bolt11PaymentInfo?, onchain: OnchainPaymentInfo?) { - self.bolt11 = bolt11 - self.onchain = onchain + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(outpoint: OutPoint, valueSats: UInt64) { + self.outpoint = outpoint + self.valueSats = valueSats } } +extension SpendableUtxo: Equatable, Hashable { + public static func == (lhs: SpendableUtxo, rhs: SpendableUtxo) -> Bool { + if lhs.outpoint != rhs.outpoint { + return false + } + if lhs.valueSats != rhs.valueSats { + return false + } + return true + } + public func hash(into hasher: inout Hasher) { + hasher.combine(outpoint) + hasher.combine(valueSats) + } +} -public struct FfiConverterTypePaymentInfo: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> PaymentInfo { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeSpendableUtxo: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SpendableUtxo { return - try PaymentInfo( - bolt11: FfiConverterOptionTypeBolt11PaymentInfo.read(from: &buf), - onchain: FfiConverterOptionTypeOnchainPaymentInfo.read(from: &buf) - ) + try SpendableUtxo( + outpoint: FfiConverterTypeOutPoint.read(from: &buf), + valueSats: FfiConverterUInt64.read(from: &buf) + ) } - public static func write(_ value: PaymentInfo, into buf: inout [UInt8]) { - FfiConverterOptionTypeBolt11PaymentInfo.write(value.bolt11, into: &buf) - FfiConverterOptionTypeOnchainPaymentInfo.write(value.onchain, into: &buf) + public static func write(_ value: SpendableUtxo, into buf: inout [UInt8]) { + FfiConverterTypeOutPoint.write(value.outpoint, into: &buf) + FfiConverterUInt64.write(value.valueSats, into: &buf) } } - -public func FfiConverterTypePaymentInfo_lift(_ buf: RustBuffer) throws -> PaymentInfo { - return try FfiConverterTypePaymentInfo.lift(buf) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeSpendableUtxo_lift(_ buf: RustBuffer) throws -> SpendableUtxo { + return try FfiConverterTypeSpendableUtxo.lift(buf) } -public func FfiConverterTypePaymentInfo_lower(_ value: PaymentInfo) -> RustBuffer { - return FfiConverterTypePaymentInfo.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeSpendableUtxo_lower(_ value: SpendableUtxo) -> RustBuffer { + return FfiConverterTypeSpendableUtxo.lower(value) } +public struct TransactionDetails { + public var amountSats: Int64 + public var inputs: [TxInput] + public var outputs: [TxOutput] -public struct PeerDetails { - public var nodeId: PublicKey - public var address: SocketAddress - public var isPersisted: Bool - public var isConnected: Bool - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(nodeId: PublicKey, address: SocketAddress, isPersisted: Bool, isConnected: Bool) { - self.nodeId = nodeId - self.address = address - self.isPersisted = isPersisted - self.isConnected = isConnected + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(amountSats: Int64, inputs: [TxInput], outputs: [TxOutput]) { + self.amountSats = amountSats + self.inputs = inputs + self.outputs = outputs } } - - -extension PeerDetails: Equatable, Hashable { - public static func ==(lhs: PeerDetails, rhs: PeerDetails) -> Bool { - if lhs.nodeId != rhs.nodeId { +extension TransactionDetails: Equatable, Hashable { + public static func == (lhs: TransactionDetails, rhs: TransactionDetails) -> Bool { + if lhs.amountSats != rhs.amountSats { return false } - if lhs.address != rhs.address { - return false - } - if lhs.isPersisted != rhs.isPersisted { + if lhs.inputs != rhs.inputs { return false } - if lhs.isConnected != rhs.isConnected { + if lhs.outputs != rhs.outputs { return false } return true } public func hash(into hasher: inout Hasher) { - hasher.combine(nodeId) - hasher.combine(address) - hasher.combine(isPersisted) - hasher.combine(isConnected) + hasher.combine(amountSats) + hasher.combine(inputs) + hasher.combine(outputs) } } - -public struct FfiConverterTypePeerDetails: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> PeerDetails { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeTransactionDetails: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> TransactionDetails { return - try PeerDetails( - nodeId: FfiConverterTypePublicKey.read(from: &buf), - address: FfiConverterTypeSocketAddress.read(from: &buf), - isPersisted: FfiConverterBool.read(from: &buf), - isConnected: FfiConverterBool.read(from: &buf) - ) + try TransactionDetails( + amountSats: FfiConverterInt64.read(from: &buf), + inputs: FfiConverterSequenceTypeTxInput.read(from: &buf), + outputs: FfiConverterSequenceTypeTxOutput.read(from: &buf) + ) } - public static func write(_ value: PeerDetails, into buf: inout [UInt8]) { - FfiConverterTypePublicKey.write(value.nodeId, into: &buf) - FfiConverterTypeSocketAddress.write(value.address, into: &buf) - FfiConverterBool.write(value.isPersisted, into: &buf) - FfiConverterBool.write(value.isConnected, into: &buf) + public static func write(_ value: TransactionDetails, into buf: inout [UInt8]) { + FfiConverterInt64.write(value.amountSats, into: &buf) + FfiConverterSequenceTypeTxInput.write(value.inputs, into: &buf) + FfiConverterSequenceTypeTxOutput.write(value.outputs, into: &buf) } } - -public func FfiConverterTypePeerDetails_lift(_ buf: RustBuffer) throws -> PeerDetails { - return try FfiConverterTypePeerDetails.lift(buf) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeTransactionDetails_lift(_ buf: RustBuffer) throws -> TransactionDetails { + return try FfiConverterTypeTransactionDetails.lift(buf) } -public func FfiConverterTypePeerDetails_lower(_ value: PeerDetails) -> RustBuffer { - return FfiConverterTypePeerDetails.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeTransactionDetails_lower(_ value: TransactionDetails) -> RustBuffer { + return FfiConverterTypeTransactionDetails.lower(value) } +public struct TxInput { + public var txid: Txid + public var vout: UInt32 + public var scriptsig: String + public var witness: [String] + public var sequence: UInt32 -public struct RouteHintHop { - public var srcNodeId: PublicKey - public var shortChannelId: UInt64 - public var cltvExpiryDelta: UInt16 - public var htlcMinimumMsat: UInt64? - public var htlcMaximumMsat: UInt64? - public var fees: RoutingFees - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(srcNodeId: PublicKey, shortChannelId: UInt64, cltvExpiryDelta: UInt16, htlcMinimumMsat: UInt64?, htlcMaximumMsat: UInt64?, fees: RoutingFees) { - self.srcNodeId = srcNodeId - self.shortChannelId = shortChannelId - self.cltvExpiryDelta = cltvExpiryDelta - self.htlcMinimumMsat = htlcMinimumMsat - self.htlcMaximumMsat = htlcMaximumMsat - self.fees = fees + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(txid: Txid, vout: UInt32, scriptsig: String, witness: [String], sequence: UInt32) { + self.txid = txid + self.vout = vout + self.scriptsig = scriptsig + self.witness = witness + self.sequence = sequence } } - - -extension RouteHintHop: Equatable, Hashable { - public static func ==(lhs: RouteHintHop, rhs: RouteHintHop) -> Bool { - if lhs.srcNodeId != rhs.srcNodeId { - return false - } - if lhs.shortChannelId != rhs.shortChannelId { +extension TxInput: Equatable, Hashable { + public static func == (lhs: TxInput, rhs: TxInput) -> Bool { + if lhs.txid != rhs.txid { return false } - if lhs.cltvExpiryDelta != rhs.cltvExpiryDelta { + if lhs.vout != rhs.vout { return false } - if lhs.htlcMinimumMsat != rhs.htlcMinimumMsat { + if lhs.scriptsig != rhs.scriptsig { return false } - if lhs.htlcMaximumMsat != rhs.htlcMaximumMsat { + if lhs.witness != rhs.witness { return false } - if lhs.fees != rhs.fees { + if lhs.sequence != rhs.sequence { return false } return true } public func hash(into hasher: inout Hasher) { - hasher.combine(srcNodeId) - hasher.combine(shortChannelId) - hasher.combine(cltvExpiryDelta) - hasher.combine(htlcMinimumMsat) - hasher.combine(htlcMaximumMsat) - hasher.combine(fees) + hasher.combine(txid) + hasher.combine(vout) + hasher.combine(scriptsig) + hasher.combine(witness) + hasher.combine(sequence) } } - -public struct FfiConverterTypeRouteHintHop: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> RouteHintHop { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeTxInput: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> TxInput { return - try RouteHintHop( - srcNodeId: FfiConverterTypePublicKey.read(from: &buf), - shortChannelId: FfiConverterUInt64.read(from: &buf), - cltvExpiryDelta: FfiConverterUInt16.read(from: &buf), - htlcMinimumMsat: FfiConverterOptionUInt64.read(from: &buf), - htlcMaximumMsat: FfiConverterOptionUInt64.read(from: &buf), - fees: FfiConverterTypeRoutingFees.read(from: &buf) - ) + try TxInput( + txid: FfiConverterTypeTxid.read(from: &buf), + vout: FfiConverterUInt32.read(from: &buf), + scriptsig: FfiConverterString.read(from: &buf), + witness: FfiConverterSequenceString.read(from: &buf), + sequence: FfiConverterUInt32.read(from: &buf) + ) } - public static func write(_ value: RouteHintHop, into buf: inout [UInt8]) { - FfiConverterTypePublicKey.write(value.srcNodeId, into: &buf) - FfiConverterUInt64.write(value.shortChannelId, into: &buf) - FfiConverterUInt16.write(value.cltvExpiryDelta, into: &buf) - FfiConverterOptionUInt64.write(value.htlcMinimumMsat, into: &buf) - FfiConverterOptionUInt64.write(value.htlcMaximumMsat, into: &buf) - FfiConverterTypeRoutingFees.write(value.fees, into: &buf) + public static func write(_ value: TxInput, into buf: inout [UInt8]) { + FfiConverterTypeTxid.write(value.txid, into: &buf) + FfiConverterUInt32.write(value.vout, into: &buf) + FfiConverterString.write(value.scriptsig, into: &buf) + FfiConverterSequenceString.write(value.witness, into: &buf) + FfiConverterUInt32.write(value.sequence, into: &buf) } } - -public func FfiConverterTypeRouteHintHop_lift(_ buf: RustBuffer) throws -> RouteHintHop { - return try FfiConverterTypeRouteHintHop.lift(buf) -} - -public func FfiConverterTypeRouteHintHop_lower(_ value: RouteHintHop) -> RustBuffer { - return FfiConverterTypeRouteHintHop.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeTxInput_lift(_ buf: RustBuffer) throws -> TxInput { + return try FfiConverterTypeTxInput.lift(buf) } - -public struct RoutingFees { - public var baseMsat: UInt32 - public var proportionalMillionths: UInt32 - - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(baseMsat: UInt32, proportionalMillionths: UInt32) { - self.baseMsat = baseMsat - self.proportionalMillionths = proportionalMillionths +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeTxInput_lower(_ value: TxInput) -> RustBuffer { + return FfiConverterTypeTxInput.lower(value) +} + +public struct TxOutput { + public var scriptpubkey: String + public var scriptpubkeyType: String? + public var scriptpubkeyAddress: String? + public var value: Int64 + public var n: UInt32 + + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(scriptpubkey: String, scriptpubkeyType: String?, scriptpubkeyAddress: String?, value: Int64, n: UInt32) { + self.scriptpubkey = scriptpubkey + self.scriptpubkeyType = scriptpubkeyType + self.scriptpubkeyAddress = scriptpubkeyAddress + self.value = value + self.n = n } } - - -extension RoutingFees: Equatable, Hashable { - public static func ==(lhs: RoutingFees, rhs: RoutingFees) -> Bool { - if lhs.baseMsat != rhs.baseMsat { +extension TxOutput: Equatable, Hashable { + public static func == (lhs: TxOutput, rhs: TxOutput) -> Bool { + if lhs.scriptpubkey != rhs.scriptpubkey { return false } - if lhs.proportionalMillionths != rhs.proportionalMillionths { + if lhs.scriptpubkeyType != rhs.scriptpubkeyType { + return false + } + if lhs.scriptpubkeyAddress != rhs.scriptpubkeyAddress { + return false + } + if lhs.value != rhs.value { + return false + } + if lhs.n != rhs.n { return false } return true } public func hash(into hasher: inout Hasher) { - hasher.combine(baseMsat) - hasher.combine(proportionalMillionths) + hasher.combine(scriptpubkey) + hasher.combine(scriptpubkeyType) + hasher.combine(scriptpubkeyAddress) + hasher.combine(value) + hasher.combine(n) } } - -public struct FfiConverterTypeRoutingFees: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> RoutingFees { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeTxOutput: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> TxOutput { return - try RoutingFees( - baseMsat: FfiConverterUInt32.read(from: &buf), - proportionalMillionths: FfiConverterUInt32.read(from: &buf) - ) + try TxOutput( + scriptpubkey: FfiConverterString.read(from: &buf), + scriptpubkeyType: FfiConverterOptionString.read(from: &buf), + scriptpubkeyAddress: FfiConverterOptionString.read(from: &buf), + value: FfiConverterInt64.read(from: &buf), + n: FfiConverterUInt32.read(from: &buf) + ) } - public static func write(_ value: RoutingFees, into buf: inout [UInt8]) { - FfiConverterUInt32.write(value.baseMsat, into: &buf) - FfiConverterUInt32.write(value.proportionalMillionths, into: &buf) + public static func write(_ value: TxOutput, into buf: inout [UInt8]) { + FfiConverterString.write(value.scriptpubkey, into: &buf) + FfiConverterOptionString.write(value.scriptpubkeyType, into: &buf) + FfiConverterOptionString.write(value.scriptpubkeyAddress, into: &buf) + FfiConverterInt64.write(value.value, into: &buf) + FfiConverterUInt32.write(value.n, into: &buf) } } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeTxOutput_lift(_ buf: RustBuffer) throws -> TxOutput { + return try FfiConverterTypeTxOutput.lift(buf) +} -public func FfiConverterTypeRoutingFees_lift(_ buf: RustBuffer) throws -> RoutingFees { - return try FfiConverterTypeRoutingFees.lift(buf) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeTxOutput_lower(_ value: TxOutput) -> RustBuffer { + return FfiConverterTypeTxOutput.lower(value) } -public func FfiConverterTypeRoutingFees_lower(_ value: RoutingFees) -> RustBuffer { - return FfiConverterTypeRoutingFees.lower(value) +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum AddressType { + case legacy + case nestedSegwit + case nativeSegwit + case taproot } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeAddressType: FfiConverterRustBuffer { + typealias SwiftType = AddressType -public struct SendingParameters { - public var maxTotalRoutingFeeMsat: MaxTotalRoutingFeeLimit? - public var maxTotalCltvExpiryDelta: UInt32? - public var maxPathCount: UInt8? - public var maxChannelSaturationPowerOfHalf: UInt8? + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AddressType { + let variant: Int32 = try readInt(&buf) + switch variant { + case 1: return .legacy - // Default memberwise initializers are never public by default, so we - // declare one manually. - public init(maxTotalRoutingFeeMsat: MaxTotalRoutingFeeLimit?, maxTotalCltvExpiryDelta: UInt32?, maxPathCount: UInt8?, maxChannelSaturationPowerOfHalf: UInt8?) { - self.maxTotalRoutingFeeMsat = maxTotalRoutingFeeMsat - self.maxTotalCltvExpiryDelta = maxTotalCltvExpiryDelta - self.maxPathCount = maxPathCount - self.maxChannelSaturationPowerOfHalf = maxChannelSaturationPowerOfHalf - } -} + case 2: return .nestedSegwit + case 3: return .nativeSegwit + case 4: return .taproot -extension SendingParameters: Equatable, Hashable { - public static func ==(lhs: SendingParameters, rhs: SendingParameters) -> Bool { - if lhs.maxTotalRoutingFeeMsat != rhs.maxTotalRoutingFeeMsat { - return false - } - if lhs.maxTotalCltvExpiryDelta != rhs.maxTotalCltvExpiryDelta { - return false - } - if lhs.maxPathCount != rhs.maxPathCount { - return false - } - if lhs.maxChannelSaturationPowerOfHalf != rhs.maxChannelSaturationPowerOfHalf { - return false + default: throw UniffiInternalError.unexpectedEnumCase } - return true } - public func hash(into hasher: inout Hasher) { - hasher.combine(maxTotalRoutingFeeMsat) - hasher.combine(maxTotalCltvExpiryDelta) - hasher.combine(maxPathCount) - hasher.combine(maxChannelSaturationPowerOfHalf) + public static func write(_ value: AddressType, into buf: inout [UInt8]) { + switch value { + case .legacy: + writeInt(&buf, Int32(1)) + + case .nestedSegwit: + writeInt(&buf, Int32(2)) + + case .nativeSegwit: + writeInt(&buf, Int32(3)) + + case .taproot: + writeInt(&buf, Int32(4)) + } } } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeAddressType_lift(_ buf: RustBuffer) throws -> AddressType { + return try FfiConverterTypeAddressType.lift(buf) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeAddressType_lower(_ value: AddressType) -> RustBuffer { + return FfiConverterTypeAddressType.lower(value) +} + +extension AddressType: Equatable, Hashable {} + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum AsyncPaymentsRole { + case client + case server +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeAsyncPaymentsRole: FfiConverterRustBuffer { + typealias SwiftType = AsyncPaymentsRole + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AsyncPaymentsRole { + let variant: Int32 = try readInt(&buf) + switch variant { + case 1: return .client + + case 2: return .server -public struct FfiConverterTypeSendingParameters: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SendingParameters { - return - try SendingParameters( - maxTotalRoutingFeeMsat: FfiConverterOptionTypeMaxTotalRoutingFeeLimit.read(from: &buf), - maxTotalCltvExpiryDelta: FfiConverterOptionUInt32.read(from: &buf), - maxPathCount: FfiConverterOptionUInt8.read(from: &buf), - maxChannelSaturationPowerOfHalf: FfiConverterOptionUInt8.read(from: &buf) - ) + default: throw UniffiInternalError.unexpectedEnumCase + } } - public static func write(_ value: SendingParameters, into buf: inout [UInt8]) { - FfiConverterOptionTypeMaxTotalRoutingFeeLimit.write(value.maxTotalRoutingFeeMsat, into: &buf) - FfiConverterOptionUInt32.write(value.maxTotalCltvExpiryDelta, into: &buf) - FfiConverterOptionUInt8.write(value.maxPathCount, into: &buf) - FfiConverterOptionUInt8.write(value.maxChannelSaturationPowerOfHalf, into: &buf) + public static func write(_ value: AsyncPaymentsRole, into buf: inout [UInt8]) { + switch value { + case .client: + writeInt(&buf, Int32(1)) + + case .server: + writeInt(&buf, Int32(2)) + } } } - -public func FfiConverterTypeSendingParameters_lift(_ buf: RustBuffer) throws -> SendingParameters { - return try FfiConverterTypeSendingParameters.lift(buf) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeAsyncPaymentsRole_lift(_ buf: RustBuffer) throws -> AsyncPaymentsRole { + return try FfiConverterTypeAsyncPaymentsRole.lift(buf) } -public func FfiConverterTypeSendingParameters_lower(_ value: SendingParameters) -> RustBuffer { - return FfiConverterTypeSendingParameters.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeAsyncPaymentsRole_lower(_ value: AsyncPaymentsRole) -> RustBuffer { + return FfiConverterTypeAsyncPaymentsRole.lower(value) } +extension AsyncPaymentsRole: Equatable, Hashable {} + // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. public enum BalanceSource { - case holderForceClosed case counterpartyForceClosed case coopClose case htlc } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypeBalanceSource: FfiConverterRustBuffer { typealias SwiftType = BalanceSource public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> BalanceSource { let variant: Int32 = try readInt(&buf) switch variant { - case 1: return .holderForceClosed - + case 2: return .counterpartyForceClosed - + case 3: return .coopClose - + case 4: return .htlc - + default: throw UniffiInternalError.unexpectedEnumCase } } public static func write(_ value: BalanceSource, into buf: inout [UInt8]) { switch value { - - case .holderForceClosed: writeInt(&buf, Int32(1)) - - + case .counterpartyForceClosed: writeInt(&buf, Int32(2)) - - + case .coopClose: writeInt(&buf, Int32(3)) - - + case .htlc: writeInt(&buf, Int32(4)) - } } } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeBalanceSource_lift(_ buf: RustBuffer) throws -> BalanceSource { return try FfiConverterTypeBalanceSource.lift(buf) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeBalanceSource_lower(_ value: BalanceSource) -> RustBuffer { return FfiConverterTypeBalanceSource.lower(value) } - - extension BalanceSource: Equatable, Hashable {} - - // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. public enum Bolt11InvoiceDescription { - - case hash(hash: String - ) - case direct(description: String - ) + case hash(hash: String) + case direct(description: String) } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypeBolt11InvoiceDescription: FfiConverterRustBuffer { typealias SwiftType = Bolt11InvoiceDescription public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Bolt11InvoiceDescription { let variant: Int32 = try readInt(&buf) switch variant { - - case 1: return .hash(hash: try FfiConverterString.read(from: &buf) - ) - - case 2: return .direct(description: try FfiConverterString.read(from: &buf) - ) - + case 1: return try .hash(hash: FfiConverterString.read(from: &buf)) + + case 2: return try .direct(description: FfiConverterString.read(from: &buf)) + default: throw UniffiInternalError.unexpectedEnumCase } } public static func write(_ value: Bolt11InvoiceDescription, into buf: inout [UInt8]) { switch value { - - case let .hash(hash): writeInt(&buf, Int32(1)) FfiConverterString.write(hash, into: &buf) - - + case let .direct(description): writeInt(&buf, Int32(2)) FfiConverterString.write(description, into: &buf) - } } } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeBolt11InvoiceDescription_lift(_ buf: RustBuffer) throws -> Bolt11InvoiceDescription { return try FfiConverterTypeBolt11InvoiceDescription.lift(buf) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeBolt11InvoiceDescription_lower(_ value: Bolt11InvoiceDescription) -> RustBuffer { return FfiConverterTypeBolt11InvoiceDescription.lower(value) } - - extension Bolt11InvoiceDescription: Equatable, Hashable {} - - - public enum BuildError { - - - case InvalidSeedBytes(message: String) - + case InvalidSeedFile(message: String) - + case InvalidSystemTime(message: String) - + case InvalidChannelMonitor(message: String) - + case InvalidListeningAddresses(message: String) - + case InvalidAnnouncementAddresses(message: String) - + case InvalidNodeAlias(message: String) - + + case RuntimeSetupFailed(message: String) + case ReadFailed(message: String) - + + case DangerousValue(message: String) + case WriteFailed(message: String) - + case StoragePathAccessFailed(message: String) - + case KvStoreSetupFailed(message: String) - + case WalletSetupFailed(message: String) - + case LoggerSetupFailed(message: String) - + case NetworkMismatch(message: String) - -} + case AsyncPaymentsConfigMismatch(message: String) +} +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypeBuildError: FfiConverterRustBuffer { typealias SwiftType = BuildError public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> BuildError { let variant: Int32 = try readInt(&buf) switch variant { + case 1: return try .InvalidSeedBytes( + message: FfiConverterString.read(from: &buf) + ) - + case 2: return try .InvalidSeedFile( + message: FfiConverterString.read(from: &buf) + ) - - case 1: return .InvalidSeedBytes( - message: try FfiConverterString.read(from: &buf) - ) - - case 2: return .InvalidSeedFile( - message: try FfiConverterString.read(from: &buf) - ) - - case 3: return .InvalidSystemTime( - message: try FfiConverterString.read(from: &buf) - ) - - case 4: return .InvalidChannelMonitor( - message: try FfiConverterString.read(from: &buf) - ) - - case 5: return .InvalidListeningAddresses( - message: try FfiConverterString.read(from: &buf) - ) - - case 6: return .InvalidAnnouncementAddresses( - message: try FfiConverterString.read(from: &buf) - ) - - case 7: return .InvalidNodeAlias( - message: try FfiConverterString.read(from: &buf) - ) - - case 8: return .ReadFailed( - message: try FfiConverterString.read(from: &buf) - ) - - case 9: return .WriteFailed( - message: try FfiConverterString.read(from: &buf) - ) - - case 10: return .StoragePathAccessFailed( - message: try FfiConverterString.read(from: &buf) - ) - - case 11: return .KvStoreSetupFailed( - message: try FfiConverterString.read(from: &buf) - ) - - case 12: return .WalletSetupFailed( - message: try FfiConverterString.read(from: &buf) - ) - - case 13: return .LoggerSetupFailed( - message: try FfiConverterString.read(from: &buf) - ) - - case 14: return .NetworkMismatch( - message: try FfiConverterString.read(from: &buf) - ) - + case 3: return try .InvalidSystemTime( + message: FfiConverterString.read(from: &buf) + ) + + case 4: return try .InvalidChannelMonitor( + message: FfiConverterString.read(from: &buf) + ) + + case 5: return try .InvalidListeningAddresses( + message: FfiConverterString.read(from: &buf) + ) + + case 6: return try .InvalidAnnouncementAddresses( + message: FfiConverterString.read(from: &buf) + ) + + case 7: return try .InvalidNodeAlias( + message: FfiConverterString.read(from: &buf) + ) + + case 8: return try .RuntimeSetupFailed( + message: FfiConverterString.read(from: &buf) + ) + + case 9: return try .ReadFailed( + message: FfiConverterString.read(from: &buf) + ) + + case 10: return try .DangerousValue( + message: FfiConverterString.read(from: &buf) + ) + + case 11: return try .WriteFailed( + message: FfiConverterString.read(from: &buf) + ) + + case 12: return try .StoragePathAccessFailed( + message: FfiConverterString.read(from: &buf) + ) + + case 13: return try .KvStoreSetupFailed( + message: FfiConverterString.read(from: &buf) + ) + + case 14: return try .WalletSetupFailed( + message: FfiConverterString.read(from: &buf) + ) + + case 15: return try .LoggerSetupFailed( + message: FfiConverterString.read(from: &buf) + ) + + case 16: return try .NetworkMismatch( + message: FfiConverterString.read(from: &buf) + ) + + case 17: return try .AsyncPaymentsConfigMismatch( + message: FfiConverterString.read(from: &buf) + ) default: throw UniffiInternalError.unexpectedEnumCase } @@ -5584,266 +8155,312 @@ public struct FfiConverterTypeBuildError: FfiConverterRustBuffer { public static func write(_ value: BuildError, into buf: inout [UInt8]) { switch value { - - - - - case .InvalidSeedBytes(_ /* message is ignored*/): + case .InvalidSeedBytes(_ /* message is ignored*/ ): writeInt(&buf, Int32(1)) - case .InvalidSeedFile(_ /* message is ignored*/): + case .InvalidSeedFile(_ /* message is ignored*/ ): writeInt(&buf, Int32(2)) - case .InvalidSystemTime(_ /* message is ignored*/): + case .InvalidSystemTime(_ /* message is ignored*/ ): writeInt(&buf, Int32(3)) - case .InvalidChannelMonitor(_ /* message is ignored*/): + case .InvalidChannelMonitor(_ /* message is ignored*/ ): writeInt(&buf, Int32(4)) - case .InvalidListeningAddresses(_ /* message is ignored*/): + case .InvalidListeningAddresses(_ /* message is ignored*/ ): writeInt(&buf, Int32(5)) - case .InvalidAnnouncementAddresses(_ /* message is ignored*/): + case .InvalidAnnouncementAddresses(_ /* message is ignored*/ ): writeInt(&buf, Int32(6)) - case .InvalidNodeAlias(_ /* message is ignored*/): + case .InvalidNodeAlias(_ /* message is ignored*/ ): writeInt(&buf, Int32(7)) - case .ReadFailed(_ /* message is ignored*/): + case .RuntimeSetupFailed(_ /* message is ignored*/ ): writeInt(&buf, Int32(8)) - case .WriteFailed(_ /* message is ignored*/): + case .ReadFailed(_ /* message is ignored*/ ): writeInt(&buf, Int32(9)) - case .StoragePathAccessFailed(_ /* message is ignored*/): + case .DangerousValue(_ /* message is ignored*/ ): writeInt(&buf, Int32(10)) - case .KvStoreSetupFailed(_ /* message is ignored*/): + case .WriteFailed(_ /* message is ignored*/ ): writeInt(&buf, Int32(11)) - case .WalletSetupFailed(_ /* message is ignored*/): + case .StoragePathAccessFailed(_ /* message is ignored*/ ): writeInt(&buf, Int32(12)) - case .LoggerSetupFailed(_ /* message is ignored*/): + case .KvStoreSetupFailed(_ /* message is ignored*/ ): writeInt(&buf, Int32(13)) - case .NetworkMismatch(_ /* message is ignored*/): + case .WalletSetupFailed(_ /* message is ignored*/ ): writeInt(&buf, Int32(14)) - - + case .LoggerSetupFailed(_ /* message is ignored*/ ): + writeInt(&buf, Int32(15)) + case .NetworkMismatch(_ /* message is ignored*/ ): + writeInt(&buf, Int32(16)) + case .AsyncPaymentsConfigMismatch(_ /* message is ignored*/ ): + writeInt(&buf, Int32(17)) } } } - extension BuildError: Equatable, Hashable {} -extension BuildError: Error { } +extension BuildError: Foundation.LocalizedError { + public var errorDescription: String? { + String(reflecting: self) + } +} // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. public enum ClosureReason { - - case counterpartyForceClosed(peerMsg: UntrustedString - ) - case holderForceClosed(broadcastedLatestTxn: Bool? - ) + case counterpartyForceClosed(peerMsg: UntrustedString) + case holderForceClosed(broadcastedLatestTxn: Bool?, message: String) case legacyCooperativeClosure case counterpartyInitiatedCooperativeClosure case locallyInitiatedCooperativeClosure case commitmentTxConfirmed case fundingTimedOut - case processingError(err: String - ) + case processingError(err: String) case disconnectedPeer case outdatedChannelManager case counterpartyCoopClosedUnfundedChannel + case locallyCoopClosedUnfundedChannel case fundingBatchClosure - case htlCsTimedOut - case peerFeerateTooLow(peerFeerateSatPerKw: UInt32, requiredFeerateSatPerKw: UInt32 - ) + case htlCsTimedOut(paymentHash: PaymentHash?) + case peerFeerateTooLow(peerFeerateSatPerKw: UInt32, requiredFeerateSatPerKw: UInt32) } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypeClosureReason: FfiConverterRustBuffer { typealias SwiftType = ClosureReason public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ClosureReason { let variant: Int32 = try readInt(&buf) switch variant { - - case 1: return .counterpartyForceClosed(peerMsg: try FfiConverterTypeUntrustedString.read(from: &buf) - ) - - case 2: return .holderForceClosed(broadcastedLatestTxn: try FfiConverterOptionBool.read(from: &buf) - ) - + case 1: return try .counterpartyForceClosed(peerMsg: FfiConverterTypeUntrustedString.read(from: &buf)) + + case 2: return try .holderForceClosed(broadcastedLatestTxn: FfiConverterOptionBool.read(from: &buf), message: FfiConverterString.read(from: &buf)) + case 3: return .legacyCooperativeClosure - + case 4: return .counterpartyInitiatedCooperativeClosure - + case 5: return .locallyInitiatedCooperativeClosure - + case 6: return .commitmentTxConfirmed - + case 7: return .fundingTimedOut - - case 8: return .processingError(err: try FfiConverterString.read(from: &buf) - ) - + + case 8: return try .processingError(err: FfiConverterString.read(from: &buf)) + case 9: return .disconnectedPeer - + case 10: return .outdatedChannelManager - + case 11: return .counterpartyCoopClosedUnfundedChannel - - case 12: return .fundingBatchClosure - - case 13: return .htlCsTimedOut - - case 14: return .peerFeerateTooLow(peerFeerateSatPerKw: try FfiConverterUInt32.read(from: &buf), requiredFeerateSatPerKw: try FfiConverterUInt32.read(from: &buf) - ) - + + case 12: return .locallyCoopClosedUnfundedChannel + + case 13: return .fundingBatchClosure + + case 14: return try .htlCsTimedOut(paymentHash: FfiConverterOptionTypePaymentHash.read(from: &buf)) + + case 15: return try .peerFeerateTooLow(peerFeerateSatPerKw: FfiConverterUInt32.read(from: &buf), requiredFeerateSatPerKw: FfiConverterUInt32.read(from: &buf)) + default: throw UniffiInternalError.unexpectedEnumCase } } public static func write(_ value: ClosureReason, into buf: inout [UInt8]) { switch value { - - case let .counterpartyForceClosed(peerMsg): writeInt(&buf, Int32(1)) FfiConverterTypeUntrustedString.write(peerMsg, into: &buf) - - - case let .holderForceClosed(broadcastedLatestTxn): + + case let .holderForceClosed(broadcastedLatestTxn, message): writeInt(&buf, Int32(2)) FfiConverterOptionBool.write(broadcastedLatestTxn, into: &buf) - - + FfiConverterString.write(message, into: &buf) + case .legacyCooperativeClosure: writeInt(&buf, Int32(3)) - - + case .counterpartyInitiatedCooperativeClosure: writeInt(&buf, Int32(4)) - - + case .locallyInitiatedCooperativeClosure: writeInt(&buf, Int32(5)) - - + case .commitmentTxConfirmed: writeInt(&buf, Int32(6)) - - + case .fundingTimedOut: writeInt(&buf, Int32(7)) - - + case let .processingError(err): writeInt(&buf, Int32(8)) FfiConverterString.write(err, into: &buf) - - + case .disconnectedPeer: writeInt(&buf, Int32(9)) - - + case .outdatedChannelManager: writeInt(&buf, Int32(10)) - - + case .counterpartyCoopClosedUnfundedChannel: writeInt(&buf, Int32(11)) - - - case .fundingBatchClosure: + + case .locallyCoopClosedUnfundedChannel: writeInt(&buf, Int32(12)) - - - case .htlCsTimedOut: + + case .fundingBatchClosure: writeInt(&buf, Int32(13)) - - - case let .peerFeerateTooLow(peerFeerateSatPerKw,requiredFeerateSatPerKw): + + case let .htlCsTimedOut(paymentHash): writeInt(&buf, Int32(14)) + FfiConverterOptionTypePaymentHash.write(paymentHash, into: &buf) + + case let .peerFeerateTooLow(peerFeerateSatPerKw, requiredFeerateSatPerKw): + writeInt(&buf, Int32(15)) FfiConverterUInt32.write(peerFeerateSatPerKw, into: &buf) FfiConverterUInt32.write(requiredFeerateSatPerKw, into: &buf) - } } } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeClosureReason_lift(_ buf: RustBuffer) throws -> ClosureReason { return try FfiConverterTypeClosureReason.lift(buf) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeClosureReason_lower(_ value: ClosureReason) -> RustBuffer { return FfiConverterTypeClosureReason.lower(value) } +extension ClosureReason: Equatable, Hashable {} + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum CoinSelectionAlgorithm { + case branchAndBound + case largestFirst + case oldestFirst + case singleRandomDraw +} +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeCoinSelectionAlgorithm: FfiConverterRustBuffer { + typealias SwiftType = CoinSelectionAlgorithm -extension ClosureReason: Equatable, Hashable {} + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> CoinSelectionAlgorithm { + let variant: Int32 = try readInt(&buf) + switch variant { + case 1: return .branchAndBound + + case 2: return .largestFirst + + case 3: return .oldestFirst + + case 4: return .singleRandomDraw + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: CoinSelectionAlgorithm, into buf: inout [UInt8]) { + switch value { + case .branchAndBound: + writeInt(&buf, Int32(1)) + + case .largestFirst: + writeInt(&buf, Int32(2)) + + case .oldestFirst: + writeInt(&buf, Int32(3)) + + case .singleRandomDraw: + writeInt(&buf, Int32(4)) + } + } +} +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeCoinSelectionAlgorithm_lift(_ buf: RustBuffer) throws -> CoinSelectionAlgorithm { + return try FfiConverterTypeCoinSelectionAlgorithm.lift(buf) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeCoinSelectionAlgorithm_lower(_ value: CoinSelectionAlgorithm) -> RustBuffer { + return FfiConverterTypeCoinSelectionAlgorithm.lower(value) +} +extension CoinSelectionAlgorithm: Equatable, Hashable {} // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. public enum ConfirmationStatus { - - case confirmed(blockHash: BlockHash, height: UInt32, timestamp: UInt64 - ) + case confirmed(blockHash: BlockHash, height: UInt32, timestamp: UInt64) case unconfirmed } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypeConfirmationStatus: FfiConverterRustBuffer { typealias SwiftType = ConfirmationStatus public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ConfirmationStatus { let variant: Int32 = try readInt(&buf) switch variant { - - case 1: return .confirmed(blockHash: try FfiConverterTypeBlockHash.read(from: &buf), height: try FfiConverterUInt32.read(from: &buf), timestamp: try FfiConverterUInt64.read(from: &buf) - ) - + case 1: return try .confirmed(blockHash: FfiConverterTypeBlockHash.read(from: &buf), height: FfiConverterUInt32.read(from: &buf), timestamp: FfiConverterUInt64.read(from: &buf)) + case 2: return .unconfirmed - + default: throw UniffiInternalError.unexpectedEnumCase } } public static func write(_ value: ConfirmationStatus, into buf: inout [UInt8]) { switch value { - - - case let .confirmed(blockHash,height,timestamp): + case let .confirmed(blockHash, height, timestamp): writeInt(&buf, Int32(1)) FfiConverterTypeBlockHash.write(blockHash, into: &buf) FfiConverterUInt32.write(height, into: &buf) FfiConverterUInt64.write(timestamp, into: &buf) - - + case .unconfirmed: writeInt(&buf, Int32(2)) - } } } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeConfirmationStatus_lift(_ buf: RustBuffer) throws -> ConfirmationStatus { return try FfiConverterTypeConfirmationStatus.lift(buf) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeConfirmationStatus_lower(_ value: ConfirmationStatus) -> RustBuffer { return FfiConverterTypeConfirmationStatus.lower(value) } - - extension ConfirmationStatus: Equatable, Hashable {} - - // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. public enum Currency { - case bitcoin case bitcoinTestnet case regtest @@ -5851,166 +8468,175 @@ public enum Currency { case signet } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypeCurrency: FfiConverterRustBuffer { typealias SwiftType = Currency public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Currency { let variant: Int32 = try readInt(&buf) switch variant { - case 1: return .bitcoin - + case 2: return .bitcoinTestnet - + case 3: return .regtest - + case 4: return .simnet - + case 5: return .signet - + default: throw UniffiInternalError.unexpectedEnumCase } } public static func write(_ value: Currency, into buf: inout [UInt8]) { switch value { - - case .bitcoin: writeInt(&buf, Int32(1)) - - + case .bitcoinTestnet: writeInt(&buf, Int32(2)) - - + case .regtest: writeInt(&buf, Int32(3)) - - + case .simnet: writeInt(&buf, Int32(4)) - - + case .signet: writeInt(&buf, Int32(5)) - } } } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeCurrency_lift(_ buf: RustBuffer) throws -> Currency { + return try FfiConverterTypeCurrency.lift(buf) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeCurrency_lower(_ value: Currency) -> RustBuffer { + return FfiConverterTypeCurrency.lower(value) +} + +extension Currency: Equatable, Hashable {} + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum Event { + case paymentSuccessful(paymentId: PaymentId?, paymentHash: PaymentHash, paymentPreimage: PaymentPreimage?, feePaidMsat: UInt64?) + case paymentFailed(paymentId: PaymentId?, paymentHash: PaymentHash?, reason: PaymentFailureReason?) + case paymentReceived(paymentId: PaymentId?, paymentHash: PaymentHash, amountMsat: UInt64, customRecords: [CustomTlvRecord]) + case paymentClaimable(paymentId: PaymentId, paymentHash: PaymentHash, claimableAmountMsat: UInt64, claimDeadline: UInt32?, customRecords: [CustomTlvRecord]) + case paymentForwarded(prevChannelId: ChannelId, nextChannelId: ChannelId, prevUserChannelId: UserChannelId?, nextUserChannelId: UserChannelId?, prevNodeId: PublicKey?, nextNodeId: PublicKey?, totalFeeEarnedMsat: UInt64?, skimmedFeeMsat: UInt64?, claimFromOnchainTx: Bool, outboundAmountForwardedMsat: UInt64?) + case probeSuccessful(paymentId: PaymentId, paymentHash: PaymentHash, routeFeeMsat: UInt64?) + case probeFailed(paymentId: PaymentId, paymentHash: PaymentHash, shortChannelId: UInt64?, routeFeeMsat: UInt64?) + case channelPending(channelId: ChannelId, userChannelId: UserChannelId, formerTemporaryChannelId: ChannelId, counterpartyNodeId: PublicKey, fundingTxo: OutPoint) + case channelReady(channelId: ChannelId, userChannelId: UserChannelId, counterpartyNodeId: PublicKey?, fundingTxo: OutPoint?) + case channelClosed(channelId: ChannelId, userChannelId: UserChannelId, counterpartyNodeId: PublicKey?, reason: ClosureReason?) + case splicePending(channelId: ChannelId, userChannelId: UserChannelId, counterpartyNodeId: PublicKey, newFundingTxo: OutPoint) + case spliceFailed(channelId: ChannelId, userChannelId: UserChannelId, counterpartyNodeId: PublicKey, abandonedFundingTxo: OutPoint?) + case onchainTransactionConfirmed(txid: Txid, blockHash: BlockHash, blockHeight: UInt32, confirmationTime: UInt64, details: TransactionDetails) + case onchainTransactionReceived(txid: Txid, details: TransactionDetails) + case onchainTransactionReplaced(txid: Txid, conflicts: [Txid]) + case onchainTransactionReorged(txid: Txid) + case onchainTransactionEvicted(txid: Txid) + case syncProgress(syncType: SyncType, progressPercent: UInt8, currentBlockHeight: UInt32, targetBlockHeight: UInt32) + case syncCompleted(syncType: SyncType, syncedBlockHeight: UInt32) + case balanceChanged(oldSpendableOnchainBalanceSats: UInt64, newSpendableOnchainBalanceSats: UInt64, oldTotalOnchainBalanceSats: UInt64, newTotalOnchainBalanceSats: UInt64, oldTotalLightningBalanceSats: UInt64, newTotalLightningBalanceSats: UInt64) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeEvent: FfiConverterRustBuffer { + typealias SwiftType = Event + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Event { + let variant: Int32 = try readInt(&buf) + switch variant { + case 1: return try .paymentSuccessful(paymentId: FfiConverterOptionTypePaymentId.read(from: &buf), paymentHash: FfiConverterTypePaymentHash.read(from: &buf), paymentPreimage: FfiConverterOptionTypePaymentPreimage.read(from: &buf), feePaidMsat: FfiConverterOptionUInt64.read(from: &buf)) + + case 2: return try .paymentFailed(paymentId: FfiConverterOptionTypePaymentId.read(from: &buf), paymentHash: FfiConverterOptionTypePaymentHash.read(from: &buf), reason: FfiConverterOptionTypePaymentFailureReason.read(from: &buf)) + + case 3: return try .paymentReceived(paymentId: FfiConverterOptionTypePaymentId.read(from: &buf), paymentHash: FfiConverterTypePaymentHash.read(from: &buf), amountMsat: FfiConverterUInt64.read(from: &buf), customRecords: FfiConverterSequenceTypeCustomTlvRecord.read(from: &buf)) + + case 4: return try .paymentClaimable(paymentId: FfiConverterTypePaymentId.read(from: &buf), paymentHash: FfiConverterTypePaymentHash.read(from: &buf), claimableAmountMsat: FfiConverterUInt64.read(from: &buf), claimDeadline: FfiConverterOptionUInt32.read(from: &buf), customRecords: FfiConverterSequenceTypeCustomTlvRecord.read(from: &buf)) + + case 5: return try .paymentForwarded(prevChannelId: FfiConverterTypeChannelId.read(from: &buf), nextChannelId: FfiConverterTypeChannelId.read(from: &buf), prevUserChannelId: FfiConverterOptionTypeUserChannelId.read(from: &buf), nextUserChannelId: FfiConverterOptionTypeUserChannelId.read(from: &buf), prevNodeId: FfiConverterOptionTypePublicKey.read(from: &buf), nextNodeId: FfiConverterOptionTypePublicKey.read(from: &buf), totalFeeEarnedMsat: FfiConverterOptionUInt64.read(from: &buf), skimmedFeeMsat: FfiConverterOptionUInt64.read(from: &buf), claimFromOnchainTx: FfiConverterBool.read(from: &buf), outboundAmountForwardedMsat: FfiConverterOptionUInt64.read(from: &buf)) + + case 6: return try .probeSuccessful(paymentId: FfiConverterTypePaymentId.read(from: &buf), paymentHash: FfiConverterTypePaymentHash.read(from: &buf), routeFeeMsat: FfiConverterOptionUInt64.read(from: &buf)) + + case 7: return try .probeFailed(paymentId: FfiConverterTypePaymentId.read(from: &buf), paymentHash: FfiConverterTypePaymentHash.read(from: &buf), shortChannelId: FfiConverterOptionUInt64.read(from: &buf), routeFeeMsat: FfiConverterOptionUInt64.read(from: &buf)) + + case 8: return try .channelPending(channelId: FfiConverterTypeChannelId.read(from: &buf), userChannelId: FfiConverterTypeUserChannelId.read(from: &buf), formerTemporaryChannelId: FfiConverterTypeChannelId.read(from: &buf), counterpartyNodeId: FfiConverterTypePublicKey.read(from: &buf), fundingTxo: FfiConverterTypeOutPoint.read(from: &buf)) -public func FfiConverterTypeCurrency_lift(_ buf: RustBuffer) throws -> Currency { - return try FfiConverterTypeCurrency.lift(buf) -} + case 9: return try .channelReady(channelId: FfiConverterTypeChannelId.read(from: &buf), userChannelId: FfiConverterTypeUserChannelId.read(from: &buf), counterpartyNodeId: FfiConverterOptionTypePublicKey.read(from: &buf), fundingTxo: FfiConverterOptionTypeOutPoint.read(from: &buf)) -public func FfiConverterTypeCurrency_lower(_ value: Currency) -> RustBuffer { - return FfiConverterTypeCurrency.lower(value) -} + case 10: return try .channelClosed(channelId: FfiConverterTypeChannelId.read(from: &buf), userChannelId: FfiConverterTypeUserChannelId.read(from: &buf), counterpartyNodeId: FfiConverterOptionTypePublicKey.read(from: &buf), reason: FfiConverterOptionTypeClosureReason.read(from: &buf)) + case 11: return try .splicePending(channelId: FfiConverterTypeChannelId.read(from: &buf), userChannelId: FfiConverterTypeUserChannelId.read(from: &buf), counterpartyNodeId: FfiConverterTypePublicKey.read(from: &buf), newFundingTxo: FfiConverterTypeOutPoint.read(from: &buf)) + case 12: return try .spliceFailed(channelId: FfiConverterTypeChannelId.read(from: &buf), userChannelId: FfiConverterTypeUserChannelId.read(from: &buf), counterpartyNodeId: FfiConverterTypePublicKey.read(from: &buf), abandonedFundingTxo: FfiConverterOptionTypeOutPoint.read(from: &buf)) -extension Currency: Equatable, Hashable {} + case 13: return try .onchainTransactionConfirmed(txid: FfiConverterTypeTxid.read(from: &buf), blockHash: FfiConverterTypeBlockHash.read(from: &buf), blockHeight: FfiConverterUInt32.read(from: &buf), confirmationTime: FfiConverterUInt64.read(from: &buf), details: FfiConverterTypeTransactionDetails.read(from: &buf)) + case 14: return try .onchainTransactionReceived(txid: FfiConverterTypeTxid.read(from: &buf), details: FfiConverterTypeTransactionDetails.read(from: &buf)) + case 15: return try .onchainTransactionReplaced(txid: FfiConverterTypeTxid.read(from: &buf), conflicts: FfiConverterSequenceTypeTxid.read(from: &buf)) -// Note that we don't yet support `indirect` for enums. -// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + case 16: return try .onchainTransactionReorged(txid: FfiConverterTypeTxid.read(from: &buf)) -public enum Event { - - case paymentSuccessful(paymentId: PaymentId?, paymentHash: PaymentHash, paymentPreimage: PaymentPreimage?, feePaidMsat: UInt64? - ) - case paymentFailed(paymentId: PaymentId?, paymentHash: PaymentHash?, reason: PaymentFailureReason? - ) - case paymentReceived(paymentId: PaymentId?, paymentHash: PaymentHash, amountMsat: UInt64, customRecords: [CustomTlvRecord] - ) - case paymentClaimable(paymentId: PaymentId, paymentHash: PaymentHash, claimableAmountMsat: UInt64, claimDeadline: UInt32?, customRecords: [CustomTlvRecord] - ) - case paymentForwarded(prevChannelId: ChannelId, nextChannelId: ChannelId, prevUserChannelId: UserChannelId?, nextUserChannelId: UserChannelId?, prevNodeId: PublicKey?, nextNodeId: PublicKey?, totalFeeEarnedMsat: UInt64?, skimmedFeeMsat: UInt64?, claimFromOnchainTx: Bool, outboundAmountForwardedMsat: UInt64? - ) - case channelPending(channelId: ChannelId, userChannelId: UserChannelId, formerTemporaryChannelId: ChannelId, counterpartyNodeId: PublicKey, fundingTxo: OutPoint - ) - case channelReady(channelId: ChannelId, userChannelId: UserChannelId, counterpartyNodeId: PublicKey? - ) - case channelClosed(channelId: ChannelId, userChannelId: UserChannelId, counterpartyNodeId: PublicKey?, reason: ClosureReason? - ) -} + case 17: return try .onchainTransactionEvicted(txid: FfiConverterTypeTxid.read(from: &buf)) + case 18: return try .syncProgress(syncType: FfiConverterTypeSyncType.read(from: &buf), progressPercent: FfiConverterUInt8.read(from: &buf), currentBlockHeight: FfiConverterUInt32.read(from: &buf), targetBlockHeight: FfiConverterUInt32.read(from: &buf)) -public struct FfiConverterTypeEvent: FfiConverterRustBuffer { - typealias SwiftType = Event + case 19: return try .syncCompleted(syncType: FfiConverterTypeSyncType.read(from: &buf), syncedBlockHeight: FfiConverterUInt32.read(from: &buf)) + + case 20: return try .balanceChanged(oldSpendableOnchainBalanceSats: FfiConverterUInt64.read(from: &buf), newSpendableOnchainBalanceSats: FfiConverterUInt64.read(from: &buf), oldTotalOnchainBalanceSats: FfiConverterUInt64.read(from: &buf), newTotalOnchainBalanceSats: FfiConverterUInt64.read(from: &buf), oldTotalLightningBalanceSats: FfiConverterUInt64.read(from: &buf), newTotalLightningBalanceSats: FfiConverterUInt64.read(from: &buf)) - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Event { - let variant: Int32 = try readInt(&buf) - switch variant { - - case 1: return .paymentSuccessful(paymentId: try FfiConverterOptionTypePaymentId.read(from: &buf), paymentHash: try FfiConverterTypePaymentHash.read(from: &buf), paymentPreimage: try FfiConverterOptionTypePaymentPreimage.read(from: &buf), feePaidMsat: try FfiConverterOptionUInt64.read(from: &buf) - ) - - case 2: return .paymentFailed(paymentId: try FfiConverterOptionTypePaymentId.read(from: &buf), paymentHash: try FfiConverterOptionTypePaymentHash.read(from: &buf), reason: try FfiConverterOptionTypePaymentFailureReason.read(from: &buf) - ) - - case 3: return .paymentReceived(paymentId: try FfiConverterOptionTypePaymentId.read(from: &buf), paymentHash: try FfiConverterTypePaymentHash.read(from: &buf), amountMsat: try FfiConverterUInt64.read(from: &buf), customRecords: try FfiConverterSequenceTypeCustomTlvRecord.read(from: &buf) - ) - - case 4: return .paymentClaimable(paymentId: try FfiConverterTypePaymentId.read(from: &buf), paymentHash: try FfiConverterTypePaymentHash.read(from: &buf), claimableAmountMsat: try FfiConverterUInt64.read(from: &buf), claimDeadline: try FfiConverterOptionUInt32.read(from: &buf), customRecords: try FfiConverterSequenceTypeCustomTlvRecord.read(from: &buf) - ) - - case 5: return .paymentForwarded(prevChannelId: try FfiConverterTypeChannelId.read(from: &buf), nextChannelId: try FfiConverterTypeChannelId.read(from: &buf), prevUserChannelId: try FfiConverterOptionTypeUserChannelId.read(from: &buf), nextUserChannelId: try FfiConverterOptionTypeUserChannelId.read(from: &buf), prevNodeId: try FfiConverterOptionTypePublicKey.read(from: &buf), nextNodeId: try FfiConverterOptionTypePublicKey.read(from: &buf), totalFeeEarnedMsat: try FfiConverterOptionUInt64.read(from: &buf), skimmedFeeMsat: try FfiConverterOptionUInt64.read(from: &buf), claimFromOnchainTx: try FfiConverterBool.read(from: &buf), outboundAmountForwardedMsat: try FfiConverterOptionUInt64.read(from: &buf) - ) - - case 6: return .channelPending(channelId: try FfiConverterTypeChannelId.read(from: &buf), userChannelId: try FfiConverterTypeUserChannelId.read(from: &buf), formerTemporaryChannelId: try FfiConverterTypeChannelId.read(from: &buf), counterpartyNodeId: try FfiConverterTypePublicKey.read(from: &buf), fundingTxo: try FfiConverterTypeOutPoint.read(from: &buf) - ) - - case 7: return .channelReady(channelId: try FfiConverterTypeChannelId.read(from: &buf), userChannelId: try FfiConverterTypeUserChannelId.read(from: &buf), counterpartyNodeId: try FfiConverterOptionTypePublicKey.read(from: &buf) - ) - - case 8: return .channelClosed(channelId: try FfiConverterTypeChannelId.read(from: &buf), userChannelId: try FfiConverterTypeUserChannelId.read(from: &buf), counterpartyNodeId: try FfiConverterOptionTypePublicKey.read(from: &buf), reason: try FfiConverterOptionTypeClosureReason.read(from: &buf) - ) - default: throw UniffiInternalError.unexpectedEnumCase } } public static func write(_ value: Event, into buf: inout [UInt8]) { switch value { - - - case let .paymentSuccessful(paymentId,paymentHash,paymentPreimage,feePaidMsat): + case let .paymentSuccessful(paymentId, paymentHash, paymentPreimage, feePaidMsat): writeInt(&buf, Int32(1)) FfiConverterOptionTypePaymentId.write(paymentId, into: &buf) FfiConverterTypePaymentHash.write(paymentHash, into: &buf) FfiConverterOptionTypePaymentPreimage.write(paymentPreimage, into: &buf) FfiConverterOptionUInt64.write(feePaidMsat, into: &buf) - - - case let .paymentFailed(paymentId,paymentHash,reason): + + case let .paymentFailed(paymentId, paymentHash, reason): writeInt(&buf, Int32(2)) FfiConverterOptionTypePaymentId.write(paymentId, into: &buf) FfiConverterOptionTypePaymentHash.write(paymentHash, into: &buf) FfiConverterOptionTypePaymentFailureReason.write(reason, into: &buf) - - - case let .paymentReceived(paymentId,paymentHash,amountMsat,customRecords): + + case let .paymentReceived(paymentId, paymentHash, amountMsat, customRecords): writeInt(&buf, Int32(3)) FfiConverterOptionTypePaymentId.write(paymentId, into: &buf) FfiConverterTypePaymentHash.write(paymentHash, into: &buf) FfiConverterUInt64.write(amountMsat, into: &buf) FfiConverterSequenceTypeCustomTlvRecord.write(customRecords, into: &buf) - - - case let .paymentClaimable(paymentId,paymentHash,claimableAmountMsat,claimDeadline,customRecords): + + case let .paymentClaimable(paymentId, paymentHash, claimableAmountMsat, claimDeadline, customRecords): writeInt(&buf, Int32(4)) FfiConverterTypePaymentId.write(paymentId, into: &buf) FfiConverterTypePaymentHash.write(paymentHash, into: &buf) FfiConverterUInt64.write(claimableAmountMsat, into: &buf) FfiConverterOptionUInt32.write(claimDeadline, into: &buf) FfiConverterSequenceTypeCustomTlvRecord.write(customRecords, into: &buf) - - - case let .paymentForwarded(prevChannelId,nextChannelId,prevUserChannelId,nextUserChannelId,prevNodeId,nextNodeId,totalFeeEarnedMsat,skimmedFeeMsat,claimFromOnchainTx,outboundAmountForwardedMsat): + + case let .paymentForwarded(prevChannelId, nextChannelId, prevUserChannelId, nextUserChannelId, prevNodeId, nextNodeId, totalFeeEarnedMsat, skimmedFeeMsat, claimFromOnchainTx, outboundAmountForwardedMsat): writeInt(&buf, Int32(5)) FfiConverterTypeChannelId.write(prevChannelId, into: &buf) FfiConverterTypeChannelId.write(nextChannelId, into: &buf) @@ -6022,104 +8648,272 @@ public struct FfiConverterTypeEvent: FfiConverterRustBuffer { FfiConverterOptionUInt64.write(skimmedFeeMsat, into: &buf) FfiConverterBool.write(claimFromOnchainTx, into: &buf) FfiConverterOptionUInt64.write(outboundAmountForwardedMsat, into: &buf) - - - case let .channelPending(channelId,userChannelId,formerTemporaryChannelId,counterpartyNodeId,fundingTxo): + + case let .probeSuccessful(paymentId, paymentHash, routeFeeMsat): writeInt(&buf, Int32(6)) + FfiConverterTypePaymentId.write(paymentId, into: &buf) + FfiConverterTypePaymentHash.write(paymentHash, into: &buf) + FfiConverterOptionUInt64.write(routeFeeMsat, into: &buf) + + case let .probeFailed(paymentId, paymentHash, shortChannelId, routeFeeMsat): + writeInt(&buf, Int32(7)) + FfiConverterTypePaymentId.write(paymentId, into: &buf) + FfiConverterTypePaymentHash.write(paymentHash, into: &buf) + FfiConverterOptionUInt64.write(shortChannelId, into: &buf) + FfiConverterOptionUInt64.write(routeFeeMsat, into: &buf) + + case let .channelPending(channelId, userChannelId, formerTemporaryChannelId, counterpartyNodeId, fundingTxo): + writeInt(&buf, Int32(8)) FfiConverterTypeChannelId.write(channelId, into: &buf) FfiConverterTypeUserChannelId.write(userChannelId, into: &buf) FfiConverterTypeChannelId.write(formerTemporaryChannelId, into: &buf) FfiConverterTypePublicKey.write(counterpartyNodeId, into: &buf) FfiConverterTypeOutPoint.write(fundingTxo, into: &buf) - - - case let .channelReady(channelId,userChannelId,counterpartyNodeId): - writeInt(&buf, Int32(7)) + + case let .channelReady(channelId, userChannelId, counterpartyNodeId, fundingTxo): + writeInt(&buf, Int32(9)) FfiConverterTypeChannelId.write(channelId, into: &buf) FfiConverterTypeUserChannelId.write(userChannelId, into: &buf) FfiConverterOptionTypePublicKey.write(counterpartyNodeId, into: &buf) - - - case let .channelClosed(channelId,userChannelId,counterpartyNodeId,reason): - writeInt(&buf, Int32(8)) + FfiConverterOptionTypeOutPoint.write(fundingTxo, into: &buf) + + case let .channelClosed(channelId, userChannelId, counterpartyNodeId, reason): + writeInt(&buf, Int32(10)) FfiConverterTypeChannelId.write(channelId, into: &buf) FfiConverterTypeUserChannelId.write(userChannelId, into: &buf) FfiConverterOptionTypePublicKey.write(counterpartyNodeId, into: &buf) FfiConverterOptionTypeClosureReason.write(reason, into: &buf) - + + case let .splicePending(channelId, userChannelId, counterpartyNodeId, newFundingTxo): + writeInt(&buf, Int32(11)) + FfiConverterTypeChannelId.write(channelId, into: &buf) + FfiConverterTypeUserChannelId.write(userChannelId, into: &buf) + FfiConverterTypePublicKey.write(counterpartyNodeId, into: &buf) + FfiConverterTypeOutPoint.write(newFundingTxo, into: &buf) + + case let .spliceFailed(channelId, userChannelId, counterpartyNodeId, abandonedFundingTxo): + writeInt(&buf, Int32(12)) + FfiConverterTypeChannelId.write(channelId, into: &buf) + FfiConverterTypeUserChannelId.write(userChannelId, into: &buf) + FfiConverterTypePublicKey.write(counterpartyNodeId, into: &buf) + FfiConverterOptionTypeOutPoint.write(abandonedFundingTxo, into: &buf) + + case let .onchainTransactionConfirmed(txid, blockHash, blockHeight, confirmationTime, details): + writeInt(&buf, Int32(13)) + FfiConverterTypeTxid.write(txid, into: &buf) + FfiConverterTypeBlockHash.write(blockHash, into: &buf) + FfiConverterUInt32.write(blockHeight, into: &buf) + FfiConverterUInt64.write(confirmationTime, into: &buf) + FfiConverterTypeTransactionDetails.write(details, into: &buf) + + case let .onchainTransactionReceived(txid, details): + writeInt(&buf, Int32(14)) + FfiConverterTypeTxid.write(txid, into: &buf) + FfiConverterTypeTransactionDetails.write(details, into: &buf) + + case let .onchainTransactionReplaced(txid, conflicts): + writeInt(&buf, Int32(15)) + FfiConverterTypeTxid.write(txid, into: &buf) + FfiConverterSequenceTypeTxid.write(conflicts, into: &buf) + + case let .onchainTransactionReorged(txid): + writeInt(&buf, Int32(16)) + FfiConverterTypeTxid.write(txid, into: &buf) + + case let .onchainTransactionEvicted(txid): + writeInt(&buf, Int32(17)) + FfiConverterTypeTxid.write(txid, into: &buf) + + case let .syncProgress(syncType, progressPercent, currentBlockHeight, targetBlockHeight): + writeInt(&buf, Int32(18)) + FfiConverterTypeSyncType.write(syncType, into: &buf) + FfiConverterUInt8.write(progressPercent, into: &buf) + FfiConverterUInt32.write(currentBlockHeight, into: &buf) + FfiConverterUInt32.write(targetBlockHeight, into: &buf) + + case let .syncCompleted(syncType, syncedBlockHeight): + writeInt(&buf, Int32(19)) + FfiConverterTypeSyncType.write(syncType, into: &buf) + FfiConverterUInt32.write(syncedBlockHeight, into: &buf) + + case let .balanceChanged(oldSpendableOnchainBalanceSats, newSpendableOnchainBalanceSats, oldTotalOnchainBalanceSats, newTotalOnchainBalanceSats, oldTotalLightningBalanceSats, newTotalLightningBalanceSats): + writeInt(&buf, Int32(20)) + FfiConverterUInt64.write(oldSpendableOnchainBalanceSats, into: &buf) + FfiConverterUInt64.write(newSpendableOnchainBalanceSats, into: &buf) + FfiConverterUInt64.write(oldTotalOnchainBalanceSats, into: &buf) + FfiConverterUInt64.write(newTotalOnchainBalanceSats, into: &buf) + FfiConverterUInt64.write(oldTotalLightningBalanceSats, into: &buf) + FfiConverterUInt64.write(newTotalLightningBalanceSats, into: &buf) } } } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeEvent_lift(_ buf: RustBuffer) throws -> Event { return try FfiConverterTypeEvent.lift(buf) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeEvent_lower(_ value: Event) -> RustBuffer { return FfiConverterTypeEvent.lower(value) } +extension Event: Equatable, Hashable {} + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum KeychainKind { + case external + case `internal` +} +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeKeychainKind: FfiConverterRustBuffer { + typealias SwiftType = KeychainKind -extension Event: Equatable, Hashable {} + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> KeychainKind { + let variant: Int32 = try readInt(&buf) + switch variant { + case 1: return .external + + case 2: return .internal + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: KeychainKind, into buf: inout [UInt8]) { + switch value { + case .external: + writeInt(&buf, Int32(1)) + + case .internal: + writeInt(&buf, Int32(2)) + } + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeKeychainKind_lift(_ buf: RustBuffer) throws -> KeychainKind { + return try FfiConverterTypeKeychainKind.lift(buf) +} +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeKeychainKind_lower(_ value: KeychainKind) -> RustBuffer { + return FfiConverterTypeKeychainKind.lower(value) +} +extension KeychainKind: Equatable, Hashable {} // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. -public enum LightningBalance { - - case claimableOnChannelClose(channelId: ChannelId, counterpartyNodeId: PublicKey, amountSatoshis: UInt64, transactionFeeSatoshis: UInt64, outboundPaymentHtlcRoundedMsat: UInt64, outboundForwardedHtlcRoundedMsat: UInt64, inboundClaimingHtlcRoundedMsat: UInt64, inboundHtlcRoundedMsat: UInt64 - ) - case claimableAwaitingConfirmations(channelId: ChannelId, counterpartyNodeId: PublicKey, amountSatoshis: UInt64, confirmationHeight: UInt32, source: BalanceSource - ) - case contentiousClaimable(channelId: ChannelId, counterpartyNodeId: PublicKey, amountSatoshis: UInt64, timeoutHeight: UInt32, paymentHash: PaymentHash, paymentPreimage: PaymentPreimage - ) - case maybeTimeoutClaimableHtlc(channelId: ChannelId, counterpartyNodeId: PublicKey, amountSatoshis: UInt64, claimableHeight: UInt32, paymentHash: PaymentHash, outboundPayment: Bool - ) - case maybePreimageClaimableHtlc(channelId: ChannelId, counterpartyNodeId: PublicKey, amountSatoshis: UInt64, expiryHeight: UInt32, paymentHash: PaymentHash - ) - case counterpartyRevokedOutputClaimable(channelId: ChannelId, counterpartyNodeId: PublicKey, amountSatoshis: UInt64 - ) +public enum Lsps1PaymentState { + case expectPayment + case paid + case refunded +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeLSPS1PaymentState: FfiConverterRustBuffer { + typealias SwiftType = Lsps1PaymentState + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Lsps1PaymentState { + let variant: Int32 = try readInt(&buf) + switch variant { + case 1: return .expectPayment + + case 2: return .paid + + case 3: return .refunded + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: Lsps1PaymentState, into buf: inout [UInt8]) { + switch value { + case .expectPayment: + writeInt(&buf, Int32(1)) + + case .paid: + writeInt(&buf, Int32(2)) + + case .refunded: + writeInt(&buf, Int32(3)) + } + } } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeLSPS1PaymentState_lift(_ buf: RustBuffer) throws -> Lsps1PaymentState { + return try FfiConverterTypeLSPS1PaymentState.lift(buf) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeLSPS1PaymentState_lower(_ value: Lsps1PaymentState) -> RustBuffer { + return FfiConverterTypeLSPS1PaymentState.lower(value) +} + +extension Lsps1PaymentState: Equatable, Hashable {} + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum LightningBalance { + case claimableOnChannelClose(channelId: ChannelId, counterpartyNodeId: PublicKey, amountSatoshis: UInt64, transactionFeeSatoshis: UInt64, outboundPaymentHtlcRoundedMsat: UInt64, outboundForwardedHtlcRoundedMsat: UInt64, inboundClaimingHtlcRoundedMsat: UInt64, inboundHtlcRoundedMsat: UInt64) + case claimableAwaitingConfirmations(channelId: ChannelId, counterpartyNodeId: PublicKey, amountSatoshis: UInt64, confirmationHeight: UInt32, source: BalanceSource) + case contentiousClaimable(channelId: ChannelId, counterpartyNodeId: PublicKey, amountSatoshis: UInt64, timeoutHeight: UInt32, paymentHash: PaymentHash, paymentPreimage: PaymentPreimage) + case maybeTimeoutClaimableHtlc(channelId: ChannelId, counterpartyNodeId: PublicKey, amountSatoshis: UInt64, claimableHeight: UInt32, paymentHash: PaymentHash, outboundPayment: Bool) + case maybePreimageClaimableHtlc(channelId: ChannelId, counterpartyNodeId: PublicKey, amountSatoshis: UInt64, expiryHeight: UInt32, paymentHash: PaymentHash) + case counterpartyRevokedOutputClaimable(channelId: ChannelId, counterpartyNodeId: PublicKey, amountSatoshis: UInt64) +} +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypeLightningBalance: FfiConverterRustBuffer { typealias SwiftType = LightningBalance public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> LightningBalance { let variant: Int32 = try readInt(&buf) switch variant { - - case 1: return .claimableOnChannelClose(channelId: try FfiConverterTypeChannelId.read(from: &buf), counterpartyNodeId: try FfiConverterTypePublicKey.read(from: &buf), amountSatoshis: try FfiConverterUInt64.read(from: &buf), transactionFeeSatoshis: try FfiConverterUInt64.read(from: &buf), outboundPaymentHtlcRoundedMsat: try FfiConverterUInt64.read(from: &buf), outboundForwardedHtlcRoundedMsat: try FfiConverterUInt64.read(from: &buf), inboundClaimingHtlcRoundedMsat: try FfiConverterUInt64.read(from: &buf), inboundHtlcRoundedMsat: try FfiConverterUInt64.read(from: &buf) - ) - - case 2: return .claimableAwaitingConfirmations(channelId: try FfiConverterTypeChannelId.read(from: &buf), counterpartyNodeId: try FfiConverterTypePublicKey.read(from: &buf), amountSatoshis: try FfiConverterUInt64.read(from: &buf), confirmationHeight: try FfiConverterUInt32.read(from: &buf), source: try FfiConverterTypeBalanceSource.read(from: &buf) - ) - - case 3: return .contentiousClaimable(channelId: try FfiConverterTypeChannelId.read(from: &buf), counterpartyNodeId: try FfiConverterTypePublicKey.read(from: &buf), amountSatoshis: try FfiConverterUInt64.read(from: &buf), timeoutHeight: try FfiConverterUInt32.read(from: &buf), paymentHash: try FfiConverterTypePaymentHash.read(from: &buf), paymentPreimage: try FfiConverterTypePaymentPreimage.read(from: &buf) - ) - - case 4: return .maybeTimeoutClaimableHtlc(channelId: try FfiConverterTypeChannelId.read(from: &buf), counterpartyNodeId: try FfiConverterTypePublicKey.read(from: &buf), amountSatoshis: try FfiConverterUInt64.read(from: &buf), claimableHeight: try FfiConverterUInt32.read(from: &buf), paymentHash: try FfiConverterTypePaymentHash.read(from: &buf), outboundPayment: try FfiConverterBool.read(from: &buf) - ) - - case 5: return .maybePreimageClaimableHtlc(channelId: try FfiConverterTypeChannelId.read(from: &buf), counterpartyNodeId: try FfiConverterTypePublicKey.read(from: &buf), amountSatoshis: try FfiConverterUInt64.read(from: &buf), expiryHeight: try FfiConverterUInt32.read(from: &buf), paymentHash: try FfiConverterTypePaymentHash.read(from: &buf) - ) - - case 6: return .counterpartyRevokedOutputClaimable(channelId: try FfiConverterTypeChannelId.read(from: &buf), counterpartyNodeId: try FfiConverterTypePublicKey.read(from: &buf), amountSatoshis: try FfiConverterUInt64.read(from: &buf) - ) - + case 1: return try .claimableOnChannelClose(channelId: FfiConverterTypeChannelId.read(from: &buf), counterpartyNodeId: FfiConverterTypePublicKey.read(from: &buf), amountSatoshis: FfiConverterUInt64.read(from: &buf), transactionFeeSatoshis: FfiConverterUInt64.read(from: &buf), outboundPaymentHtlcRoundedMsat: FfiConverterUInt64.read(from: &buf), outboundForwardedHtlcRoundedMsat: FfiConverterUInt64.read(from: &buf), inboundClaimingHtlcRoundedMsat: FfiConverterUInt64.read(from: &buf), inboundHtlcRoundedMsat: FfiConverterUInt64.read(from: &buf)) + + case 2: return try .claimableAwaitingConfirmations(channelId: FfiConverterTypeChannelId.read(from: &buf), counterpartyNodeId: FfiConverterTypePublicKey.read(from: &buf), amountSatoshis: FfiConverterUInt64.read(from: &buf), confirmationHeight: FfiConverterUInt32.read(from: &buf), source: FfiConverterTypeBalanceSource.read(from: &buf)) + + case 3: return try .contentiousClaimable(channelId: FfiConverterTypeChannelId.read(from: &buf), counterpartyNodeId: FfiConverterTypePublicKey.read(from: &buf), amountSatoshis: FfiConverterUInt64.read(from: &buf), timeoutHeight: FfiConverterUInt32.read(from: &buf), paymentHash: FfiConverterTypePaymentHash.read(from: &buf), paymentPreimage: FfiConverterTypePaymentPreimage.read(from: &buf)) + + case 4: return try .maybeTimeoutClaimableHtlc(channelId: FfiConverterTypeChannelId.read(from: &buf), counterpartyNodeId: FfiConverterTypePublicKey.read(from: &buf), amountSatoshis: FfiConverterUInt64.read(from: &buf), claimableHeight: FfiConverterUInt32.read(from: &buf), paymentHash: FfiConverterTypePaymentHash.read(from: &buf), outboundPayment: FfiConverterBool.read(from: &buf)) + + case 5: return try .maybePreimageClaimableHtlc(channelId: FfiConverterTypeChannelId.read(from: &buf), counterpartyNodeId: FfiConverterTypePublicKey.read(from: &buf), amountSatoshis: FfiConverterUInt64.read(from: &buf), expiryHeight: FfiConverterUInt32.read(from: &buf), paymentHash: FfiConverterTypePaymentHash.read(from: &buf)) + + case 6: return try .counterpartyRevokedOutputClaimable(channelId: FfiConverterTypeChannelId.read(from: &buf), counterpartyNodeId: FfiConverterTypePublicKey.read(from: &buf), amountSatoshis: FfiConverterUInt64.read(from: &buf)) + default: throw UniffiInternalError.unexpectedEnumCase } } public static func write(_ value: LightningBalance, into buf: inout [UInt8]) { switch value { - - - case let .claimableOnChannelClose(channelId,counterpartyNodeId,amountSatoshis,transactionFeeSatoshis,outboundPaymentHtlcRoundedMsat,outboundForwardedHtlcRoundedMsat,inboundClaimingHtlcRoundedMsat,inboundHtlcRoundedMsat): + case let .claimableOnChannelClose(channelId, counterpartyNodeId, amountSatoshis, transactionFeeSatoshis, outboundPaymentHtlcRoundedMsat, outboundForwardedHtlcRoundedMsat, inboundClaimingHtlcRoundedMsat, inboundHtlcRoundedMsat): writeInt(&buf, Int32(1)) FfiConverterTypeChannelId.write(channelId, into: &buf) FfiConverterTypePublicKey.write(counterpartyNodeId, into: &buf) @@ -6129,18 +8923,16 @@ public struct FfiConverterTypeLightningBalance: FfiConverterRustBuffer { FfiConverterUInt64.write(outboundForwardedHtlcRoundedMsat, into: &buf) FfiConverterUInt64.write(inboundClaimingHtlcRoundedMsat, into: &buf) FfiConverterUInt64.write(inboundHtlcRoundedMsat, into: &buf) - - - case let .claimableAwaitingConfirmations(channelId,counterpartyNodeId,amountSatoshis,confirmationHeight,source): + + case let .claimableAwaitingConfirmations(channelId, counterpartyNodeId, amountSatoshis, confirmationHeight, source): writeInt(&buf, Int32(2)) FfiConverterTypeChannelId.write(channelId, into: &buf) FfiConverterTypePublicKey.write(counterpartyNodeId, into: &buf) FfiConverterUInt64.write(amountSatoshis, into: &buf) FfiConverterUInt32.write(confirmationHeight, into: &buf) FfiConverterTypeBalanceSource.write(source, into: &buf) - - - case let .contentiousClaimable(channelId,counterpartyNodeId,amountSatoshis,timeoutHeight,paymentHash,paymentPreimage): + + case let .contentiousClaimable(channelId, counterpartyNodeId, amountSatoshis, timeoutHeight, paymentHash, paymentPreimage): writeInt(&buf, Int32(3)) FfiConverterTypeChannelId.write(channelId, into: &buf) FfiConverterTypePublicKey.write(counterpartyNodeId, into: &buf) @@ -6148,9 +8940,8 @@ public struct FfiConverterTypeLightningBalance: FfiConverterRustBuffer { FfiConverterUInt32.write(timeoutHeight, into: &buf) FfiConverterTypePaymentHash.write(paymentHash, into: &buf) FfiConverterTypePaymentPreimage.write(paymentPreimage, into: &buf) - - - case let .maybeTimeoutClaimableHtlc(channelId,counterpartyNodeId,amountSatoshis,claimableHeight,paymentHash,outboundPayment): + + case let .maybeTimeoutClaimableHtlc(channelId, counterpartyNodeId, amountSatoshis, claimableHeight, paymentHash, outboundPayment): writeInt(&buf, Int32(4)) FfiConverterTypeChannelId.write(channelId, into: &buf) FfiConverterTypePublicKey.write(counterpartyNodeId, into: &buf) @@ -6158,47 +8949,44 @@ public struct FfiConverterTypeLightningBalance: FfiConverterRustBuffer { FfiConverterUInt32.write(claimableHeight, into: &buf) FfiConverterTypePaymentHash.write(paymentHash, into: &buf) FfiConverterBool.write(outboundPayment, into: &buf) - - - case let .maybePreimageClaimableHtlc(channelId,counterpartyNodeId,amountSatoshis,expiryHeight,paymentHash): + + case let .maybePreimageClaimableHtlc(channelId, counterpartyNodeId, amountSatoshis, expiryHeight, paymentHash): writeInt(&buf, Int32(5)) FfiConverterTypeChannelId.write(channelId, into: &buf) FfiConverterTypePublicKey.write(counterpartyNodeId, into: &buf) FfiConverterUInt64.write(amountSatoshis, into: &buf) FfiConverterUInt32.write(expiryHeight, into: &buf) FfiConverterTypePaymentHash.write(paymentHash, into: &buf) - - - case let .counterpartyRevokedOutputClaimable(channelId,counterpartyNodeId,amountSatoshis): + + case let .counterpartyRevokedOutputClaimable(channelId, counterpartyNodeId, amountSatoshis): writeInt(&buf, Int32(6)) FfiConverterTypeChannelId.write(channelId, into: &buf) FfiConverterTypePublicKey.write(counterpartyNodeId, into: &buf) FfiConverterUInt64.write(amountSatoshis, into: &buf) - } } } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeLightningBalance_lift(_ buf: RustBuffer) throws -> LightningBalance { return try FfiConverterTypeLightningBalance.lift(buf) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeLightningBalance_lower(_ value: LightningBalance) -> RustBuffer { return FfiConverterTypeLightningBalance.lower(value) } - - extension LightningBalance: Equatable, Hashable {} - - // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. public enum LogLevel { - case gossip case trace case debug @@ -6207,594 +8995,606 @@ public enum LogLevel { case error } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypeLogLevel: FfiConverterRustBuffer { typealias SwiftType = LogLevel public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> LogLevel { let variant: Int32 = try readInt(&buf) switch variant { - case 1: return .gossip - + case 2: return .trace - + case 3: return .debug - + case 4: return .info - + case 5: return .warn - + case 6: return .error - + default: throw UniffiInternalError.unexpectedEnumCase } } public static func write(_ value: LogLevel, into buf: inout [UInt8]) { switch value { - - case .gossip: writeInt(&buf, Int32(1)) - - + case .trace: writeInt(&buf, Int32(2)) - - + case .debug: writeInt(&buf, Int32(3)) - - + case .info: writeInt(&buf, Int32(4)) - - + case .warn: writeInt(&buf, Int32(5)) - - + case .error: writeInt(&buf, Int32(6)) - } } } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeLogLevel_lift(_ buf: RustBuffer) throws -> LogLevel { return try FfiConverterTypeLogLevel.lift(buf) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeLogLevel_lower(_ value: LogLevel) -> RustBuffer { return FfiConverterTypeLogLevel.lower(value) } - - extension LogLevel: Equatable, Hashable {} - - // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. public enum MaxDustHtlcExposure { - - case fixedLimit(limitMsat: UInt64 - ) - case feeRateMultiplier(multiplier: UInt64 - ) + case fixedLimit(limitMsat: UInt64) + case feeRateMultiplier(multiplier: UInt64) } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypeMaxDustHTLCExposure: FfiConverterRustBuffer { typealias SwiftType = MaxDustHtlcExposure public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> MaxDustHtlcExposure { let variant: Int32 = try readInt(&buf) switch variant { - - case 1: return .fixedLimit(limitMsat: try FfiConverterUInt64.read(from: &buf) - ) - - case 2: return .feeRateMultiplier(multiplier: try FfiConverterUInt64.read(from: &buf) - ) - + case 1: return try .fixedLimit(limitMsat: FfiConverterUInt64.read(from: &buf)) + + case 2: return try .feeRateMultiplier(multiplier: FfiConverterUInt64.read(from: &buf)) + default: throw UniffiInternalError.unexpectedEnumCase } } public static func write(_ value: MaxDustHtlcExposure, into buf: inout [UInt8]) { switch value { - - case let .fixedLimit(limitMsat): writeInt(&buf, Int32(1)) FfiConverterUInt64.write(limitMsat, into: &buf) - - - case let .feeRateMultiplier(multiplier): - writeInt(&buf, Int32(2)) - FfiConverterUInt64.write(multiplier, into: &buf) - - } - } -} - -public func FfiConverterTypeMaxDustHTLCExposure_lift(_ buf: RustBuffer) throws -> MaxDustHtlcExposure { - return try FfiConverterTypeMaxDustHTLCExposure.lift(buf) -} - -public func FfiConverterTypeMaxDustHTLCExposure_lower(_ value: MaxDustHtlcExposure) -> RustBuffer { - return FfiConverterTypeMaxDustHTLCExposure.lower(value) -} - - - -extension MaxDustHtlcExposure: Equatable, Hashable {} - - - -// Note that we don't yet support `indirect` for enums. -// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. - -public enum MaxTotalRoutingFeeLimit { - - case none - case some(amountMsat: UInt64 - ) -} - - -public struct FfiConverterTypeMaxTotalRoutingFeeLimit: FfiConverterRustBuffer { - typealias SwiftType = MaxTotalRoutingFeeLimit - - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> MaxTotalRoutingFeeLimit { - let variant: Int32 = try readInt(&buf) - switch variant { - - case 1: return .none - - case 2: return .some(amountMsat: try FfiConverterUInt64.read(from: &buf) - ) - - default: throw UniffiInternalError.unexpectedEnumCase - } - } - - public static func write(_ value: MaxTotalRoutingFeeLimit, into buf: inout [UInt8]) { - switch value { - - - case .none: - writeInt(&buf, Int32(1)) - - - case let .some(amountMsat): + case let .feeRateMultiplier(multiplier): writeInt(&buf, Int32(2)) - FfiConverterUInt64.write(amountMsat, into: &buf) - + FfiConverterUInt64.write(multiplier, into: &buf) } } } - -public func FfiConverterTypeMaxTotalRoutingFeeLimit_lift(_ buf: RustBuffer) throws -> MaxTotalRoutingFeeLimit { - return try FfiConverterTypeMaxTotalRoutingFeeLimit.lift(buf) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeMaxDustHTLCExposure_lift(_ buf: RustBuffer) throws -> MaxDustHtlcExposure { + return try FfiConverterTypeMaxDustHTLCExposure.lift(buf) } -public func FfiConverterTypeMaxTotalRoutingFeeLimit_lower(_ value: MaxTotalRoutingFeeLimit) -> RustBuffer { - return FfiConverterTypeMaxTotalRoutingFeeLimit.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeMaxDustHTLCExposure_lower(_ value: MaxDustHtlcExposure) -> RustBuffer { + return FfiConverterTypeMaxDustHTLCExposure.lower(value) } - - -extension MaxTotalRoutingFeeLimit: Equatable, Hashable {} - - +extension MaxDustHtlcExposure: Equatable, Hashable {} // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. public enum Network { - case bitcoin case testnet case signet case regtest } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypeNetwork: FfiConverterRustBuffer { typealias SwiftType = Network public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Network { let variant: Int32 = try readInt(&buf) switch variant { - case 1: return .bitcoin - + case 2: return .testnet - + case 3: return .signet - + case 4: return .regtest - + default: throw UniffiInternalError.unexpectedEnumCase } } public static func write(_ value: Network, into buf: inout [UInt8]) { switch value { - - case .bitcoin: writeInt(&buf, Int32(1)) - - + case .testnet: writeInt(&buf, Int32(2)) - - + case .signet: writeInt(&buf, Int32(3)) - - + case .regtest: writeInt(&buf, Int32(4)) - } } } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeNetwork_lift(_ buf: RustBuffer) throws -> Network { return try FfiConverterTypeNetwork.lift(buf) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeNetwork_lower(_ value: Network) -> RustBuffer { return FfiConverterTypeNetwork.lower(value) } - - extension Network: Equatable, Hashable {} - - - public enum NodeError { - - - case AlreadyRunning(message: String) - + case NotRunning(message: String) - + case OnchainTxCreationFailed(message: String) - + case ConnectionFailed(message: String) - + case InvoiceCreationFailed(message: String) - + case InvoiceRequestCreationFailed(message: String) - + case OfferCreationFailed(message: String) - + case RefundCreationFailed(message: String) - + case PaymentSendingFailed(message: String) - + case InvalidCustomTlvs(message: String) - + case ProbeSendingFailed(message: String) - + + case RouteNotFound(message: String) + case ChannelCreationFailed(message: String) - + case ChannelClosingFailed(message: String) - + + case ChannelSplicingFailed(message: String) + case ChannelConfigUpdateFailed(message: String) - + case PersistenceFailed(message: String) - + case FeerateEstimationUpdateFailed(message: String) - + case FeerateEstimationUpdateTimeout(message: String) - + case WalletOperationFailed(message: String) - + case WalletOperationTimeout(message: String) - + case OnchainTxSigningFailed(message: String) - + case TxSyncFailed(message: String) - + case TxSyncTimeout(message: String) - + case GossipUpdateFailed(message: String) - + case GossipUpdateTimeout(message: String) - + case LiquidityRequestFailed(message: String) - + case UriParameterParsingFailed(message: String) - + case InvalidAddress(message: String) - + case InvalidSocketAddress(message: String) - + case InvalidPublicKey(message: String) - + case InvalidSecretKey(message: String) - + case InvalidOfferId(message: String) - + case InvalidNodeId(message: String) - + case InvalidPaymentId(message: String) - + case InvalidPaymentHash(message: String) - + case InvalidPaymentPreimage(message: String) - + case InvalidPaymentSecret(message: String) - + case InvalidAmount(message: String) - + case InvalidInvoice(message: String) - + case InvalidOffer(message: String) - + case InvalidRefund(message: String) - + case InvalidChannelId(message: String) - + case InvalidNetwork(message: String) - + case InvalidUri(message: String) - + case InvalidQuantity(message: String) - + case InvalidNodeAlias(message: String) - + case InvalidDateTime(message: String) - + case InvalidFeeRate(message: String) - + case DuplicatePayment(message: String) - + case UnsupportedCurrency(message: String) - + case InsufficientFunds(message: String) - + case LiquiditySourceUnavailable(message: String) - + case LiquidityFeeTooHigh(message: String) - -} + case InvalidBlindedPaths(message: String) + + case AsyncPaymentServicesDisabled(message: String) + + case CannotRbfFundingTransaction(message: String) + + case TransactionNotFound(message: String) + + case TransactionAlreadyConfirmed(message: String) + + case NoSpendableOutputs(message: String) + + case CoinSelectionFailed(message: String) + + case InvalidMnemonic(message: String) + + case BackgroundSyncNotEnabled(message: String) + + case AddressTypeAlreadyMonitored(message: String) + + case AddressTypeIsPrimary(message: String) + case AddressTypeNotMonitored(message: String) + + case OnchainWalletAccountNotRegistered(message: String) + + case InvalidSeedBytes(message: String) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypeNodeError: FfiConverterRustBuffer { typealias SwiftType = NodeError public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> NodeError { let variant: Int32 = try readInt(&buf) switch variant { + case 1: return try .AlreadyRunning( + message: FfiConverterString.read(from: &buf) + ) - + case 2: return try .NotRunning( + message: FfiConverterString.read(from: &buf) + ) - - case 1: return .AlreadyRunning( - message: try FfiConverterString.read(from: &buf) - ) - - case 2: return .NotRunning( - message: try FfiConverterString.read(from: &buf) - ) - - case 3: return .OnchainTxCreationFailed( - message: try FfiConverterString.read(from: &buf) - ) - - case 4: return .ConnectionFailed( - message: try FfiConverterString.read(from: &buf) - ) - - case 5: return .InvoiceCreationFailed( - message: try FfiConverterString.read(from: &buf) - ) - - case 6: return .InvoiceRequestCreationFailed( - message: try FfiConverterString.read(from: &buf) - ) - - case 7: return .OfferCreationFailed( - message: try FfiConverterString.read(from: &buf) - ) - - case 8: return .RefundCreationFailed( - message: try FfiConverterString.read(from: &buf) - ) - - case 9: return .PaymentSendingFailed( - message: try FfiConverterString.read(from: &buf) - ) - - case 10: return .InvalidCustomTlvs( - message: try FfiConverterString.read(from: &buf) - ) - - case 11: return .ProbeSendingFailed( - message: try FfiConverterString.read(from: &buf) - ) - - case 12: return .ChannelCreationFailed( - message: try FfiConverterString.read(from: &buf) - ) - - case 13: return .ChannelClosingFailed( - message: try FfiConverterString.read(from: &buf) - ) - - case 14: return .ChannelConfigUpdateFailed( - message: try FfiConverterString.read(from: &buf) - ) - - case 15: return .PersistenceFailed( - message: try FfiConverterString.read(from: &buf) - ) - - case 16: return .FeerateEstimationUpdateFailed( - message: try FfiConverterString.read(from: &buf) - ) - - case 17: return .FeerateEstimationUpdateTimeout( - message: try FfiConverterString.read(from: &buf) - ) - - case 18: return .WalletOperationFailed( - message: try FfiConverterString.read(from: &buf) - ) - - case 19: return .WalletOperationTimeout( - message: try FfiConverterString.read(from: &buf) - ) - - case 20: return .OnchainTxSigningFailed( - message: try FfiConverterString.read(from: &buf) - ) - - case 21: return .TxSyncFailed( - message: try FfiConverterString.read(from: &buf) - ) - - case 22: return .TxSyncTimeout( - message: try FfiConverterString.read(from: &buf) - ) - - case 23: return .GossipUpdateFailed( - message: try FfiConverterString.read(from: &buf) - ) - - case 24: return .GossipUpdateTimeout( - message: try FfiConverterString.read(from: &buf) - ) - - case 25: return .LiquidityRequestFailed( - message: try FfiConverterString.read(from: &buf) - ) - - case 26: return .UriParameterParsingFailed( - message: try FfiConverterString.read(from: &buf) - ) - - case 27: return .InvalidAddress( - message: try FfiConverterString.read(from: &buf) - ) - - case 28: return .InvalidSocketAddress( - message: try FfiConverterString.read(from: &buf) - ) - - case 29: return .InvalidPublicKey( - message: try FfiConverterString.read(from: &buf) - ) - - case 30: return .InvalidSecretKey( - message: try FfiConverterString.read(from: &buf) - ) - - case 31: return .InvalidOfferId( - message: try FfiConverterString.read(from: &buf) - ) - - case 32: return .InvalidNodeId( - message: try FfiConverterString.read(from: &buf) - ) - - case 33: return .InvalidPaymentId( - message: try FfiConverterString.read(from: &buf) - ) - - case 34: return .InvalidPaymentHash( - message: try FfiConverterString.read(from: &buf) - ) - - case 35: return .InvalidPaymentPreimage( - message: try FfiConverterString.read(from: &buf) - ) - - case 36: return .InvalidPaymentSecret( - message: try FfiConverterString.read(from: &buf) - ) - - case 37: return .InvalidAmount( - message: try FfiConverterString.read(from: &buf) - ) - - case 38: return .InvalidInvoice( - message: try FfiConverterString.read(from: &buf) - ) - - case 39: return .InvalidOffer( - message: try FfiConverterString.read(from: &buf) - ) - - case 40: return .InvalidRefund( - message: try FfiConverterString.read(from: &buf) - ) - - case 41: return .InvalidChannelId( - message: try FfiConverterString.read(from: &buf) - ) - - case 42: return .InvalidNetwork( - message: try FfiConverterString.read(from: &buf) - ) - - case 43: return .InvalidUri( - message: try FfiConverterString.read(from: &buf) - ) - - case 44: return .InvalidQuantity( - message: try FfiConverterString.read(from: &buf) - ) - - case 45: return .InvalidNodeAlias( - message: try FfiConverterString.read(from: &buf) - ) - - case 46: return .InvalidDateTime( - message: try FfiConverterString.read(from: &buf) - ) - - case 47: return .InvalidFeeRate( - message: try FfiConverterString.read(from: &buf) - ) - - case 48: return .DuplicatePayment( - message: try FfiConverterString.read(from: &buf) - ) - - case 49: return .UnsupportedCurrency( - message: try FfiConverterString.read(from: &buf) - ) - - case 50: return .InsufficientFunds( - message: try FfiConverterString.read(from: &buf) - ) - - case 51: return .LiquiditySourceUnavailable( - message: try FfiConverterString.read(from: &buf) - ) - - case 52: return .LiquidityFeeTooHigh( - message: try FfiConverterString.read(from: &buf) - ) - + case 3: return try .OnchainTxCreationFailed( + message: FfiConverterString.read(from: &buf) + ) + + case 4: return try .ConnectionFailed( + message: FfiConverterString.read(from: &buf) + ) + + case 5: return try .InvoiceCreationFailed( + message: FfiConverterString.read(from: &buf) + ) + + case 6: return try .InvoiceRequestCreationFailed( + message: FfiConverterString.read(from: &buf) + ) + + case 7: return try .OfferCreationFailed( + message: FfiConverterString.read(from: &buf) + ) + + case 8: return try .RefundCreationFailed( + message: FfiConverterString.read(from: &buf) + ) + + case 9: return try .PaymentSendingFailed( + message: FfiConverterString.read(from: &buf) + ) + + case 10: return try .InvalidCustomTlvs( + message: FfiConverterString.read(from: &buf) + ) + + case 11: return try .ProbeSendingFailed( + message: FfiConverterString.read(from: &buf) + ) + + case 12: return try .RouteNotFound( + message: FfiConverterString.read(from: &buf) + ) + + case 13: return try .ChannelCreationFailed( + message: FfiConverterString.read(from: &buf) + ) + + case 14: return try .ChannelClosingFailed( + message: FfiConverterString.read(from: &buf) + ) + + case 15: return try .ChannelSplicingFailed( + message: FfiConverterString.read(from: &buf) + ) + + case 16: return try .ChannelConfigUpdateFailed( + message: FfiConverterString.read(from: &buf) + ) + + case 17: return try .PersistenceFailed( + message: FfiConverterString.read(from: &buf) + ) + + case 18: return try .FeerateEstimationUpdateFailed( + message: FfiConverterString.read(from: &buf) + ) + + case 19: return try .FeerateEstimationUpdateTimeout( + message: FfiConverterString.read(from: &buf) + ) + + case 20: return try .WalletOperationFailed( + message: FfiConverterString.read(from: &buf) + ) + + case 21: return try .WalletOperationTimeout( + message: FfiConverterString.read(from: &buf) + ) + + case 22: return try .OnchainTxSigningFailed( + message: FfiConverterString.read(from: &buf) + ) + + case 23: return try .TxSyncFailed( + message: FfiConverterString.read(from: &buf) + ) + + case 24: return try .TxSyncTimeout( + message: FfiConverterString.read(from: &buf) + ) + + case 25: return try .GossipUpdateFailed( + message: FfiConverterString.read(from: &buf) + ) + + case 26: return try .GossipUpdateTimeout( + message: FfiConverterString.read(from: &buf) + ) + + case 27: return try .LiquidityRequestFailed( + message: FfiConverterString.read(from: &buf) + ) + + case 28: return try .UriParameterParsingFailed( + message: FfiConverterString.read(from: &buf) + ) + + case 29: return try .InvalidAddress( + message: FfiConverterString.read(from: &buf) + ) + + case 30: return try .InvalidSocketAddress( + message: FfiConverterString.read(from: &buf) + ) + + case 31: return try .InvalidPublicKey( + message: FfiConverterString.read(from: &buf) + ) + + case 32: return try .InvalidSecretKey( + message: FfiConverterString.read(from: &buf) + ) + + case 33: return try .InvalidOfferId( + message: FfiConverterString.read(from: &buf) + ) + + case 34: return try .InvalidNodeId( + message: FfiConverterString.read(from: &buf) + ) + + case 35: return try .InvalidPaymentId( + message: FfiConverterString.read(from: &buf) + ) + + case 36: return try .InvalidPaymentHash( + message: FfiConverterString.read(from: &buf) + ) + + case 37: return try .InvalidPaymentPreimage( + message: FfiConverterString.read(from: &buf) + ) + + case 38: return try .InvalidPaymentSecret( + message: FfiConverterString.read(from: &buf) + ) + + case 39: return try .InvalidAmount( + message: FfiConverterString.read(from: &buf) + ) + + case 40: return try .InvalidInvoice( + message: FfiConverterString.read(from: &buf) + ) + + case 41: return try .InvalidOffer( + message: FfiConverterString.read(from: &buf) + ) + + case 42: return try .InvalidRefund( + message: FfiConverterString.read(from: &buf) + ) + + case 43: return try .InvalidChannelId( + message: FfiConverterString.read(from: &buf) + ) + + case 44: return try .InvalidNetwork( + message: FfiConverterString.read(from: &buf) + ) + + case 45: return try .InvalidUri( + message: FfiConverterString.read(from: &buf) + ) + + case 46: return try .InvalidQuantity( + message: FfiConverterString.read(from: &buf) + ) + + case 47: return try .InvalidNodeAlias( + message: FfiConverterString.read(from: &buf) + ) + + case 48: return try .InvalidDateTime( + message: FfiConverterString.read(from: &buf) + ) + + case 49: return try .InvalidFeeRate( + message: FfiConverterString.read(from: &buf) + ) + + case 50: return try .DuplicatePayment( + message: FfiConverterString.read(from: &buf) + ) + + case 51: return try .UnsupportedCurrency( + message: FfiConverterString.read(from: &buf) + ) + + case 52: return try .InsufficientFunds( + message: FfiConverterString.read(from: &buf) + ) + + case 53: return try .LiquiditySourceUnavailable( + message: FfiConverterString.read(from: &buf) + ) + + case 54: return try .LiquidityFeeTooHigh( + message: FfiConverterString.read(from: &buf) + ) + + case 55: return try .InvalidBlindedPaths( + message: FfiConverterString.read(from: &buf) + ) + + case 56: return try .AsyncPaymentServicesDisabled( + message: FfiConverterString.read(from: &buf) + ) + + case 57: return try .CannotRbfFundingTransaction( + message: FfiConverterString.read(from: &buf) + ) + + case 58: return try .TransactionNotFound( + message: FfiConverterString.read(from: &buf) + ) + + case 59: return try .TransactionAlreadyConfirmed( + message: FfiConverterString.read(from: &buf) + ) + + case 60: return try .NoSpendableOutputs( + message: FfiConverterString.read(from: &buf) + ) + + case 61: return try .CoinSelectionFailed( + message: FfiConverterString.read(from: &buf) + ) + + case 62: return try .InvalidMnemonic( + message: FfiConverterString.read(from: &buf) + ) + + case 63: return try .BackgroundSyncNotEnabled( + message: FfiConverterString.read(from: &buf) + ) + + case 64: return try .AddressTypeAlreadyMonitored( + message: FfiConverterString.read(from: &buf) + ) + + case 65: return try .AddressTypeIsPrimary( + message: FfiConverterString.read(from: &buf) + ) + + case 66: return try .AddressTypeNotMonitored( + message: FfiConverterString.read(from: &buf) + ) + + case 67: return try .OnchainWalletAccountNotRegistered( + message: FfiConverterString.read(from: &buf) + ) + + case 68: return try .InvalidSeedBytes( + message: FfiConverterString.read(from: &buf) + ) default: throw UniffiInternalError.unexpectedEnumCase } @@ -6802,185 +9602,265 @@ public struct FfiConverterTypeNodeError: FfiConverterRustBuffer { public static func write(_ value: NodeError, into buf: inout [UInt8]) { switch value { - - - - - case .AlreadyRunning(_ /* message is ignored*/): + case .AlreadyRunning(_ /* message is ignored*/ ): writeInt(&buf, Int32(1)) - case .NotRunning(_ /* message is ignored*/): + case .NotRunning(_ /* message is ignored*/ ): writeInt(&buf, Int32(2)) - case .OnchainTxCreationFailed(_ /* message is ignored*/): + case .OnchainTxCreationFailed(_ /* message is ignored*/ ): writeInt(&buf, Int32(3)) - case .ConnectionFailed(_ /* message is ignored*/): + case .ConnectionFailed(_ /* message is ignored*/ ): writeInt(&buf, Int32(4)) - case .InvoiceCreationFailed(_ /* message is ignored*/): + case .InvoiceCreationFailed(_ /* message is ignored*/ ): writeInt(&buf, Int32(5)) - case .InvoiceRequestCreationFailed(_ /* message is ignored*/): + case .InvoiceRequestCreationFailed(_ /* message is ignored*/ ): writeInt(&buf, Int32(6)) - case .OfferCreationFailed(_ /* message is ignored*/): + case .OfferCreationFailed(_ /* message is ignored*/ ): writeInt(&buf, Int32(7)) - case .RefundCreationFailed(_ /* message is ignored*/): + case .RefundCreationFailed(_ /* message is ignored*/ ): writeInt(&buf, Int32(8)) - case .PaymentSendingFailed(_ /* message is ignored*/): + case .PaymentSendingFailed(_ /* message is ignored*/ ): writeInt(&buf, Int32(9)) - case .InvalidCustomTlvs(_ /* message is ignored*/): + case .InvalidCustomTlvs(_ /* message is ignored*/ ): writeInt(&buf, Int32(10)) - case .ProbeSendingFailed(_ /* message is ignored*/): + case .ProbeSendingFailed(_ /* message is ignored*/ ): writeInt(&buf, Int32(11)) - case .ChannelCreationFailed(_ /* message is ignored*/): + case .RouteNotFound(_ /* message is ignored*/ ): writeInt(&buf, Int32(12)) - case .ChannelClosingFailed(_ /* message is ignored*/): + case .ChannelCreationFailed(_ /* message is ignored*/ ): writeInt(&buf, Int32(13)) - case .ChannelConfigUpdateFailed(_ /* message is ignored*/): + case .ChannelClosingFailed(_ /* message is ignored*/ ): writeInt(&buf, Int32(14)) - case .PersistenceFailed(_ /* message is ignored*/): + case .ChannelSplicingFailed(_ /* message is ignored*/ ): writeInt(&buf, Int32(15)) - case .FeerateEstimationUpdateFailed(_ /* message is ignored*/): + case .ChannelConfigUpdateFailed(_ /* message is ignored*/ ): writeInt(&buf, Int32(16)) - case .FeerateEstimationUpdateTimeout(_ /* message is ignored*/): + case .PersistenceFailed(_ /* message is ignored*/ ): writeInt(&buf, Int32(17)) - case .WalletOperationFailed(_ /* message is ignored*/): + case .FeerateEstimationUpdateFailed(_ /* message is ignored*/ ): writeInt(&buf, Int32(18)) - case .WalletOperationTimeout(_ /* message is ignored*/): + case .FeerateEstimationUpdateTimeout(_ /* message is ignored*/ ): writeInt(&buf, Int32(19)) - case .OnchainTxSigningFailed(_ /* message is ignored*/): + case .WalletOperationFailed(_ /* message is ignored*/ ): writeInt(&buf, Int32(20)) - case .TxSyncFailed(_ /* message is ignored*/): + case .WalletOperationTimeout(_ /* message is ignored*/ ): writeInt(&buf, Int32(21)) - case .TxSyncTimeout(_ /* message is ignored*/): + case .OnchainTxSigningFailed(_ /* message is ignored*/ ): writeInt(&buf, Int32(22)) - case .GossipUpdateFailed(_ /* message is ignored*/): + case .TxSyncFailed(_ /* message is ignored*/ ): writeInt(&buf, Int32(23)) - case .GossipUpdateTimeout(_ /* message is ignored*/): + case .TxSyncTimeout(_ /* message is ignored*/ ): writeInt(&buf, Int32(24)) - case .LiquidityRequestFailed(_ /* message is ignored*/): + case .GossipUpdateFailed(_ /* message is ignored*/ ): writeInt(&buf, Int32(25)) - case .UriParameterParsingFailed(_ /* message is ignored*/): + case .GossipUpdateTimeout(_ /* message is ignored*/ ): writeInt(&buf, Int32(26)) - case .InvalidAddress(_ /* message is ignored*/): + case .LiquidityRequestFailed(_ /* message is ignored*/ ): writeInt(&buf, Int32(27)) - case .InvalidSocketAddress(_ /* message is ignored*/): + case .UriParameterParsingFailed(_ /* message is ignored*/ ): writeInt(&buf, Int32(28)) - case .InvalidPublicKey(_ /* message is ignored*/): + case .InvalidAddress(_ /* message is ignored*/ ): writeInt(&buf, Int32(29)) - case .InvalidSecretKey(_ /* message is ignored*/): + case .InvalidSocketAddress(_ /* message is ignored*/ ): writeInt(&buf, Int32(30)) - case .InvalidOfferId(_ /* message is ignored*/): + case .InvalidPublicKey(_ /* message is ignored*/ ): writeInt(&buf, Int32(31)) - case .InvalidNodeId(_ /* message is ignored*/): + case .InvalidSecretKey(_ /* message is ignored*/ ): writeInt(&buf, Int32(32)) - case .InvalidPaymentId(_ /* message is ignored*/): + case .InvalidOfferId(_ /* message is ignored*/ ): writeInt(&buf, Int32(33)) - case .InvalidPaymentHash(_ /* message is ignored*/): + case .InvalidNodeId(_ /* message is ignored*/ ): writeInt(&buf, Int32(34)) - case .InvalidPaymentPreimage(_ /* message is ignored*/): + case .InvalidPaymentId(_ /* message is ignored*/ ): writeInt(&buf, Int32(35)) - case .InvalidPaymentSecret(_ /* message is ignored*/): + case .InvalidPaymentHash(_ /* message is ignored*/ ): writeInt(&buf, Int32(36)) - case .InvalidAmount(_ /* message is ignored*/): + case .InvalidPaymentPreimage(_ /* message is ignored*/ ): writeInt(&buf, Int32(37)) - case .InvalidInvoice(_ /* message is ignored*/): + case .InvalidPaymentSecret(_ /* message is ignored*/ ): writeInt(&buf, Int32(38)) - case .InvalidOffer(_ /* message is ignored*/): + case .InvalidAmount(_ /* message is ignored*/ ): writeInt(&buf, Int32(39)) - case .InvalidRefund(_ /* message is ignored*/): + case .InvalidInvoice(_ /* message is ignored*/ ): writeInt(&buf, Int32(40)) - case .InvalidChannelId(_ /* message is ignored*/): + case .InvalidOffer(_ /* message is ignored*/ ): writeInt(&buf, Int32(41)) - case .InvalidNetwork(_ /* message is ignored*/): + case .InvalidRefund(_ /* message is ignored*/ ): writeInt(&buf, Int32(42)) - case .InvalidUri(_ /* message is ignored*/): + case .InvalidChannelId(_ /* message is ignored*/ ): writeInt(&buf, Int32(43)) - case .InvalidQuantity(_ /* message is ignored*/): + case .InvalidNetwork(_ /* message is ignored*/ ): writeInt(&buf, Int32(44)) - case .InvalidNodeAlias(_ /* message is ignored*/): + case .InvalidUri(_ /* message is ignored*/ ): writeInt(&buf, Int32(45)) - case .InvalidDateTime(_ /* message is ignored*/): + case .InvalidQuantity(_ /* message is ignored*/ ): writeInt(&buf, Int32(46)) - case .InvalidFeeRate(_ /* message is ignored*/): + case .InvalidNodeAlias(_ /* message is ignored*/ ): writeInt(&buf, Int32(47)) - case .DuplicatePayment(_ /* message is ignored*/): + case .InvalidDateTime(_ /* message is ignored*/ ): writeInt(&buf, Int32(48)) - case .UnsupportedCurrency(_ /* message is ignored*/): + case .InvalidFeeRate(_ /* message is ignored*/ ): writeInt(&buf, Int32(49)) - case .InsufficientFunds(_ /* message is ignored*/): + case .DuplicatePayment(_ /* message is ignored*/ ): writeInt(&buf, Int32(50)) - case .LiquiditySourceUnavailable(_ /* message is ignored*/): + case .UnsupportedCurrency(_ /* message is ignored*/ ): writeInt(&buf, Int32(51)) - case .LiquidityFeeTooHigh(_ /* message is ignored*/): + case .InsufficientFunds(_ /* message is ignored*/ ): writeInt(&buf, Int32(52)) + case .LiquiditySourceUnavailable(_ /* message is ignored*/ ): + writeInt(&buf, Int32(53)) + case .LiquidityFeeTooHigh(_ /* message is ignored*/ ): + writeInt(&buf, Int32(54)) + case .InvalidBlindedPaths(_ /* message is ignored*/ ): + writeInt(&buf, Int32(55)) + case .AsyncPaymentServicesDisabled(_ /* message is ignored*/ ): + writeInt(&buf, Int32(56)) + case .CannotRbfFundingTransaction(_ /* message is ignored*/ ): + writeInt(&buf, Int32(57)) + case .TransactionNotFound(_ /* message is ignored*/ ): + writeInt(&buf, Int32(58)) + case .TransactionAlreadyConfirmed(_ /* message is ignored*/ ): + writeInt(&buf, Int32(59)) + case .NoSpendableOutputs(_ /* message is ignored*/ ): + writeInt(&buf, Int32(60)) + case .CoinSelectionFailed(_ /* message is ignored*/ ): + writeInt(&buf, Int32(61)) + case .InvalidMnemonic(_ /* message is ignored*/ ): + writeInt(&buf, Int32(62)) + case .BackgroundSyncNotEnabled(_ /* message is ignored*/ ): + writeInt(&buf, Int32(63)) + case .AddressTypeAlreadyMonitored(_ /* message is ignored*/ ): + writeInt(&buf, Int32(64)) + case .AddressTypeIsPrimary(_ /* message is ignored*/ ): + writeInt(&buf, Int32(65)) + case .AddressTypeNotMonitored(_ /* message is ignored*/ ): + writeInt(&buf, Int32(66)) + case .OnchainWalletAccountNotRegistered(_ /* message is ignored*/ ): + writeInt(&buf, Int32(67)) + case .InvalidSeedBytes(_ /* message is ignored*/ ): + writeInt(&buf, Int32(68)) + } + } +} + +extension NodeError: Equatable, Hashable {} + +extension NodeError: Foundation.LocalizedError { + public var errorDescription: String? { + String(reflecting: self) + } +} + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum OfferAmount { + case bitcoin(amountMsats: UInt64) + case currency(iso4217Code: String, amount: UInt64) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeOfferAmount: FfiConverterRustBuffer { + typealias SwiftType = OfferAmount + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> OfferAmount { + let variant: Int32 = try readInt(&buf) + switch variant { + case 1: return try .bitcoin(amountMsats: FfiConverterUInt64.read(from: &buf)) + + case 2: return try .currency(iso4217Code: FfiConverterString.read(from: &buf), amount: FfiConverterUInt64.read(from: &buf)) + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: OfferAmount, into buf: inout [UInt8]) { + switch value { + case let .bitcoin(amountMsats): + writeInt(&buf, Int32(1)) + FfiConverterUInt64.write(amountMsats, into: &buf) - + case let .currency(iso4217Code, amount): + writeInt(&buf, Int32(2)) + FfiConverterString.write(iso4217Code, into: &buf) + FfiConverterUInt64.write(amount, into: &buf) } } } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeOfferAmount_lift(_ buf: RustBuffer) throws -> OfferAmount { + return try FfiConverterTypeOfferAmount.lift(buf) +} -extension NodeError: Equatable, Hashable {} +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeOfferAmount_lower(_ value: OfferAmount) -> RustBuffer { + return FfiConverterTypeOfferAmount.lower(value) +} -extension NodeError: Error { } +extension OfferAmount: Equatable, Hashable {} // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. public enum PaymentDirection { - case inbound case outbound } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypePaymentDirection: FfiConverterRustBuffer { typealias SwiftType = PaymentDirection public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> PaymentDirection { let variant: Int32 = try readInt(&buf) switch variant { - case 1: return .inbound - + case 2: return .outbound - + default: throw UniffiInternalError.unexpectedEnumCase } } public static func write(_ value: PaymentDirection, into buf: inout [UInt8]) { switch value { - - case .inbound: writeInt(&buf, Int32(1)) - - + case .outbound: writeInt(&buf, Int32(2)) - } } } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypePaymentDirection_lift(_ buf: RustBuffer) throws -> PaymentDirection { return try FfiConverterTypePaymentDirection.lift(buf) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypePaymentDirection_lower(_ value: PaymentDirection) -> RustBuffer { return FfiConverterTypePaymentDirection.lower(value) } - - extension PaymentDirection: Equatable, Hashable {} - - // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. public enum PaymentFailureReason { - case recipientRejected case userAbandoned case retriesExhausted @@ -6993,176 +9873,153 @@ public enum PaymentFailureReason { case blindedPathCreationFailed } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypePaymentFailureReason: FfiConverterRustBuffer { typealias SwiftType = PaymentFailureReason public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> PaymentFailureReason { let variant: Int32 = try readInt(&buf) switch variant { - case 1: return .recipientRejected - + case 2: return .userAbandoned - + case 3: return .retriesExhausted - + case 4: return .paymentExpired - + case 5: return .routeNotFound - + case 6: return .unexpectedError - + case 7: return .unknownRequiredFeatures - + case 8: return .invoiceRequestExpired - + case 9: return .invoiceRequestRejected - + case 10: return .blindedPathCreationFailed - + default: throw UniffiInternalError.unexpectedEnumCase } } public static func write(_ value: PaymentFailureReason, into buf: inout [UInt8]) { switch value { - - case .recipientRejected: writeInt(&buf, Int32(1)) - - + case .userAbandoned: writeInt(&buf, Int32(2)) - - + case .retriesExhausted: writeInt(&buf, Int32(3)) - - + case .paymentExpired: writeInt(&buf, Int32(4)) - - + case .routeNotFound: writeInt(&buf, Int32(5)) - - + case .unexpectedError: writeInt(&buf, Int32(6)) - - + case .unknownRequiredFeatures: writeInt(&buf, Int32(7)) - - + case .invoiceRequestExpired: writeInt(&buf, Int32(8)) - - + case .invoiceRequestRejected: writeInt(&buf, Int32(9)) - - + case .blindedPathCreationFailed: writeInt(&buf, Int32(10)) - } } } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypePaymentFailureReason_lift(_ buf: RustBuffer) throws -> PaymentFailureReason { return try FfiConverterTypePaymentFailureReason.lift(buf) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypePaymentFailureReason_lower(_ value: PaymentFailureReason) -> RustBuffer { return FfiConverterTypePaymentFailureReason.lower(value) } - - extension PaymentFailureReason: Equatable, Hashable {} - - // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. public enum PaymentKind { - - case onchain(txid: Txid, status: ConfirmationStatus - ) - case bolt11(hash: PaymentHash, preimage: PaymentPreimage?, secret: PaymentSecret? - ) - case bolt11Jit(hash: PaymentHash, preimage: PaymentPreimage?, secret: PaymentSecret?, counterpartySkimmedFeeMsat: UInt64?, lspFeeLimits: LspFeeLimits - ) - case bolt12Offer(hash: PaymentHash?, preimage: PaymentPreimage?, secret: PaymentSecret?, offerId: OfferId, payerNote: UntrustedString?, quantity: UInt64? - ) - case bolt12Refund(hash: PaymentHash?, preimage: PaymentPreimage?, secret: PaymentSecret?, payerNote: UntrustedString?, quantity: UInt64? - ) - case spontaneous(hash: PaymentHash, preimage: PaymentPreimage? - ) + case onchain(txid: Txid, status: ConfirmationStatus) + case bolt11(hash: PaymentHash, preimage: PaymentPreimage?, secret: PaymentSecret?, description: String?, bolt11: String?) + case bolt11Jit(hash: PaymentHash, preimage: PaymentPreimage?, secret: PaymentSecret?, counterpartySkimmedFeeMsat: UInt64?, lspFeeLimits: LspFeeLimits, description: String?, bolt11: String?) + case bolt12Offer(hash: PaymentHash?, preimage: PaymentPreimage?, secret: PaymentSecret?, offerId: OfferId, payerNote: UntrustedString?, quantity: UInt64?) + case bolt12Refund(hash: PaymentHash?, preimage: PaymentPreimage?, secret: PaymentSecret?, payerNote: UntrustedString?, quantity: UInt64?) + case spontaneous(hash: PaymentHash, preimage: PaymentPreimage?) } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypePaymentKind: FfiConverterRustBuffer { typealias SwiftType = PaymentKind public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> PaymentKind { let variant: Int32 = try readInt(&buf) switch variant { - - case 1: return .onchain(txid: try FfiConverterTypeTxid.read(from: &buf), status: try FfiConverterTypeConfirmationStatus.read(from: &buf) - ) - - case 2: return .bolt11(hash: try FfiConverterTypePaymentHash.read(from: &buf), preimage: try FfiConverterOptionTypePaymentPreimage.read(from: &buf), secret: try FfiConverterOptionTypePaymentSecret.read(from: &buf) - ) - - case 3: return .bolt11Jit(hash: try FfiConverterTypePaymentHash.read(from: &buf), preimage: try FfiConverterOptionTypePaymentPreimage.read(from: &buf), secret: try FfiConverterOptionTypePaymentSecret.read(from: &buf), counterpartySkimmedFeeMsat: try FfiConverterOptionUInt64.read(from: &buf), lspFeeLimits: try FfiConverterTypeLSPFeeLimits.read(from: &buf) - ) - - case 4: return .bolt12Offer(hash: try FfiConverterOptionTypePaymentHash.read(from: &buf), preimage: try FfiConverterOptionTypePaymentPreimage.read(from: &buf), secret: try FfiConverterOptionTypePaymentSecret.read(from: &buf), offerId: try FfiConverterTypeOfferId.read(from: &buf), payerNote: try FfiConverterOptionTypeUntrustedString.read(from: &buf), quantity: try FfiConverterOptionUInt64.read(from: &buf) - ) - - case 5: return .bolt12Refund(hash: try FfiConverterOptionTypePaymentHash.read(from: &buf), preimage: try FfiConverterOptionTypePaymentPreimage.read(from: &buf), secret: try FfiConverterOptionTypePaymentSecret.read(from: &buf), payerNote: try FfiConverterOptionTypeUntrustedString.read(from: &buf), quantity: try FfiConverterOptionUInt64.read(from: &buf) - ) - - case 6: return .spontaneous(hash: try FfiConverterTypePaymentHash.read(from: &buf), preimage: try FfiConverterOptionTypePaymentPreimage.read(from: &buf) - ) - + case 1: return try .onchain(txid: FfiConverterTypeTxid.read(from: &buf), status: FfiConverterTypeConfirmationStatus.read(from: &buf)) + + case 2: return try .bolt11(hash: FfiConverterTypePaymentHash.read(from: &buf), preimage: FfiConverterOptionTypePaymentPreimage.read(from: &buf), secret: FfiConverterOptionTypePaymentSecret.read(from: &buf), description: FfiConverterOptionString.read(from: &buf), bolt11: FfiConverterOptionString.read(from: &buf)) + + case 3: return try .bolt11Jit(hash: FfiConverterTypePaymentHash.read(from: &buf), preimage: FfiConverterOptionTypePaymentPreimage.read(from: &buf), secret: FfiConverterOptionTypePaymentSecret.read(from: &buf), counterpartySkimmedFeeMsat: FfiConverterOptionUInt64.read(from: &buf), lspFeeLimits: FfiConverterTypeLSPFeeLimits.read(from: &buf), description: FfiConverterOptionString.read(from: &buf), bolt11: FfiConverterOptionString.read(from: &buf)) + + case 4: return try .bolt12Offer(hash: FfiConverterOptionTypePaymentHash.read(from: &buf), preimage: FfiConverterOptionTypePaymentPreimage.read(from: &buf), secret: FfiConverterOptionTypePaymentSecret.read(from: &buf), offerId: FfiConverterTypeOfferId.read(from: &buf), payerNote: FfiConverterOptionTypeUntrustedString.read(from: &buf), quantity: FfiConverterOptionUInt64.read(from: &buf)) + + case 5: return try .bolt12Refund(hash: FfiConverterOptionTypePaymentHash.read(from: &buf), preimage: FfiConverterOptionTypePaymentPreimage.read(from: &buf), secret: FfiConverterOptionTypePaymentSecret.read(from: &buf), payerNote: FfiConverterOptionTypeUntrustedString.read(from: &buf), quantity: FfiConverterOptionUInt64.read(from: &buf)) + + case 6: return try .spontaneous(hash: FfiConverterTypePaymentHash.read(from: &buf), preimage: FfiConverterOptionTypePaymentPreimage.read(from: &buf)) + default: throw UniffiInternalError.unexpectedEnumCase } } public static func write(_ value: PaymentKind, into buf: inout [UInt8]) { switch value { - - - case let .onchain(txid,status): + case let .onchain(txid, status): writeInt(&buf, Int32(1)) FfiConverterTypeTxid.write(txid, into: &buf) FfiConverterTypeConfirmationStatus.write(status, into: &buf) - - - case let .bolt11(hash,preimage,secret): + + case let .bolt11(hash, preimage, secret, description, bolt11): writeInt(&buf, Int32(2)) FfiConverterTypePaymentHash.write(hash, into: &buf) FfiConverterOptionTypePaymentPreimage.write(preimage, into: &buf) FfiConverterOptionTypePaymentSecret.write(secret, into: &buf) - - - case let .bolt11Jit(hash,preimage,secret,counterpartySkimmedFeeMsat,lspFeeLimits): + FfiConverterOptionString.write(description, into: &buf) + FfiConverterOptionString.write(bolt11, into: &buf) + + case let .bolt11Jit(hash, preimage, secret, counterpartySkimmedFeeMsat, lspFeeLimits, description, bolt11): writeInt(&buf, Int32(3)) FfiConverterTypePaymentHash.write(hash, into: &buf) FfiConverterOptionTypePaymentPreimage.write(preimage, into: &buf) FfiConverterOptionTypePaymentSecret.write(secret, into: &buf) FfiConverterOptionUInt64.write(counterpartySkimmedFeeMsat, into: &buf) FfiConverterTypeLSPFeeLimits.write(lspFeeLimits, into: &buf) - - - case let .bolt12Offer(hash,preimage,secret,offerId,payerNote,quantity): + FfiConverterOptionString.write(description, into: &buf) + FfiConverterOptionString.write(bolt11, into: &buf) + + case let .bolt12Offer(hash, preimage, secret, offerId, payerNote, quantity): writeInt(&buf, Int32(4)) FfiConverterOptionTypePaymentHash.write(hash, into: &buf) FfiConverterOptionTypePaymentPreimage.write(preimage, into: &buf) @@ -7170,357 +10027,319 @@ public struct FfiConverterTypePaymentKind: FfiConverterRustBuffer { FfiConverterTypeOfferId.write(offerId, into: &buf) FfiConverterOptionTypeUntrustedString.write(payerNote, into: &buf) FfiConverterOptionUInt64.write(quantity, into: &buf) - - - case let .bolt12Refund(hash,preimage,secret,payerNote,quantity): + + case let .bolt12Refund(hash, preimage, secret, payerNote, quantity): writeInt(&buf, Int32(5)) FfiConverterOptionTypePaymentHash.write(hash, into: &buf) FfiConverterOptionTypePaymentPreimage.write(preimage, into: &buf) FfiConverterOptionTypePaymentSecret.write(secret, into: &buf) FfiConverterOptionTypeUntrustedString.write(payerNote, into: &buf) FfiConverterOptionUInt64.write(quantity, into: &buf) - - - case let .spontaneous(hash,preimage): + + case let .spontaneous(hash, preimage): writeInt(&buf, Int32(6)) FfiConverterTypePaymentHash.write(hash, into: &buf) FfiConverterOptionTypePaymentPreimage.write(preimage, into: &buf) - } } } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypePaymentKind_lift(_ buf: RustBuffer) throws -> PaymentKind { return try FfiConverterTypePaymentKind.lift(buf) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypePaymentKind_lower(_ value: PaymentKind) -> RustBuffer { return FfiConverterTypePaymentKind.lower(value) } - - extension PaymentKind: Equatable, Hashable {} - - -// Note that we don't yet support `indirect` for enums. -// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. - -public enum PaymentState { - - case expectPayment - case paid - case refunded -} - - -public struct FfiConverterTypePaymentState: FfiConverterRustBuffer { - typealias SwiftType = PaymentState - - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> PaymentState { - let variant: Int32 = try readInt(&buf) - switch variant { - - case 1: return .expectPayment - - case 2: return .paid - - case 3: return .refunded - - default: throw UniffiInternalError.unexpectedEnumCase - } - } - - public static func write(_ value: PaymentState, into buf: inout [UInt8]) { - switch value { - - - case .expectPayment: - writeInt(&buf, Int32(1)) - - - case .paid: - writeInt(&buf, Int32(2)) - - - case .refunded: - writeInt(&buf, Int32(3)) - - } - } -} - - -public func FfiConverterTypePaymentState_lift(_ buf: RustBuffer) throws -> PaymentState { - return try FfiConverterTypePaymentState.lift(buf) -} - -public func FfiConverterTypePaymentState_lower(_ value: PaymentState) -> RustBuffer { - return FfiConverterTypePaymentState.lower(value) -} - - - -extension PaymentState: Equatable, Hashable {} - - - // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. public enum PaymentStatus { - case pending case succeeded case failed } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypePaymentStatus: FfiConverterRustBuffer { typealias SwiftType = PaymentStatus public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> PaymentStatus { let variant: Int32 = try readInt(&buf) switch variant { - case 1: return .pending - + case 2: return .succeeded - + case 3: return .failed - + default: throw UniffiInternalError.unexpectedEnumCase } } public static func write(_ value: PaymentStatus, into buf: inout [UInt8]) { switch value { - - case .pending: writeInt(&buf, Int32(1)) - - + case .succeeded: writeInt(&buf, Int32(2)) - - + case .failed: writeInt(&buf, Int32(3)) - } } } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypePaymentStatus_lift(_ buf: RustBuffer) throws -> PaymentStatus { return try FfiConverterTypePaymentStatus.lift(buf) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypePaymentStatus_lower(_ value: PaymentStatus) -> RustBuffer { return FfiConverterTypePaymentStatus.lower(value) } - - extension PaymentStatus: Equatable, Hashable {} - - // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. public enum PendingSweepBalance { - - case pendingBroadcast(channelId: ChannelId?, amountSatoshis: UInt64 - ) - case broadcastAwaitingConfirmation(channelId: ChannelId?, latestBroadcastHeight: UInt32, latestSpendingTxid: Txid, amountSatoshis: UInt64 - ) - case awaitingThresholdConfirmations(channelId: ChannelId?, latestSpendingTxid: Txid, confirmationHash: BlockHash, confirmationHeight: UInt32, amountSatoshis: UInt64 - ) + case pendingBroadcast(channelId: ChannelId?, amountSatoshis: UInt64) + case broadcastAwaitingConfirmation(channelId: ChannelId?, latestBroadcastHeight: UInt32, latestSpendingTxid: Txid, amountSatoshis: UInt64) + case awaitingThresholdConfirmations(channelId: ChannelId?, latestSpendingTxid: Txid, confirmationHash: BlockHash, confirmationHeight: UInt32, amountSatoshis: UInt64) } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypePendingSweepBalance: FfiConverterRustBuffer { typealias SwiftType = PendingSweepBalance public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> PendingSweepBalance { let variant: Int32 = try readInt(&buf) switch variant { - - case 1: return .pendingBroadcast(channelId: try FfiConverterOptionTypeChannelId.read(from: &buf), amountSatoshis: try FfiConverterUInt64.read(from: &buf) - ) - - case 2: return .broadcastAwaitingConfirmation(channelId: try FfiConverterOptionTypeChannelId.read(from: &buf), latestBroadcastHeight: try FfiConverterUInt32.read(from: &buf), latestSpendingTxid: try FfiConverterTypeTxid.read(from: &buf), amountSatoshis: try FfiConverterUInt64.read(from: &buf) - ) - - case 3: return .awaitingThresholdConfirmations(channelId: try FfiConverterOptionTypeChannelId.read(from: &buf), latestSpendingTxid: try FfiConverterTypeTxid.read(from: &buf), confirmationHash: try FfiConverterTypeBlockHash.read(from: &buf), confirmationHeight: try FfiConverterUInt32.read(from: &buf), amountSatoshis: try FfiConverterUInt64.read(from: &buf) - ) - + case 1: return try .pendingBroadcast(channelId: FfiConverterOptionTypeChannelId.read(from: &buf), amountSatoshis: FfiConverterUInt64.read(from: &buf)) + + case 2: return try .broadcastAwaitingConfirmation(channelId: FfiConverterOptionTypeChannelId.read(from: &buf), latestBroadcastHeight: FfiConverterUInt32.read(from: &buf), latestSpendingTxid: FfiConverterTypeTxid.read(from: &buf), amountSatoshis: FfiConverterUInt64.read(from: &buf)) + + case 3: return try .awaitingThresholdConfirmations(channelId: FfiConverterOptionTypeChannelId.read(from: &buf), latestSpendingTxid: FfiConverterTypeTxid.read(from: &buf), confirmationHash: FfiConverterTypeBlockHash.read(from: &buf), confirmationHeight: FfiConverterUInt32.read(from: &buf), amountSatoshis: FfiConverterUInt64.read(from: &buf)) + default: throw UniffiInternalError.unexpectedEnumCase } } public static func write(_ value: PendingSweepBalance, into buf: inout [UInt8]) { switch value { - - - case let .pendingBroadcast(channelId,amountSatoshis): + case let .pendingBroadcast(channelId, amountSatoshis): writeInt(&buf, Int32(1)) FfiConverterOptionTypeChannelId.write(channelId, into: &buf) FfiConverterUInt64.write(amountSatoshis, into: &buf) - - - case let .broadcastAwaitingConfirmation(channelId,latestBroadcastHeight,latestSpendingTxid,amountSatoshis): + + case let .broadcastAwaitingConfirmation(channelId, latestBroadcastHeight, latestSpendingTxid, amountSatoshis): writeInt(&buf, Int32(2)) FfiConverterOptionTypeChannelId.write(channelId, into: &buf) FfiConverterUInt32.write(latestBroadcastHeight, into: &buf) FfiConverterTypeTxid.write(latestSpendingTxid, into: &buf) FfiConverterUInt64.write(amountSatoshis, into: &buf) - - - case let .awaitingThresholdConfirmations(channelId,latestSpendingTxid,confirmationHash,confirmationHeight,amountSatoshis): + + case let .awaitingThresholdConfirmations(channelId, latestSpendingTxid, confirmationHash, confirmationHeight, amountSatoshis): writeInt(&buf, Int32(3)) FfiConverterOptionTypeChannelId.write(channelId, into: &buf) FfiConverterTypeTxid.write(latestSpendingTxid, into: &buf) FfiConverterTypeBlockHash.write(confirmationHash, into: &buf) FfiConverterUInt32.write(confirmationHeight, into: &buf) FfiConverterUInt64.write(amountSatoshis, into: &buf) - } } } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypePendingSweepBalance_lift(_ buf: RustBuffer) throws -> PendingSweepBalance { return try FfiConverterTypePendingSweepBalance.lift(buf) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypePendingSweepBalance_lower(_ value: PendingSweepBalance) -> RustBuffer { return FfiConverterTypePendingSweepBalance.lower(value) } - - extension PendingSweepBalance: Equatable, Hashable {} - - // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. public enum QrPaymentResult { - - case onchain(txid: Txid - ) - case bolt11(paymentId: PaymentId - ) - case bolt12(paymentId: PaymentId - ) + case onchain(txid: Txid) + case bolt11(paymentId: PaymentId) + case bolt12(paymentId: PaymentId) } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypeQrPaymentResult: FfiConverterRustBuffer { typealias SwiftType = QrPaymentResult public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> QrPaymentResult { let variant: Int32 = try readInt(&buf) switch variant { - - case 1: return .onchain(txid: try FfiConverterTypeTxid.read(from: &buf) - ) - - case 2: return .bolt11(paymentId: try FfiConverterTypePaymentId.read(from: &buf) - ) - - case 3: return .bolt12(paymentId: try FfiConverterTypePaymentId.read(from: &buf) - ) - + case 1: return try .onchain(txid: FfiConverterTypeTxid.read(from: &buf)) + + case 2: return try .bolt11(paymentId: FfiConverterTypePaymentId.read(from: &buf)) + + case 3: return try .bolt12(paymentId: FfiConverterTypePaymentId.read(from: &buf)) + default: throw UniffiInternalError.unexpectedEnumCase } } public static func write(_ value: QrPaymentResult, into buf: inout [UInt8]) { switch value { - - case let .onchain(txid): writeInt(&buf, Int32(1)) FfiConverterTypeTxid.write(txid, into: &buf) - - + case let .bolt11(paymentId): writeInt(&buf, Int32(2)) FfiConverterTypePaymentId.write(paymentId, into: &buf) - - + case let .bolt12(paymentId): writeInt(&buf, Int32(3)) FfiConverterTypePaymentId.write(paymentId, into: &buf) - } } } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeQrPaymentResult_lift(_ buf: RustBuffer) throws -> QrPaymentResult { return try FfiConverterTypeQrPaymentResult.lift(buf) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeQrPaymentResult_lower(_ value: QrPaymentResult) -> RustBuffer { return FfiConverterTypeQrPaymentResult.lower(value) } +extension QrPaymentResult: Equatable, Hashable {} +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. -extension QrPaymentResult: Equatable, Hashable {} +public enum SyncType { + case onchainWallet + case lightningWallet + case feeRateCache +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeSyncType: FfiConverterRustBuffer { + typealias SwiftType = SyncType + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SyncType { + let variant: Int32 = try readInt(&buf) + switch variant { + case 1: return .onchainWallet + + case 2: return .lightningWallet + + case 3: return .feeRateCache + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: SyncType, into buf: inout [UInt8]) { + switch value { + case .onchainWallet: + writeInt(&buf, Int32(1)) + + case .lightningWallet: + writeInt(&buf, Int32(2)) + + case .feeRateCache: + writeInt(&buf, Int32(3)) + } + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeSyncType_lift(_ buf: RustBuffer) throws -> SyncType { + return try FfiConverterTypeSyncType.lift(buf) +} +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeSyncType_lower(_ value: SyncType) -> RustBuffer { + return FfiConverterTypeSyncType.lower(value) +} +extension SyncType: Equatable, Hashable {} public enum VssHeaderProviderError { - - - case InvalidData(message: String) - + case RequestError(message: String) - + case AuthorizationError(message: String) - + case InternalError(message: String) - } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypeVssHeaderProviderError: FfiConverterRustBuffer { typealias SwiftType = VssHeaderProviderError public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> VssHeaderProviderError { let variant: Int32 = try readInt(&buf) switch variant { + case 1: return try .InvalidData( + message: FfiConverterString.read(from: &buf) + ) - + case 2: return try .RequestError( + message: FfiConverterString.read(from: &buf) + ) - - case 1: return .InvalidData( - message: try FfiConverterString.read(from: &buf) - ) - - case 2: return .RequestError( - message: try FfiConverterString.read(from: &buf) - ) - - case 3: return .AuthorizationError( - message: try FfiConverterString.read(from: &buf) - ) - - case 4: return .InternalError( - message: try FfiConverterString.read(from: &buf) - ) - + case 3: return try .AuthorizationError( + message: FfiConverterString.read(from: &buf) + ) + + case 4: return try .InternalError( + message: FfiConverterString.read(from: &buf) + ) default: throw UniffiInternalError.unexpectedEnumCase } @@ -7528,54 +10347,103 @@ public struct FfiConverterTypeVssHeaderProviderError: FfiConverterRustBuffer { public static func write(_ value: VssHeaderProviderError, into buf: inout [UInt8]) { switch value { - - - - - case .InvalidData(_ /* message is ignored*/): + case .InvalidData(_ /* message is ignored*/ ): writeInt(&buf, Int32(1)) - case .RequestError(_ /* message is ignored*/): + case .RequestError(_ /* message is ignored*/ ): writeInt(&buf, Int32(2)) - case .AuthorizationError(_ /* message is ignored*/): + case .AuthorizationError(_ /* message is ignored*/ ): writeInt(&buf, Int32(3)) - case .InternalError(_ /* message is ignored*/): + case .InternalError(_ /* message is ignored*/ ): writeInt(&buf, Int32(4)) - - } } } - extension VssHeaderProviderError: Equatable, Hashable {} -extension VssHeaderProviderError: Error { } +extension VssHeaderProviderError: Foundation.LocalizedError { + public var errorDescription: String? { + String(reflecting: self) + } +} + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. -fileprivate struct FfiConverterOptionUInt8: FfiConverterRustBuffer { - typealias SwiftType = UInt8? +public enum WordCount { + case words12 + case words15 + case words18 + case words21 + case words24 +} - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { - guard let value = value else { - writeInt(&buf, Int8(0)) - return +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeWordCount: FfiConverterRustBuffer { + typealias SwiftType = WordCount + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> WordCount { + let variant: Int32 = try readInt(&buf) + switch variant { + case 1: return .words12 + + case 2: return .words15 + + case 3: return .words18 + + case 4: return .words21 + + case 5: return .words24 + + default: throw UniffiInternalError.unexpectedEnumCase } - writeInt(&buf, Int8(1)) - FfiConverterUInt8.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { - switch try readInt(&buf) as Int8 { - case 0: return nil - case 1: return try FfiConverterUInt8.read(from: &buf) - default: throw UniffiInternalError.unexpectedOptionalTag + public static func write(_ value: WordCount, into buf: inout [UInt8]) { + switch value { + case .words12: + writeInt(&buf, Int32(1)) + + case .words15: + writeInt(&buf, Int32(2)) + + case .words18: + writeInt(&buf, Int32(3)) + + case .words21: + writeInt(&buf, Int32(4)) + + case .words24: + writeInt(&buf, Int32(5)) } } } -fileprivate struct FfiConverterOptionUInt16: FfiConverterRustBuffer { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeWordCount_lift(_ buf: RustBuffer) throws -> WordCount { + return try FfiConverterTypeWordCount.lift(buf) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeWordCount_lower(_ value: WordCount) -> RustBuffer { + return FfiConverterTypeWordCount.lower(value) +} + +extension WordCount: Equatable, Hashable {} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionUInt16: FfiConverterRustBuffer { typealias SwiftType = UInt16? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return @@ -7584,7 +10452,7 @@ fileprivate struct FfiConverterOptionUInt16: FfiConverterRustBuffer { FfiConverterUInt16.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil case 1: return try FfiConverterUInt16.read(from: &buf) @@ -7593,10 +10461,13 @@ fileprivate struct FfiConverterOptionUInt16: FfiConverterRustBuffer { } } -fileprivate struct FfiConverterOptionUInt32: FfiConverterRustBuffer { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionUInt32: FfiConverterRustBuffer { typealias SwiftType = UInt32? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return @@ -7605,7 +10476,7 @@ fileprivate struct FfiConverterOptionUInt32: FfiConverterRustBuffer { FfiConverterUInt32.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil case 1: return try FfiConverterUInt32.read(from: &buf) @@ -7614,10 +10485,13 @@ fileprivate struct FfiConverterOptionUInt32: FfiConverterRustBuffer { } } -fileprivate struct FfiConverterOptionUInt64: FfiConverterRustBuffer { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionUInt64: FfiConverterRustBuffer { typealias SwiftType = UInt64? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return @@ -7626,7 +10500,7 @@ fileprivate struct FfiConverterOptionUInt64: FfiConverterRustBuffer { FfiConverterUInt64.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil case 1: return try FfiConverterUInt64.read(from: &buf) @@ -7635,10 +10509,13 @@ fileprivate struct FfiConverterOptionUInt64: FfiConverterRustBuffer { } } -fileprivate struct FfiConverterOptionBool: FfiConverterRustBuffer { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionBool: FfiConverterRustBuffer { typealias SwiftType = Bool? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return @@ -7647,7 +10524,7 @@ fileprivate struct FfiConverterOptionBool: FfiConverterRustBuffer { FfiConverterBool.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil case 1: return try FfiConverterBool.read(from: &buf) @@ -7656,10 +10533,13 @@ fileprivate struct FfiConverterOptionBool: FfiConverterRustBuffer { } } -fileprivate struct FfiConverterOptionString: FfiConverterRustBuffer { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionString: FfiConverterRustBuffer { typealias SwiftType = String? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return @@ -7668,7 +10548,7 @@ fileprivate struct FfiConverterOptionString: FfiConverterRustBuffer { FfiConverterString.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil case 1: return try FfiConverterString.read(from: &buf) @@ -7677,10 +10557,13 @@ fileprivate struct FfiConverterOptionString: FfiConverterRustBuffer { } } -fileprivate struct FfiConverterOptionTypeFeeRate: FfiConverterRustBuffer { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeFeeRate: FfiConverterRustBuffer { typealias SwiftType = FeeRate? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return @@ -7689,7 +10572,7 @@ fileprivate struct FfiConverterOptionTypeFeeRate: FfiConverterRustBuffer { FfiConverterTypeFeeRate.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil case 1: return try FfiConverterTypeFeeRate.read(from: &buf) @@ -7698,10 +10581,13 @@ fileprivate struct FfiConverterOptionTypeFeeRate: FfiConverterRustBuffer { } } -fileprivate struct FfiConverterOptionTypeAnchorChannelsConfig: FfiConverterRustBuffer { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeAnchorChannelsConfig: FfiConverterRustBuffer { typealias SwiftType = AnchorChannelsConfig? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return @@ -7710,7 +10596,7 @@ fileprivate struct FfiConverterOptionTypeAnchorChannelsConfig: FfiConverterRustB FfiConverterTypeAnchorChannelsConfig.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil case 1: return try FfiConverterTypeAnchorChannelsConfig.read(from: &buf) @@ -7719,10 +10605,13 @@ fileprivate struct FfiConverterOptionTypeAnchorChannelsConfig: FfiConverterRustB } } -fileprivate struct FfiConverterOptionTypeBackgroundSyncConfig: FfiConverterRustBuffer { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeBackgroundSyncConfig: FfiConverterRustBuffer { typealias SwiftType = BackgroundSyncConfig? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return @@ -7731,7 +10620,7 @@ fileprivate struct FfiConverterOptionTypeBackgroundSyncConfig: FfiConverterRustB FfiConverterTypeBackgroundSyncConfig.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil case 1: return try FfiConverterTypeBackgroundSyncConfig.read(from: &buf) @@ -7740,388 +10629,661 @@ fileprivate struct FfiConverterOptionTypeBackgroundSyncConfig: FfiConverterRustB } } -fileprivate struct FfiConverterOptionTypeBolt11PaymentInfo: FfiConverterRustBuffer { - typealias SwiftType = Bolt11PaymentInfo? +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeChannelConfig: FfiConverterRustBuffer { + typealias SwiftType = ChannelConfig? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return } writeInt(&buf, Int8(1)) - FfiConverterTypeBolt11PaymentInfo.write(value, into: &buf) + FfiConverterTypeChannelConfig.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil - case 1: return try FfiConverterTypeBolt11PaymentInfo.read(from: &buf) + case 1: return try FfiConverterTypeChannelConfig.read(from: &buf) default: throw UniffiInternalError.unexpectedOptionalTag } } } -fileprivate struct FfiConverterOptionTypeChannelConfig: FfiConverterRustBuffer { - typealias SwiftType = ChannelConfig? +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeChannelInfo: FfiConverterRustBuffer { + typealias SwiftType = ChannelInfo? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return } writeInt(&buf, Int8(1)) - FfiConverterTypeChannelConfig.write(value, into: &buf) + FfiConverterTypeChannelInfo.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil - case 1: return try FfiConverterTypeChannelConfig.read(from: &buf) + case 1: return try FfiConverterTypeChannelInfo.read(from: &buf) default: throw UniffiInternalError.unexpectedOptionalTag } } } -fileprivate struct FfiConverterOptionTypeChannelInfo: FfiConverterRustBuffer { - typealias SwiftType = ChannelInfo? +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeChannelUpdateInfo: FfiConverterRustBuffer { + typealias SwiftType = ChannelUpdateInfo? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return } writeInt(&buf, Int8(1)) - FfiConverterTypeChannelInfo.write(value, into: &buf) + FfiConverterTypeChannelUpdateInfo.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil - case 1: return try FfiConverterTypeChannelInfo.read(from: &buf) + case 1: return try FfiConverterTypeChannelUpdateInfo.read(from: &buf) default: throw UniffiInternalError.unexpectedOptionalTag } } } -fileprivate struct FfiConverterOptionTypeChannelOrderInfo: FfiConverterRustBuffer { - typealias SwiftType = ChannelOrderInfo? +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeElectrumSyncConfig: FfiConverterRustBuffer { + typealias SwiftType = ElectrumSyncConfig? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return } writeInt(&buf, Int8(1)) - FfiConverterTypeChannelOrderInfo.write(value, into: &buf) + FfiConverterTypeElectrumSyncConfig.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil - case 1: return try FfiConverterTypeChannelOrderInfo.read(from: &buf) + case 1: return try FfiConverterTypeElectrumSyncConfig.read(from: &buf) default: throw UniffiInternalError.unexpectedOptionalTag } } } -fileprivate struct FfiConverterOptionTypeChannelUpdateInfo: FfiConverterRustBuffer { - typealias SwiftType = ChannelUpdateInfo? +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeEsploraSyncConfig: FfiConverterRustBuffer { + typealias SwiftType = EsploraSyncConfig? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return } writeInt(&buf, Int8(1)) - FfiConverterTypeChannelUpdateInfo.write(value, into: &buf) + FfiConverterTypeEsploraSyncConfig.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil - case 1: return try FfiConverterTypeChannelUpdateInfo.read(from: &buf) + case 1: return try FfiConverterTypeEsploraSyncConfig.read(from: &buf) default: throw UniffiInternalError.unexpectedOptionalTag } } } -fileprivate struct FfiConverterOptionTypeElectrumSyncConfig: FfiConverterRustBuffer { - typealias SwiftType = ElectrumSyncConfig? +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeLSPS1Bolt11PaymentInfo: FfiConverterRustBuffer { + typealias SwiftType = Lsps1Bolt11PaymentInfo? + + static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterTypeLSPS1Bolt11PaymentInfo.write(value, into: &buf) + } + + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterTypeLSPS1Bolt11PaymentInfo.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeLSPS1ChannelInfo: FfiConverterRustBuffer { + typealias SwiftType = Lsps1ChannelInfo? + + static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterTypeLSPS1ChannelInfo.write(value, into: &buf) + } + + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterTypeLSPS1ChannelInfo.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeLSPS1OnchainPaymentInfo: FfiConverterRustBuffer { + typealias SwiftType = Lsps1OnchainPaymentInfo? + + static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterTypeLSPS1OnchainPaymentInfo.write(value, into: &buf) + } + + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterTypeLSPS1OnchainPaymentInfo.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeNodeAnnouncementInfo: FfiConverterRustBuffer { + typealias SwiftType = NodeAnnouncementInfo? + + static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterTypeNodeAnnouncementInfo.write(value, into: &buf) + } + + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterTypeNodeAnnouncementInfo.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeNodeInfo: FfiConverterRustBuffer { + typealias SwiftType = NodeInfo? + + static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterTypeNodeInfo.write(value, into: &buf) + } + + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterTypeNodeInfo.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeOutPoint: FfiConverterRustBuffer { + typealias SwiftType = OutPoint? + + static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterTypeOutPoint.write(value, into: &buf) + } + + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterTypeOutPoint.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypePaymentDetails: FfiConverterRustBuffer { + typealias SwiftType = PaymentDetails? + + static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterTypePaymentDetails.write(value, into: &buf) + } + + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterTypePaymentDetails.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeRouteParametersConfig: FfiConverterRustBuffer { + typealias SwiftType = RouteParametersConfig? + + static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterTypeRouteParametersConfig.write(value, into: &buf) + } + + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterTypeRouteParametersConfig.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeScoringDecayParameters: FfiConverterRustBuffer { + typealias SwiftType = ScoringDecayParameters? + + static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterTypeScoringDecayParameters.write(value, into: &buf) + } + + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterTypeScoringDecayParameters.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeScoringFeeParameters: FfiConverterRustBuffer { + typealias SwiftType = ScoringFeeParameters? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return } writeInt(&buf, Int8(1)) - FfiConverterTypeElectrumSyncConfig.write(value, into: &buf) + FfiConverterTypeScoringFeeParameters.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil - case 1: return try FfiConverterTypeElectrumSyncConfig.read(from: &buf) + case 1: return try FfiConverterTypeScoringFeeParameters.read(from: &buf) default: throw UniffiInternalError.unexpectedOptionalTag } } } -fileprivate struct FfiConverterOptionTypeEsploraSyncConfig: FfiConverterRustBuffer { - typealias SwiftType = EsploraSyncConfig? +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeTransactionDetails: FfiConverterRustBuffer { + typealias SwiftType = TransactionDetails? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return } writeInt(&buf, Int8(1)) - FfiConverterTypeEsploraSyncConfig.write(value, into: &buf) + FfiConverterTypeTransactionDetails.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil - case 1: return try FfiConverterTypeEsploraSyncConfig.read(from: &buf) + case 1: return try FfiConverterTypeTransactionDetails.read(from: &buf) default: throw UniffiInternalError.unexpectedOptionalTag } } } -fileprivate struct FfiConverterOptionTypeNodeAnnouncementInfo: FfiConverterRustBuffer { - typealias SwiftType = NodeAnnouncementInfo? +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeAsyncPaymentsRole: FfiConverterRustBuffer { + typealias SwiftType = AsyncPaymentsRole? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return } writeInt(&buf, Int8(1)) - FfiConverterTypeNodeAnnouncementInfo.write(value, into: &buf) + FfiConverterTypeAsyncPaymentsRole.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil - case 1: return try FfiConverterTypeNodeAnnouncementInfo.read(from: &buf) + case 1: return try FfiConverterTypeAsyncPaymentsRole.read(from: &buf) default: throw UniffiInternalError.unexpectedOptionalTag } } } -fileprivate struct FfiConverterOptionTypeNodeInfo: FfiConverterRustBuffer { - typealias SwiftType = NodeInfo? +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeClosureReason: FfiConverterRustBuffer { + typealias SwiftType = ClosureReason? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return } writeInt(&buf, Int8(1)) - FfiConverterTypeNodeInfo.write(value, into: &buf) + FfiConverterTypeClosureReason.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil - case 1: return try FfiConverterTypeNodeInfo.read(from: &buf) + case 1: return try FfiConverterTypeClosureReason.read(from: &buf) default: throw UniffiInternalError.unexpectedOptionalTag } } } -fileprivate struct FfiConverterOptionTypeOnchainPaymentInfo: FfiConverterRustBuffer { - typealias SwiftType = OnchainPaymentInfo? +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeEvent: FfiConverterRustBuffer { + typealias SwiftType = Event? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return } writeInt(&buf, Int8(1)) - FfiConverterTypeOnchainPaymentInfo.write(value, into: &buf) + FfiConverterTypeEvent.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil - case 1: return try FfiConverterTypeOnchainPaymentInfo.read(from: &buf) + case 1: return try FfiConverterTypeEvent.read(from: &buf) default: throw UniffiInternalError.unexpectedOptionalTag } } } -fileprivate struct FfiConverterOptionTypeOutPoint: FfiConverterRustBuffer { - typealias SwiftType = OutPoint? +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeLogLevel: FfiConverterRustBuffer { + typealias SwiftType = LogLevel? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return } writeInt(&buf, Int8(1)) - FfiConverterTypeOutPoint.write(value, into: &buf) + FfiConverterTypeLogLevel.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil - case 1: return try FfiConverterTypeOutPoint.read(from: &buf) + case 1: return try FfiConverterTypeLogLevel.read(from: &buf) default: throw UniffiInternalError.unexpectedOptionalTag } } } -fileprivate struct FfiConverterOptionTypePaymentDetails: FfiConverterRustBuffer { - typealias SwiftType = PaymentDetails? +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeNetwork: FfiConverterRustBuffer { + typealias SwiftType = Network? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return } writeInt(&buf, Int8(1)) - FfiConverterTypePaymentDetails.write(value, into: &buf) + FfiConverterTypeNetwork.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil - case 1: return try FfiConverterTypePaymentDetails.read(from: &buf) + case 1: return try FfiConverterTypeNetwork.read(from: &buf) default: throw UniffiInternalError.unexpectedOptionalTag } } } -fileprivate struct FfiConverterOptionTypeSendingParameters: FfiConverterRustBuffer { - typealias SwiftType = SendingParameters? +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeOfferAmount: FfiConverterRustBuffer { + typealias SwiftType = OfferAmount? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return } writeInt(&buf, Int8(1)) - FfiConverterTypeSendingParameters.write(value, into: &buf) + FfiConverterTypeOfferAmount.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil - case 1: return try FfiConverterTypeSendingParameters.read(from: &buf) + case 1: return try FfiConverterTypeOfferAmount.read(from: &buf) default: throw UniffiInternalError.unexpectedOptionalTag } } } -fileprivate struct FfiConverterOptionTypeClosureReason: FfiConverterRustBuffer { - typealias SwiftType = ClosureReason? +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypePaymentFailureReason: FfiConverterRustBuffer { + typealias SwiftType = PaymentFailureReason? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return } writeInt(&buf, Int8(1)) - FfiConverterTypeClosureReason.write(value, into: &buf) + FfiConverterTypePaymentFailureReason.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil - case 1: return try FfiConverterTypeClosureReason.read(from: &buf) + case 1: return try FfiConverterTypePaymentFailureReason.read(from: &buf) default: throw UniffiInternalError.unexpectedOptionalTag } } } -fileprivate struct FfiConverterOptionTypeEvent: FfiConverterRustBuffer { - typealias SwiftType = Event? +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeWordCount: FfiConverterRustBuffer { + typealias SwiftType = WordCount? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return } writeInt(&buf, Int8(1)) - FfiConverterTypeEvent.write(value, into: &buf) + FfiConverterTypeWordCount.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil - case 1: return try FfiConverterTypeEvent.read(from: &buf) + case 1: return try FfiConverterTypeWordCount.read(from: &buf) default: throw UniffiInternalError.unexpectedOptionalTag } } } -fileprivate struct FfiConverterOptionTypeLogLevel: FfiConverterRustBuffer { - typealias SwiftType = LogLevel? +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionSequenceUInt8: FfiConverterRustBuffer { + typealias SwiftType = [UInt8]? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return } writeInt(&buf, Int8(1)) - FfiConverterTypeLogLevel.write(value, into: &buf) + FfiConverterSequenceUInt8.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil - case 1: return try FfiConverterTypeLogLevel.read(from: &buf) + case 1: return try FfiConverterSequenceUInt8.read(from: &buf) default: throw UniffiInternalError.unexpectedOptionalTag } } } -fileprivate struct FfiConverterOptionTypeMaxTotalRoutingFeeLimit: FfiConverterRustBuffer { - typealias SwiftType = MaxTotalRoutingFeeLimit? +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionSequenceTypeSpendableUtxo: FfiConverterRustBuffer { + typealias SwiftType = [SpendableUtxo]? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return } writeInt(&buf, Int8(1)) - FfiConverterTypeMaxTotalRoutingFeeLimit.write(value, into: &buf) + FfiConverterSequenceTypeSpendableUtxo.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil - case 1: return try FfiConverterTypeMaxTotalRoutingFeeLimit.read(from: &buf) + case 1: return try FfiConverterSequenceTypeSpendableUtxo.read(from: &buf) default: throw UniffiInternalError.unexpectedOptionalTag } } } -fileprivate struct FfiConverterOptionTypePaymentFailureReason: FfiConverterRustBuffer { - typealias SwiftType = PaymentFailureReason? +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionSequenceSequenceUInt8: FfiConverterRustBuffer { + typealias SwiftType = [[UInt8]]? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return } writeInt(&buf, Int8(1)) - FfiConverterTypePaymentFailureReason.write(value, into: &buf) + FfiConverterSequenceSequenceUInt8.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil - case 1: return try FfiConverterTypePaymentFailureReason.read(from: &buf) + case 1: return try FfiConverterSequenceSequenceUInt8.read(from: &buf) default: throw UniffiInternalError.unexpectedOptionalTag } } } -fileprivate struct FfiConverterOptionSequenceTypeSocketAddress: FfiConverterRustBuffer { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionSequenceTypeSocketAddress: FfiConverterRustBuffer { typealias SwiftType = [SocketAddress]? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return @@ -8130,7 +11292,7 @@ fileprivate struct FfiConverterOptionSequenceTypeSocketAddress: FfiConverterRust FfiConverterSequenceTypeSocketAddress.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil case 1: return try FfiConverterSequenceTypeSocketAddress.read(from: &buf) @@ -8139,10 +11301,13 @@ fileprivate struct FfiConverterOptionSequenceTypeSocketAddress: FfiConverterRust } } -fileprivate struct FfiConverterOptionTypeAddress: FfiConverterRustBuffer { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeAddress: FfiConverterRustBuffer { typealias SwiftType = Address? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return @@ -8151,7 +11316,7 @@ fileprivate struct FfiConverterOptionTypeAddress: FfiConverterRustBuffer { FfiConverterTypeAddress.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil case 1: return try FfiConverterTypeAddress.read(from: &buf) @@ -8160,10 +11325,13 @@ fileprivate struct FfiConverterOptionTypeAddress: FfiConverterRustBuffer { } } -fileprivate struct FfiConverterOptionTypeChannelId: FfiConverterRustBuffer { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeChannelId: FfiConverterRustBuffer { typealias SwiftType = ChannelId? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return @@ -8172,7 +11340,7 @@ fileprivate struct FfiConverterOptionTypeChannelId: FfiConverterRustBuffer { FfiConverterTypeChannelId.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil case 1: return try FfiConverterTypeChannelId.read(from: &buf) @@ -8181,10 +11349,13 @@ fileprivate struct FfiConverterOptionTypeChannelId: FfiConverterRustBuffer { } } -fileprivate struct FfiConverterOptionTypeNodeAlias: FfiConverterRustBuffer { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeNodeAlias: FfiConverterRustBuffer { typealias SwiftType = NodeAlias? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return @@ -8193,7 +11364,7 @@ fileprivate struct FfiConverterOptionTypeNodeAlias: FfiConverterRustBuffer { FfiConverterTypeNodeAlias.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil case 1: return try FfiConverterTypeNodeAlias.read(from: &buf) @@ -8202,10 +11373,13 @@ fileprivate struct FfiConverterOptionTypeNodeAlias: FfiConverterRustBuffer { } } -fileprivate struct FfiConverterOptionTypePaymentHash: FfiConverterRustBuffer { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypePaymentHash: FfiConverterRustBuffer { typealias SwiftType = PaymentHash? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return @@ -8214,7 +11388,7 @@ fileprivate struct FfiConverterOptionTypePaymentHash: FfiConverterRustBuffer { FfiConverterTypePaymentHash.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil case 1: return try FfiConverterTypePaymentHash.read(from: &buf) @@ -8223,10 +11397,13 @@ fileprivate struct FfiConverterOptionTypePaymentHash: FfiConverterRustBuffer { } } -fileprivate struct FfiConverterOptionTypePaymentId: FfiConverterRustBuffer { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypePaymentId: FfiConverterRustBuffer { typealias SwiftType = PaymentId? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return @@ -8235,7 +11412,7 @@ fileprivate struct FfiConverterOptionTypePaymentId: FfiConverterRustBuffer { FfiConverterTypePaymentId.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil case 1: return try FfiConverterTypePaymentId.read(from: &buf) @@ -8244,10 +11421,13 @@ fileprivate struct FfiConverterOptionTypePaymentId: FfiConverterRustBuffer { } } -fileprivate struct FfiConverterOptionTypePaymentPreimage: FfiConverterRustBuffer { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypePaymentPreimage: FfiConverterRustBuffer { typealias SwiftType = PaymentPreimage? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return @@ -8256,7 +11436,7 @@ fileprivate struct FfiConverterOptionTypePaymentPreimage: FfiConverterRustBuffer FfiConverterTypePaymentPreimage.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil case 1: return try FfiConverterTypePaymentPreimage.read(from: &buf) @@ -8265,10 +11445,13 @@ fileprivate struct FfiConverterOptionTypePaymentPreimage: FfiConverterRustBuffer } } -fileprivate struct FfiConverterOptionTypePaymentSecret: FfiConverterRustBuffer { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypePaymentSecret: FfiConverterRustBuffer { typealias SwiftType = PaymentSecret? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return @@ -8277,7 +11460,7 @@ fileprivate struct FfiConverterOptionTypePaymentSecret: FfiConverterRustBuffer { FfiConverterTypePaymentSecret.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil case 1: return try FfiConverterTypePaymentSecret.read(from: &buf) @@ -8286,10 +11469,13 @@ fileprivate struct FfiConverterOptionTypePaymentSecret: FfiConverterRustBuffer { } } -fileprivate struct FfiConverterOptionTypePublicKey: FfiConverterRustBuffer { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypePublicKey: FfiConverterRustBuffer { typealias SwiftType = PublicKey? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return @@ -8298,7 +11484,7 @@ fileprivate struct FfiConverterOptionTypePublicKey: FfiConverterRustBuffer { FfiConverterTypePublicKey.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil case 1: return try FfiConverterTypePublicKey.read(from: &buf) @@ -8307,10 +11493,13 @@ fileprivate struct FfiConverterOptionTypePublicKey: FfiConverterRustBuffer { } } -fileprivate struct FfiConverterOptionTypeUntrustedString: FfiConverterRustBuffer { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeUntrustedString: FfiConverterRustBuffer { typealias SwiftType = UntrustedString? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return @@ -8319,7 +11508,7 @@ fileprivate struct FfiConverterOptionTypeUntrustedString: FfiConverterRustBuffer FfiConverterTypeUntrustedString.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil case 1: return try FfiConverterTypeUntrustedString.read(from: &buf) @@ -8328,10 +11517,13 @@ fileprivate struct FfiConverterOptionTypeUntrustedString: FfiConverterRustBuffer } } -fileprivate struct FfiConverterOptionTypeUserChannelId: FfiConverterRustBuffer { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterOptionTypeUserChannelId: FfiConverterRustBuffer { typealias SwiftType = UserChannelId? - public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + static func write(_ value: SwiftType, into buf: inout [UInt8]) { guard let value = value else { writeInt(&buf, Int8(0)) return @@ -8340,7 +11532,7 @@ fileprivate struct FfiConverterOptionTypeUserChannelId: FfiConverterRustBuffer { FfiConverterTypeUserChannelId.write(value, into: &buf) } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { switch try readInt(&buf) as Int8 { case 0: return nil case 1: return try FfiConverterTypeUserChannelId.read(from: &buf) @@ -8349,10 +11541,13 @@ fileprivate struct FfiConverterOptionTypeUserChannelId: FfiConverterRustBuffer { } } -fileprivate struct FfiConverterSequenceUInt8: FfiConverterRustBuffer { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterSequenceUInt8: FfiConverterRustBuffer { typealias SwiftType = [UInt8] - public static func write(_ value: [UInt8], into buf: inout [UInt8]) { + static func write(_ value: [UInt8], into buf: inout [UInt8]) { let len = Int32(value.count) writeInt(&buf, len) for item in value { @@ -8360,21 +11555,24 @@ fileprivate struct FfiConverterSequenceUInt8: FfiConverterRustBuffer { } } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [UInt8] { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [UInt8] { let len: Int32 = try readInt(&buf) var seq = [UInt8]() seq.reserveCapacity(Int(len)) for _ in 0 ..< len { - seq.append(try FfiConverterUInt8.read(from: &buf)) + try seq.append(FfiConverterUInt8.read(from: &buf)) } return seq } } -fileprivate struct FfiConverterSequenceUInt64: FfiConverterRustBuffer { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterSequenceUInt64: FfiConverterRustBuffer { typealias SwiftType = [UInt64] - public static func write(_ value: [UInt64], into buf: inout [UInt8]) { + static func write(_ value: [UInt64], into buf: inout [UInt8]) { let len = Int32(value.count) writeInt(&buf, len) for item in value { @@ -8382,21 +11580,74 @@ fileprivate struct FfiConverterSequenceUInt64: FfiConverterRustBuffer { } } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [UInt64] { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [UInt64] { let len: Int32 = try readInt(&buf) var seq = [UInt64]() seq.reserveCapacity(Int(len)) for _ in 0 ..< len { - seq.append(try FfiConverterUInt64.read(from: &buf)) + try seq.append(FfiConverterUInt64.read(from: &buf)) + } + return seq + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterSequenceString: FfiConverterRustBuffer { + typealias SwiftType = [String] + + static func write(_ value: [String], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterString.write(item, into: &buf) + } + } + + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [String] { + let len: Int32 = try readInt(&buf) + var seq = [String]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + try seq.append(FfiConverterString.read(from: &buf)) + } + return seq + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterSequenceTypeAddressInfo: FfiConverterRustBuffer { + typealias SwiftType = [AddressInfo] + + static func write(_ value: [AddressInfo], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterTypeAddressInfo.write(item, into: &buf) + } + } + + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [AddressInfo] { + let len: Int32 = try readInt(&buf) + var seq = [AddressInfo]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + try seq.append(FfiConverterTypeAddressInfo.read(from: &buf)) } return seq } } -fileprivate struct FfiConverterSequenceTypeChannelDetails: FfiConverterRustBuffer { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterSequenceTypeChannelDetails: FfiConverterRustBuffer { typealias SwiftType = [ChannelDetails] - public static func write(_ value: [ChannelDetails], into buf: inout [UInt8]) { + static func write(_ value: [ChannelDetails], into buf: inout [UInt8]) { let len = Int32(value.count) writeInt(&buf, len) for item in value { @@ -8404,153 +11655,399 @@ fileprivate struct FfiConverterSequenceTypeChannelDetails: FfiConverterRustBuffe } } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [ChannelDetails] { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [ChannelDetails] { let len: Int32 = try readInt(&buf) var seq = [ChannelDetails]() seq.reserveCapacity(Int(len)) for _ in 0 ..< len { - seq.append(try FfiConverterTypeChannelDetails.read(from: &buf)) + try seq.append(FfiConverterTypeChannelDetails.read(from: &buf)) + } + return seq + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterSequenceTypeCustomTlvRecord: FfiConverterRustBuffer { + typealias SwiftType = [CustomTlvRecord] + + static func write(_ value: [CustomTlvRecord], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterTypeCustomTlvRecord.write(item, into: &buf) + } + } + + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [CustomTlvRecord] { + let len: Int32 = try readInt(&buf) + var seq = [CustomTlvRecord]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + try seq.append(FfiConverterTypeCustomTlvRecord.read(from: &buf)) + } + return seq + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterSequenceTypeOnchainWalletAccount: FfiConverterRustBuffer { + typealias SwiftType = [OnchainWalletAccount] + + static func write(_ value: [OnchainWalletAccount], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterTypeOnchainWalletAccount.write(item, into: &buf) + } + } + + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [OnchainWalletAccount] { + let len: Int32 = try readInt(&buf) + var seq = [OnchainWalletAccount]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + try seq.append(FfiConverterTypeOnchainWalletAccount.read(from: &buf)) + } + return seq + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterSequenceTypeOnchainWalletAccountConfig: FfiConverterRustBuffer { + typealias SwiftType = [OnchainWalletAccountConfig] + + static func write(_ value: [OnchainWalletAccountConfig], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterTypeOnchainWalletAccountConfig.write(item, into: &buf) + } + } + + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [OnchainWalletAccountConfig] { + let len: Int32 = try readInt(&buf) + var seq = [OnchainWalletAccountConfig]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + try seq.append(FfiConverterTypeOnchainWalletAccountConfig.read(from: &buf)) + } + return seq + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterSequenceTypePaymentDetails: FfiConverterRustBuffer { + typealias SwiftType = [PaymentDetails] + + static func write(_ value: [PaymentDetails], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterTypePaymentDetails.write(item, into: &buf) + } + } + + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [PaymentDetails] { + let len: Int32 = try readInt(&buf) + var seq = [PaymentDetails]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + try seq.append(FfiConverterTypePaymentDetails.read(from: &buf)) + } + return seq + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterSequenceTypePeerDetails: FfiConverterRustBuffer { + typealias SwiftType = [PeerDetails] + + static func write(_ value: [PeerDetails], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterTypePeerDetails.write(item, into: &buf) + } + } + + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [PeerDetails] { + let len: Int32 = try readInt(&buf) + var seq = [PeerDetails]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + try seq.append(FfiConverterTypePeerDetails.read(from: &buf)) + } + return seq + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterSequenceTypeProbeHandle: FfiConverterRustBuffer { + typealias SwiftType = [ProbeHandle] + + static func write(_ value: [ProbeHandle], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterTypeProbeHandle.write(item, into: &buf) + } + } + + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [ProbeHandle] { + let len: Int32 = try readInt(&buf) + var seq = [ProbeHandle]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + try seq.append(FfiConverterTypeProbeHandle.read(from: &buf)) + } + return seq + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterSequenceTypeRouteHintHop: FfiConverterRustBuffer { + typealias SwiftType = [RouteHintHop] + + static func write(_ value: [RouteHintHop], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterTypeRouteHintHop.write(item, into: &buf) + } + } + + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [RouteHintHop] { + let len: Int32 = try readInt(&buf) + var seq = [RouteHintHop]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + try seq.append(FfiConverterTypeRouteHintHop.read(from: &buf)) + } + return seq + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterSequenceTypeSpendableUtxo: FfiConverterRustBuffer { + typealias SwiftType = [SpendableUtxo] + + static func write(_ value: [SpendableUtxo], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterTypeSpendableUtxo.write(item, into: &buf) + } + } + + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [SpendableUtxo] { + let len: Int32 = try readInt(&buf) + var seq = [SpendableUtxo]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + try seq.append(FfiConverterTypeSpendableUtxo.read(from: &buf)) + } + return seq + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterSequenceTypeTxInput: FfiConverterRustBuffer { + typealias SwiftType = [TxInput] + + static func write(_ value: [TxInput], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterTypeTxInput.write(item, into: &buf) + } + } + + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [TxInput] { + let len: Int32 = try readInt(&buf) + var seq = [TxInput]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + try seq.append(FfiConverterTypeTxInput.read(from: &buf)) } return seq } } -fileprivate struct FfiConverterSequenceTypeCustomTlvRecord: FfiConverterRustBuffer { - typealias SwiftType = [CustomTlvRecord] +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterSequenceTypeTxOutput: FfiConverterRustBuffer { + typealias SwiftType = [TxOutput] - public static func write(_ value: [CustomTlvRecord], into buf: inout [UInt8]) { + static func write(_ value: [TxOutput], into buf: inout [UInt8]) { let len = Int32(value.count) writeInt(&buf, len) for item in value { - FfiConverterTypeCustomTlvRecord.write(item, into: &buf) + FfiConverterTypeTxOutput.write(item, into: &buf) } } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [CustomTlvRecord] { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [TxOutput] { let len: Int32 = try readInt(&buf) - var seq = [CustomTlvRecord]() + var seq = [TxOutput]() seq.reserveCapacity(Int(len)) for _ in 0 ..< len { - seq.append(try FfiConverterTypeCustomTlvRecord.read(from: &buf)) + try seq.append(FfiConverterTypeTxOutput.read(from: &buf)) } return seq } } -fileprivate struct FfiConverterSequenceTypePaymentDetails: FfiConverterRustBuffer { - typealias SwiftType = [PaymentDetails] +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterSequenceTypeAddressType: FfiConverterRustBuffer { + typealias SwiftType = [AddressType] - public static func write(_ value: [PaymentDetails], into buf: inout [UInt8]) { + static func write(_ value: [AddressType], into buf: inout [UInt8]) { let len = Int32(value.count) writeInt(&buf, len) for item in value { - FfiConverterTypePaymentDetails.write(item, into: &buf) + FfiConverterTypeAddressType.write(item, into: &buf) } } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [PaymentDetails] { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [AddressType] { let len: Int32 = try readInt(&buf) - var seq = [PaymentDetails]() + var seq = [AddressType]() seq.reserveCapacity(Int(len)) for _ in 0 ..< len { - seq.append(try FfiConverterTypePaymentDetails.read(from: &buf)) + try seq.append(FfiConverterTypeAddressType.read(from: &buf)) } return seq } } -fileprivate struct FfiConverterSequenceTypePeerDetails: FfiConverterRustBuffer { - typealias SwiftType = [PeerDetails] +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterSequenceTypeLightningBalance: FfiConverterRustBuffer { + typealias SwiftType = [LightningBalance] - public static func write(_ value: [PeerDetails], into buf: inout [UInt8]) { + static func write(_ value: [LightningBalance], into buf: inout [UInt8]) { let len = Int32(value.count) writeInt(&buf, len) for item in value { - FfiConverterTypePeerDetails.write(item, into: &buf) + FfiConverterTypeLightningBalance.write(item, into: &buf) } } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [PeerDetails] { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [LightningBalance] { let len: Int32 = try readInt(&buf) - var seq = [PeerDetails]() + var seq = [LightningBalance]() seq.reserveCapacity(Int(len)) for _ in 0 ..< len { - seq.append(try FfiConverterTypePeerDetails.read(from: &buf)) + try seq.append(FfiConverterTypeLightningBalance.read(from: &buf)) } return seq } } -fileprivate struct FfiConverterSequenceTypeRouteHintHop: FfiConverterRustBuffer { - typealias SwiftType = [RouteHintHop] +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterSequenceTypeNetwork: FfiConverterRustBuffer { + typealias SwiftType = [Network] - public static func write(_ value: [RouteHintHop], into buf: inout [UInt8]) { + static func write(_ value: [Network], into buf: inout [UInt8]) { let len = Int32(value.count) writeInt(&buf, len) for item in value { - FfiConverterTypeRouteHintHop.write(item, into: &buf) + FfiConverterTypeNetwork.write(item, into: &buf) } } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [RouteHintHop] { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [Network] { let len: Int32 = try readInt(&buf) - var seq = [RouteHintHop]() + var seq = [Network]() seq.reserveCapacity(Int(len)) for _ in 0 ..< len { - seq.append(try FfiConverterTypeRouteHintHop.read(from: &buf)) + try seq.append(FfiConverterTypeNetwork.read(from: &buf)) } return seq } } -fileprivate struct FfiConverterSequenceTypeLightningBalance: FfiConverterRustBuffer { - typealias SwiftType = [LightningBalance] +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterSequenceTypePendingSweepBalance: FfiConverterRustBuffer { + typealias SwiftType = [PendingSweepBalance] - public static func write(_ value: [LightningBalance], into buf: inout [UInt8]) { + static func write(_ value: [PendingSweepBalance], into buf: inout [UInt8]) { let len = Int32(value.count) writeInt(&buf, len) for item in value { - FfiConverterTypeLightningBalance.write(item, into: &buf) + FfiConverterTypePendingSweepBalance.write(item, into: &buf) } } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [LightningBalance] { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [PendingSweepBalance] { let len: Int32 = try readInt(&buf) - var seq = [LightningBalance]() + var seq = [PendingSweepBalance]() seq.reserveCapacity(Int(len)) for _ in 0 ..< len { - seq.append(try FfiConverterTypeLightningBalance.read(from: &buf)) + try seq.append(FfiConverterTypePendingSweepBalance.read(from: &buf)) } return seq } } -fileprivate struct FfiConverterSequenceTypePendingSweepBalance: FfiConverterRustBuffer { - typealias SwiftType = [PendingSweepBalance] +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterSequenceSequenceUInt8: FfiConverterRustBuffer { + typealias SwiftType = [[UInt8]] - public static func write(_ value: [PendingSweepBalance], into buf: inout [UInt8]) { + static func write(_ value: [[UInt8]], into buf: inout [UInt8]) { let len = Int32(value.count) writeInt(&buf, len) for item in value { - FfiConverterTypePendingSweepBalance.write(item, into: &buf) + FfiConverterSequenceUInt8.write(item, into: &buf) } } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [PendingSweepBalance] { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [[UInt8]] { let len: Int32 = try readInt(&buf) - var seq = [PendingSweepBalance]() + var seq = [[UInt8]]() seq.reserveCapacity(Int(len)) for _ in 0 ..< len { - seq.append(try FfiConverterTypePendingSweepBalance.read(from: &buf)) + try seq.append(FfiConverterSequenceUInt8.read(from: &buf)) } return seq } } -fileprivate struct FfiConverterSequenceSequenceTypeRouteHintHop: FfiConverterRustBuffer { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterSequenceSequenceTypeRouteHintHop: FfiConverterRustBuffer { typealias SwiftType = [[RouteHintHop]] - public static func write(_ value: [[RouteHintHop]], into buf: inout [UInt8]) { + static func write(_ value: [[RouteHintHop]], into buf: inout [UInt8]) { let len = Int32(value.count) writeInt(&buf, len) for item in value { @@ -8558,21 +12055,24 @@ fileprivate struct FfiConverterSequenceSequenceTypeRouteHintHop: FfiConverterRus } } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [[RouteHintHop]] { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [[RouteHintHop]] { let len: Int32 = try readInt(&buf) var seq = [[RouteHintHop]]() seq.reserveCapacity(Int(len)) for _ in 0 ..< len { - seq.append(try FfiConverterSequenceTypeRouteHintHop.read(from: &buf)) + try seq.append(FfiConverterSequenceTypeRouteHintHop.read(from: &buf)) } return seq } } -fileprivate struct FfiConverterSequenceTypeAddress: FfiConverterRustBuffer { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterSequenceTypeAddress: FfiConverterRustBuffer { typealias SwiftType = [Address] - public static func write(_ value: [Address], into buf: inout [UInt8]) { + static func write(_ value: [Address], into buf: inout [UInt8]) { let len = Int32(value.count) writeInt(&buf, len) for item in value { @@ -8580,21 +12080,24 @@ fileprivate struct FfiConverterSequenceTypeAddress: FfiConverterRustBuffer { } } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [Address] { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [Address] { let len: Int32 = try readInt(&buf) var seq = [Address]() seq.reserveCapacity(Int(len)) for _ in 0 ..< len { - seq.append(try FfiConverterTypeAddress.read(from: &buf)) + try seq.append(FfiConverterTypeAddress.read(from: &buf)) } return seq } } -fileprivate struct FfiConverterSequenceTypeNodeId: FfiConverterRustBuffer { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterSequenceTypeNodeId: FfiConverterRustBuffer { typealias SwiftType = [NodeId] - public static func write(_ value: [NodeId], into buf: inout [UInt8]) { + static func write(_ value: [NodeId], into buf: inout [UInt8]) { let len = Int32(value.count) writeInt(&buf, len) for item in value { @@ -8602,21 +12105,24 @@ fileprivate struct FfiConverterSequenceTypeNodeId: FfiConverterRustBuffer { } } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [NodeId] { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [NodeId] { let len: Int32 = try readInt(&buf) var seq = [NodeId]() seq.reserveCapacity(Int(len)) for _ in 0 ..< len { - seq.append(try FfiConverterTypeNodeId.read(from: &buf)) + try seq.append(FfiConverterTypeNodeId.read(from: &buf)) } return seq } } -fileprivate struct FfiConverterSequenceTypePublicKey: FfiConverterRustBuffer { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterSequenceTypePublicKey: FfiConverterRustBuffer { typealias SwiftType = [PublicKey] - public static func write(_ value: [PublicKey], into buf: inout [UInt8]) { + static func write(_ value: [PublicKey], into buf: inout [UInt8]) { let len = Int32(value.count) writeInt(&buf, len) for item in value { @@ -8624,21 +12130,24 @@ fileprivate struct FfiConverterSequenceTypePublicKey: FfiConverterRustBuffer { } } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [PublicKey] { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [PublicKey] { let len: Int32 = try readInt(&buf) var seq = [PublicKey]() seq.reserveCapacity(Int(len)) for _ in 0 ..< len { - seq.append(try FfiConverterTypePublicKey.read(from: &buf)) + try seq.append(FfiConverterTypePublicKey.read(from: &buf)) } return seq } } -fileprivate struct FfiConverterSequenceTypeSocketAddress: FfiConverterRustBuffer { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterSequenceTypeSocketAddress: FfiConverterRustBuffer { typealias SwiftType = [SocketAddress] - public static func write(_ value: [SocketAddress], into buf: inout [UInt8]) { + static func write(_ value: [SocketAddress], into buf: inout [UInt8]) { let len = Int32(value.count) writeInt(&buf, len) for item in value { @@ -8646,19 +12155,47 @@ fileprivate struct FfiConverterSequenceTypeSocketAddress: FfiConverterRustBuffer } } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [SocketAddress] { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [SocketAddress] { let len: Int32 = try readInt(&buf) var seq = [SocketAddress]() seq.reserveCapacity(Int(len)) for _ in 0 ..< len { - seq.append(try FfiConverterTypeSocketAddress.read(from: &buf)) + try seq.append(FfiConverterTypeSocketAddress.read(from: &buf)) + } + return seq + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterSequenceTypeTxid: FfiConverterRustBuffer { + typealias SwiftType = [Txid] + + static func write(_ value: [Txid], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterTypeTxid.write(item, into: &buf) + } + } + + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [Txid] { + let len: Int32 = try readInt(&buf) + var seq = [Txid]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + try seq.append(FfiConverterTypeTxid.read(from: &buf)) } return seq } } -fileprivate struct FfiConverterDictionaryStringString: FfiConverterRustBuffer { - public static func write(_ value: [String: String], into buf: inout [UInt8]) { +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterDictionaryStringString: FfiConverterRustBuffer { + static func write(_ value: [String: String], into buf: inout [UInt8]) { let len = Int32(value.count) writeInt(&buf, len) for (key, value) in value { @@ -8667,11 +12204,11 @@ fileprivate struct FfiConverterDictionaryStringString: FfiConverterRustBuffer { } } - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [String: String] { + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [String: String] { let len: Int32 = try readInt(&buf) var dict = [String: String]() dict.reserveCapacity(Int(len)) - for _ in 0..=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypeAddress: FfiConverter { public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Address { return try FfiConverterString.read(from: &buf) @@ -8704,22 +12244,29 @@ public struct FfiConverterTypeAddress: FfiConverter { } } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeAddress_lift(_ value: RustBuffer) throws -> Address { return try FfiConverterTypeAddress.lift(value) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeAddress_lower(_ value: Address) -> RustBuffer { return FfiConverterTypeAddress.lower(value) } - - /** * Typealias from the type name used in the UDL file to the builtin type. This * is needed because the UDL type name is used in function/method signatures. */ public typealias BlockHash = String + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypeBlockHash: FfiConverter { public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> BlockHash { return try FfiConverterString.read(from: &buf) @@ -8738,124 +12285,152 @@ public struct FfiConverterTypeBlockHash: FfiConverter { } } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeBlockHash_lift(_ value: RustBuffer) throws -> BlockHash { return try FfiConverterTypeBlockHash.lift(value) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeBlockHash_lower(_ value: BlockHash) -> RustBuffer { return FfiConverterTypeBlockHash.lower(value) } - - /** * Typealias from the type name used in the UDL file to the builtin type. This * is needed because the UDL type name is used in function/method signatures. */ -public typealias Bolt12Invoice = String -public struct FfiConverterTypeBolt12Invoice: FfiConverter { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Bolt12Invoice { +public typealias ChannelId = String + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeChannelId: FfiConverter { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ChannelId { return try FfiConverterString.read(from: &buf) } - public static func write(_ value: Bolt12Invoice, into buf: inout [UInt8]) { + public static func write(_ value: ChannelId, into buf: inout [UInt8]) { return FfiConverterString.write(value, into: &buf) } - public static func lift(_ value: RustBuffer) throws -> Bolt12Invoice { + public static func lift(_ value: RustBuffer) throws -> ChannelId { return try FfiConverterString.lift(value) } - public static func lower(_ value: Bolt12Invoice) -> RustBuffer { + public static func lower(_ value: ChannelId) -> RustBuffer { return FfiConverterString.lower(value) } } - -public func FfiConverterTypeBolt12Invoice_lift(_ value: RustBuffer) throws -> Bolt12Invoice { - return try FfiConverterTypeBolt12Invoice.lift(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeChannelId_lift(_ value: RustBuffer) throws -> ChannelId { + return try FfiConverterTypeChannelId.lift(value) } -public func FfiConverterTypeBolt12Invoice_lower(_ value: Bolt12Invoice) -> RustBuffer { - return FfiConverterTypeBolt12Invoice.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeChannelId_lower(_ value: ChannelId) -> RustBuffer { + return FfiConverterTypeChannelId.lower(value) } - - /** * Typealias from the type name used in the UDL file to the builtin type. This * is needed because the UDL type name is used in function/method signatures. */ -public typealias ChannelId = String -public struct FfiConverterTypeChannelId: FfiConverter { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ChannelId { +public typealias Lsps1OrderId = String + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeLSPS1OrderId: FfiConverter { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Lsps1OrderId { return try FfiConverterString.read(from: &buf) } - public static func write(_ value: ChannelId, into buf: inout [UInt8]) { + public static func write(_ value: Lsps1OrderId, into buf: inout [UInt8]) { return FfiConverterString.write(value, into: &buf) } - public static func lift(_ value: RustBuffer) throws -> ChannelId { + public static func lift(_ value: RustBuffer) throws -> Lsps1OrderId { return try FfiConverterString.lift(value) } - public static func lower(_ value: ChannelId) -> RustBuffer { + public static func lower(_ value: Lsps1OrderId) -> RustBuffer { return FfiConverterString.lower(value) } } - -public func FfiConverterTypeChannelId_lift(_ value: RustBuffer) throws -> ChannelId { - return try FfiConverterTypeChannelId.lift(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeLSPS1OrderId_lift(_ value: RustBuffer) throws -> Lsps1OrderId { + return try FfiConverterTypeLSPS1OrderId.lift(value) } -public func FfiConverterTypeChannelId_lower(_ value: ChannelId) -> RustBuffer { - return FfiConverterTypeChannelId.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeLSPS1OrderId_lower(_ value: Lsps1OrderId) -> RustBuffer { + return FfiConverterTypeLSPS1OrderId.lower(value) } - - /** * Typealias from the type name used in the UDL file to the builtin type. This * is needed because the UDL type name is used in function/method signatures. */ -public typealias DateTime = String -public struct FfiConverterTypeDateTime: FfiConverter { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> DateTime { +public typealias LspsDateTime = String + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeLSPSDateTime: FfiConverter { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> LspsDateTime { return try FfiConverterString.read(from: &buf) } - public static func write(_ value: DateTime, into buf: inout [UInt8]) { + public static func write(_ value: LspsDateTime, into buf: inout [UInt8]) { return FfiConverterString.write(value, into: &buf) } - public static func lift(_ value: RustBuffer) throws -> DateTime { + public static func lift(_ value: RustBuffer) throws -> LspsDateTime { return try FfiConverterString.lift(value) } - public static func lower(_ value: DateTime) -> RustBuffer { + public static func lower(_ value: LspsDateTime) -> RustBuffer { return FfiConverterString.lower(value) } } - -public func FfiConverterTypeDateTime_lift(_ value: RustBuffer) throws -> DateTime { - return try FfiConverterTypeDateTime.lift(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeLSPSDateTime_lift(_ value: RustBuffer) throws -> LspsDateTime { + return try FfiConverterTypeLSPSDateTime.lift(value) } -public func FfiConverterTypeDateTime_lower(_ value: DateTime) -> RustBuffer { - return FfiConverterTypeDateTime.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeLSPSDateTime_lower(_ value: LspsDateTime) -> RustBuffer { + return FfiConverterTypeLSPSDateTime.lower(value) } - - /** * Typealias from the type name used in the UDL file to the builtin type. This * is needed because the UDL type name is used in function/method signatures. */ public typealias Mnemonic = String + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypeMnemonic: FfiConverter { public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Mnemonic { return try FfiConverterString.read(from: &buf) @@ -8874,22 +12449,29 @@ public struct FfiConverterTypeMnemonic: FfiConverter { } } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeMnemonic_lift(_ value: RustBuffer) throws -> Mnemonic { return try FfiConverterTypeMnemonic.lift(value) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeMnemonic_lower(_ value: Mnemonic) -> RustBuffer { return FfiConverterTypeMnemonic.lower(value) } - - /** * Typealias from the type name used in the UDL file to the builtin type. This * is needed because the UDL type name is used in function/method signatures. */ public typealias NodeAlias = String + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypeNodeAlias: FfiConverter { public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> NodeAlias { return try FfiConverterString.read(from: &buf) @@ -8908,22 +12490,29 @@ public struct FfiConverterTypeNodeAlias: FfiConverter { } } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeNodeAlias_lift(_ value: RustBuffer) throws -> NodeAlias { return try FfiConverterTypeNodeAlias.lift(value) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeNodeAlias_lower(_ value: NodeAlias) -> RustBuffer { return FfiConverterTypeNodeAlias.lower(value) } - - /** * Typealias from the type name used in the UDL file to the builtin type. This * is needed because the UDL type name is used in function/method signatures. */ public typealias NodeId = String + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypeNodeId: FfiConverter { public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> NodeId { return try FfiConverterString.read(from: &buf) @@ -8942,56 +12531,29 @@ public struct FfiConverterTypeNodeId: FfiConverter { } } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeNodeId_lift(_ value: RustBuffer) throws -> NodeId { return try FfiConverterTypeNodeId.lift(value) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeNodeId_lower(_ value: NodeId) -> RustBuffer { return FfiConverterTypeNodeId.lower(value) } - - -/** - * Typealias from the type name used in the UDL file to the builtin type. This - * is needed because the UDL type name is used in function/method signatures. - */ -public typealias Offer = String -public struct FfiConverterTypeOffer: FfiConverter { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Offer { - return try FfiConverterString.read(from: &buf) - } - - public static func write(_ value: Offer, into buf: inout [UInt8]) { - return FfiConverterString.write(value, into: &buf) - } - - public static func lift(_ value: RustBuffer) throws -> Offer { - return try FfiConverterString.lift(value) - } - - public static func lower(_ value: Offer) -> RustBuffer { - return FfiConverterString.lower(value) - } -} - - -public func FfiConverterTypeOffer_lift(_ value: RustBuffer) throws -> Offer { - return try FfiConverterTypeOffer.lift(value) -} - -public func FfiConverterTypeOffer_lower(_ value: Offer) -> RustBuffer { - return FfiConverterTypeOffer.lower(value) -} - - - /** * Typealias from the type name used in the UDL file to the builtin type. This * is needed because the UDL type name is used in function/method signatures. */ public typealias OfferId = String + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypeOfferId: FfiConverter { public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> OfferId { return try FfiConverterString.read(from: &buf) @@ -9010,56 +12572,29 @@ public struct FfiConverterTypeOfferId: FfiConverter { } } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeOfferId_lift(_ value: RustBuffer) throws -> OfferId { return try FfiConverterTypeOfferId.lift(value) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeOfferId_lower(_ value: OfferId) -> RustBuffer { return FfiConverterTypeOfferId.lower(value) } - - -/** - * Typealias from the type name used in the UDL file to the builtin type. This - * is needed because the UDL type name is used in function/method signatures. - */ -public typealias OrderId = String -public struct FfiConverterTypeOrderId: FfiConverter { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> OrderId { - return try FfiConverterString.read(from: &buf) - } - - public static func write(_ value: OrderId, into buf: inout [UInt8]) { - return FfiConverterString.write(value, into: &buf) - } - - public static func lift(_ value: RustBuffer) throws -> OrderId { - return try FfiConverterString.lift(value) - } - - public static func lower(_ value: OrderId) -> RustBuffer { - return FfiConverterString.lower(value) - } -} - - -public func FfiConverterTypeOrderId_lift(_ value: RustBuffer) throws -> OrderId { - return try FfiConverterTypeOrderId.lift(value) -} - -public func FfiConverterTypeOrderId_lower(_ value: OrderId) -> RustBuffer { - return FfiConverterTypeOrderId.lower(value) -} - - - /** * Typealias from the type name used in the UDL file to the builtin type. This * is needed because the UDL type name is used in function/method signatures. */ public typealias PaymentHash = String + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypePaymentHash: FfiConverter { public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> PaymentHash { return try FfiConverterString.read(from: &buf) @@ -9078,22 +12613,29 @@ public struct FfiConverterTypePaymentHash: FfiConverter { } } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypePaymentHash_lift(_ value: RustBuffer) throws -> PaymentHash { return try FfiConverterTypePaymentHash.lift(value) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypePaymentHash_lower(_ value: PaymentHash) -> RustBuffer { return FfiConverterTypePaymentHash.lower(value) } - - /** * Typealias from the type name used in the UDL file to the builtin type. This * is needed because the UDL type name is used in function/method signatures. */ public typealias PaymentId = String + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypePaymentId: FfiConverter { public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> PaymentId { return try FfiConverterString.read(from: &buf) @@ -9112,22 +12654,29 @@ public struct FfiConverterTypePaymentId: FfiConverter { } } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypePaymentId_lift(_ value: RustBuffer) throws -> PaymentId { return try FfiConverterTypePaymentId.lift(value) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypePaymentId_lower(_ value: PaymentId) -> RustBuffer { return FfiConverterTypePaymentId.lower(value) } - - /** * Typealias from the type name used in the UDL file to the builtin type. This * is needed because the UDL type name is used in function/method signatures. */ public typealias PaymentPreimage = String + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypePaymentPreimage: FfiConverter { public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> PaymentPreimage { return try FfiConverterString.read(from: &buf) @@ -9146,22 +12695,29 @@ public struct FfiConverterTypePaymentPreimage: FfiConverter { } } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypePaymentPreimage_lift(_ value: RustBuffer) throws -> PaymentPreimage { return try FfiConverterTypePaymentPreimage.lift(value) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypePaymentPreimage_lower(_ value: PaymentPreimage) -> RustBuffer { return FfiConverterTypePaymentPreimage.lower(value) } - - /** * Typealias from the type name used in the UDL file to the builtin type. This * is needed because the UDL type name is used in function/method signatures. */ public typealias PaymentSecret = String + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypePaymentSecret: FfiConverter { public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> PaymentSecret { return try FfiConverterString.read(from: &buf) @@ -9180,90 +12736,70 @@ public struct FfiConverterTypePaymentSecret: FfiConverter { } } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypePaymentSecret_lift(_ value: RustBuffer) throws -> PaymentSecret { return try FfiConverterTypePaymentSecret.lift(value) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypePaymentSecret_lower(_ value: PaymentSecret) -> RustBuffer { return FfiConverterTypePaymentSecret.lower(value) } - - /** * Typealias from the type name used in the UDL file to the builtin type. This * is needed because the UDL type name is used in function/method signatures. */ public typealias PublicKey = String + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypePublicKey: FfiConverter { public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> PublicKey { return try FfiConverterString.read(from: &buf) } - public static func write(_ value: PublicKey, into buf: inout [UInt8]) { - return FfiConverterString.write(value, into: &buf) - } - - public static func lift(_ value: RustBuffer) throws -> PublicKey { - return try FfiConverterString.lift(value) - } - - public static func lower(_ value: PublicKey) -> RustBuffer { - return FfiConverterString.lower(value) - } -} - - -public func FfiConverterTypePublicKey_lift(_ value: RustBuffer) throws -> PublicKey { - return try FfiConverterTypePublicKey.lift(value) -} - -public func FfiConverterTypePublicKey_lower(_ value: PublicKey) -> RustBuffer { - return FfiConverterTypePublicKey.lower(value) -} - - - -/** - * Typealias from the type name used in the UDL file to the builtin type. This - * is needed because the UDL type name is used in function/method signatures. - */ -public typealias Refund = String -public struct FfiConverterTypeRefund: FfiConverter { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Refund { - return try FfiConverterString.read(from: &buf) - } - - public static func write(_ value: Refund, into buf: inout [UInt8]) { + public static func write(_ value: PublicKey, into buf: inout [UInt8]) { return FfiConverterString.write(value, into: &buf) } - public static func lift(_ value: RustBuffer) throws -> Refund { + public static func lift(_ value: RustBuffer) throws -> PublicKey { return try FfiConverterString.lift(value) } - public static func lower(_ value: Refund) -> RustBuffer { + public static func lower(_ value: PublicKey) -> RustBuffer { return FfiConverterString.lower(value) } } - -public func FfiConverterTypeRefund_lift(_ value: RustBuffer) throws -> Refund { - return try FfiConverterTypeRefund.lift(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypePublicKey_lift(_ value: RustBuffer) throws -> PublicKey { + return try FfiConverterTypePublicKey.lift(value) } -public func FfiConverterTypeRefund_lower(_ value: Refund) -> RustBuffer { - return FfiConverterTypeRefund.lower(value) +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypePublicKey_lower(_ value: PublicKey) -> RustBuffer { + return FfiConverterTypePublicKey.lower(value) } - - /** * Typealias from the type name used in the UDL file to the builtin type. This * is needed because the UDL type name is used in function/method signatures. */ public typealias SocketAddress = String + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypeSocketAddress: FfiConverter { public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SocketAddress { return try FfiConverterString.read(from: &buf) @@ -9282,22 +12818,29 @@ public struct FfiConverterTypeSocketAddress: FfiConverter { } } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeSocketAddress_lift(_ value: RustBuffer) throws -> SocketAddress { return try FfiConverterTypeSocketAddress.lift(value) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeSocketAddress_lower(_ value: SocketAddress) -> RustBuffer { return FfiConverterTypeSocketAddress.lower(value) } - - /** * Typealias from the type name used in the UDL file to the builtin type. This * is needed because the UDL type name is used in function/method signatures. */ public typealias Txid = String + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypeTxid: FfiConverter { public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Txid { return try FfiConverterString.read(from: &buf) @@ -9316,22 +12859,29 @@ public struct FfiConverterTypeTxid: FfiConverter { } } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeTxid_lift(_ value: RustBuffer) throws -> Txid { return try FfiConverterTypeTxid.lift(value) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeTxid_lower(_ value: Txid) -> RustBuffer { return FfiConverterTypeTxid.lower(value) } - - /** * Typealias from the type name used in the UDL file to the builtin type. This * is needed because the UDL type name is used in function/method signatures. */ public typealias UntrustedString = String + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypeUntrustedString: FfiConverter { public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UntrustedString { return try FfiConverterString.read(from: &buf) @@ -9350,22 +12900,29 @@ public struct FfiConverterTypeUntrustedString: FfiConverter { } } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeUntrustedString_lift(_ value: RustBuffer) throws -> UntrustedString { return try FfiConverterTypeUntrustedString.lift(value) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeUntrustedString_lower(_ value: UntrustedString) -> RustBuffer { return FfiConverterTypeUntrustedString.lower(value) } - - /** * Typealias from the type name used in the UDL file to the builtin type. This * is needed because the UDL type name is used in function/method signatures. */ public typealias UserChannelId = String + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public struct FfiConverterTypeUserChannelId: FfiConverter { public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UserChannelId { return try FfiConverterString.read(from: &buf) @@ -9384,11 +12941,16 @@ public struct FfiConverterTypeUserChannelId: FfiConverter { } } - +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeUserChannelId_lift(_ value: RustBuffer) throws -> UserChannelId { return try FfiConverterTypeUserChannelId.lift(value) } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif public func FfiConverterTypeUserChannelId_lower(_ value: UserChannelId) -> RustBuffer { return FfiConverterTypeUserChannelId.lower(value) } @@ -9396,15 +12958,15 @@ public func FfiConverterTypeUserChannelId_lower(_ value: UserChannelId) -> RustB private let UNIFFI_RUST_FUTURE_POLL_READY: Int8 = 0 private let UNIFFI_RUST_FUTURE_POLL_MAYBE_READY: Int8 = 1 -fileprivate let uniffiContinuationHandleMap = UniffiHandleMap>() +private let uniffiContinuationHandleMap = UniffiHandleMap>() -fileprivate func uniffiRustCallAsync( +private func uniffiRustCallAsync( rustFutureFunc: () -> UInt64, - pollFunc: (UInt64, @escaping UniffiRustFutureContinuationCallback, UInt64) -> (), + pollFunc: (UInt64, @escaping UniffiRustFutureContinuationCallback, UInt64) -> Void, completeFunc: (UInt64, UnsafeMutablePointer) -> F, - freeFunc: (UInt64) -> (), + freeFunc: (UInt64) -> Void, liftFunc: (F) throws -> T, - errorHandler: ((RustBuffer) throws -> Error)? + errorHandler: ((RustBuffer) throws -> Swift.Error)? ) async throws -> T { // Make sure to call uniffiEnsureInitialized() since future creation doesn't have a // RustCallStatus param, so doesn't use makeRustCall() @@ -9413,7 +12975,7 @@ fileprivate func uniffiRustCallAsync( defer { freeFunc(rustFuture) } - var pollResult: Int8; + var pollResult: Int8 repeat { pollResult = await withUnsafeContinuation { pollFunc( @@ -9430,26 +12992,43 @@ fileprivate func uniffiRustCallAsync( )) } -// Callback handlers for an async calls. These are invoked by Rust when the future is ready. They -// lift the return value or error and resume the suspended function. -fileprivate func uniffiFutureContinuationCallback(handle: UInt64, pollResult: Int8) { +/// Callback handlers for an async calls. These are invoked by Rust when the future is ready. They +/// lift the return value or error and resume the suspended function. +private func uniffiFutureContinuationCallback(handle: UInt64, pollResult: Int8) { if let continuation = try? uniffiContinuationHandleMap.remove(handle: handle) { continuation.resume(returning: pollResult) } else { print("uniffiFutureContinuationCallback invalid handle") } } + +public func batterySavingSyncIntervals() -> RuntimeSyncIntervals { + return try! FfiConverterTypeRuntimeSyncIntervals.lift(try! rustCall { + uniffi_ldk_node_fn_func_battery_saving_sync_intervals($0) + }) +} + public func defaultConfig() -> Config { - return try! FfiConverterTypeConfig.lift(try! rustCall() { - uniffi_ldk_node_fn_func_default_config($0 - ) -}) + return try! FfiConverterTypeConfig.lift(try! rustCall { + uniffi_ldk_node_fn_func_default_config($0) + }) } -public func generateEntropyMnemonic() -> Mnemonic { - return try! FfiConverterTypeMnemonic.lift(try! rustCall() { - uniffi_ldk_node_fn_func_generate_entropy_mnemonic($0 - ) -}) + +public func deriveNodeSecretFromMnemonic(mnemonic: String, passphrase: String?) throws -> [UInt8] { + return try FfiConverterSequenceUInt8.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { + uniffi_ldk_node_fn_func_derive_node_secret_from_mnemonic( + FfiConverterString.lower(mnemonic), + FfiConverterOptionString.lower(passphrase), $0 + ) + }) +} + +public func generateEntropyMnemonic(wordCount: WordCount?) -> Mnemonic { + return try! FfiConverterTypeMnemonic.lift(try! rustCall { + uniffi_ldk_node_fn_func_generate_entropy_mnemonic( + FfiConverterOptionTypeWordCount.lower(wordCount), $0 + ) + }) } private enum InitializationResult { @@ -9457,9 +13036,10 @@ private enum InitializationResult { case contractVersionMismatch case apiChecksumMismatch } -// Use a global variables to perform the versioning checks. Swift ensures that -// the code inside is only computed once. -private var initializationResult: InitializationResult { + +/// Use a global variable to perform the versioning checks. Swift ensures that +/// the code inside is only computed once. +private var initializationResult: InitializationResult = { // Get the bindings contract version from our ComponentInterface let bindings_contract_version = 26 // Get the scaffolding contract version by calling the into the dylib @@ -9467,367 +13047,667 @@ private var initializationResult: InitializationResult { if bindings_contract_version != scaffolding_contract_version { return InitializationResult.contractVersionMismatch } - if (uniffi_ldk_node_checksum_func_default_config() != 55381) { + if uniffi_ldk_node_checksum_func_battery_saving_sync_intervals() != 25473 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_func_default_config() != 55381 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_func_derive_node_secret_from_mnemonic() != 15067 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_func_generate_entropy_mnemonic() != 48014 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11invoice_amount_milli_satoshis() != 50823 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11invoice_currency() != 32179 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11invoice_expiry_time_seconds() != 23625 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11invoice_fallback_addresses() != 55276 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11invoice_invoice_description() != 395 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11invoice_is_expired() != 15932 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11invoice_min_final_cltv_expiry_delta() != 8855 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11invoice_network() != 10420 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11invoice_payment_hash() != 42571 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11invoice_payment_secret() != 26081 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11invoice_recover_payee_pub_key() != 18874 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11invoice_route_hints() != 63051 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11invoice_seconds_since_epoch() != 53979 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11invoice_seconds_until_expiry() != 64193 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11invoice_signable_hash() != 30910 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11invoice_would_expire() != 30331 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11payment_claim_for_hash() != 52848 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11payment_estimate_routing_fees() != 5123 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11payment_estimate_routing_fees_using_amount() != 46411 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11payment_fail_for_hash() != 24516 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11payment_receive() != 6073 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11payment_receive_for_hash() != 27050 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount() != 4893 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount_for_hash() != 1402 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount_via_jit_channel() != 24506 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount_via_jit_channel_for_hash() != 38025 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11payment_receive_via_jit_channel() != 16532 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11payment_receive_via_jit_channel_for_hash() != 1143 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11payment_send() != 12953 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11payment_send_probes() != 16067 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11payment_send_probes_using_amount() != 37281 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt11payment_send_using_amount() != 42793 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt12invoice_absolute_expiry_seconds() != 28589 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt12invoice_amount() != 5213 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt12invoice_amount_msats() != 9297 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt12invoice_chain() != 3308 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt12invoice_created_at() != 56866 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt12invoice_encode() != 13200 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt12invoice_fallback_addresses() != 7925 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt12invoice_invoice_description() != 1713 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt12invoice_is_expired() != 39560 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt12invoice_issuer() != 65270 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt12invoice_issuer_signing_pubkey() != 55411 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt12invoice_metadata() != 37374 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt12invoice_offer_chains() != 39622 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt12invoice_payer_note() != 28018 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt12invoice_payer_signing_pubkey() != 12798 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt12invoice_payment_hash() != 63778 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt12invoice_quantity() != 43105 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt12invoice_relative_expiry() != 14024 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt12invoice_signable_hash() != 39303 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt12invoice_signing_pubkey() != 35202 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt12payment_blinded_paths_for_async_recipient() != 14695 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt12payment_initiate_refund() != 15019 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt12payment_receive() != 59252 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt12payment_receive_async() != 23867 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt12payment_receive_variable_amount() != 35484 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt12payment_request_refund_payment() != 43248 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt12payment_send() != 27679 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt12payment_send_using_amount() != 33255 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_bolt12payment_set_paths_to_static_invoice_server() != 20921 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_build() != 785 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_build_with_fs_store() != 61304 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_build_with_vss_store() != 2871 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_build_with_vss_store_and_fixed_headers() != 24910 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_build_with_vss_store_and_header_provider() != 9090 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_set_address_type() != 647 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_set_address_types_to_monitor() != 23561 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_set_announcement_addresses() != 39271 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_set_async_payments_role() != 16463 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_set_chain_source_bitcoind_rest() != 37382 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_set_chain_source_bitcoind_rpc() != 2111 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_set_chain_source_electrum() != 55552 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_set_chain_source_esplora() != 1781 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_set_channel_data_migration() != 58453 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_set_custom_logger() != 51232 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_set_entropy_bip39_mnemonic() != 827 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_set_entropy_seed_bytes() != 44799 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_set_entropy_seed_path() != 64056 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_set_filesystem_logger() != 10249 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_set_gossip_source_p2p() != 9279 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_set_gossip_source_rgs() != 64312 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_set_liquidity_source_lsps1() != 51527 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_set_liquidity_source_lsps2() != 14430 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_set_listening_addresses() != 14051 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_set_log_facade_logger() != 58410 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_set_network() != 27539 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_set_node_alias() != 18342 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_set_pathfinding_scores_source() != 63501 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_set_scoring_decay_params() != 19869 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_set_scoring_fee_params() != 11588 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_builder_set_storage_dir_path() != 59019 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_feerate_to_sat_per_kwu() != 58911 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_feerate_to_sat_per_vb_ceil() != 58575 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_feerate_to_sat_per_vb_floor() != 59617 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_lsps1liquidity_check_order_status() != 57147 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ldk_node_checksum_method_lsps1liquidity_request_channel() != 18153 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_func_generate_entropy_mnemonic() != 59926) { + if uniffi_ldk_node_checksum_method_logwriter_log() != 3299 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt11invoice_amount_milli_satoshis() != 50823) { + if uniffi_ldk_node_checksum_method_networkgraph_channel() != 38070 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt11invoice_currency() != 32179) { + if uniffi_ldk_node_checksum_method_networkgraph_list_channels() != 4693 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt11invoice_expiry_time_seconds() != 23625) { + if uniffi_ldk_node_checksum_method_networkgraph_list_nodes() != 36715 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt11invoice_fallback_addresses() != 55276) { + if uniffi_ldk_node_checksum_method_networkgraph_node() != 48925 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt11invoice_invoice_description() != 395) { + if uniffi_ldk_node_checksum_method_node_add_address_type_to_monitor() != 14706 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt11invoice_is_expired() != 15932) { + if uniffi_ldk_node_checksum_method_node_add_address_type_to_monitor_with_mnemonic() != 4517 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt11invoice_min_final_cltv_expiry_delta() != 8855) { + if uniffi_ldk_node_checksum_method_node_add_onchain_wallet_account() != 37245 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt11invoice_network() != 10420) { + if uniffi_ldk_node_checksum_method_node_announcement_addresses() != 61426 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt11invoice_payment_hash() != 42571) { + if uniffi_ldk_node_checksum_method_node_bolt11_payment() != 41402 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt11invoice_payment_secret() != 26081) { + if uniffi_ldk_node_checksum_method_node_bolt12_payment() != 49254 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt11invoice_recover_payee_pub_key() != 18874) { + if uniffi_ldk_node_checksum_method_node_close_channel() != 62479 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt11invoice_route_hints() != 63051) { + if uniffi_ldk_node_checksum_method_node_config() != 7511 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt11invoice_seconds_since_epoch() != 53979) { + if uniffi_ldk_node_checksum_method_node_connect() != 34120 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt11invoice_seconds_until_expiry() != 64193) { + if uniffi_ldk_node_checksum_method_node_current_sync_intervals() != 51918 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt11invoice_signable_hash() != 30910) { + if uniffi_ldk_node_checksum_method_node_disconnect() != 43538 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt11invoice_would_expire() != 30331) { + if uniffi_ldk_node_checksum_method_node_event_handled() != 38712 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt11payment_claim_for_hash() != 52848) { + if uniffi_ldk_node_checksum_method_node_export_onchain_wallet_account_xpub() != 5977 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt11payment_fail_for_hash() != 24516) { + if uniffi_ldk_node_checksum_method_node_export_pathfinding_scores() != 62331 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt11payment_receive() != 6073) { + if uniffi_ldk_node_checksum_method_node_force_close_channel() != 48831 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt11payment_receive_for_hash() != 27050) { + if uniffi_ldk_node_checksum_method_node_get_address_balance() != 45284 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount() != 4893) { + if uniffi_ldk_node_checksum_method_node_get_balance_for_address_type() != 34906 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount_for_hash() != 1402) { + if uniffi_ldk_node_checksum_method_node_get_balance_for_onchain_wallet_account() != 18159 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt11payment_receive_variable_amount_via_jit_channel() != 24506) { + if uniffi_ldk_node_checksum_method_node_get_transaction_details() != 65000 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt11payment_receive_via_jit_channel() != 16532) { + if uniffi_ldk_node_checksum_method_node_list_balances() != 57528 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt11payment_send() != 63952) { + if uniffi_ldk_node_checksum_method_node_list_channels() != 7954 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt11payment_send_probes() != 969) { + if uniffi_ldk_node_checksum_method_node_list_monitored_address_types() != 25084 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt11payment_send_probes_using_amount() != 50136) { + if uniffi_ldk_node_checksum_method_node_list_onchain_wallet_accounts() != 4403 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt11payment_send_using_amount() != 36530) { + if uniffi_ldk_node_checksum_method_node_list_payments() != 35002 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt12payment_initiate_refund() != 38039) { + if uniffi_ldk_node_checksum_method_node_list_peers() != 14889 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt12payment_receive() != 15049) { + if uniffi_ldk_node_checksum_method_node_listening_addresses() != 2665 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt12payment_receive_variable_amount() != 7279) { + if uniffi_ldk_node_checksum_method_node_lsps1_liquidity() != 38201 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt12payment_request_refund_payment() != 61945) { + if uniffi_ldk_node_checksum_method_node_network_graph() != 2695 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt12payment_send() != 56449) { + if uniffi_ldk_node_checksum_method_node_next_event() != 7682 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_bolt12payment_send_using_amount() != 26006) { + if uniffi_ldk_node_checksum_method_node_next_event_async() != 25426 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_builder_build() != 785) { + if uniffi_ldk_node_checksum_method_node_node_alias() != 29526 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_builder_build_with_fs_store() != 61304) { + if uniffi_ldk_node_checksum_method_node_node_id() != 51489 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_builder_build_with_vss_store() != 2871) { + if uniffi_ldk_node_checksum_method_node_onchain_payment() != 6092 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_builder_build_with_vss_store_and_fixed_headers() != 24910) { + if uniffi_ldk_node_checksum_method_node_open_announced_channel() != 36623 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_builder_build_with_vss_store_and_header_provider() != 9090) { + if uniffi_ldk_node_checksum_method_node_open_channel() != 40283 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_builder_set_announcement_addresses() != 39271) { + if uniffi_ldk_node_checksum_method_node_payment() != 60296 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_builder_set_chain_source_bitcoind_rpc() != 2111) { + if uniffi_ldk_node_checksum_method_node_remove_address_type_from_monitor() != 37081 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_builder_set_chain_source_electrum() != 55552) { + if uniffi_ldk_node_checksum_method_node_remove_onchain_wallet_account() != 21186 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_builder_set_chain_source_esplora() != 1781) { + if uniffi_ldk_node_checksum_method_node_remove_payment() != 47952 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_builder_set_custom_logger() != 51232) { + if uniffi_ldk_node_checksum_method_node_set_primary_address_type() != 11005 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_builder_set_entropy_bip39_mnemonic() != 827) { + if uniffi_ldk_node_checksum_method_node_set_primary_address_type_with_mnemonic() != 50783 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_builder_set_entropy_seed_bytes() != 44799) { + if uniffi_ldk_node_checksum_method_node_sign_message() != 49319 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_builder_set_entropy_seed_path() != 64056) { + if uniffi_ldk_node_checksum_method_node_splice_in() != 46431 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_builder_set_filesystem_logger() != 10249) { + if uniffi_ldk_node_checksum_method_node_splice_out() != 22115 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_builder_set_gossip_source_p2p() != 9279) { + if uniffi_ldk_node_checksum_method_node_spontaneous_payment() != 37403 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_builder_set_gossip_source_rgs() != 64312) { + if uniffi_ldk_node_checksum_method_node_start() != 58480 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_builder_set_liquidity_source_lsps1() != 51527) { + if uniffi_ldk_node_checksum_method_node_status() != 55952 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_builder_set_liquidity_source_lsps2() != 14430) { + if uniffi_ldk_node_checksum_method_node_stop() != 42188 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_builder_set_listening_addresses() != 14051) { + if uniffi_ldk_node_checksum_method_node_sync_wallets() != 32474 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_builder_set_log_facade_logger() != 58410) { + if uniffi_ldk_node_checksum_method_node_unified_qr_payment() != 9837 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_builder_set_network() != 27539) { + if uniffi_ldk_node_checksum_method_node_update_channel_config() != 37852 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_builder_set_node_alias() != 18342) { + if uniffi_ldk_node_checksum_method_node_update_sync_intervals() != 42322 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_builder_set_storage_dir_path() != 59019) { + if uniffi_ldk_node_checksum_method_node_verify_signature() != 20486 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_feerate_to_sat_per_kwu() != 58911) { + if uniffi_ldk_node_checksum_method_node_wait_next_event() != 55101 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_feerate_to_sat_per_vb_ceil() != 58575) { + if uniffi_ldk_node_checksum_method_offer_absolute_expiry_seconds() != 22836 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_feerate_to_sat_per_vb_floor() != 59617) { + if uniffi_ldk_node_checksum_method_offer_amount() != 59890 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_lsps1liquidity_check_order_status() != 64731) { + if uniffi_ldk_node_checksum_method_offer_chains() != 59522 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_lsps1liquidity_request_channel() != 18153) { + if uniffi_ldk_node_checksum_method_offer_expects_quantity() != 58457 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_logwriter_log() != 3299) { + if uniffi_ldk_node_checksum_method_offer_id() != 8391 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_networkgraph_channel() != 38070) { + if uniffi_ldk_node_checksum_method_offer_is_expired() != 22651 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_networkgraph_list_channels() != 4693) { + if uniffi_ldk_node_checksum_method_offer_is_valid_quantity() != 58469 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_networkgraph_list_nodes() != 36715) { + if uniffi_ldk_node_checksum_method_offer_issuer() != 41632 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_networkgraph_node() != 48925) { + if uniffi_ldk_node_checksum_method_offer_issuer_signing_pubkey() != 38162 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_announcement_addresses() != 61426) { + if uniffi_ldk_node_checksum_method_offer_metadata() != 18979 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_bolt11_payment() != 41402) { + if uniffi_ldk_node_checksum_method_offer_offer_description() != 11122 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_bolt12_payment() != 49254) { + if uniffi_ldk_node_checksum_method_offer_supports_chain() != 2135 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_close_channel() != 62479) { + if uniffi_ldk_node_checksum_method_onchainpayment_accelerate_by_cpfp() != 31954 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_config() != 7511) { + if uniffi_ldk_node_checksum_method_onchainpayment_address_info_for_account_at_index() != 63246 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_connect() != 34120) { + if uniffi_ldk_node_checksum_method_onchainpayment_address_info_for_type_at_index() != 42692 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_disconnect() != 43538) { + if uniffi_ldk_node_checksum_method_onchainpayment_address_infos_for_account() != 39321 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_event_handled() != 38712) { + if uniffi_ldk_node_checksum_method_onchainpayment_address_infos_for_type() != 3701 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_export_pathfinding_scores() != 62331) { + if uniffi_ldk_node_checksum_method_onchainpayment_bump_fee_by_rbf() != 53877 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_force_close_channel() != 48831) { + if uniffi_ldk_node_checksum_method_onchainpayment_calculate_cpfp_fee_rate() != 32879 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_list_balances() != 57528) { + if uniffi_ldk_node_checksum_method_onchainpayment_calculate_send_all_fee() != 16052 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_list_channels() != 7954) { + if uniffi_ldk_node_checksum_method_onchainpayment_calculate_total_fee() != 57218 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_list_payments() != 35002) { + if uniffi_ldk_node_checksum_method_onchainpayment_list_spendable_outputs() != 19144 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_list_peers() != 14889) { + if uniffi_ldk_node_checksum_method_onchainpayment_new_address() != 37251 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_listening_addresses() != 2665) { + if uniffi_ldk_node_checksum_method_onchainpayment_new_address_for_account() != 9932 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_lsps1_liquidity() != 38201) { + if uniffi_ldk_node_checksum_method_onchainpayment_new_address_for_type() != 9083 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_network_graph() != 2695) { + if uniffi_ldk_node_checksum_method_onchainpayment_new_address_info() != 9889 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_next_event() != 7682) { + if uniffi_ldk_node_checksum_method_onchainpayment_new_address_info_for_account() != 30767 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_next_event_async() != 25426) { + if uniffi_ldk_node_checksum_method_onchainpayment_new_address_info_for_type() != 62171 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_node_alias() != 29526) { + if uniffi_ldk_node_checksum_method_onchainpayment_reveal_receive_addresses_to() != 44189 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_node_id() != 51489) { + if uniffi_ldk_node_checksum_method_onchainpayment_reveal_receive_addresses_to_account() != 53588 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_onchain_payment() != 6092) { + if uniffi_ldk_node_checksum_method_onchainpayment_select_utxos_with_algorithm() != 14084 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_open_announced_channel() != 36623) { + if uniffi_ldk_node_checksum_method_onchainpayment_send_all_to_address() != 37748 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_open_channel() != 40283) { + if uniffi_ldk_node_checksum_method_onchainpayment_send_to_address() != 28826 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_payment() != 60296) { + if uniffi_ldk_node_checksum_method_refund_absolute_expiry_seconds() != 43722 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_remove_payment() != 47952) { + if uniffi_ldk_node_checksum_method_refund_amount_msats() != 26467 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_sign_message() != 49319) { + if uniffi_ldk_node_checksum_method_refund_chain() != 36565 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_spontaneous_payment() != 37403) { + if uniffi_ldk_node_checksum_method_refund_is_expired() != 10232 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_start() != 58480) { + if uniffi_ldk_node_checksum_method_refund_issuer() != 40306 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_status() != 55952) { + if uniffi_ldk_node_checksum_method_refund_payer_metadata() != 23501 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_stop() != 42188) { + if uniffi_ldk_node_checksum_method_refund_payer_note() != 47799 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_sync_wallets() != 32474) { + if uniffi_ldk_node_checksum_method_refund_payer_signing_pubkey() != 40880 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_unified_qr_payment() != 9837) { + if uniffi_ldk_node_checksum_method_refund_quantity() != 15192 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_update_channel_config() != 37852) { + if uniffi_ldk_node_checksum_method_refund_refund_description() != 39295 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_verify_signature() != 20486) { + if uniffi_ldk_node_checksum_method_spontaneouspayment_send() != 27905 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_node_wait_next_event() != 55101) { + if uniffi_ldk_node_checksum_method_spontaneouspayment_send_probes() != 44206 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_onchainpayment_new_address() != 37251) { + if uniffi_ldk_node_checksum_method_spontaneouspayment_send_with_custom_tlvs() != 17876 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_onchainpayment_send_all_to_address() != 37748) { + if uniffi_ldk_node_checksum_method_spontaneouspayment_send_with_preimage() != 30854 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_onchainpayment_send_to_address() != 55646) { + if uniffi_ldk_node_checksum_method_spontaneouspayment_send_with_preimage_and_custom_tlvs() != 12104 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_spontaneouspayment_send() != 48210) { + if uniffi_ldk_node_checksum_method_unifiedqrpayment_receive() != 913 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_spontaneouspayment_send_probes() != 25937) { + if uniffi_ldk_node_checksum_method_unifiedqrpayment_send() != 28285 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_spontaneouspayment_send_with_custom_tlvs() != 2376) { + if uniffi_ldk_node_checksum_method_vssheaderprovider_get_headers() != 7788 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_unifiedqrpayment_receive() != 913) { + if uniffi_ldk_node_checksum_constructor_bolt11invoice_from_str() != 349 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_unifiedqrpayment_send() != 53900) { + if uniffi_ldk_node_checksum_constructor_bolt12invoice_from_str() != 22276 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_method_vssheaderprovider_get_headers() != 7788) { + if uniffi_ldk_node_checksum_constructor_builder_from_config() != 994 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_constructor_bolt11invoice_from_str() != 349) { + if uniffi_ldk_node_checksum_constructor_builder_new() != 40499 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_constructor_builder_from_config() != 994) { + if uniffi_ldk_node_checksum_constructor_feerate_from_sat_per_kwu() != 50548 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_constructor_builder_new() != 40499) { + if uniffi_ldk_node_checksum_constructor_feerate_from_sat_per_vb_unchecked() != 41808 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_constructor_feerate_from_sat_per_kwu() != 50548) { + if uniffi_ldk_node_checksum_constructor_offer_from_str() != 37070 { return InitializationResult.apiChecksumMismatch } - if (uniffi_ldk_node_checksum_constructor_feerate_from_sat_per_vb_unchecked() != 41808) { + if uniffi_ldk_node_checksum_constructor_refund_from_str() != 64884 { return InitializationResult.apiChecksumMismatch } uniffiCallbackInitLogWriter() return InitializationResult.ok -} +}() private func uniffiEnsureInitialized() { switch initializationResult { @@ -9840,4 +13720,4 @@ private func uniffiEnsureInitialized() { } } -// swiftlint:enable all \ No newline at end of file +// swiftlint:enable all diff --git a/bindings/uniffi-bindgen/Cargo.toml b/bindings/uniffi-bindgen/Cargo.toml index a33c0f9ae0..baeafe91b6 100644 --- a/bindings/uniffi-bindgen/Cargo.toml +++ b/bindings/uniffi-bindgen/Cargo.toml @@ -3,6 +3,8 @@ name = "uniffi-bindgen" version = "0.1.0" edition = "2021" +[workspace] + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] diff --git a/crates/bdk-wallet-aggregate/Cargo.toml b/crates/bdk-wallet-aggregate/Cargo.toml new file mode 100644 index 0000000000..af81a0db56 --- /dev/null +++ b/crates/bdk-wallet-aggregate/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "bdk-wallet-aggregate" +version = "0.1.0" +edition = "2021" +rust-version = "1.85" +description = "Aggregates multiple BDK wallets (one per address type) into a single logical wallet." +license = "MIT OR Apache-2.0" + +[dependencies] +bdk_chain = { version = "0.23.0", default-features = false, features = ["std"] } +bdk_wallet = { version = "2.2.0", default-features = false, features = ["std", "keys-bip39"] } +bitcoin = "0.32.7" +bip39 = { version = "2.0.0", features = ["rand"] } +log = { version = "0.4", default-features = false, features = ["std"] } diff --git a/crates/bdk-wallet-aggregate/src/lib.rs b/crates/bdk-wallet-aggregate/src/lib.rs new file mode 100644 index 0000000000..6215359f17 --- /dev/null +++ b/crates/bdk-wallet-aggregate/src/lib.rs @@ -0,0 +1,3006 @@ +// This file is Copyright its original authors, visible in version control history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license , at your option. You may not use this file except in +// accordance with one or both of these licenses. + +//! A library that aggregates multiple BDK wallets into a single logical wallet +//! with unified balance, UTXO management, transaction building, and signing. +//! +//! # Overview +//! +//! [`AggregateWallet`] wraps a *primary* BDK wallet and zero or more +//! *secondary* wallets, keyed by a user-defined type `K` (e.g. an address-type +//! enum). The primary wallet is used for generating new addresses and change +//! outputs; secondary wallets are monitored for existing funds and their UTXOs +//! participate in transaction construction and signing. + +pub mod rbf; +pub mod signing; +pub mod types; +pub mod utxo; + +use std::collections::{HashMap, HashSet}; +use std::fmt::Debug; +use std::hash::Hash; +use std::ops::{Deref, DerefMut}; +use std::sync::Arc; + +use bdk_chain::spk_client::{FullScanRequest, SyncRequest}; +use bdk_chain::{ChainPosition, ConfirmationBlockTime}; +use bdk_wallet::error::CreateTxError; +use bdk_wallet::event::WalletEvent; +use bdk_wallet::{ + AddressInfo, Balance, KeychainKind, LocalOutput, PersistedWallet, Update, WalletPersister, +}; +use bitcoin::blockdata::locktime::absolute::LockTime; +use bitcoin::hashes::Hash as _; +use bitcoin::psbt::Psbt; +use bitcoin::{ + Address, Amount, Block, BlockHash, FeeRate, OutPoint, Script, ScriptBuf, Transaction, Txid, + WPubkeyHash, +}; +pub use types::{CoinSelectionAlgorithm, Error, UtxoPsbtInfo}; + +const BIP32_MAX_NORMAL_INDEX: u32 = (1 << 31) - 1; + +/// Maximum number of address metadata entries returned by a single batch derivation call. +pub const MAX_ADDRESS_INFO_BATCH_COUNT: u32 = 10_000; + +#[derive(Clone, Copy)] +struct CanonicalTransactionState { + confirmation: Option, + last_seen: u64, +} + +fn validate_derivation_index(index: u32) -> Result<(), Error> { + if index > BIP32_MAX_NORMAL_INDEX { + return Err(Error::InvalidQuantity); + } + Ok(()) +} + +fn validate_derivation_range(start_index: u32, count: u32) -> Result<(), Error> { + validate_derivation_index(start_index)?; + if count > MAX_ADDRESS_INFO_BATCH_COUNT { + return Err(Error::InvalidQuantity); + } + if count == 0 { + return Ok(()); + } + + let last_index = start_index.checked_add(count - 1).ok_or(Error::InvalidQuantity)?; + validate_derivation_index(last_index) +} + +fn map_tx_builder_error(error: CreateTxError) -> Error { + match error { + CreateTxError::CoinSelection(_) => Error::InsufficientFunds, + _ => Error::OnchainTxCreationFailed, + } +} + +/// A wallet aggregator that presents multiple BDK wallets as a single logical +/// wallet. +/// +/// Generic over: +/// * `K` – the key type used to identify individual wallets (e.g. an +/// `AddressType` enum). +/// * `P` – the BDK `WalletPersister` implementation. +pub struct AggregateWallet +where + K: Eq + Hash + Copy + Debug, + P: WalletPersister, +{ + wallets: HashMap>, + persisters: HashMap, + primary: K, +} + +/// Delegates to the primary wallet. +impl Deref for AggregateWallet +where + K: Eq + Hash + Copy + Debug, + P: WalletPersister, +{ + type Target = PersistedWallet

; + + fn deref(&self) -> &Self::Target { + self.wallets.get(&self.primary).expect("Primary wallet must always exist") + } +} + +impl DerefMut for AggregateWallet +where + K: Eq + Hash + Copy + Debug, + P: WalletPersister, +{ + fn deref_mut(&mut self) -> &mut Self::Target { + self.wallets.get_mut(&self.primary).expect("Primary wallet must always exist") + } +} + +impl AggregateWallet +where + K: Eq + Hash + Copy + Debug, + P: WalletPersister, + P::Error: std::fmt::Display, +{ + /// Create a new aggregate wallet. + /// + /// * `primary_wallet` / `primary_persister` – the wallet used for new + /// address generation and change outputs. + /// * `primary_key` – the key identifying the primary wallet. + /// * `additional_wallets` – secondary wallets to monitor and use for + /// transaction construction. + pub fn new( + primary_wallet: PersistedWallet

, primary_persister: P, primary_key: K, + additional_wallets: Vec<(K, PersistedWallet

, P)>, + ) -> Self { + let mut wallets = HashMap::new(); + let mut persisters = HashMap::new(); + + wallets.insert(primary_key, primary_wallet); + persisters.insert(primary_key, primary_persister); + + for (key, wallet, persister) in additional_wallets { + debug_assert!( + !wallets.contains_key(&key), + "duplicate wallet key in AggregateWallet::new" + ); + wallets.insert(key, wallet); + persisters.insert(key, persister); + } + + Self { wallets, persisters, primary: primary_key } + } + + // ─── Accessors ────────────────────────────────────────────────────── + + /// The primary wallet key. + pub fn primary_key(&self) -> K { + self.primary + } + + /// All loaded wallet keys (primary + monitored). + pub fn loaded_keys(&self) -> Vec { + self.wallets.keys().copied().collect() + } + + /// Immutable access to the underlying wallet map. + pub fn wallets(&self) -> &HashMap> { + &self.wallets + } + + /// Mutable access to the underlying wallet map. + pub fn wallets_mut(&mut self) -> &mut HashMap> { + &mut self.wallets + } + + /// Immutable access to the persister map. + pub fn persisters(&self) -> &HashMap { + &self.persisters + } + + /// Mutable access to the underlying persister map. + pub fn persisters_mut(&mut self) -> &mut HashMap { + &mut self.persisters + } + + /// Get a reference to a specific wallet. + pub fn wallet(&self, key: &K) -> Option<&PersistedWallet

> { + self.wallets.get(key) + } + + /// Get a mutable reference to a specific wallet. + pub fn wallet_mut(&mut self, key: &K) -> Option<&mut PersistedWallet

> { + self.wallets.get_mut(key) + } + + /// Get a reference to the primary wallet. + pub fn primary_wallet(&self) -> &PersistedWallet

{ + self.wallets.get(&self.primary).expect("Primary wallet must always exist") + } + + /// Get a mutable reference to the primary wallet. + pub fn primary_wallet_mut(&mut self) -> &mut PersistedWallet

{ + self.wallets.get_mut(&self.primary).expect("Primary wallet must always exist") + } + + /// Get a mutable reference to the primary persister. + pub fn primary_persister_mut(&mut self) -> &mut P { + self.persisters.get_mut(&self.primary).expect("Primary persister must always exist") + } + + /// Add a secondary wallet. Returns `Err(WalletAlreadyExists)` if key exists. + pub fn add_wallet( + &mut self, key: K, wallet: PersistedWallet

, persister: P, + ) -> Result<(), Error> { + if self.wallets.contains_key(&key) { + return Err(Error::WalletAlreadyExists); + } + self.wallets.insert(key, wallet); + self.persisters.insert(key, persister); + Ok(()) + } + + /// Add a secondary wallet and roll it back if persistence fails. + pub fn add_wallet_and_persist( + &mut self, key: K, wallet: PersistedWallet

, persister: P, + ) -> Result<(), Error> { + self.add_wallet(key, wallet, persister)?; + if let Err(e) = self.persist_all() { + self.remove_wallet(key).expect("newly added wallet must be removable"); + return Err(e); + } + Ok(()) + } + + /// Change the primary wallet. New primary must already be in the aggregate. + pub fn set_primary(&mut self, new_primary: K) -> Result<(), Error> { + if !self.wallets.contains_key(&new_primary) { + return Err(Error::WalletNotFound); + } + self.primary = new_primary; + Ok(()) + } + + /// Remove a secondary wallet. Returns `Err` if key is primary or not found. + pub fn remove_wallet(&mut self, key: K) -> Result<(), Error> { + if key == self.primary { + return Err(Error::CannotRemovePrimary); + } + if !self.wallets.contains_key(&key) { + return Err(Error::WalletNotFound); + } + if !self.persisters.contains_key(&key) { + return Err(Error::PersisterNotFound); + } + self.wallets.remove(&key); + self.persisters.remove(&key); + Ok(()) + } + + // ─── Balance ──────────────────────────────────────────────────────── + + /// Aggregate balance across all wallets. + pub fn balance(&self) -> Balance { + let mut total = Balance::default(); + for wallet in self.wallets.values() { + let balance = wallet.balance(); + total.confirmed += balance.confirmed; + total.trusted_pending += balance.trusted_pending; + total.untrusted_pending += balance.untrusted_pending; + total.immature += balance.immature; + } + total + } + + /// Balance for a single wallet identified by key. + pub fn balance_for(&self, key: &K) -> Result { + self.wallets.get(key).map(|w| w.balance()).ok_or(Error::WalletNotFound) + } + + // ─── UTXO Listing ─────────────────────────────────────────────────── + + /// List all unspent outputs across every wallet. + pub fn list_unspent(&self) -> Vec { + self.wallets.values().flat_map(|w| w.list_unspent()).collect() + } + + /// List confirmed unspent outputs across all wallets. + pub fn list_confirmed_unspent(&self) -> Vec { + let mut confirmed_outputs = Vec::new(); + for wallet in self.wallets.values() { + let confirmed_txids: HashSet = wallet + .transactions() + .filter(|wallet_tx| wallet_tx.chain_position.is_confirmed()) + .map(|wallet_tx| wallet_tx.tx_node.txid) + .collect(); + confirmed_outputs.extend( + wallet.list_unspent().filter(|utxo| confirmed_txids.contains(&utxo.outpoint.txid)), + ); + } + confirmed_outputs + } + + /// Derive the inner `WPubkeyHash` for a P2SH-wrapped P2WPKH UTXO. + /// + /// For NestedSegwit wallets (BIP-49) the descriptor is `Sh(Wpkh(...))`. + /// This method finds the wallet that owns `utxo`, derives the script at + /// the UTXO's derivation index, and extracts the 20-byte witness + /// program hash from the inner redeemScript (`OP_0 <20-byte-wpkh>`). + /// + /// Returns `None` if the UTXO is not owned by any wallet or if the + /// inner script cannot be parsed as P2WPKH. + pub fn derive_wpkh_for_p2sh(&self, utxo: &LocalOutput) -> Option { + for wallet in self.wallets.values() { + if wallet.get_utxo(utxo.outpoint).is_some() { + let descriptor = wallet.public_descriptor(utxo.keychain); + if let Ok(derived_desc) = descriptor.at_derivation_index(utxo.derivation_index) { + // For Sh(Wpkh(..)) descriptors, `explicit_script()` gives + // the inner P2WPKH redeemScript: OP_0 <20-byte-wpkh>. + if let Ok(explicit) = derived_desc.explicit_script() { + if explicit.len() == 22 + && explicit.as_bytes()[0] == 0x00 + && explicit.as_bytes()[1] == 0x14 + { + return WPubkeyHash::from_slice(&explicit.as_bytes()[2..22]).ok(); + } + } + } + break; + } + } + None + } + + // ─── Transaction Lookup ───────────────────────────────────────────── + + /// Find which wallet key contains a transaction. + pub fn find_wallet_for_tx(&self, txid: Txid) -> Option { + self.wallets.iter().find_map(|(key, wallet)| wallet.get_tx(txid).map(|_| *key)) + } + + /// Find a transaction across all wallets. + pub fn find_tx(&self, txid: Txid) -> Option { + for wallet in self.wallets.values() { + if let Some(tx_node) = wallet.get_tx(txid) { + return Some((*tx_node.tx_node.tx).clone()); + } + } + None + } + + /// Return the confirmation shared by every wallet tracking a transaction. + pub fn transaction_confirmation(&self, txid: &Txid) -> Option { + self.canonical_transaction_states().get(txid).and_then(|state| state.confirmation) + } + + /// Return confirmations agreed on by every wallet tracking each transaction. + pub fn transaction_confirmations(&self) -> HashMap { + self.canonical_transaction_states() + .into_iter() + .filter_map(|(txid, state)| state.confirmation.map(|confirmation| (txid, confirmation))) + .collect() + } + + /// Check whether every wallet tracking a transaction agrees it is confirmed. + pub fn is_tx_confirmed(&self, txid: &Txid) -> bool { + self.transaction_confirmation(txid).is_some() + } + + /// Check whether any wallet tracking a transaction sees it as confirmed. + pub fn is_tx_confirmed_in_any_wallet(&self, txid: &Txid) -> bool { + self.wallets.values().any(|wallet| { + wallet + .transactions() + .find(|tx| tx.tx_node.txid == *txid) + .is_some_and(|tx| tx.chain_position.is_confirmed()) + }) + } + + /// Aggregated sent and received amounts for a transaction across all wallets. + pub fn sent_and_received(&self, txid: Txid) -> Option<(u64, u64)> { + let tx = self.find_tx(txid)?; + let mut total_sent = 0u64; + let mut total_received = 0u64; + for wallet in self.wallets.values() { + if wallet.get_tx(txid).is_some() { + let (sent, received) = wallet.sent_and_received(&tx); + total_sent += sent.to_sat(); + total_received += received.to_sat(); + } + } + Some((total_sent, total_received)) + } + + /// Collect all cached transactions from all wallets, deduplicated by txid. + pub fn cached_txs(&self) -> Vec> { + let mut seen = HashSet::new(); + self.wallets + .values() + .flat_map(|w| w.tx_graph().full_txs()) + .filter(|tx_node| seen.insert(tx_node.txid)) + .map(|tx_node| tx_node.tx) + .collect() + } + + /// Collect all unconfirmed transaction IDs across wallets (deduplicated). + pub fn unconfirmed_txids(&self) -> Vec { + self.canonical_transaction_states() + .into_iter() + .filter_map(|(txid, state)| state.confirmation.is_none().then_some(txid)) + .collect() + } + + /// Collect unconfirmed transaction IDs and their latest observed timestamps. + pub fn unconfirmed_txids_with_last_seen(&self) -> Vec<(Txid, u64)> { + self.canonical_transaction_states() + .into_iter() + .filter_map(|(txid, state)| { + state.confirmation.is_none().then_some((txid, state.last_seen)) + }) + .collect() + } + + /// All canonical transaction IDs across all wallets, deduplicated. + pub fn all_txids(&self) -> Vec { + self.canonical_transaction_states().into_keys().collect() + } + + fn canonical_transaction_states(&self) -> HashMap { + let mut states = HashMap::new(); + for wallet in self.wallets.values() { + for wallet_tx in wallet.transactions() { + let (confirmation, last_seen) = match wallet_tx.chain_position { + ChainPosition::Confirmed { anchor, .. } => (Some(anchor), 0), + ChainPosition::Unconfirmed { last_seen, .. } => (None, last_seen.unwrap_or(0)), + }; + states + .entry(wallet_tx.tx_node.txid) + .and_modify(|state: &mut CanonicalTransactionState| { + if state.confirmation != confirmation { + state.confirmation = None; + } + state.last_seen = state.last_seen.max(last_seen); + }) + .or_insert(CanonicalTransactionState { confirmation, last_seen }); + } + } + states + } + + // ─── Chain Tip ────────────────────────────────────────────────────── + + /// Tips of every loaded wallet as `(block_hash, height)`. + /// + /// Bitcoind catch-up should start from each tip that is behind or on a stale fork relative to + /// the canonical shared tip, rather than assuming a single aggregate cursor is sufficient. + pub fn chain_tips(&self) -> Vec<(BlockHash, u32)> { + self.chain_tips_by_key().into_iter().map(|(_, hash, height)| (hash, height)).collect() + } + + /// Tips of every loaded wallet paired with their key. + pub fn chain_tips_by_key(&self) -> Vec<(K, BlockHash, u32)> { + self.wallets + .iter() + .map(|(key, wallet)| { + let checkpoint = wallet.latest_checkpoint(); + (*key, checkpoint.hash(), checkpoint.height()) + }) + .collect() + } + /// Apply a connected block to a single wallet, then persist. + /// + /// Same skip rules as [`Self::apply_block`], scoped to `key`. + pub fn apply_block_to( + &mut self, key: &K, block: &Block, height: u32, + ) -> Result, Error> { + let block_hash = block.block_hash(); + let wallet = self.wallets.get_mut(key).ok_or(Error::WalletNotFound)?; + let tip = wallet.latest_checkpoint(); + let checkpoint_at_height = tip.get(height); + let sparse_ahead = checkpoint_at_height.is_none() && tip.height() > height; + if !sparse_ahead { + wallet.apply_block(block, height).map_err(|e| { + log::error!( + "Failed to apply connected block {} at height {} to wallet {:?} (tip {}): {}", + block_hash, + height, + key, + tip.height(), + e + ); + Error::WalletOperationFailed + })?; + let persister = self.persisters.get_mut(key).ok_or(Error::PersisterNotFound)?; + wallet.persist(persister).map_err(|e| { + log::error!("Failed to persist wallet {:?}: {}", key, e); + Error::PersistenceFailed + })?; + } + + Ok(wallet.transactions().map(|wtx| wtx.tx_node.txid).collect()) + } + + /// A Listen-oriented aggregate tip: the oldest height across wallets. + /// + /// When multiple wallets share that minimum height but disagree on the hash (fork), pick the + /// lexicographically smallest hash. Preferring the primary here would hide stale secondary + /// tips from Bitcoind catch-up when heights match after an equal-height reorg. + /// + /// Callers that need to reconcile every loaded wallet (including same-height forks) should use + /// [`Self::chain_tips`] and sync from each divergent tip. + pub fn current_best_block(&self) -> (BlockHash, u32) { + self.wallets + .values() + .map(|wallet| wallet.latest_checkpoint()) + .min_by(|a, b| { + a.height() + .cmp(&b.height()) + .then_with(|| a.hash().to_byte_array().cmp(&b.hash().to_byte_array())) + }) + .map(|checkpoint| (checkpoint.hash(), checkpoint.height())) + .unwrap_or_else(|| { + let checkpoint = self.primary_wallet().latest_checkpoint(); + (checkpoint.hash(), checkpoint.height()) + }) + } + + // ─── Address Generation ───────────────────────────────────────────── + + /// Generate a new receiving address from the primary wallet. + pub fn new_address(&mut self) -> Result { + self.new_address_info().map(|address_info| address_info.address) + } + + /// Generate a new receiving address with derivation metadata from the primary wallet. + pub fn new_address_info(&mut self) -> Result { + let key = self.primary; + self.new_address_info_for(&key) + } + + /// Generate a new receiving address for a specific wallet. + pub fn new_address_for(&mut self, key: &K) -> Result { + self.new_address_info_for(key).map(|address_info| address_info.address) + } + + /// Generate a new receiving address with derivation metadata for a specific wallet. + pub fn new_address_info_for(&mut self, key: &K) -> Result { + let wallet = self.wallets.get_mut(key).ok_or(Error::WalletNotFound)?; + let persister = self.persisters.get_mut(key).ok_or(Error::PersisterNotFound)?; + + let address_info = wallet.reveal_next_address(KeychainKind::External); + wallet.persist(persister).map_err(|e| { + log::error!("Failed to persist wallet for {:?}: {}", key, e); + Error::PersistenceFailed + })?; + Ok(address_info) + } + + /// Return address metadata at a derivation index without revealing it. + pub fn address_info_for( + &self, key: &K, keychain: KeychainKind, index: u32, + ) -> Result { + validate_derivation_index(index)?; + + let wallet = self.wallets.get(key).ok_or(Error::WalletNotFound)?; + Ok(wallet.peek_address(keychain, index)) + } + + /// Return address metadata for a range of derivation indexes without revealing them. + pub fn address_infos_for( + &self, key: &K, keychain: KeychainKind, start_index: u32, count: u32, + ) -> Result, Error> { + validate_derivation_range(start_index, count)?; + + let wallet = self.wallets.get(key).ok_or(Error::WalletNotFound)?; + let end_index = start_index.checked_add(count).ok_or(Error::InvalidQuantity)?; + Ok((start_index..end_index).map(|index| wallet.peek_address(keychain, index)).collect()) + } + + /// Reveal external receiving addresses through `index` for a specific wallet and persist. + pub fn reveal_addresses_to(&mut self, key: &K, index: u32) -> Result<(), Error> { + validate_derivation_index(index)?; + + let wallet = self.wallets.get_mut(key).ok_or(Error::WalletNotFound)?; + let persister = self.persisters.get_mut(key).ok_or(Error::PersisterNotFound)?; + + wallet.reveal_addresses_to(KeychainKind::External, index).count(); + wallet.persist(persister).map_err(|e| { + log::error!("Failed to persist wallet for {:?}: {}", key, e); + Error::PersistenceFailed + })?; + Ok(()) + } + + /// Generate a new internal (change) address from the primary wallet. + pub fn new_internal_address(&mut self) -> Result { + let primary = self.primary; + let wallet = self.wallets.get_mut(&primary).ok_or(Error::WalletNotFound)?; + let persister = self.persisters.get_mut(&primary).ok_or(Error::PersisterNotFound)?; + + let address_info = wallet.next_unused_address(KeychainKind::Internal); + wallet.persist(persister).map_err(|e| { + log::error!("Failed to persist wallet: {}", e); + Error::PersistenceFailed + })?; + Ok(address_info.address) + } + + // ─── Transaction Cancellation ─────────────────────────────────────── + + /// Cancel a transaction in all wallets that know about it. + pub fn cancel_tx(&mut self, tx: &Transaction) -> Result<(), Error> { + for (key, wallet) in self.wallets.iter_mut() { + wallet.cancel_tx(tx); + let persister = self.persisters.get_mut(key).ok_or(Error::PersisterNotFound)?; + wallet.persist(persister).map_err(|e| { + log::error!("Failed to persist wallet {:?}: {}", key, e); + Error::PersistenceFailed + })?; + } + Ok(()) + } + + /// Cancel a dry-run transaction on the primary wallet without persisting. + /// + /// Unmarks change addresses that were marked "used" by `finish()`, so + /// the next `finish()` reuses them instead of revealing new ones. The + /// reveal itself is left in the staged changeset and persists harmlessly. + /// + /// Only targets the primary wallet. All current build paths use the primary. + pub fn cancel_dry_run_tx(&mut self, tx: &Transaction) { + let primary = + self.wallets.get_mut(&self.primary).expect("Primary wallet must always exist"); + primary.cancel_tx(tx); + } + + // ─── Fee Calculation ──────────────────────────────────────────────── + + /// Calculate the fee of a PSBT by summing input values and subtracting + /// output values. + pub fn calculate_fee_from_psbt(&self, psbt: &Psbt) -> Result { + let mut total_input_value = 0u64; + + for (i, txin) in psbt.unsigned_tx.input.iter().enumerate() { + if let Some(psbt_input) = psbt.inputs.get(i) { + if let Some(witness_utxo) = &psbt_input.witness_utxo { + total_input_value = total_input_value + .checked_add(witness_utxo.value.to_sat()) + .ok_or(Error::OnchainTxCreationFailed)?; + } else if let Some(non_witness_tx) = &psbt_input.non_witness_utxo { + if let Some(txout) = + non_witness_tx.output.get(txin.previous_output.vout as usize) + { + total_input_value = total_input_value + .checked_add(txout.value.to_sat()) + .ok_or(Error::OnchainTxCreationFailed)?; + } else { + return Err(Error::OnchainTxCreationFailed); + } + } else { + let mut found = false; + for wallet in self.wallets.values() { + if let Some(local_utxo) = wallet.get_utxo(txin.previous_output) { + total_input_value = total_input_value + .checked_add(local_utxo.txout.value.to_sat()) + .ok_or(Error::OnchainTxCreationFailed)?; + found = true; + break; + } + } + if !found { + return Err(Error::OnchainTxCreationFailed); + } + } + } else { + let mut found = false; + for wallet in self.wallets.values() { + if let Some(local_utxo) = wallet.get_utxo(txin.previous_output) { + total_input_value = total_input_value + .checked_add(local_utxo.txout.value.to_sat()) + .ok_or(Error::OnchainTxCreationFailed)?; + found = true; + break; + } + } + if !found { + return Err(Error::OnchainTxCreationFailed); + } + } + } + + let total_output_value = + psbt.unsigned_tx.output.iter().try_fold(0u64, |total, txout| { + total.checked_add(txout.value.to_sat()).ok_or(Error::OnchainTxCreationFailed) + })?; + + total_input_value.checked_sub(total_output_value).ok_or(Error::OnchainTxCreationFailed) + } + + /// Calculate fee from PSBT with fallback to primary wallet calculation. + pub fn calculate_fee_with_fallback(&self, psbt: &Psbt) -> Result { + self.calculate_fee_from_psbt(psbt).or_else(|_| { + self.primary_wallet() + .calculate_fee(&psbt.unsigned_tx) + .map(|f| f.to_sat()) + .map_err(|_| Error::OnchainTxCreationFailed) + }) + } + + /// Calculate the drain amount from a PSBT using sent_and_received across + /// all wallets. Returns the net outgoing amount (sent - received) in sats. + /// + /// For not-yet-broadcast PSBTs the transaction won't be in any wallet's + /// tx-graph, so we compute sent/received directly from the unsigned tx + /// against every wallet's script set. + pub fn drain_amount_from_psbt(&self, psbt: &Psbt) -> u64 { + let mut total_sent = Amount::ZERO; + let mut total_received = Amount::ZERO; + for wallet in self.wallets.values() { + let (s, r) = wallet.sent_and_received(&psbt.unsigned_tx); + total_sent += s; + total_received += r; + } + total_sent.to_sat().saturating_sub(total_received.to_sat()) + } + + // ─── Sync ─────────────────────────────────────────────────────────── + + /// Build a full scan request for a specific wallet. + pub fn wallet_full_scan_request( + &self, key: &K, + ) -> Result, Error> { + let wallet = self.wallets.get(key).ok_or(Error::WalletNotFound)?; + Ok(wallet.start_full_scan().build()) + } + + /// Build an incremental sync request for a specific wallet. + pub fn wallet_incremental_sync_request( + &self, key: &K, + ) -> Result, Error> { + let wallet = self.wallets.get(key).ok_or(Error::WalletNotFound)?; + Ok(wallet.start_sync_with_revealed_spks().build()) + } + + /// Build an incremental sync request including external lookahead scripts. + /// + /// The wallet's configured lookahead determines how many unrevealed scripts are included. + pub fn wallet_incremental_sync_request_with_lookahead( + &self, key: &K, + ) -> Result, Error> { + let wallet = self.wallets.get(key).ok_or(Error::WalletNotFound)?; + let mut request = wallet.start_sync_with_revealed_spks(); + let external_lookahead = wallet.spk_index().lookahead(); + if external_lookahead == 0 { + return Ok(request.build()); + } + + let start_index = match wallet.derivation_index(KeychainKind::External) { + Some(BIP32_MAX_NORMAL_INDEX) => return Ok(request.build()), + Some(index) => index + 1, + None => 0, + }; + let end_index = + start_index.saturating_add(external_lookahead - 1).min(BIP32_MAX_NORMAL_INDEX); + let lookahead_spks = (start_index..=end_index) + .map(|index| { + wallet + .spk_index() + .spk_at_index(KeychainKind::External, index) + .map(|spk| ((KeychainKind::External, index), spk)) + .ok_or(Error::WalletOperationFailed) + }) + .collect::, _>>()?; + request = request.spks_with_indexes(lookahead_spks); + Ok(request.build()) + } + + /// Apply a chain update to the primary wallet. + /// + /// Returns the wallet events and a list of all transaction IDs in the + /// primary wallet (so the caller can update its payment store). + pub fn apply_update( + &mut self, update: impl Into, + ) -> Result<(Vec, Vec), Error> { + let update = update.into(); + let primary = self.primary; + let wallet = self.wallets.get_mut(&primary).ok_or(Error::WalletNotFound)?; + + let events = wallet.apply_update_events(update).map_err(|e| { + log::error!("Failed to apply update to primary wallet: {}", e); + Error::WalletOperationFailed + })?; + + let persister = self.persisters.get_mut(&primary).ok_or(Error::PersisterNotFound)?; + wallet.persist(persister).map_err(|e| { + log::error!("Failed to persist primary wallet: {}", e); + Error::PersistenceFailed + })?; + + let txids: Vec = wallet.transactions().map(|wtx| wtx.tx_node.txid).collect(); + + Ok((events, txids)) + } + + /// Apply a chain update to a specific wallet. + /// + /// Returns the wallet events and a list of all transaction IDs in that + /// wallet. + pub fn apply_update_to_wallet( + &mut self, key: K, update: impl Into, + ) -> Result<(Vec, Vec), Error> { + let update = update.into(); + let wallet = self.wallets.get_mut(&key).ok_or(Error::WalletNotFound)?; + + let events = wallet.apply_update_events(update).map_err(|e| { + log::error!("Failed to apply update to wallet {:?}: {}", key, e); + Error::WalletOperationFailed + })?; + + let persister = self.persisters.get_mut(&key).ok_or(Error::PersisterNotFound)?; + wallet.persist(persister).map_err(|e| { + log::error!("Failed to persist wallet {:?}: {}", key, e); + Error::PersistenceFailed + })?; + + let txids: Vec = wallet.transactions().map(|wtx| wtx.tx_node.txid).collect(); + + Ok((events, txids)) + } + + /// Apply mempool (unconfirmed) transactions to all wallets. + pub fn apply_mempool_txs( + &mut self, unconfirmed_txs: Vec<(Transaction, u64)>, evicted_txids: Vec<(Txid, u64)>, + ) -> Result<(), Error> { + for (key, wallet) in self.wallets.iter_mut() { + wallet.apply_unconfirmed_txs(unconfirmed_txs.clone()); + wallet.apply_evicted_txs(evicted_txids.clone()); + + let persister = self.persisters.get_mut(key).ok_or(Error::PersisterNotFound)?; + wallet.persist(persister).map_err(|e| { + log::error!("Failed to persist wallet {:?}: {}", key, e); + Error::PersistenceFailed + })?; + } + Ok(()) + } + + /// Apply a connected block to wallets that still need it, then persist. + /// + /// Skip rules per wallet: + /// - Exact hash already present at `height` → scan again and persist. BDK deduplicates indexed + /// transactions, and this also retries stranded changesets. + /// - Different hash at `height` → apply (same-height reorg replacement; `blocks_disconnected` + /// is a no-op in the node wallet, so BDK must see replacements here) + /// - No checkpoint at `height` but tip height is already above `height` → skip. Brand-new + /// wallets may only store a sparse `{genesis, tip}` chain; `get(height)` returning `None` + /// means "unknown", not "different block". Applying historical blocks into that sparse tip + /// makes BDK reject the update because a higher unmatched checkpoint already exists. + /// - Otherwise → apply (linear catch-up / extension) + /// + /// Returns the set of all transaction IDs across all wallets. + pub fn apply_block(&mut self, block: &Block, height: u32) -> Result, Error> { + let block_hash = block.block_hash(); + let pre_checkpoint = self.primary_wallet().latest_checkpoint(); + if height > 0 + && (pre_checkpoint.height() != height - 1 + || pre_checkpoint.hash() != block.header.prev_blockhash) + { + log::debug!("Detected reorg while applying connected block at height {}", height); + } + + for (key, wallet) in self.wallets.iter_mut() { + let tip = wallet.latest_checkpoint(); + let checkpoint_at_height = tip.get(height); + let sparse_ahead = checkpoint_at_height.is_none() && tip.height() > height; + if sparse_ahead { + continue; + } + + wallet.apply_block(block, height).map_err(|e| { + log::error!( + "Failed to apply connected block {} at height {} to wallet {:?} (tip {}): {}", + block_hash, + height, + key, + tip.height(), + e + ); + Error::WalletOperationFailed + })?; + + let persister = self.persisters.get_mut(key).ok_or(Error::PersisterNotFound)?; + wallet.persist(persister).map_err(|e| { + log::error!("Failed to persist wallet {:?}: {}", key, e); + Error::PersistenceFailed + })?; + } + + let mut all_txids = HashSet::new(); + for wallet in self.wallets.values() { + for wtx in wallet.transactions() { + all_txids.insert(wtx.tx_node.txid); + } + } + + Ok(all_txids) + } + + // ─── UTXO Preparation Helpers ─────────────────────────────────────── + + /// Prepare local outputs for cross-wallet PSBT building. + pub fn prepare_utxos_for_psbt( + &self, utxos: &[LocalOutput], + ) -> Result, Error> { + utxo::prepare_utxos_for_psbt(utxos, &self.wallets, &self.primary) + } + + /// Prepare outpoints for cross-wallet PSBT building. + pub fn prepare_outpoints_for_psbt( + &self, outpoints: &[OutPoint], + ) -> Result, Error> { + utxo::prepare_outpoints_for_psbt(outpoints, &self.wallets, &self.primary) + } + + // ─── Signing ──────────────────────────────────────────────────────── + + /// Sign an unsigned transaction using all wallets that own inputs. + pub fn sign_owned_inputs(&mut self, unsigned_tx: Transaction) -> Result { + signing::sign_owned_inputs(unsigned_tx, &mut self.wallets) + } + + /// Sign a PSBT using all wallets that own inputs. + pub fn sign_psbt_all(&mut self, psbt: Psbt) -> Result { + signing::sign_psbt_all_wallets(psbt, &mut self.wallets) + } + + // ─── Cross-wallet RBF ─────────────────────────────────────────────── + + /// Build a cross-wallet RBF replacement, adding extra inputs if needed. + /// + /// 1. Tries adjusting the change output only (no new inputs). + /// 2. If that is insufficient, selects minimum additional UTXOs from all + /// wallets and retries. + fn build_cross_wallet_rbf_with_fallback( + &mut self, original_tx: &Transaction, new_fee_rate: FeeRate, + ) -> Result { + // Attempt 1: change-only bump. + match rbf::build_cross_wallet_rbf( + &mut self.wallets, + &self.primary, + original_tx, + new_fee_rate, + &[], + ) { + Ok(tx) => return Ok(tx), + Err(Error::InsufficientFunds) => {}, + Err(e) => return Err(e), + } + + // Attempt 2: select enough effective value to pay the fee and retain change. + let deficit = rbf::additional_input_value_needed( + &self.wallets, + &self.primary, + original_tx, + new_fee_rate, + )?; + + // Collect UTXOs from all wallets, excluding those already in the + // original tx and outputs created by the original tx. + let original_outpoints: HashSet = + original_tx.input.iter().map(|i| i.previous_output).collect(); + let original_txid = original_tx.compute_txid(); + + let available: Vec = self + .list_confirmed_unspent() + .into_iter() + .filter(|u| !original_outpoints.contains(&u.outpoint)) + .filter(|u| u.outpoint.txid != original_txid) + .collect(); + + if available.is_empty() { + return Err(Error::InsufficientFunds); + } + + let drain_script = + self.primary_wallet().peek_address(KeychainKind::Internal, 0).address.script_pubkey(); + + let selected = utxo::select_utxos_with_algorithm( + deficit.to_sat(), + available, + new_fee_rate, + CoinSelectionAlgorithm::BranchAndBound, + &drain_script, + &[], + &self.wallets, + )?; + + let extra_infos = self.prepare_outpoints_for_psbt(&selected)?; + if extra_infos.is_empty() { + return Err(Error::InsufficientFunds); + } + + rbf::build_cross_wallet_rbf( + &mut self.wallets, + &self.primary, + original_tx, + new_fee_rate, + &extra_infos, + ) + } + + /// Look up an input value across local wallets. + pub fn get_input_value(&self, outpoint: &OutPoint) -> Result { + rbf::get_input_value(outpoint, &self.wallets) + } + + // ─── Coin Selection ───────────────────────────────────────────────── + + /// Run coin selection across all wallets. + pub fn select_utxos( + &self, target_amount: u64, available_utxos: Vec, fee_rate: FeeRate, + algorithm: CoinSelectionAlgorithm, drain_script: &Script, excluded_outpoints: &[OutPoint], + ) -> Result, Error> { + utxo::select_utxos_with_algorithm( + target_amount, + available_utxos, + fee_rate, + algorithm, + drain_script, + excluded_outpoints, + &self.wallets, + ) + } + + // ─── Fee Calculation ───────────────────────────────────────────────── + + /// Calculate the fee of a transaction by looking up input values across + /// all wallets and subtracting total output values. + /// + /// Tries BDK's native `calculate_fee` on each wallet first (works + /// reliably for transactions that were built by that wallet), then + /// falls back to manual input-value lookup across all wallets. + pub fn calculate_tx_fee(&self, tx: &Transaction) -> Result { + // Fast path: BDK knows the fee for transactions it built. + for wallet in self.wallets.values() { + if let Ok(fee) = wallet.calculate_fee(tx) { + return Ok(fee); + } + } + + // Slow path: manually look up each input value. + let mut total_input = 0u64; + for txin in &tx.input { + total_input = total_input + .checked_add(self.get_input_value(&txin.previous_output)?) + .ok_or(Error::WalletOperationFailed)?; + } + let total_output = tx.output.iter().try_fold(0u64, |total, output| { + total.checked_add(output.value.to_sat()).ok_or(Error::WalletOperationFailed) + })?; + let fee = total_input.checked_sub(total_output).ok_or(Error::WalletOperationFailed)?; + Ok(Amount::from_sat(fee)) + } + + // ─── High-Level Helpers ───────────────────────────────────────────── + + /// Return prepared PSBT info for all non-primary UTXOs, suitable for + /// adding as foreign inputs to a transaction built on the primary wallet. + /// + /// `excluded_txids` allows the caller to filter out UTXOs belonging to + /// specific transactions (e.g. channel funding transactions). + pub fn non_primary_foreign_utxos( + &self, excluded_txids: &HashSet, + ) -> Result, Error> { + let primary_outpoints: HashSet = + self.primary_wallet().list_unspent().map(|u| u.outpoint).collect(); + + let non_primary: Vec = self + .list_unspent() + .into_iter() + .filter(|u| !primary_outpoints.contains(&u.outpoint)) + .filter(|u| !excluded_txids.contains(&u.outpoint.txid)) + .collect(); + + if non_primary.is_empty() { + return Ok(Vec::new()); + } + + self.prepare_utxos_for_psbt(&non_primary) + } + + /// Select the minimum set of confirmed non-primary UTXOs needed to cover + /// `deficit`, using the given coin selection algorithm. + /// + /// * `segwit_only` – if `true`, excludes bare P2PKH UTXOs (includes + /// P2SH-P2WPKH / NestedSegwit since those carry witness data). + /// * `algorithm` – the coin selection strategy to use. + /// + /// Returns prepared `UtxoPsbtInfo` entries ready to add as foreign + /// inputs, or an empty vec if no non-primary UTXOs are available. + pub fn select_non_primary_foreign_utxos( + &self, deficit: Amount, fee_rate: FeeRate, excluded_txids: &HashSet, + segwit_only: bool, algorithm: CoinSelectionAlgorithm, + ) -> Result, Error> { + let primary_outpoints: HashSet = + self.primary_wallet().list_unspent().map(|u| u.outpoint).collect(); + + let non_primary: Vec = self + .list_confirmed_unspent() + .into_iter() + .filter(|u| !primary_outpoints.contains(&u.outpoint)) + .filter(|u| !excluded_txids.contains(&u.outpoint.txid)) + .filter(|u| { + !segwit_only + || u.txout.script_pubkey.witness_version().is_some() + || u.txout.script_pubkey.is_p2sh() + }) + .collect(); + + if non_primary.is_empty() { + return Ok(Vec::new()); + } + + let drain_script = + self.primary_wallet().peek_address(KeychainKind::Internal, 0).address.script_pubkey(); + + let selected_outpoints = utxo::select_utxos_with_algorithm( + deficit.to_sat(), + non_primary, + fee_rate, + algorithm, + &drain_script, + &[], + &self.wallets, + )?; + + self.prepare_outpoints_for_psbt(&selected_outpoints) + } + + /// Build a transaction using unified coin selection across all eligible + /// wallets. + /// + /// Pools UTXOs from every wallet that passes `utxo_filter`, runs coin + /// selection once on the combined set, then builds a PSBT on the + /// `build_key` wallet with primary UTXOs as native inputs and foreign + /// UTXOs via `add_foreign_utxo`. Signs with all wallets and persists. + #[allow(deprecated, clippy::too_many_arguments)] + fn build_tx_unified( + &mut self, build_key: &K, output_script: ScriptBuf, amount: Amount, fee_rate: FeeRate, + locktime: Option, excluded_txids: &HashSet, + algorithm: CoinSelectionAlgorithm, utxo_filter: impl Fn(&LocalOutput) -> bool, + ) -> Result { + let all_utxos: Vec = self + .list_unspent() + .into_iter() + .filter(|u| !excluded_txids.contains(&u.outpoint.txid)) + .filter(&utxo_filter) + .collect(); + + if all_utxos.is_empty() { + return Err(Error::NoSpendableOutputs); + } + + let drain_script = self + .wallet(build_key) + .ok_or(Error::WalletNotFound)? + .peek_address(KeychainKind::Internal, 0) + .address + .script_pubkey(); + + let selected = utxo::select_utxos_with_algorithm( + amount.to_sat(), + all_utxos, + fee_rate, + algorithm, + &drain_script, + &[], + &self.wallets, + )?; + + let infos = self.prepare_outpoints_for_psbt(&selected)?; + if infos.is_empty() { + return Err(Error::InsufficientFunds); + } + + let w = self.wallets.get_mut(build_key).ok_or(Error::WalletNotFound)?; + let mut b = w.build_tx(); + b.add_recipient(output_script, amount).fee_rate(fee_rate); + if let Some(lt) = locktime { + b.nlocktime(lt); + } + utxo::add_utxos_to_tx_builder(&mut b, &infos)?; + // BDK must not add extra UTXOs — we already selected everything. + b.manually_selected_only(); + b.finish().map_err(|e| { + log::error!("Failed to build tx with unified selection: {}", e); + Error::InsufficientFunds + }) + } + + /// Build a channel-funding transaction using unified coin selection + /// across all wallets. Only SegWit-compatible UTXOs are included + /// (Legacy/P2PKH excluded) as required by BOLT 2. + #[allow(deprecated)] + pub fn build_and_sign_funding_tx( + &mut self, output_script: ScriptBuf, amount: Amount, fee_rate: FeeRate, locktime: LockTime, + ) -> Result { + let psbt = self.build_tx_unified( + &self.primary.clone(), + output_script, + amount, + fee_rate, + Some(locktime), + &HashSet::new(), + CoinSelectionAlgorithm::BranchAndBound, + |u| { + u.txout.script_pubkey.witness_version().is_some() || u.txout.script_pubkey.is_p2sh() + }, + )?; + + let tx = self.sign_psbt_all(psbt)?; + self.persist_all()?; + Ok(tx) + } + + /// Build a channel-funding transaction when the primary wallet is not + /// eligible (e.g. Legacy). Picks the highest-balance wallet from those + /// passing `filter` as the PSBT builder, then runs unified coin + /// selection across all eligible wallets. + #[allow(deprecated)] + pub fn build_and_sign_tx_with_best_wallet( + &mut self, output_script: ScriptBuf, amount: Amount, fee_rate: FeeRate, locktime: LockTime, + filter: impl Fn(&K) -> bool, + ) -> Result { + let mut matching_keys: Vec = + self.wallets.keys().filter(|k| filter(k)).cloned().collect(); + + if matching_keys.is_empty() { + return Err(Error::InsufficientFunds); + } + + matching_keys.sort_by(|a, b| { + let bal_a = self + .balance_for(a) + .map(|bal| bal.confirmed.to_sat() + bal.trusted_pending.to_sat()) + .unwrap_or(0); + let bal_b = self + .balance_for(b) + .map(|bal| bal.confirmed.to_sat() + bal.trusted_pending.to_sat()) + .unwrap_or(0); + bal_b.cmp(&bal_a) + }); + + let build_key = matching_keys[0]; + + let psbt = self.build_tx_unified( + &build_key, + output_script, + amount, + fee_rate, + Some(locktime), + &HashSet::new(), + CoinSelectionAlgorithm::BranchAndBound, + |u| { + u.txout.script_pubkey.witness_version().is_some() || u.txout.script_pubkey.is_p2sh() + }, + )?; + + let tx = self.sign_psbt_all(psbt)?; + self.persist_all()?; + Ok(tx) + } + + /// Build a PSBT using unified coin selection across all wallets. + /// Returns the **unsigned** PSBT — the caller is responsible for + /// signing and persisting. + #[allow(deprecated)] + pub fn build_psbt_with_cross_wallet_fallback( + &mut self, output_script: ScriptBuf, amount: Amount, fee_rate: FeeRate, + excluded_txids: &HashSet, algorithm: CoinSelectionAlgorithm, + ) -> Result { + self.build_tx_unified( + &self.primary.clone(), + output_script, + amount, + fee_rate, + None, + excluded_txids, + algorithm, + |_| true, + ) + } + + /// Aggregate balance across wallets whose keys satisfy `filter`. + pub fn balance_filtered(&self, filter: impl Fn(&K) -> bool) -> Balance { + let mut total = Balance::default(); + for (key, wallet) in &self.wallets { + if filter(key) { + let balance = wallet.balance(); + total.confirmed += balance.confirmed; + total.trusted_pending += balance.trusted_pending; + total.untrusted_pending += balance.untrusted_pending; + total.immature += balance.immature; + } + } + total + } + + /// Build and sign a transaction that drains ALL wallets (primary + + /// monitored) to a single destination script. + /// + /// Uses `drain_wallet()` for the primary wallet and adds non-primary + /// UTXOs as foreign inputs. BDK's drain calculation then accounts for + /// the full input value (primary + foreign) minus fees. + pub fn build_and_sign_drain( + &mut self, destination: ScriptBuf, fee_rate: FeeRate, + ) -> Result { + // Collect non-primary UTXOs first (immutable borrow). + let non_primary_infos = self.non_primary_foreign_utxos(&HashSet::new())?; + + let primary = self.primary; + let wallet = self.wallets.get_mut(&primary).ok_or(Error::WalletNotFound)?; + + // Check primary wallet has at least something to drain. + if wallet.balance().total() == Amount::ZERO && non_primary_infos.is_empty() { + return Err(Error::NoSpendableOutputs); + } + + let mut builder = wallet.build_tx(); + + // drain_wallet() tells BDK to include all primary UTXOs. + builder.drain_wallet(); + builder.drain_to(destination); + builder.fee_rate(fee_rate); + + // Add non-primary UTXOs as foreign inputs. + for info in &non_primary_infos { + builder + .add_foreign_utxo_with_sequence( + info.outpoint, + info.psbt_input.clone(), + info.weight, + bitcoin::Sequence::ENABLE_RBF_NO_LOCKTIME, + ) + .map_err(|e| { + log::error!("Failed to add foreign UTXO {:?} for drain: {}", info.outpoint, e); + Error::OnchainTxCreationFailed + })?; + } + + let psbt = builder.finish().map_err(|e| { + log::error!("Failed to build drain transaction: {}", e); + Error::OnchainTxCreationFailed + })?; + + self.sign_psbt_all(psbt) + } + + // ─── CPFP ────────────────────────────────────────────────────────── + + /// Build a CPFP (Child-Pays-For-Parent) transaction. + /// + /// Finds spendable outputs of `parent_txid` across all wallets, builds + /// a child transaction at `fee_rate` that spends those outputs to + /// `destination_script`. If `destination_script` is `None` the + /// primary wallet's next internal address is used. + /// + /// Returns `(signed_child_tx, parent_fee, parent_fee_rate)`. + pub fn build_cpfp( + &mut self, parent_txid: Txid, fee_rate: FeeRate, destination_script: Option, + ) -> Result<(Transaction, Amount, FeeRate), Error> { + // Find and validate the parent transaction. + let parent_tx = self.find_tx(parent_txid).ok_or(Error::TransactionNotFound)?; + if self.is_tx_confirmed_in_any_wallet(&parent_txid) { + return Err(Error::TransactionAlreadyConfirmed); + } + + // Calculate parent fee. + let parent_fee = self.calculate_tx_fee(&parent_tx)?; + let parent_fee_rate = parent_fee / parent_tx.weight(); + + // Find spendable outputs from this transaction across ALL wallets. + let utxos: Vec = + self.list_unspent().into_iter().filter(|u| u.outpoint.txid == parent_txid).collect(); + if utxos.is_empty() { + return Err(Error::NoSpendableOutputs); + } + + // Classify UTXOs as primary or foreign for tx building. + let utxo_infos = self.prepare_utxos_for_psbt(&utxos)?; + + // Determine destination. + let drain_script = match destination_script { + Some(s) => s, + None => { + let wallet = self.primary_wallet_mut(); + wallet.next_unused_address(KeychainKind::Internal).address.script_pubkey() + }, + }; + + // Build the child transaction on the primary wallet. + let wallet = self.primary_wallet_mut(); + let mut tx_builder = wallet.build_tx(); + + utxo::add_utxos_to_tx_builder(&mut tx_builder, &utxo_infos) + .map_err(|_| Error::OnchainTxCreationFailed)?; + + tx_builder.fee_rate(fee_rate); + tx_builder.drain_to(drain_script); + tx_builder.manually_selected_only(); + + let psbt = tx_builder.finish().map_err(|e| { + log::error!("Failed to create CPFP transaction: {}", e); + Error::OnchainTxCreationFailed + })?; + + let tx = self.sign_psbt_all(psbt)?; + Ok((tx, parent_fee, parent_fee_rate)) + } + + /// Calculate an appropriate CPFP child fee rate given a parent txid and + /// a `target_fee_rate` that the caller wants the package to achieve. + /// + /// Returns the recommended child fee rate. If the parent already meets + /// the target, returns `target + 1 sat/vB`. + pub fn calculate_cpfp_fee_rate( + &self, parent_txid: Txid, target_fee_rate: FeeRate, + ) -> Result { + let parent_tx = self.find_tx(parent_txid).ok_or(Error::TransactionNotFound)?; + if self.is_tx_confirmed_in_any_wallet(&parent_txid) { + return Err(Error::TransactionAlreadyConfirmed); + } + + let parent_fee = self.calculate_tx_fee(&parent_tx)?; + let parent_fee_rate = parent_fee / parent_tx.weight(); + + // If parent already meets target, return slightly higher rate. + if parent_fee_rate >= target_fee_rate { + return Ok(FeeRate::from_sat_per_kwu(parent_fee_rate.to_sat_per_kwu() + 250)); + } + + // Estimate child size: conservative 1-in/1-out (~120 vB). + let estimated_child_vbytes: u64 = 120; + let parent_vbytes = parent_tx.weight().to_vbytes_ceil(); + + let parent_fee_deficit = (target_fee_rate.to_sat_per_vb_ceil() + - parent_fee_rate.to_sat_per_vb_ceil()) + * parent_vbytes; + let base_child_fee = target_fee_rate.to_sat_per_vb_ceil() * estimated_child_vbytes; + let total_child_fee = base_child_fee + parent_fee_deficit; + let child_fee_rate_sat_vb = total_child_fee / estimated_child_vbytes; + + Ok(FeeRate::from_sat_per_vb(child_fee_rate_sat_vb) + .unwrap_or(FeeRate::from_sat_per_kwu(child_fee_rate_sat_vb * 250))) + } + + // ─── RBF ──────────────────────────────────────────────────────────── + + /// Returns `true` if all inputs of the transaction belong to the primary wallet. + pub fn is_primary_only_tx(&self, txid: Txid) -> bool { + let primary = self.primary_wallet(); + if primary.get_tx(txid).is_none() { + return false; + } + let tx = match self.find_tx(txid) { + Some(tx) => tx, + None => return false, + }; + tx.input.iter().all(|txin| { + // Fast path: primary still has the UTXO (unspent). + if primary.get_utxo(txin.previous_output).is_some() { + return true; + } + // Slow path: the UTXO was already spent (by this tx). Check + // whether the output script belongs to the primary wallet. + if let Some(tx_node) = primary.get_tx(txin.previous_output.txid) { + if let Some(txout) = + tx_node.tx_node.tx.output.get(txin.previous_output.vout as usize) + { + return primary.is_mine(txout.script_pubkey.clone()); + } + } + false + }) + } + + /// Build an RBF replacement transaction. + /// + /// This is a high-level method that: + /// 1. Finds the original transaction across all wallets. + /// 2. Validates that it is unconfirmed and the new fee rate meets replacement policy. + /// 3. If the original tx was primary-only, tries BDK's built-in fee + /// bump and falls back to adding foreign inputs if the primary wallet + /// has insufficient funds. + /// 4. If the original tx was cross-wallet, uses manual RBF construction. + /// 5. Signs the replacement with all wallets. + /// + /// Returns the signed replacement transaction and the original fee + /// (for caller logging). + pub fn build_rbf( + &mut self, txid: Txid, new_fee_rate: FeeRate, + ) -> Result<(Transaction, Amount), Error> { + // Find original transaction. + let original_tx = self.find_tx(txid).ok_or(Error::TransactionNotFound)?; + + // Must not be confirmed. + if self.is_tx_confirmed_in_any_wallet(&txid) { + return Err(Error::TransactionAlreadyConfirmed); + } + + // Calculate original fee. + let original_fee = self.calculate_tx_fee(&original_tx)?; + let minimum_fee_rate = + rbf::minimum_replacement_fee_rate(original_fee, original_tx.weight())?; + + if new_fee_rate < minimum_fee_rate { + return Err(Error::InvalidFeeRate); + } + + // Build the replacement. + let is_primary = self.is_primary_only_tx(txid); + + let tx = if is_primary { + self.build_rbf_primary_with_fallback(txid, new_fee_rate)? + } else { + self.build_cross_wallet_rbf_with_fallback(&original_tx, new_fee_rate)? + }; + + Ok((tx, original_fee)) + } + + /// Try a primary-only RBF first; if the primary wallet doesn't have + /// enough funds for the higher fee, fall back to adding non-primary + /// UTXOs as additional inputs. + fn build_rbf_primary_with_fallback( + &mut self, txid: Txid, fee_rate: FeeRate, + ) -> Result { + // Attempt 1: primary-only fee bump. + let primary_result: Result = { + let wallet = self.wallets.get_mut(&self.primary).ok_or(Error::WalletNotFound)?; + match wallet.build_fee_bump(txid) { + Ok(mut builder) => { + builder.fee_rate(fee_rate); + builder.finish().map_err(|e| { + log::debug!("Primary-only RBF failed: {}", e); + map_tx_builder_error(e) + }) + }, + Err(e) => { + log::debug!("build_fee_bump failed: {}", e); + Err(Error::OnchainTxCreationFailed) + }, + } + }; // mutable wallet borrow released here + + match primary_result { + Ok(psbt) => self.sign_psbt_all(psbt), + Err(Error::InsufficientFunds) => { + // Attempt 2: select minimum non-primary UTXOs for the fee deficit. + let original_tx = self.find_tx(txid).ok_or(Error::TransactionNotFound)?; + let original_fee = self.calculate_tx_fee(&original_tx)?; + let new_fee = fee_rate.fee_wu(original_tx.weight()).ok_or(Error::InvalidFeeRate)?; + let fee_increase = new_fee.checked_sub(original_fee).unwrap_or(Amount::ZERO); + + let absorbable = + rbf::find_internal_change_output(&self.wallets, &self.primary, &original_tx) + .map(|(_, output)| output.value) + .unwrap_or(Amount::ZERO); + let required_value = fee_increase + .checked_add(Amount::from_sat(utxo::DUST_LIMIT_SATS)) + .ok_or(Error::OnchainTxCreationFailed)?; + let deficit = required_value.checked_sub(absorbable).unwrap_or(Amount::ZERO); + + let excluded_txids = HashSet::from([txid]); + let non_primary_infos = self.select_non_primary_foreign_utxos( + deficit, + fee_rate, + &excluded_txids, + false, + CoinSelectionAlgorithm::BranchAndBound, + )?; + if non_primary_infos.is_empty() { + return Err(Error::InsufficientFunds); + } + + let wallet = self.wallets.get_mut(&self.primary).ok_or(Error::WalletNotFound)?; + let mut builder = wallet.build_fee_bump(txid).map_err(|e| { + log::error!("Failed to create fee bump builder (with foreign): {}", e); + Error::OnchainTxCreationFailed + })?; + builder.fee_rate(fee_rate); + + for info in &non_primary_infos { + builder + .add_foreign_utxo_with_sequence( + info.outpoint, + info.psbt_input.clone(), + info.weight, + bitcoin::Sequence::ENABLE_RBF_NO_LOCKTIME, + ) + .map_err(|e| { + log::error!("Failed to add foreign UTXO {:?}: {}", info.outpoint, e); + Error::OnchainTxCreationFailed + })?; + } + + let psbt = builder.finish().map_err(|e| { + log::error!("Failed to build RBF with additional inputs: {}", e); + Error::OnchainTxCreationFailed + })?; + + self.sign_psbt_all(psbt) + }, + Err(e) => Err(e), + } + } + + // ─── Persistence ──────────────────────────────────────────────────── + + /// Persist all wallets. + pub fn persist_all(&mut self) -> Result<(), Error> { + for (key, wallet) in self.wallets.iter_mut() { + let persister = self.persisters.get_mut(key).ok_or(Error::PersisterNotFound)?; + wallet.persist(persister).map_err(|e| { + log::error!("Failed to persist wallet {:?}: {}", key, e); + Error::PersistenceFailed + })?; + } + Ok(()) + } + + /// Check if an output belongs to any wallet. + pub fn is_mine(&self, script_pubkey: ScriptBuf) -> bool { + self.wallets.values().any(|w| w.is_mine(script_pubkey.clone())) + } +} + +#[cfg(test)] +mod tests { + use std::sync::atomic::{AtomicUsize, Ordering}; + use std::sync::{Arc, Mutex}; + + use bdk_chain::Merge; + use bdk_wallet::template::Bip84; + use bdk_wallet::{ + ChangeSet, KeychainKind, PersistedWallet, SignOptions, Wallet, WalletPersister, + }; + use bitcoin::bip32::Xpriv; + use bitcoin::{ + Amount, Block, FeeRate, Network, OutPoint, ScriptBuf, Transaction, TxIn, TxOut, Txid, + }; + + use super::*; + + struct NoopPersister; + + impl WalletPersister for NoopPersister { + type Error = std::convert::Infallible; + + fn initialize(_: &mut Self) -> Result { + Ok(ChangeSet::default()) + } + + fn persist(_: &mut Self, _: &ChangeSet) -> Result<(), Self::Error> { + Ok(()) + } + } + + #[derive(Clone, Default)] + struct MemoryPersister { + change_set: Arc>, + } + + impl WalletPersister for MemoryPersister { + type Error = std::convert::Infallible; + + fn initialize(persister: &mut Self) -> Result { + Ok(persister.change_set.lock().unwrap().clone()) + } + + fn persist(persister: &mut Self, change_set: &ChangeSet) -> Result<(), Self::Error> { + persister.change_set.lock().unwrap().merge(change_set.clone()); + Ok(()) + } + } + + struct FailOncePersister { + failures: Arc, + inner: MemoryPersister, + } + + impl WalletPersister for FailOncePersister { + type Error = std::io::Error; + + fn initialize(persister: &mut Self) -> Result { + Ok(persister.inner.change_set.lock().unwrap().clone()) + } + + fn persist(persister: &mut Self, change_set: &ChangeSet) -> Result<(), Self::Error> { + if persister.failures.load(Ordering::SeqCst) > 0 { + persister.failures.fetch_sub(1, Ordering::SeqCst); + return Err(std::io::Error::other("injected persist failure")); + } + persister.inner.change_set.lock().unwrap().merge(change_set.clone()); + Ok(()) + } + } + + fn test_xprv() -> Xpriv { + test_xprv_from_byte(0x42) + } + + fn test_xprv_from_byte(byte: u8) -> Xpriv { + Xpriv::new_master(Network::Regtest, &[byte; 32]).unwrap() + } + + fn create_empty_wallet

(persister: &mut P) -> PersistedWallet

+ where + P: WalletPersister, + P::Error: std::fmt::Debug, + { + create_empty_wallet_from_xprv(persister, test_xprv()) + } + + fn create_empty_wallet_from_xprv

(persister: &mut P, xprv: Xpriv) -> PersistedWallet

+ where + P: WalletPersister, + P::Error: std::fmt::Debug, + { + create_empty_wallet_from_xprv_with_lookahead(persister, xprv, None) + } + + fn create_empty_wallet_from_xprv_with_lookahead

( + persister: &mut P, xprv: Xpriv, lookahead: Option, + ) -> PersistedWallet

+ where + P: WalletPersister, + P::Error: std::fmt::Debug, + { + let mut params = Wallet::create( + Bip84(xprv, KeychainKind::External), + Bip84(xprv, KeychainKind::Internal), + ) + .network(Network::Regtest); + if let Some(lookahead) = lookahead { + params = params.lookahead(lookahead); + } + PersistedWallet::create(persister, params).unwrap() + } + + fn load_empty_wallet

(persister: &mut P) -> PersistedWallet

+ where + P: WalletPersister, + P::Error: std::fmt::Debug, + { + load_empty_wallet_with_lookahead(persister, None) + } + + fn load_empty_wallet_with_lookahead

( + persister: &mut P, lookahead: Option, + ) -> PersistedWallet

+ where + P: WalletPersister, + P::Error: std::fmt::Debug, + { + let xprv = test_xprv(); + let mut params = Wallet::load() + .descriptor(KeychainKind::External, Some(Bip84(xprv, KeychainKind::External))) + .descriptor(KeychainKind::Internal, Some(Bip84(xprv, KeychainKind::Internal))) + .extract_keys() + .check_network(Network::Regtest); + if let Some(lookahead) = lookahead { + params = params.lookahead(lookahead); + } + params.load_wallet(persister).unwrap().expect("wallet should have been persisted") + } + + #[test] + fn add_wallet_and_persist_rolls_back_on_persist_failure() { + let failures = Arc::new(AtomicUsize::new(0)); + let mut primary_persister = FailOncePersister { + failures: Arc::clone(&failures), + inner: MemoryPersister::default(), + }; + let primary = create_empty_wallet(&mut primary_persister); + let mut secondary_persister = FailOncePersister { + failures: Arc::clone(&failures), + inner: MemoryPersister::default(), + }; + let mut secondary = create_empty_wallet(&mut secondary_persister); + secondary.reveal_next_address(KeychainKind::External); + let secondary_state = secondary_persister.inner.clone(); + + let mut aggregate = AggregateWallet::new(primary, primary_persister, 0u8, vec![]); + failures.store(1, Ordering::SeqCst); + assert_eq!( + aggregate.add_wallet_and_persist(1, secondary, secondary_persister), + Err(Error::PersistenceFailed) + ); + assert!(!aggregate.loaded_keys().contains(&1)); + + let mut retry_persister = FailOncePersister { failures, inner: secondary_state }; + let retry_wallet = load_empty_wallet(&mut retry_persister); + aggregate.add_wallet_and_persist(1, retry_wallet, retry_persister).unwrap(); + assert!(aggregate.loaded_keys().contains(&1)); + } + + fn create_funded_wallet( + persister: &mut NoopPersister, amount: Amount, + ) -> PersistedWallet { + let mut wallet = create_empty_wallet(persister); + fund_wallet(&mut wallet, amount, 0x01); + wallet + } + + fn fund_wallet

(wallet: &mut PersistedWallet

, amount: Amount, distinct: u8) -> Transaction + where + P: WalletPersister, + { + let addr = wallet.reveal_next_address(KeychainKind::External); + let funding_tx = Transaction { + version: bitcoin::transaction::Version::TWO, + lock_time: bitcoin::blockdata::locktime::absolute::LockTime::ZERO, + input: vec![TxIn { + previous_output: OutPoint { txid: Txid::from_byte_array([distinct; 32]), vout: 0 }, + ..Default::default() + }], + output: vec![TxOut { value: amount, script_pubkey: addr.address.script_pubkey() }], + }; + wallet.apply_unconfirmed_txs([(funding_tx.clone(), 0)]); + funding_tx + } + + fn recipient_script() -> ScriptBuf { + ScriptBuf::new_p2wpkh(&bitcoin::WPubkeyHash::from_byte_array([0xab; 20])) + } + + #[test] + fn persistence_fails_when_a_wallet_has_no_persister() { + let mut persister = NoopPersister; + let wallet = create_empty_wallet(&mut persister); + let mut aggregate = AggregateWallet::::new(wallet, persister, 0, vec![]); + aggregate.persisters_mut().remove(&0); + + assert_eq!(aggregate.persist_all().unwrap_err(), Error::PersisterNotFound); + } + + #[test] + fn removing_an_unknown_wallet_reports_wallet_not_found() { + let mut persister = NoopPersister; + let wallet = create_empty_wallet(&mut persister); + let mut aggregate = AggregateWallet::::new(wallet, persister, 0, vec![]); + + assert_eq!(aggregate.remove_wallet(1), Err(Error::WalletNotFound)); + } + + #[test] + fn removal_preserves_a_wallet_when_its_persister_is_missing() { + let mut primary_persister = NoopPersister; + let primary = create_empty_wallet(&mut primary_persister); + let mut secondary_persister = NoopPersister; + let secondary = create_empty_wallet(&mut secondary_persister); + let mut aggregate = AggregateWallet::new( + primary, + primary_persister, + 0u8, + vec![(1u8, secondary, secondary_persister)], + ); + aggregate.persisters_mut().remove(&1); + + assert_eq!(aggregate.remove_wallet(1), Err(Error::PersisterNotFound)); + assert!(aggregate.loaded_keys().contains(&1)); + } + + #[test] + fn fee_calculation_rejects_outputs_exceeding_inputs() { + let mut persister = NoopPersister; + let mut wallet = create_empty_wallet(&mut persister); + let funding_tx = fund_wallet(&mut wallet, Amount::from_sat(100_000), 0x14); + let unsigned_tx = Transaction { + version: bitcoin::transaction::Version::TWO, + lock_time: bitcoin::absolute::LockTime::ZERO, + input: vec![TxIn { + previous_output: OutPoint { txid: funding_tx.compute_txid(), vout: 0 }, + ..Default::default() + }], + output: vec![TxOut { + value: Amount::from_sat(110_000), + script_pubkey: recipient_script(), + }], + }; + let psbt = bitcoin::psbt::Psbt::from_unsigned_tx(unsigned_tx).unwrap(); + let aggregate = AggregateWallet::::new(wallet, persister, 0, vec![]); + + assert_eq!( + aggregate.calculate_fee_from_psbt(&psbt).unwrap_err(), + Error::OnchainTxCreationFailed + ); + } + + #[test] + fn fee_calculation_supports_foreign_wallet_inputs() { + let mut primary_persister = NoopPersister; + let primary = + create_empty_wallet_from_xprv(&mut primary_persister, test_xprv_from_byte(0x15)); + let mut secondary_persister = NoopPersister; + let mut secondary = + create_empty_wallet_from_xprv(&mut secondary_persister, test_xprv_from_byte(0x16)); + let funding_tx = fund_wallet(&mut secondary, Amount::from_sat(100_000), 0x17); + let funding_outpoint = OutPoint { txid: funding_tx.compute_txid(), vout: 0 }; + let mut aggregate = AggregateWallet::new( + primary, + primary_persister, + 0u8, + vec![(1u8, secondary, secondary_persister)], + ); + let infos = aggregate.prepare_outpoints_for_psbt(&[funding_outpoint]).unwrap(); + let expected_weight = aggregate + .wallet(&1) + .unwrap() + .public_descriptor(KeychainKind::External) + .max_weight_to_satisfy() + .unwrap(); + assert_eq!(infos[0].weight, expected_weight); + let psbt = { + let mut builder = aggregate.primary_wallet_mut().build_tx(); + builder + .add_recipient(recipient_script(), Amount::from_sat(90_000)) + .fee_rate(FeeRate::from_sat_per_kwu(250)); + utxo::add_utxos_to_tx_builder(&mut builder, &infos).unwrap(); + builder.manually_selected_only(); + builder.finish().unwrap() + }; + + assert!(aggregate.calculate_fee_from_psbt(&psbt).unwrap() > 0); + } + + #[test] + fn only_coin_selection_errors_trigger_the_rbf_fallback() { + let insufficient = bdk_wallet::coin_selection::InsufficientFunds { + needed: Amount::from_sat(2), + available: Amount::from_sat(1), + }; + + assert_eq!( + map_tx_builder_error(CreateTxError::CoinSelection(insufficient)), + Error::InsufficientFunds + ); + assert_eq!( + map_tx_builder_error(CreateTxError::NoRecipients), + Error::OnchainTxCreationFailed + ); + } + + #[test] + fn confirmed_utxos_use_the_owning_wallet_chain_state() { + use bitcoin::blockdata::constants::genesis_block; + + let mut primary_persister = NoopPersister; + let mut primary = + create_empty_wallet_from_xprv(&mut primary_persister, test_xprv_from_byte(0x21)); + let mut secondary_persister = NoopPersister; + let mut secondary = + create_empty_wallet_from_xprv(&mut secondary_persister, test_xprv_from_byte(0x22)); + let primary_script = + primary.reveal_next_address(KeychainKind::External).address.script_pubkey(); + let secondary_script = + secondary.reveal_next_address(KeychainKind::External).address.script_pubkey(); + let shared_tx = Transaction { + version: bitcoin::transaction::Version::TWO, + lock_time: bitcoin::absolute::LockTime::ZERO, + input: vec![TxIn { + previous_output: OutPoint { txid: Txid::from_byte_array([0x23; 32]), vout: 0 }, + ..Default::default() + }], + output: vec![ + TxOut { value: Amount::from_sat(40_000), script_pubkey: primary_script.clone() }, + TxOut { value: Amount::from_sat(50_000), script_pubkey: secondary_script.clone() }, + ], + }; + primary.apply_unconfirmed_txs([(shared_tx.clone(), 1)]); + secondary.apply_unconfirmed_txs([(shared_tx.clone(), 1)]); + + let genesis = genesis_block(Network::Regtest); + primary.apply_block(&genesis, 0).unwrap(); + secondary.apply_block(&genesis, 0).unwrap(); + let block = regtest_child_block_with_transaction(&genesis, 1, shared_tx.clone()); + primary.apply_block(&block, 1).unwrap(); + + let txid = shared_tx.compute_txid(); + let mut aggregate = AggregateWallet::new( + primary, + primary_persister, + 0u8, + vec![(1u8, secondary, secondary_persister)], + ); + let confirmed = aggregate.list_confirmed_unspent(); + assert_eq!(confirmed.len(), 1); + assert_eq!(confirmed[0].txout.script_pubkey, primary_script); + assert!(aggregate.transaction_confirmation(&txid).is_none()); + assert!(!aggregate.transaction_confirmations().contains_key(&txid)); + assert!(aggregate.unconfirmed_txids().contains(&txid)); + assert!(aggregate.unconfirmed_txids_with_last_seen().contains(&(txid, 1))); + assert!(aggregate.is_tx_confirmed_in_any_wallet(&txid)); + assert_eq!( + aggregate.build_rbf(txid, FeeRate::from_sat_per_kwu(1_000)).unwrap_err(), + Error::TransactionAlreadyConfirmed + ); + assert_eq!( + aggregate.calculate_cpfp_fee_rate(txid, FeeRate::from_sat_per_kwu(1_000)).unwrap_err(), + Error::TransactionAlreadyConfirmed + ); + assert_eq!( + aggregate.build_cpfp(txid, FeeRate::from_sat_per_kwu(1_000), None).unwrap_err(), + Error::TransactionAlreadyConfirmed + ); + + aggregate.apply_block_to(&1, &block, 1).unwrap(); + assert_eq!(aggregate.list_confirmed_unspent().len(), 2); + assert_eq!( + aggregate.transaction_confirmation(&txid).unwrap().block_id.hash, + block.block_hash() + ); + assert_eq!( + aggregate.transaction_confirmations().get(&txid).unwrap().block_id.hash, + block.block_hash() + ); + assert!(!aggregate.unconfirmed_txids().contains(&txid)); + assert!(!aggregate.unconfirmed_txids_with_last_seen().iter().any(|(id, _)| id == &txid)); + } + + #[test] + fn primary_rbf_does_not_spend_or_reduce_secondary_recipient_outputs() { + let mut primary_persister = NoopPersister; + let mut primary = + create_empty_wallet_from_xprv(&mut primary_persister, test_xprv_from_byte(0x31)); + let primary_funding = fund_wallet(&mut primary, Amount::from_sat(55_000), 0x32); + let primary_outpoint = OutPoint { txid: primary_funding.compute_txid(), vout: 0 }; + + let mut secondary_persister = NoopPersister; + let mut secondary = + create_empty_wallet_from_xprv(&mut secondary_persister, test_xprv_from_byte(0x33)); + let secondary_funding = fund_wallet(&mut secondary, Amount::from_sat(60_000), 0x34); + let secondary_outpoint = OutPoint { txid: secondary_funding.compute_txid(), vout: 0 }; + let secondary_recipient = + secondary.reveal_next_address(KeychainKind::External).address.script_pubkey(); + confirm_transactions( + &mut [&mut primary, &mut secondary], + &[primary_funding.clone(), secondary_funding.clone()], + ); + + let mut original_psbt = { + let mut builder = primary.build_tx(); + builder + .add_utxo(primary_outpoint) + .unwrap() + .add_recipient(secondary_recipient.clone(), Amount::from_sat(50_000)) + .fee_rate(FeeRate::from_sat_per_kwu(250)) + .manually_selected_only(); + builder.finish().unwrap() + }; + assert!(primary.sign(&mut original_psbt, SignOptions::default()).unwrap()); + let original_tx = original_psbt.extract_tx().unwrap(); + let original_txid = original_tx.compute_txid(); + primary.apply_unconfirmed_txs([(original_tx.clone(), 2)]); + secondary.apply_unconfirmed_txs([(original_tx.clone(), 2)]); + + let mut aggregate = AggregateWallet::new( + primary, + primary_persister, + 0u8, + vec![(1u8, secondary, secondary_persister)], + ); + let (replacement, _) = + aggregate.build_rbf(original_txid, FeeRate::from_sat_per_kwu(25_000)).unwrap(); + + assert!(replacement.input.iter().any(|input| input.previous_output == secondary_outpoint)); + assert!(replacement.input.iter().all(|input| input.previous_output.txid != original_txid)); + assert!(replacement.output.iter().any(|output| { + output.script_pubkey == secondary_recipient && output.value == Amount::from_sat(50_000) + })); + } + + #[test] + fn cross_wallet_rbf_only_counts_the_selected_change_output() { + let mut primary_persister = NoopPersister; + let mut primary = + create_empty_wallet_from_xprv(&mut primary_persister, test_xprv_from_byte(0x41)); + let primary_funding = fund_wallet(&mut primary, Amount::from_sat(70_000), 0x42); + let primary_change = + primary.reveal_next_address(KeychainKind::Internal).address.script_pubkey(); + + let mut secondary_persister = NoopPersister; + let mut secondary = + create_empty_wallet_from_xprv(&mut secondary_persister, test_xprv_from_byte(0x43)); + let secondary_funding = fund_wallet(&mut secondary, Amount::from_sat(70_000), 0x44); + let spare_funding = fund_wallet(&mut secondary, Amount::from_sat(60_000), 0x45); + let secondary_change = + secondary.reveal_next_address(KeychainKind::Internal).address.script_pubkey(); + confirm_transactions( + &mut [&mut primary, &mut secondary], + &[primary_funding.clone(), secondary_funding.clone(), spare_funding.clone()], + ); + + let original_tx = Transaction { + version: bitcoin::transaction::Version::TWO, + lock_time: bitcoin::absolute::LockTime::ZERO, + input: vec![ + TxIn { + previous_output: OutPoint { txid: primary_funding.compute_txid(), vout: 0 }, + sequence: bitcoin::Sequence::ENABLE_RBF_NO_LOCKTIME, + ..Default::default() + }, + TxIn { + previous_output: OutPoint { txid: secondary_funding.compute_txid(), vout: 0 }, + sequence: bitcoin::Sequence::ENABLE_RBF_NO_LOCKTIME, + ..Default::default() + }, + ], + output: vec![ + TxOut { value: Amount::from_sat(100_000), script_pubkey: recipient_script() }, + TxOut { value: Amount::from_sat(5_000), script_pubkey: primary_change }, + TxOut { value: Amount::from_sat(30_000), script_pubkey: secondary_change.clone() }, + ], + }; + let mut aggregate = AggregateWallet::new( + primary, + primary_persister, + 0u8, + vec![(1u8, secondary, secondary_persister)], + ); + let original_tx = aggregate.sign_owned_inputs(original_tx).unwrap(); + aggregate.apply_mempool_txs(vec![(original_tx.clone(), 3)], vec![]).unwrap(); + let original_fee = aggregate.calculate_tx_fee(&original_tx).unwrap(); + let minimum_fee_rate = + rbf::minimum_replacement_fee_rate(original_fee, original_tx.weight()).unwrap(); + let too_low_fee_rate = FeeRate::from_sat_per_kwu(minimum_fee_rate.to_sat_per_kwu() - 1); + assert_eq!( + aggregate.build_rbf(original_tx.compute_txid(), too_low_fee_rate).unwrap_err(), + Error::InvalidFeeRate + ); + let (replacement, _) = aggregate + .build_rbf(original_tx.compute_txid(), FeeRate::from_sat_per_kwu(12_500)) + .unwrap(); + + let spare_outpoint = OutPoint { txid: spare_funding.compute_txid(), vout: 0 }; + assert!(replacement.input.iter().any(|input| input.previous_output == spare_outpoint)); + assert!(replacement.output.iter().any(|output| { + output.script_pubkey == secondary_change && output.value == Amount::from_sat(30_000) + })); + let replacement_fee = aggregate.calculate_tx_fee(&replacement).unwrap(); + let minimum_fee_increase = FeeRate::BROADCAST_MIN.fee_wu(replacement.weight()).unwrap(); + assert!(replacement_fee >= original_fee + minimum_fee_increase); + } + + fn cross_wallet_dust_rbf_fixture( + confirm_spare: bool, + ) -> (AggregateWallet, Transaction, OutPoint, ScriptBuf) { + let mut primary_persister = NoopPersister; + let mut primary = + create_empty_wallet_from_xprv(&mut primary_persister, test_xprv_from_byte(0x51)); + let primary_funding = fund_wallet(&mut primary, Amount::from_sat(50_000), 0x52); + let primary_change = + primary.reveal_next_address(KeychainKind::Internal).address.script_pubkey(); + + let mut secondary_persister = NoopPersister; + let mut secondary = + create_empty_wallet_from_xprv(&mut secondary_persister, test_xprv_from_byte(0x53)); + let secondary_funding = fund_wallet(&mut secondary, Amount::from_sat(50_000), 0x54); + let spare_funding = fund_wallet(&mut secondary, Amount::from_sat(5_000), 0x55); + let spare_outpoint = OutPoint { txid: spare_funding.compute_txid(), vout: 0 }; + + let mut confirmed = vec![primary_funding.clone(), secondary_funding.clone()]; + if confirm_spare { + confirmed.push(spare_funding); + } + confirm_transactions(&mut [&mut primary, &mut secondary], &confirmed); + + let original_tx = Transaction { + version: bitcoin::transaction::Version::TWO, + lock_time: bitcoin::absolute::LockTime::ZERO, + input: vec![ + TxIn { + previous_output: OutPoint { txid: primary_funding.compute_txid(), vout: 0 }, + sequence: bitcoin::Sequence::ENABLE_RBF_NO_LOCKTIME, + ..Default::default() + }, + TxIn { + previous_output: OutPoint { txid: secondary_funding.compute_txid(), vout: 0 }, + sequence: bitcoin::Sequence::ENABLE_RBF_NO_LOCKTIME, + ..Default::default() + }, + ], + output: vec![ + TxOut { value: Amount::from_sat(98_500), script_pubkey: recipient_script() }, + TxOut { value: Amount::from_sat(1_000), script_pubkey: primary_change.clone() }, + ], + }; + let mut aggregate = AggregateWallet::new( + primary, + primary_persister, + 0u8, + vec![(1u8, secondary, secondary_persister)], + ); + let original_tx = aggregate.sign_owned_inputs(original_tx).unwrap(); + aggregate.apply_mempool_txs(vec![(original_tx.clone(), 4)], vec![]).unwrap(); + + (aggregate, original_tx, spare_outpoint, primary_change) + } + + #[test] + fn cross_wallet_rbf_selects_enough_for_non_dust_change() { + let (mut aggregate, original_tx, spare_outpoint, primary_change) = + cross_wallet_dust_rbf_fixture(true); + let original_fee = aggregate.calculate_tx_fee(&original_tx).unwrap(); + let requested_fee_rate = FeeRate::from_sat_per_kwu(1_200); + + let (replacement, _) = + aggregate.build_rbf(original_tx.compute_txid(), requested_fee_rate).unwrap(); + + assert!(replacement.input.iter().any(|input| input.previous_output == spare_outpoint)); + let change = replacement + .output + .iter() + .find(|output| output.script_pubkey == primary_change) + .unwrap(); + assert!(change.value.to_sat() >= utxo::DUST_LIMIT_SATS); + + let replacement_fee = aggregate.calculate_tx_fee(&replacement).unwrap(); + let target_fee = requested_fee_rate.fee_wu(replacement.weight()).unwrap(); + let incremental_fee = FeeRate::BROADCAST_MIN.fee_wu(replacement.weight()).unwrap(); + let required_fee = std::cmp::max(target_fee, original_fee + incremental_fee); + let excess_fee = replacement_fee.checked_sub(required_fee).unwrap(); + assert!(excess_fee <= Amount::from_sat(5)); + } + + #[test] + fn cross_wallet_rbf_does_not_add_unconfirmed_inputs() { + let (mut aggregate, original_tx, _, _) = cross_wallet_dust_rbf_fixture(false); + + assert_eq!( + aggregate + .build_rbf(original_tx.compute_txid(), FeeRate::from_sat_per_kwu(1_200)) + .unwrap_err(), + Error::InsufficientFunds + ); + } + + #[test] + fn cross_wallet_rbf_without_change_reports_insufficient_funds() { + let mut primary_persister = NoopPersister; + let mut primary = + create_empty_wallet_from_xprv(&mut primary_persister, test_xprv_from_byte(0x61)); + let primary_funding = fund_wallet(&mut primary, Amount::from_sat(50_000), 0x62); + let mut secondary_persister = NoopPersister; + let mut secondary = + create_empty_wallet_from_xprv(&mut secondary_persister, test_xprv_from_byte(0x63)); + let secondary_funding = fund_wallet(&mut secondary, Amount::from_sat(50_000), 0x64); + confirm_transactions( + &mut [&mut primary, &mut secondary], + &[primary_funding.clone(), secondary_funding.clone()], + ); + + let original_tx = Transaction { + version: bitcoin::transaction::Version::TWO, + lock_time: bitcoin::absolute::LockTime::ZERO, + input: vec![ + TxIn { + previous_output: OutPoint { txid: primary_funding.compute_txid(), vout: 0 }, + sequence: bitcoin::Sequence::ENABLE_RBF_NO_LOCKTIME, + ..Default::default() + }, + TxIn { + previous_output: OutPoint { txid: secondary_funding.compute_txid(), vout: 0 }, + sequence: bitcoin::Sequence::ENABLE_RBF_NO_LOCKTIME, + ..Default::default() + }, + ], + output: vec![TxOut { + value: Amount::from_sat(99_000), + script_pubkey: recipient_script(), + }], + }; + let mut aggregate = AggregateWallet::new( + primary, + primary_persister, + 0u8, + vec![(1u8, secondary, secondary_persister)], + ); + let original_tx = aggregate.sign_owned_inputs(original_tx).unwrap(); + aggregate.apply_mempool_txs(vec![(original_tx.clone(), 5)], vec![]).unwrap(); + + assert_eq!( + aggregate + .build_rbf(original_tx.compute_txid(), FeeRate::from_sat_per_kwu(2_000)) + .unwrap_err(), + Error::InsufficientFunds + ); + } + + #[test] + fn new_address_info_reveals_external_indexes() { + let mut persister = NoopPersister; + let wallet = create_empty_wallet(&mut persister); + let mut agg = AggregateWallet::::new(wallet, persister, 0, vec![]); + + let first = agg.new_address_info_for(&0).unwrap(); + assert_eq!(first.index, 0); + assert_eq!(first.keychain, KeychainKind::External); + + let second = agg.new_address_info().unwrap(); + assert_eq!(second.index, 1); + assert_eq!(second.keychain, KeychainKind::External); + + let third_address = agg.new_address_for(&0).unwrap(); + let third_peek = agg.address_info_for(&0, KeychainKind::External, 2).unwrap(); + assert_eq!(third_peek.index, 2); + assert_eq!(third_peek.address, third_address); + } + + #[test] + fn address_info_for_index_does_not_advance_receive_index() { + let mut persister = NoopPersister; + let wallet = create_empty_wallet(&mut persister); + let mut agg = AggregateWallet::::new(wallet, persister, 0, vec![]); + + let peeked = agg.address_info_for(&0, KeychainKind::External, 7).unwrap(); + assert_eq!(peeked.index, 7); + assert_eq!(peeked.keychain, KeychainKind::External); + + let next = agg.new_address_info_for(&0).unwrap(); + assert_eq!(next.index, 0); + assert_ne!(next.address, peeked.address); + } + + #[test] + fn incremental_lookahead_does_not_advance_receive_index() { + let mut persister = NoopPersister; + let wallet = + create_empty_wallet_from_xprv_with_lookahead(&mut persister, test_xprv(), Some(3)); + let mut aggregate = AggregateWallet::::new(wallet, persister, 0, vec![]); + + let request = aggregate.wallet_incremental_sync_request_with_lookahead(&0).unwrap(); + assert_eq!(request.progress().spks_remaining, 3); + assert_eq!(aggregate.new_address_info_for(&0).unwrap().index, 0); + } + + #[test] + fn incremental_lookahead_rolls_forward_after_activity() { + let mut persister = NoopPersister; + let wallet = + create_empty_wallet_from_xprv_with_lookahead(&mut persister, test_xprv(), Some(3)); + let mut aggregate = AggregateWallet::::new(wallet, persister, 0, vec![]); + let address = aggregate.address_info_for(&0, KeychainKind::External, 2).unwrap().address; + let transaction = Transaction { + version: bitcoin::transaction::Version::TWO, + lock_time: LockTime::ZERO, + input: vec![TxIn { + previous_output: OutPoint { txid: Txid::from_byte_array([0x18; 32]), vout: 0 }, + ..Default::default() + }], + output: vec![TxOut { + value: Amount::from_sat(50_000), + script_pubkey: address.script_pubkey(), + }], + }; + + aggregate.apply_mempool_txs(vec![(transaction, 0)], vec![]).unwrap(); + + let request = aggregate.wallet_incremental_sync_request_with_lookahead(&0).unwrap(); + assert_eq!(request.progress().spks_remaining, 6); + assert_eq!(aggregate.new_address_info_for(&0).unwrap().index, 3); + } + + #[test] + fn incremental_lookahead_activity_persists_the_active_index() { + let mut create_persister = MemoryPersister::default(); + let wallet = create_empty_wallet_from_xprv_with_lookahead( + &mut create_persister, + test_xprv(), + Some(3), + ); + let aggregate_persister = create_persister.clone(); + { + let mut aggregate = + AggregateWallet::::new(wallet, aggregate_persister, 0, vec![]); + let address = + aggregate.address_info_for(&0, KeychainKind::External, 2).unwrap().address; + let transaction = Transaction { + version: bitcoin::transaction::Version::TWO, + lock_time: LockTime::ZERO, + input: vec![TxIn { + previous_output: OutPoint { txid: Txid::from_byte_array([0x19; 32]), vout: 0 }, + ..Default::default() + }], + output: vec![TxOut { + value: Amount::from_sat(50_000), + script_pubkey: address.script_pubkey(), + }], + }; + aggregate.apply_mempool_txs(vec![(transaction, 0)], vec![]).unwrap(); + } + + let mut reload_persister = create_persister.clone(); + let wallet = load_empty_wallet_with_lookahead(&mut reload_persister, Some(3)); + let mut aggregate = AggregateWallet::::new(wallet, reload_persister, 0, vec![]); + assert_eq!(aggregate.new_address_info_for(&0).unwrap().index, 3); + } + + #[test] + fn address_info_for_index_supports_internal_keychain_without_advancing_receive_index() { + let mut persister = NoopPersister; + let wallet = create_empty_wallet(&mut persister); + let mut agg = AggregateWallet::::new(wallet, persister, 0, vec![]); + + let change = agg.address_info_for(&0, KeychainKind::Internal, 3).unwrap(); + assert_eq!(change.index, 3); + assert_eq!(change.keychain, KeychainKind::Internal); + + let next_receive = agg.new_address_info_for(&0).unwrap(); + assert_eq!(next_receive.index, 0); + assert_eq!(next_receive.keychain, KeychainKind::External); + assert_ne!(next_receive.address, change.address); + } + + #[test] + fn address_infos_for_returns_keychain_range_without_advancing() { + let mut persister = NoopPersister; + let wallet = create_empty_wallet(&mut persister); + let mut agg = AggregateWallet::::new(wallet, persister, 0, vec![]); + + let addresses = agg.address_infos_for(&0, KeychainKind::Internal, 2, 3).unwrap(); + let indexes: Vec = addresses.iter().map(|info| info.index).collect(); + assert_eq!(indexes, vec![2, 3, 4]); + assert!(addresses.iter().all(|info| info.keychain == KeychainKind::Internal)); + + let single = agg.address_info_for(&0, KeychainKind::Internal, 3).unwrap(); + assert_eq!(addresses[1], single); + + let next_receive = agg.new_address_info_for(&0).unwrap(); + assert_eq!(next_receive.index, 0); + } + + #[test] + fn address_infos_for_allows_empty_ranges() { + let mut persister = NoopPersister; + let wallet = create_empty_wallet(&mut persister); + let agg = AggregateWallet::::new(wallet, persister, 0, vec![]); + + let addresses = agg.address_infos_for(&0, KeychainKind::External, 0, 0).unwrap(); + assert!(addresses.is_empty()); + } + + #[test] + fn address_info_for_rejects_hardened_index() { + let mut persister = NoopPersister; + let wallet = create_empty_wallet(&mut persister); + let agg = AggregateWallet::::new(wallet, persister, 0, vec![]); + + let result = agg.address_info_for(&0, KeychainKind::External, BIP32_MAX_NORMAL_INDEX + 1); + assert_eq!(result, Err(Error::InvalidQuantity)); + } + + #[test] + fn address_infos_for_rejects_invalid_ranges() { + let mut persister = NoopPersister; + let wallet = create_empty_wallet(&mut persister); + let agg = AggregateWallet::::new(wallet, persister, 0, vec![]); + + let too_many = + agg.address_infos_for(&0, KeychainKind::External, 0, MAX_ADDRESS_INFO_BATCH_COUNT + 1); + assert_eq!(too_many, Err(Error::InvalidQuantity)); + + let hardened_end = + agg.address_infos_for(&0, KeychainKind::External, BIP32_MAX_NORMAL_INDEX - 1, 3); + assert_eq!(hardened_end, Err(Error::InvalidQuantity)); + + let overflow = agg.address_infos_for(&0, KeychainKind::External, u32::MAX, 1); + assert_eq!(overflow, Err(Error::InvalidQuantity)); + } + + #[test] + fn reveal_addresses_to_rejects_hardened_index() { + let mut persister = NoopPersister; + let wallet = create_empty_wallet(&mut persister); + let mut agg = AggregateWallet::::new(wallet, persister, 0, vec![]); + + let result = agg.reveal_addresses_to(&0, BIP32_MAX_NORMAL_INDEX + 1); + assert_eq!(result, Err(Error::InvalidQuantity)); + } + + #[test] + fn reveal_addresses_to_advances_next_receive_index() { + let mut persister = NoopPersister; + let wallet = create_empty_wallet(&mut persister); + let mut agg = AggregateWallet::::new(wallet, persister, 0, vec![]); + + agg.reveal_addresses_to(&0, 4).unwrap(); + agg.reveal_addresses_to(&0, 4).unwrap(); + + let next = agg.new_address_info_for(&0).unwrap(); + assert_eq!(next.index, 5); + assert_eq!(next.keychain, KeychainKind::External); + } + + #[test] + fn revealed_receive_index_persists_across_reload() { + let mut create_persister = MemoryPersister::default(); + let wallet = create_empty_wallet(&mut create_persister); + let aggregate_persister = create_persister.clone(); + + { + let mut agg = AggregateWallet::::new(wallet, aggregate_persister, 0, vec![]); + agg.reveal_addresses_to(&0, 3).unwrap(); + } + + let mut reload_persister = create_persister.clone(); + let reloaded_wallet = load_empty_wallet(&mut reload_persister); + let mut reloaded = + AggregateWallet::::new(reloaded_wallet, reload_persister, 0, vec![]); + + let next = reloaded.new_address_info_for(&0).unwrap(); + assert_eq!(next.index, 4); + } + + /// Demonstrates the bug: without cancel_tx, each finish() call + /// cumulatively advances the internal (change) derivation index. + #[test] + fn test_finish_without_cancel_leaks_change_index() { + let mut persister = NoopPersister; + let mut wallet = create_funded_wallet(&mut persister, Amount::from_sat(100_000)); + + let recipient = recipient_script(); + let fee_rate = FeeRate::from_sat_per_vb(2).unwrap(); + + let initial_idx = wallet.derivation_index(KeychainKind::Internal); + + // First dry-run finish(), no cancel + let mut b1 = wallet.build_tx(); + b1.add_recipient(recipient.clone(), Amount::from_sat(30_000)).fee_rate(fee_rate); + let _psbt1 = b1.finish().unwrap(); + let after_first = wallet.derivation_index(KeychainKind::Internal); + + // Second dry-run finish(), no cancel + let mut b2 = wallet.build_tx(); + b2.add_recipient(recipient.clone(), Amount::from_sat(30_000)).fee_rate(fee_rate); + let _psbt2 = b2.finish().unwrap(); + let after_second = wallet.derivation_index(KeychainKind::Internal); + + // Third dry-run finish(), no cancel + let mut b3 = wallet.build_tx(); + b3.add_recipient(recipient.clone(), Amount::from_sat(30_000)).fee_rate(fee_rate); + let _psbt3 = b3.finish().unwrap(); + let after_third = wallet.derivation_index(KeychainKind::Internal); + + assert!( + after_first > initial_idx || (initial_idx.is_none() && after_first.is_some()), + "First finish() should advance the internal index" + ); + assert!( + after_second > after_first, + "Second finish() without cancel should advance further: {:?} > {:?}", + after_second, + after_first, + ); + assert!( + after_third > after_second, + "Third finish() without cancel should advance further: {:?} > {:?}", + after_third, + after_second, + ); + } + + /// Cancelling repeated dry runs keeps the internal derivation index stable. + #[test] + fn test_cancel_dry_run_prevents_cumulative_index_leak() { + let mut persister = NoopPersister; + let wallet = create_funded_wallet(&mut persister, Amount::from_sat(100_000)); + let mut agg = AggregateWallet::::new(wallet, persister, 0, vec![]); + + let recipient = recipient_script(); + let fee_rate = FeeRate::from_sat_per_vb(2).unwrap(); + + let initial_idx = agg.derivation_index(KeychainKind::Internal); + + // Dry-run 1: finish + cancel + let psbt1 = { + let w = agg.primary_wallet_mut(); + let mut b = w.build_tx(); + b.add_recipient(recipient.clone(), Amount::from_sat(30_000)).fee_rate(fee_rate); + b.finish().unwrap() + }; + agg.cancel_dry_run_tx(&psbt1.unsigned_tx); + let after_first = agg.derivation_index(KeychainKind::Internal); + + assert!( + after_first > initial_idx || (initial_idx.is_none() && after_first.is_some()), + "First finish() should reveal an internal address" + ); + + // Dry-run 2: finish + cancel + let psbt2 = { + let w = agg.primary_wallet_mut(); + let mut b = w.build_tx(); + b.add_recipient(recipient.clone(), Amount::from_sat(30_000)).fee_rate(fee_rate); + b.finish().unwrap() + }; + agg.cancel_dry_run_tx(&psbt2.unsigned_tx); + let after_second = agg.derivation_index(KeychainKind::Internal); + + assert_eq!( + after_first, after_second, + "cancel_dry_run_tx should prevent cumulative index advance" + ); + + // Dry-runs 3-5: confirm stability + for i in 3..=5 { + let psbt = { + let w = agg.primary_wallet_mut(); + let mut b = w.build_tx(); + b.add_recipient(recipient.clone(), Amount::from_sat(30_000)).fee_rate(fee_rate); + b.finish().unwrap() + }; + agg.cancel_dry_run_tx(&psbt.unsigned_tx); + let idx = agg.derivation_index(KeychainKind::Internal); + assert_eq!(after_first, idx, "Dry-run {} should still reuse the same index", i); + } + } + + /// Cancelling after an intermediate failure keeps the internal derivation index stable. + #[test] + fn test_cancel_after_failed_intermediate_prevents_leak() { + let mut persister = NoopPersister; + let wallet = create_funded_wallet(&mut persister, Amount::from_sat(100_000)); + let mut agg = AggregateWallet::::new(wallet, persister, 0, vec![]); + + let recipient = recipient_script(); + let fee_rate = FeeRate::from_sat_per_vb(2).unwrap(); + + // Baseline + let initial_idx = agg.derivation_index(KeychainKind::Internal); + + // Simulate finish() + failed intermediate + unconditional cancel. + for _ in 0..5 { + let psbt = { + let w = agg.primary_wallet_mut(); + let mut b = w.build_tx(); + b.add_recipient(recipient.clone(), Amount::from_sat(30_000)).fee_rate(fee_rate); + b.finish().unwrap() + }; + + // Simulate an intermediate operation that fails. + let _simulated_failure: Result = Err("simulated fee calculation failure"); + + // Cancel regardless of failure. + agg.cancel_dry_run_tx(&psbt.unsigned_tx); + } + + let final_idx = agg.derivation_index(KeychainKind::Internal); + + assert!( + final_idx > initial_idx || (initial_idx.is_none() && final_idx.is_some()), + "Index should be revealed at least once" + ); + + // One more dry-run + cancel should not change it. + let psbt = { + let w = agg.primary_wallet_mut(); + let mut b = w.build_tx(); + b.add_recipient(recipient.clone(), Amount::from_sat(30_000)).fee_rate(fee_rate); + b.finish().unwrap() + }; + agg.cancel_dry_run_tx(&psbt.unsigned_tx); + assert_eq!( + final_idx, + agg.derivation_index(KeychainKind::Internal), + "Sixth dry-run should still reuse the same index" + ); + } + + /// A real transaction reuses the change address from a cancelled dry run. + #[test] + fn test_dry_run_cancel_then_real_tx_reuses_change_address() { + let mut persister = NoopPersister; + let wallet = create_funded_wallet(&mut persister, Amount::from_sat(200_000)); + let mut agg = AggregateWallet::::new(wallet, persister, 0, vec![]); + + let recipient = recipient_script(); + let fee_rate = FeeRate::from_sat_per_vb(2).unwrap(); + + // Dry-run + cancel + let dry_psbt = { + let w = agg.primary_wallet_mut(); + let mut b = w.build_tx(); + b.add_recipient(recipient.clone(), Amount::from_sat(50_000)).fee_rate(fee_rate); + b.finish().unwrap() + }; + let dry_run_change_script: Option = dry_psbt + .unsigned_tx + .output + .iter() + .find(|o| agg.is_mine(o.script_pubkey.clone())) + .map(|o| o.script_pubkey.clone()); + agg.cancel_dry_run_tx(&dry_psbt.unsigned_tx); + + let idx_after_dry = agg.derivation_index(KeychainKind::Internal); + + // Real tx (no cancel — this would be signed and broadcast) + let real_psbt = { + let w = agg.primary_wallet_mut(); + let mut b = w.build_tx(); + b.add_recipient(recipient.clone(), Amount::from_sat(50_000)).fee_rate(fee_rate); + b.finish().unwrap() + }; + let real_change_script: Option = real_psbt + .unsigned_tx + .output + .iter() + .find(|o| agg.is_mine(o.script_pubkey.clone())) + .map(|o| o.script_pubkey.clone()); + + let idx_after_real = agg.derivation_index(KeychainKind::Internal); + + assert_eq!( + idx_after_dry, idx_after_real, + "Real tx should not advance index beyond what dry-run already revealed" + ); + if let (Some(dry_change), Some(real_change)) = (&dry_run_change_script, &real_change_script) + { + assert_eq!( + dry_change, real_change, + "Real tx should reuse the same change address as the cancelled dry-run" + ); + } + } + + fn regtest_child_block(prev: &Block, distinct: u8) -> Block { + use bitcoin::block::Header; + use bitcoin::blockdata::locktime::absolute::LockTime; + use bitcoin::hashes::Hash as _; + use bitcoin::{Sequence, TxMerkleNode, Witness}; + + let coinbase = Transaction { + version: bitcoin::transaction::Version::ONE, + lock_time: LockTime::ZERO, + input: vec![TxIn { + previous_output: OutPoint::null(), + script_sig: ScriptBuf::builder().push_int(distinct as i64).into_script(), + sequence: Sequence::MAX, + witness: Witness::new(), + }], + output: vec![TxOut { + value: Amount::from_sat(50_0000_0000), + script_pubkey: ScriptBuf::new_op_return([distinct]), + }], + }; + let merkle_root = TxMerkleNode::from_byte_array(coinbase.compute_txid().to_byte_array()); + Block { + header: Header { + version: bitcoin::block::Version::ONE, + prev_blockhash: prev.block_hash(), + merkle_root, + time: prev.header.time.saturating_add(1), + bits: prev.header.bits, + nonce: distinct as u32, + }, + txdata: vec![coinbase], + } + } + + fn regtest_child_block_with_transaction( + prev: &Block, distinct: u8, transaction: Transaction, + ) -> Block { + let mut block = regtest_child_block(prev, distinct); + block.txdata.push(transaction); + block.header.merkle_root = block.compute_merkle_root().unwrap(); + block + } + + fn confirm_transactions( + wallets: &mut [&mut PersistedWallet], transactions: &[Transaction], + ) { + use bitcoin::blockdata::constants::genesis_block; + + let mut tip = genesis_block(Network::Regtest); + for wallet in wallets.iter_mut() { + wallet.apply_block(&tip, 0).unwrap(); + } + for (index, transaction) in transactions.iter().enumerate() { + let block = + regtest_child_block_with_transaction(&tip, index as u8 + 1, transaction.clone()); + for wallet in wallets.iter_mut() { + wallet.apply_block(&block, index as u32 + 1).unwrap(); + } + tip = block; + } + } + #[test] + fn apply_block_skips_wallets_already_ahead_during_catch_up() { + use bitcoin::blockdata::constants::genesis_block; + + let mut primary_persister = NoopPersister; + let mut primary = create_empty_wallet(&mut primary_persister); + let genesis = genesis_block(Network::Regtest); + primary.apply_block(&genesis, 0).unwrap(); + let block1 = regtest_child_block(&genesis, 1); + primary.apply_block(&block1, 1).unwrap(); + let block2 = regtest_child_block(&block1, 1); + primary.apply_block(&block2, 2).unwrap(); + assert_eq!(primary.latest_checkpoint().height(), 2); + + let mut secondary_persister = NoopPersister; + let mut secondary = create_empty_wallet(&mut secondary_persister); + secondary.apply_block(&genesis, 0).unwrap(); + assert_eq!(secondary.latest_checkpoint().height(), 0); + + let mut agg = AggregateWallet::new( + primary, + primary_persister, + 0u8, + vec![(1u8, secondary, secondary_persister)], + ); + assert_eq!(agg.current_best_block().1, 0); + + // Replaying the gap must not fail on the primary wallet that is already at height 2. + agg.apply_block(&block1, 1).expect("catch-up must skip wallets already ahead"); + assert_eq!(agg.current_best_block().1, 1); + agg.apply_block(&block2, 2).expect("catch-up must bring the lagging wallet to tip"); + assert_eq!(agg.current_best_block().1, 2); + } + + #[test] + fn apply_block_applies_same_height_reorg_replacement_when_tip_ahead() { + use bitcoin::blockdata::constants::genesis_block; + + let mut primary_persister = NoopPersister; + let mut primary = create_empty_wallet(&mut primary_persister); + let mut secondary_persister = NoopPersister; + let mut secondary = create_empty_wallet(&mut secondary_persister); + let genesis = genesis_block(Network::Regtest); + primary.apply_block(&genesis, 0).unwrap(); + secondary.apply_block(&genesis, 0).unwrap(); + + let block1_a = regtest_child_block(&genesis, 1); + let block2_a = regtest_child_block(&block1_a, 1); + primary.apply_block(&block1_a, 1).unwrap(); + primary.apply_block(&block2_a, 2).unwrap(); + secondary.apply_block(&block1_a, 1).unwrap(); + secondary.apply_block(&block2_a, 2).unwrap(); + + let mut agg = AggregateWallet::new( + primary, + primary_persister, + 0u8, + vec![(1u8, secondary, secondary_persister)], + ); + assert_eq!(agg.current_best_block().1, 2); + + // Height-only skipping would ignore this replacement because tip_height (2) >= 1. + let block1_b = regtest_child_block(&genesis, 2); + assert_ne!(block1_a.block_hash(), block1_b.block_hash()); + agg.apply_block(&block1_b, 1).expect("reorg replacement must be applied"); + + for key in [0u8, 1u8] { + let tip = agg.wallet(&key).unwrap().latest_checkpoint(); + assert_eq!(tip.height(), 1, "wallet {:?} must reorg to replacement height", key); + assert_eq!( + tip.hash(), + block1_b.block_hash(), + "wallet {:?} must adopt replacement hash", + key + ); + } + } + + #[test] + fn apply_block_skips_sparse_ahead_wallet_during_catch_up() { + use bdk_chain::BlockId; + use bdk_wallet::Update; + use bitcoin::blockdata::constants::genesis_block; + + let mut primary_persister = NoopPersister; + let mut primary = create_empty_wallet(&mut primary_persister); + let genesis = genesis_block(Network::Regtest); + primary.apply_block(&genesis, 0).unwrap(); + let block1 = regtest_child_block(&genesis, 1); + let block2 = regtest_child_block(&block1, 1); + // Brand-new wallets insert only `{genesis, tip}` — intermediate heights are absent. + let sparse_tip = BlockId { height: 2, hash: block2.block_hash() }; + let checkpoint = primary.latest_checkpoint().insert(sparse_tip); + primary.apply_update(Update { chain: Some(checkpoint), ..Default::default() }).unwrap(); + assert_eq!(primary.latest_checkpoint().height(), 2); + assert!(primary.latest_checkpoint().get(1).is_none()); + + let mut secondary_persister = NoopPersister; + let mut secondary = create_empty_wallet(&mut secondary_persister); + secondary.apply_block(&genesis, 0).unwrap(); + + let mut agg = AggregateWallet::new( + primary, + primary_persister, + 0u8, + vec![(1u8, secondary, secondary_persister)], + ); + assert!(agg.wallet(&0u8).unwrap().latest_checkpoint().get(1).is_none()); + agg.apply_block(&block1, 1) + .expect("sparse ahead wallet must skip unknown intermediate heights"); + assert_eq!(agg.wallet(&0u8).unwrap().latest_checkpoint().height(), 2); + assert_eq!(agg.wallet(&1u8).unwrap().latest_checkpoint().height(), 1); + agg.apply_block(&block2, 2).expect("lagging wallet catches up to sparse tip"); + assert_eq!(agg.current_best_block().1, 2); + } + + #[test] + fn apply_block_to_updates_only_the_targeted_wallet() { + use bitcoin::blockdata::constants::genesis_block; + + let mut primary_persister = NoopPersister; + let mut primary = create_empty_wallet(&mut primary_persister); + let mut secondary_persister = NoopPersister; + let mut secondary = create_empty_wallet(&mut secondary_persister); + let genesis = genesis_block(Network::Regtest); + primary.apply_block(&genesis, 0).unwrap(); + secondary.apply_block(&genesis, 0).unwrap(); + + let block1 = regtest_child_block(&genesis, 1); + let mut agg = AggregateWallet::new( + primary, + primary_persister, + 0u8, + vec![(1u8, secondary, secondary_persister)], + ); + agg.apply_block_to(&1u8, &block1, 1).expect("targeted apply"); + assert_eq!(agg.wallet(&0u8).unwrap().latest_checkpoint().height(), 0); + assert_eq!(agg.wallet(&1u8).unwrap().latest_checkpoint().height(), 1); + } + + #[test] + fn apply_block_retries_persist_when_block_is_already_known() { + use bitcoin::blockdata::constants::genesis_block; + + let failures = Arc::new(AtomicUsize::new(0)); + let mut primary_persister = FailOncePersister { + failures: Arc::clone(&failures), + inner: MemoryPersister::default(), + }; + let mut primary = create_empty_wallet(&mut primary_persister); + let genesis = genesis_block(Network::Regtest); + primary.apply_block(&genesis, 0).unwrap(); + let block1 = regtest_child_block(&genesis, 1); + + let mut agg = AggregateWallet::new(primary, primary_persister, 0u8, vec![]); + failures.store(1, Ordering::SeqCst); + let first = agg.apply_block(&block1, 1); + assert!(first.is_err(), "first persist must fail"); + assert_eq!(agg.primary_wallet().latest_checkpoint().hash(), block1.block_hash()); + + agg.apply_block(&block1, 1).expect("known block must retry stranded persist"); + assert_eq!(failures.load(Ordering::SeqCst), 0); + } + + #[test] + fn current_best_block_uses_lexicographic_hash_on_equal_height_fork() { + use bitcoin::blockdata::constants::genesis_block; + + let mut primary_persister = NoopPersister; + let mut primary = create_empty_wallet(&mut primary_persister); + let mut secondary_persister = NoopPersister; + let mut secondary = create_empty_wallet(&mut secondary_persister); + let genesis = genesis_block(Network::Regtest); + primary.apply_block(&genesis, 0).unwrap(); + secondary.apply_block(&genesis, 0).unwrap(); + + let block1_a = regtest_child_block(&genesis, 1); + let block1_b = regtest_child_block(&genesis, 2); + assert_ne!(block1_a.block_hash(), block1_b.block_hash()); + primary.apply_block(&block1_a, 1).unwrap(); + secondary.apply_block(&block1_b, 1).unwrap(); + + let agg = AggregateWallet::new( + primary, + primary_persister, + 0u8, + vec![(1u8, secondary, secondary_persister)], + ); + let (hash, height) = agg.current_best_block(); + assert_eq!(height, 1); + // Must not hide a secondary tip behind primary preference: pick lex-smallest hash so + // Bitcoind catch-up can start from a divergent equal-height checkpoint. + let expected = + if block1_a.block_hash().to_byte_array() <= block1_b.block_hash().to_byte_array() { + block1_a.block_hash() + } else { + block1_b.block_hash() + }; + assert_eq!(hash, expected); + let tips = agg.chain_tips(); + assert_eq!(tips.len(), 2); + assert!(tips.contains(&(block1_a.block_hash(), 1))); + assert!(tips.contains(&(block1_b.block_hash(), 1))); + } +} diff --git a/crates/bdk-wallet-aggregate/src/rbf.rs b/crates/bdk-wallet-aggregate/src/rbf.rs new file mode 100644 index 0000000000..634a6dd5e7 --- /dev/null +++ b/crates/bdk-wallet-aggregate/src/rbf.rs @@ -0,0 +1,296 @@ +// This file is Copyright its original authors, visible in version control history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license , at your option. You may not use this file except in +// accordance with one or both of these licenses. + +//! Cross-wallet RBF (Replace-By-Fee) transaction construction. + +use std::collections::HashMap; +use std::fmt::Debug; +use std::hash::Hash; + +use bdk_wallet::{KeychainKind, PersistedWallet, WalletPersister}; +use bitcoin::{Amount, FeeRate, OutPoint, ScriptBuf, Transaction, TxIn, TxOut, Weight}; + +use crate::signing; +use crate::types::{Error, UtxoPsbtInfo}; +use crate::utxo::DUST_LIMIT_SATS; + +struct ReplacementRequirements { + change_idx: Option, + recipient_value: u64, + required_fee: u64, +} + +/// Return the minimum fee rate accepted for a replacement transaction. +/// +/// This mirrors BDK's fee-bump policy by requiring at least a 1 sat/vB increase. +pub(crate) fn minimum_replacement_fee_rate( + original_fee: Amount, original_weight: Weight, +) -> Result { + let original_fee_rate = original_fee / original_weight; + let minimum_sat_per_kwu = original_fee_rate + .to_sat_per_kwu() + .checked_add(FeeRate::BROADCAST_MIN.to_sat_per_kwu()) + .ok_or(Error::InvalidFeeRate)?; + Ok(FeeRate::from_sat_per_kwu(minimum_sat_per_kwu)) +} + +fn original_input_value( + original_tx: &Transaction, wallets: &HashMap>, +) -> Result +where + K: Eq + Hash + Copy + Debug, + P: WalletPersister, +{ + original_tx.input.iter().try_fold(0u64, |total, input| { + total + .checked_add(get_input_value(&input.previous_output, wallets)?) + .ok_or(Error::OnchainTxCreationFailed) + }) +} + +fn replacement_inputs(original_tx: &Transaction, extra_utxos: &[UtxoPsbtInfo]) -> Vec { + let mut inputs: Vec = original_tx + .input + .iter() + .map(|txin| TxIn { + previous_output: txin.previous_output, + script_sig: ScriptBuf::new(), + sequence: bitcoin::Sequence::ENABLE_RBF_NO_LOCKTIME, + witness: bitcoin::Witness::default(), + }) + .collect(); + inputs.extend(extra_utxos.iter().map(|info| TxIn { + previous_output: info.outpoint, + script_sig: ScriptBuf::new(), + sequence: bitcoin::Sequence::ENABLE_RBF_NO_LOCKTIME, + witness: bitcoin::Witness::default(), + })); + inputs +} + +fn replacement_requirements( + wallets: &HashMap>, primary_key: &K, original_tx: &Transaction, + original_input_value: u64, replacement_inputs: &[TxIn], new_fee_rate: FeeRate, +) -> Result +where + K: Eq + Hash + Copy + Debug, + P: WalletPersister, +{ + let original_output_value = original_tx.output.iter().try_fold(0u64, |total, output| { + total.checked_add(output.value.to_sat()).ok_or(Error::OnchainTxCreationFailed) + })?; + let original_fee = original_input_value + .checked_sub(original_output_value) + .ok_or(Error::OnchainTxCreationFailed)?; + let minimum_fee_rate = + minimum_replacement_fee_rate(Amount::from_sat(original_fee), original_tx.weight())?; + if new_fee_rate < minimum_fee_rate { + return Err(Error::InvalidFeeRate); + } + + let estimated_weight = estimate_tx_weight(wallets, replacement_inputs, &original_tx.output); + let target_fee = new_fee_rate.fee_wu(estimated_weight).ok_or(Error::InvalidFeeRate)?.to_sat(); + let incremental_fee = + FeeRate::BROADCAST_MIN.fee_wu(estimated_weight).ok_or(Error::InvalidFeeRate)?.to_sat(); + let minimum_replacement_fee = + original_fee.checked_add(incremental_fee).ok_or(Error::OnchainTxCreationFailed)?; + let required_fee = std::cmp::max(target_fee, minimum_replacement_fee); + + let change_idx = + find_internal_change_output(wallets, primary_key, original_tx).map(|(index, _)| index); + let recipient_value = original_tx + .output + .iter() + .enumerate() + .filter(|(index, _)| Some(*index) != change_idx) + .try_fold(0u64, |total, (_, output)| { + total.checked_add(output.value.to_sat()).ok_or(Error::OnchainTxCreationFailed) + })?; + + Ok(ReplacementRequirements { change_idx, recipient_value, required_fee }) +} + +/// Return the effective value that additional inputs must contribute. +pub(crate) fn additional_input_value_needed( + wallets: &HashMap>, primary_key: &K, original_tx: &Transaction, + new_fee_rate: FeeRate, +) -> Result +where + K: Eq + Hash + Copy + Debug, + P: WalletPersister, +{ + let original_input_value = original_input_value(original_tx, wallets)?; + let replacement_inputs = replacement_inputs(original_tx, &[]); + let requirements = replacement_requirements( + wallets, + primary_key, + original_tx, + original_input_value, + &replacement_inputs, + new_fee_rate, + )?; + if requirements.change_idx.is_none() { + return Err(Error::InsufficientFunds); + } + let required_value = requirements + .required_fee + .checked_add(requirements.recipient_value) + .and_then(|value| value.checked_add(DUST_LIMIT_SATS)) + .ok_or(Error::OnchainTxCreationFailed)?; + + Ok(Amount::from_sat(required_value.saturating_sub(original_input_value))) +} + +/// Get the value of an input by looking up the referenced UTXO across all +/// wallets. +pub fn get_input_value( + outpoint: &OutPoint, wallets: &HashMap>, +) -> Result +where + K: Eq + Hash + Copy + Debug, + P: WalletPersister, +{ + for wallet in wallets.values() { + if let Some(utxo) = wallet.get_utxo(*outpoint) { + return Ok(utxo.txout.value.to_sat()); + } + + if let Some(tx_node) = wallet.get_tx(outpoint.txid) { + if let Some(txout) = tx_node.tx_node.tx.output.get(outpoint.vout as usize) { + return Ok(txout.value.to_sat()); + } + } + } + + Err(Error::UtxoNotFoundLocally(*outpoint)) +} + +/// Build a cross-wallet RBF replacement transaction. +/// +/// Re-uses the original transaction's inputs, optionally adds `extra_utxos` +/// as new inputs, recalculates the fee at `new_fee_rate`, and adjusts the +/// change output accordingly. Signs with all wallets. +/// +/// Pass an empty slice for `extra_utxos` to attempt a change-only bump. +/// If that is insufficient the caller can select additional UTXOs and retry. +pub fn build_cross_wallet_rbf( + wallets: &mut HashMap>, primary_key: &K, original_tx: &Transaction, + new_fee_rate: FeeRate, extra_utxos: &[UtxoPsbtInfo], +) -> Result +where + K: Eq + Hash + Copy + Debug, + P: WalletPersister, +{ + let original_input_value = original_input_value(original_tx, wallets)?; + + let mut total_input_value = original_input_value; + for info in extra_utxos { + let value = info + .psbt_input + .witness_utxo + .as_ref() + .map(|utxo| utxo.value.to_sat()) + .ok_or(Error::OnchainTxCreationFailed)?; + total_input_value = + total_input_value.checked_add(value).ok_or(Error::OnchainTxCreationFailed)?; + } + + let new_inputs = replacement_inputs(original_tx, extra_utxos); + let requirements = replacement_requirements( + wallets, + primary_key, + original_tx, + original_input_value, + &new_inputs, + new_fee_rate, + )?; + + let mut new_outputs = original_tx.output.clone(); + let required_value = requirements + .required_fee + .checked_add(requirements.recipient_value) + .ok_or(Error::OnchainTxCreationFailed)?; + let available_for_change = + total_input_value.checked_sub(required_value).ok_or(Error::InsufficientFunds)?; + + match requirements.change_idx { + Some(idx) => { + if available_for_change < DUST_LIMIT_SATS { + log::error!( + "Insufficient funds for cross-wallet RBF: available_for_change={}, required_fee={}, total_input={}", + available_for_change, + requirements.required_fee, + total_input_value + ); + return Err(Error::InsufficientFunds); + } + new_outputs[idx].value = Amount::from_sat(available_for_change); + }, + None => { + // A replacement cannot increase its fee without reducing a recipient output. + return Err(Error::InsufficientFunds); + }, + } + + let unsigned_tx = Transaction { + version: original_tx.version, + lock_time: original_tx.lock_time, + input: new_inputs, + output: new_outputs, + }; + + signing::sign_owned_inputs(unsigned_tx, wallets) +} + +/// Find the primary wallet's internal output that the manual RBF builder will reduce. +pub(crate) fn find_internal_change_output<'a, K, P>( + wallets: &HashMap>, primary_key: &K, transaction: &'a Transaction, +) -> Option<(usize, &'a TxOut)> +where + K: Eq + Hash + Copy + Debug, + P: WalletPersister, +{ + if transaction.output.len() <= 1 { + return None; + } + + let primary_wallet = wallets.get(primary_key)?; + transaction + .output + .iter() + .enumerate() + .filter(|(_, output)| { + primary_wallet + .derivation_of_spk(output.script_pubkey.clone()) + .is_some_and(|(keychain, _)| keychain == KeychainKind::Internal) + }) + .last() +} + +/// Estimate the weight of a transaction for fee calculation purposes. +fn estimate_tx_weight( + wallets: &HashMap>, inputs: &[TxIn], outputs: &[TxOut], +) -> bitcoin::Weight +where + K: Eq + Hash + Copy + Debug, + P: WalletPersister, +{ + let unsigned_tx = Transaction { + version: bitcoin::transaction::Version::TWO, + lock_time: bitcoin::absolute::LockTime::ZERO, + input: inputs.to_vec(), + output: outputs.to_vec(), + }; + let witness_overhead = Weight::from_wu(2 + inputs.len() as u64); + let satisfaction_weight = inputs.iter().fold(Weight::ZERO, |weight, input| { + weight + + crate::utxo::satisfaction_weight_for_outpoint(input.previous_output, wallets) + .unwrap_or_else(|| Weight::from_wu(428)) + }); + + unsigned_tx.weight() + witness_overhead + satisfaction_weight +} diff --git a/crates/bdk-wallet-aggregate/src/signing.rs b/crates/bdk-wallet-aggregate/src/signing.rs new file mode 100644 index 0000000000..4c192d3289 --- /dev/null +++ b/crates/bdk-wallet-aggregate/src/signing.rs @@ -0,0 +1,192 @@ +// This file is Copyright its original authors, visible in version control history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license , at your option. You may not use this file except in +// accordance with one or both of these licenses. + +//! Multi-wallet PSBT signing logic. + +use std::collections::HashMap; +use std::fmt::Debug; +use std::hash::Hash; + +#[allow(deprecated)] +use bdk_wallet::{PersistedWallet, SignOptions, WalletPersister}; +use bitcoin::psbt::{self, Psbt}; +use bitcoin::Transaction; + +use crate::types::Error; + +/// Sign an unsigned transaction using every wallet that owns one of its +/// inputs. This works by creating a PSBT with the transaction's inputs +/// and outputs and then having each wallet sign its owned inputs. +pub fn sign_owned_inputs( + unsigned_tx: Transaction, wallets: &mut HashMap>, +) -> Result +where + K: Eq + Hash + Copy + Debug, + P: WalletPersister, +{ + let psbt = Psbt::from_unsigned_tx(unsigned_tx).map_err(|e| { + log::error!("Failed to create PSBT from unsigned tx: {}", e); + Error::OnchainTxSigningFailed + })?; + + sign_psbt_all_wallets(psbt, wallets) +} + +/// Sign a PSBT using every wallet that owns at least one of its inputs. +pub fn sign_psbt_all_wallets( + mut psbt: Psbt, wallets: &mut HashMap>, +) -> Result +where + K: Eq + Hash + Copy + Debug, + P: WalletPersister, +{ + populate_psbt_inputs_from_wallets(&mut psbt, wallets); + + #[allow(deprecated)] + let sign_options = SignOptions { trust_witness_utxo: true, ..Default::default() }; + + for (key, wallet) in wallets.iter_mut() { + match wallet.sign(&mut psbt, sign_options.clone()) { + Ok(_) => log::trace!("Wallet {:?} processed PSBT inputs", key), + Err(e) => { + log::trace!( + "Wallet {:?} could not sign PSBT: {} (expected for foreign inputs)", + key, + e + ); + }, + } + } + + if psbt.inputs.iter().any(|input| !is_finalized(input)) { + log::error!("At least one PSBT input remains unsigned"); + return Err(Error::OnchainTxSigningFailed); + } + + match psbt.extract_tx() { + Ok(tx) => Ok(tx), + Err(psbt::ExtractTxError::MissingInputValue { tx }) => { + log::warn!( + "extract_tx could not verify fee (MissingInputValue) for txid {}", + tx.compute_txid() + ); + Ok(tx) + }, + Err(e) => { + log::error!("Failed to extract signed transaction: {}", e); + Err(Error::OnchainTxSigningFailed) + }, + } +} + +fn is_finalized(input: &psbt::Input) -> bool { + matches!(input.final_script_sig.as_ref(), Some(script) if !script.is_empty()) + || matches!(input.final_script_witness.as_ref(), Some(witness) if !witness.is_empty()) +} + +/// Populate PSBT inputs with UTXO data from all wallets. +/// +/// Handles both unspent and already-spent UTXOs (important for RBF where +/// the original transaction already consumed the inputs). +fn populate_psbt_inputs_from_wallets( + psbt: &mut Psbt, wallets: &HashMap>, +) where + K: Eq + Hash + Copy + Debug, + P: WalletPersister, +{ + for (i, txin) in psbt.unsigned_tx.input.iter().enumerate() { + if i >= psbt.inputs.len() { + psbt.inputs.push(bitcoin::psbt::Input::default()); + } + + let psbt_input = &psbt.inputs[i]; + // Only skip if BOTH witness_utxo and non_witness_utxo are already populated. + if psbt_input.witness_utxo.is_some() && psbt_input.non_witness_utxo.is_some() { + continue; + } + + let mut found = false; + for wallet in wallets.values() { + // Try get_utxo first (works for unspent outputs). + if let Some(utxo) = wallet.get_utxo(txin.previous_output) { + if psbt.inputs[i].witness_utxo.is_none() { + psbt.inputs[i].witness_utxo = Some(utxo.txout.clone()); + } + + // Always populate non_witness_utxo to guard against SegWit fee + // vulnerability and ensure BDK can verify input values. + if psbt.inputs[i].non_witness_utxo.is_none() { + if let Some(tx_node) = wallet.get_tx(txin.previous_output.txid) { + psbt.inputs[i].non_witness_utxo = Some(tx_node.tx_node.tx.as_ref().clone()); + } + } + found = true; + break; + } + + // Fallback: look up via the transaction that created this output. + // This handles the RBF case where the UTXO has already been spent + // by the transaction we are replacing. + if let Some(tx_node) = wallet.get_tx(txin.previous_output.txid) { + if let Some(txout) = + tx_node.tx_node.tx.output.get(txin.previous_output.vout as usize) + { + if psbt.inputs[i].witness_utxo.is_none() { + psbt.inputs[i].witness_utxo = Some(txout.clone()); + } + if psbt.inputs[i].non_witness_utxo.is_none() { + psbt.inputs[i].non_witness_utxo = Some(tx_node.tx_node.tx.as_ref().clone()); + } + found = true; + break; + } + } + } + + if !found { + log::debug!( + "Could not find UTXO data for input {:?} in any wallet", + txin.previous_output + ); + } + } +} + +#[cfg(test)] +mod tests { + use bitcoin::{ScriptBuf, Witness}; + + use super::is_finalized; + + #[test] + fn rejects_empty_final_scripts() { + assert!(!is_finalized(&bitcoin::psbt::Input::default())); + let script_input = + bitcoin::psbt::Input { final_script_sig: Some(ScriptBuf::new()), ..Default::default() }; + assert!(!is_finalized(&script_input)); + let witness_input = bitcoin::psbt::Input { + final_script_witness: Some(Witness::new()), + ..Default::default() + }; + assert!(!is_finalized(&witness_input)); + } + + #[test] + fn accepts_finalized_script_or_witness() { + let script_input = bitcoin::psbt::Input { + final_script_sig: Some(ScriptBuf::from_bytes(vec![1])), + ..Default::default() + }; + assert!(is_finalized(&script_input)); + + let mut witness = Witness::new(); + witness.push([1]); + let witness_input = + bitcoin::psbt::Input { final_script_witness: Some(witness), ..Default::default() }; + assert!(is_finalized(&witness_input)); + } +} diff --git a/crates/bdk-wallet-aggregate/src/types.rs b/crates/bdk-wallet-aggregate/src/types.rs new file mode 100644 index 0000000000..5c37236ce6 --- /dev/null +++ b/crates/bdk-wallet-aggregate/src/types.rs @@ -0,0 +1,104 @@ +// This file is Copyright its original authors, visible in version control history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license , at your option. You may not use this file except in +// accordance with one or both of these licenses. + +//! Core types for the aggregate wallet library. + +use std::fmt; + +use bitcoin::{psbt, OutPoint, Weight}; + +/// Errors returned by the aggregate wallet library. +#[derive(Debug, Clone, PartialEq)] +pub enum Error { + /// A wallet for the requested key was not found. + WalletNotFound, + /// A persister for the requested key was not found. + PersisterNotFound, + /// Failed to persist wallet state. + PersistenceFailed, + /// On-chain transaction creation failed. + OnchainTxCreationFailed, + /// On-chain transaction signing failed. + OnchainTxSigningFailed, + /// Insufficient funds for the requested operation. + InsufficientFunds, + /// The requested fee rate is invalid. + InvalidFeeRate, + /// The requested quantity is invalid. + InvalidQuantity, + /// No spendable outputs available. + NoSpendableOutputs, + /// Coin selection failed. + CoinSelectionFailed, + /// A generic wallet operation failed. + WalletOperationFailed, + /// UTXO not found locally (caller may want to try a chain source fallback). + UtxoNotFoundLocally(OutPoint), + /// Transaction not found in any wallet. + TransactionNotFound, + /// Cannot replace a transaction that is already confirmed. + TransactionAlreadyConfirmed, + /// A wallet for the given key already exists. + WalletAlreadyExists, + /// Cannot remove the primary wallet. + CannotRemovePrimary, +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::WalletNotFound => write!(f, "Wallet not found"), + Error::PersisterNotFound => write!(f, "Persister not found"), + Error::PersistenceFailed => write!(f, "Failed to persist wallet state"), + Error::OnchainTxCreationFailed => write!(f, "On-chain transaction creation failed"), + Error::OnchainTxSigningFailed => write!(f, "On-chain transaction signing failed"), + Error::InsufficientFunds => write!(f, "Insufficient funds"), + Error::InvalidFeeRate => write!(f, "Invalid fee rate"), + Error::InvalidQuantity => write!(f, "Invalid quantity"), + Error::NoSpendableOutputs => write!(f, "No spendable outputs available"), + Error::CoinSelectionFailed => write!(f, "Coin selection failed"), + Error::WalletOperationFailed => write!(f, "Wallet operation failed"), + Error::UtxoNotFoundLocally(op) => { + write!(f, "UTXO {:?} not found in any local wallet", op) + }, + Error::TransactionNotFound => write!(f, "Transaction not found in any wallet"), + Error::TransactionAlreadyConfirmed => { + write!(f, "Cannot replace an already-confirmed transaction") + }, + Error::WalletAlreadyExists => write!(f, "Wallet for this key already exists"), + Error::CannotRemovePrimary => write!(f, "Cannot remove the primary wallet"), + } + } +} + +impl std::error::Error for Error {} + +/// UTXO info for multi-wallet PSBT building. +#[derive(Clone)] +pub struct UtxoPsbtInfo { + /// The outpoint being spent. + pub outpoint: OutPoint, + /// The PSBT input data for this UTXO. + pub psbt_input: psbt::Input, + /// The satisfaction weight for this input type. + pub weight: Weight, + /// Whether this UTXO belongs to the primary wallet. + pub is_primary: bool, +} + +/// Available coin selection algorithms. +#[derive(Debug, Clone, Copy)] +pub enum CoinSelectionAlgorithm { + /// Branch and bound algorithm (tries to find exact match). + BranchAndBound, + /// Select largest UTXOs first. + LargestFirst, + /// Select oldest UTXOs first. + OldestFirst, + /// Select UTXOs randomly. + SingleRandomDraw, +} diff --git a/crates/bdk-wallet-aggregate/src/utxo.rs b/crates/bdk-wallet-aggregate/src/utxo.rs new file mode 100644 index 0000000000..bcc0f4de0b --- /dev/null +++ b/crates/bdk-wallet-aggregate/src/utxo.rs @@ -0,0 +1,264 @@ +// This file is Copyright its original authors, visible in version control history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license , at your option. You may not use this file except in +// accordance with one or both of these licenses. + +//! UTXO weight calculation, PSBT preparation, and coin selection helpers. + +use std::collections::HashMap; +use std::fmt::Debug; +use std::hash::Hash; + +#[allow(deprecated)] +use bdk_wallet::coin_selection::CoinSelectionAlgorithm as BdkCoinSelectionAlgorithm; +use bdk_wallet::coin_selection::{ + BranchAndBoundCoinSelection, Excess, LargestFirstCoinSelection, OldestFirstCoinSelection, + SingleRandomDraw, +}; +use bdk_wallet::{LocalOutput, PersistedWallet, WalletPersister, WeightedUtxo}; +use bip39::rand::rngs::OsRng; +use bitcoin::{psbt, Amount, FeeRate, OutPoint, Script, ScriptBuf, Weight}; + +use crate::types::{CoinSelectionAlgorithm, Error, UtxoPsbtInfo}; + +/// Minimum economical output value (dust limit). +pub const DUST_LIMIT_SATS: u64 = 546; + +/// Calculate the satisfaction weight for a UTXO based on its script type. +pub fn calculate_utxo_weight(script_pubkey: &ScriptBuf) -> Weight { + if script_pubkey.is_p2wpkh() { + Weight::from_wu(107) + } else if script_pubkey.is_p2tr() { + Weight::from_wu(65) + } else if script_pubkey.is_p2sh() { + Weight::from_wu(199) + } else { + Weight::from_wu(428) + } +} + +/// Find the descriptor satisfaction weight for a wallet-owned outpoint. +pub(crate) fn satisfaction_weight_for_outpoint( + outpoint: OutPoint, wallets: &HashMap>, +) -> Option +where + K: Eq + Hash + Copy + Debug, + P: WalletPersister, +{ + for wallet in wallets.values() { + let keychain = if let Some(utxo) = wallet.get_utxo(outpoint) { + Some(utxo.keychain) + } else { + wallet + .get_tx(outpoint.txid) + .and_then(|tx| tx.tx_node.tx.output.get(outpoint.vout as usize).cloned()) + .and_then(|txout| wallet.derivation_of_spk(txout.script_pubkey)) + .map(|(keychain, _)| keychain) + }; + + if let Some(weight) = keychain + .and_then(|keychain| wallet.public_descriptor(keychain).max_weight_to_satisfy().ok()) + { + return Some(weight); + } + } + + None +} + +/// Prepare UTXO information needed to add local outputs as foreign UTXOs in a +/// cross-wallet PSBT. +pub fn prepare_utxos_for_psbt( + utxos: &[LocalOutput], wallets: &HashMap>, primary_key: &K, +) -> Result, Error> +where + K: Eq + Hash + Copy + Debug, + P: WalletPersister, +{ + let mut result = Vec::with_capacity(utxos.len()); + + for utxo in utxos { + let is_primary = + wallets.get(primary_key).map(|w| w.get_utxo(utxo.outpoint).is_some()).unwrap_or(false); + + let weight = satisfaction_weight_for_outpoint(utxo.outpoint, wallets) + .unwrap_or_else(|| calculate_utxo_weight(&utxo.txout.script_pubkey)); + + let mut psbt_input = + psbt::Input { witness_utxo: Some(utxo.txout.clone()), ..Default::default() }; + + // Always include the full previous transaction (non_witness_utxo). + // BDK requires this for foreign UTXOs during PSBT construction to + // guard against the SegWit fee vulnerability, even for witness inputs. + let mut found_tx = false; + for wallet in wallets.values() { + if let Some(tx_node) = wallet.get_tx(utxo.outpoint.txid) { + psbt_input.non_witness_utxo = Some(tx_node.tx_node.tx.as_ref().clone()); + found_tx = true; + break; + } + } + + if !found_tx { + return Err(Error::UtxoNotFoundLocally(utxo.outpoint)); + } + + result.push(UtxoPsbtInfo { outpoint: utxo.outpoint, psbt_input, weight, is_primary }); + } + + Ok(result) +} + +/// Prepare outpoints for PSBT by looking them up across all wallets. +pub fn prepare_outpoints_for_psbt( + outpoints: &[OutPoint], wallets: &HashMap>, primary_key: &K, +) -> Result, Error> +where + K: Eq + Hash + Copy + Debug, + P: WalletPersister, +{ + let utxos: Vec = outpoints + .iter() + .filter_map(|outpoint| { + wallets.values().find_map(|w| w.get_utxo(*outpoint).filter(|u| !u.is_spent)) + }) + .collect(); + + if utxos.len() != outpoints.len() { + log::error!("Some outpoints were not found in any wallet"); + return Err(Error::WalletOperationFailed); + } + + prepare_utxos_for_psbt(&utxos, wallets, primary_key) +} + +/// Add UTXO information to a BDK `TxBuilder`. +pub fn add_utxos_to_tx_builder( + tx_builder: &mut bdk_wallet::TxBuilder<'_, Cs>, utxo_infos: &[UtxoPsbtInfo], +) -> Result<(), Error> { + for info in utxo_infos { + if info.is_primary { + tx_builder.add_utxo(info.outpoint).map_err(|e| { + log::error!("Failed to add primary UTXO {:?}: {}", info.outpoint, e); + Error::OnchainTxCreationFailed + })?; + } else { + tx_builder + .add_foreign_utxo_with_sequence( + info.outpoint, + info.psbt_input.clone(), + info.weight, + bitcoin::Sequence::ENABLE_RBF_NO_LOCKTIME, + ) + .map_err(|e| { + log::error!("Failed to add foreign UTXO {:?}: {}", info.outpoint, e); + Error::OnchainTxCreationFailed + })?; + } + } + Ok(()) +} + +/// Run coin selection across UTXOs from any wallet. +#[allow(clippy::too_many_arguments)] +pub fn select_utxos_with_algorithm( + target_amount: u64, available_utxos: Vec, fee_rate: FeeRate, + algorithm: CoinSelectionAlgorithm, drain_script: &Script, excluded_outpoints: &[OutPoint], + wallets: &HashMap>, +) -> Result, Error> +where + K: Eq + Hash + Copy + Debug, + P: WalletPersister, +{ + let safe_utxos: Vec = available_utxos + .into_iter() + .filter(|utxo| !excluded_outpoints.contains(&utxo.outpoint)) + .collect(); + + if safe_utxos.is_empty() { + log::error!("No spendable UTXOs available after filtering"); + return Err(Error::NoSpendableOutputs); + } + + let weighted_utxos: Vec = safe_utxos + .iter() + .map(|utxo| { + // Find the wallet that actually owns this UTXO and use its + // descriptor for an accurate satisfaction weight. Falls back to + // script-type heuristic if no wallet claims the output. + let satisfaction_weight = satisfaction_weight_for_outpoint(utxo.outpoint, wallets) + .unwrap_or_else(|| calculate_utxo_weight(&utxo.txout.script_pubkey)); + + WeightedUtxo { satisfaction_weight, utxo: bdk_wallet::Utxo::Local(utxo.clone()) } + }) + .collect(); + + let target = Amount::from_sat(target_amount); + let mut rng = OsRng; + + let result = match algorithm { + CoinSelectionAlgorithm::BranchAndBound => { + BranchAndBoundCoinSelection::::default().coin_select( + vec![], + weighted_utxos, + fee_rate, + target, + drain_script, + &mut rng, + ) + }, + CoinSelectionAlgorithm::LargestFirst => LargestFirstCoinSelection.coin_select( + vec![], + weighted_utxos, + fee_rate, + target, + drain_script, + &mut rng, + ), + CoinSelectionAlgorithm::OldestFirst => OldestFirstCoinSelection.coin_select( + vec![], + weighted_utxos, + fee_rate, + target, + drain_script, + &mut rng, + ), + CoinSelectionAlgorithm::SingleRandomDraw => SingleRandomDraw.coin_select( + vec![], + weighted_utxos, + fee_rate, + target, + drain_script, + &mut rng, + ), + } + .map_err(|e| { + log::error!("Coin selection failed: {}", e); + Error::CoinSelectionFailed + })?; + + if let Excess::Change { amount, .. } = result.excess { + if amount.to_sat() > 0 && amount.to_sat() < DUST_LIMIT_SATS { + return Err(Error::CoinSelectionFailed); + } + } + + let selected_outputs: Vec = result + .selected + .into_iter() + .filter_map(|utxo| match utxo { + bdk_wallet::Utxo::Local(local) => Some(local), + _ => None, + }) + .collect(); + + log::debug!( + "Selected {} UTXOs using {:?} algorithm for target {} sats", + selected_outputs.len(), + algorithm, + target_amount, + ); + Ok(selected_outputs.into_iter().map(|u| u.outpoint).collect()) +} diff --git a/scripts/normalize_generated_whitespace.sh b/scripts/normalize_generated_whitespace.sh new file mode 100755 index 0000000000..dfcc791ce1 --- /dev/null +++ b/scripts/normalize_generated_whitespace.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -euo pipefail + +if [ "$#" -eq 0 ]; then + echo "Usage: $0 FILE..." >&2 + exit 1 +fi + +for file in "$@"; do + if [ ! -f "$file" ]; then + echo "Generated binding not found: $file" >&2 + exit 1 + fi +done + +perl -0pi -e 's/[ \t]+(?=\n)//g; s/[ \t]+\z//; s/\n+\z/\n/; $_ .= "\n" unless /\n\z/' -- "$@" diff --git a/scripts/uniffi_bindgen_generate.sh b/scripts/uniffi_bindgen_generate.sh index 0658cabdb9..745a971d5e 100755 --- a/scripts/uniffi_bindgen_generate.sh +++ b/scripts/uniffi_bindgen_generate.sh @@ -1,5 +1,19 @@ #!/bin/bash +set -eox pipefail + +# Set deployment targets +export IPHONEOS_DEPLOYMENT_TARGET=13.0 +export MACOSX_DEPLOYMENT_TARGET=10.15 + +# Set CMake-specific deployment targets to match +export CMAKE_OSX_DEPLOYMENT_TARGET=$IPHONEOS_DEPLOYMENT_TARGET +export CMAKE_IOS_DEPLOYMENT_TARGET=$IPHONEOS_DEPLOYMENT_TARGET + +# Clear any potentially conflicting environment variables +unset SDKROOT +unset BINDGEN_EXTRA_CLANG_ARGS + source ./scripts/uniffi_bindgen_generate_kotlin.sh || exit 1 source ./scripts/uniffi_bindgen_generate_python.sh || exit 1 source ./scripts/uniffi_bindgen_generate_swift.sh || exit 1 - +source ./scripts/uniffi_bindgen_generate_kotlin_android.sh || exit 1 diff --git a/scripts/uniffi_bindgen_generate_kotlin.sh b/scripts/uniffi_bindgen_generate_kotlin.sh index a1085600e7..ac5213795a 100755 --- a/scripts/uniffi_bindgen_generate_kotlin.sh +++ b/scripts/uniffi_bindgen_generate_kotlin.sh @@ -1,34 +1,77 @@ #!/bin/bash + BINDINGS_DIR="bindings/kotlin" -TARGET_DIR="target/bindings/kotlin" +TARGET_DIR="target" PROJECT_DIR="ldk-node-jvm" -PACKAGE_DIR="org/lightningdevkit/ldknode" -UNIFFI_BINDGEN_BIN="cargo run --manifest-path bindings/uniffi-bindgen/Cargo.toml" +JVM_LIB_DIR="$BINDINGS_DIR/$PROJECT_DIR" + +# Install gobley-uniffi-bindgen from fork (skip if orchestrator already installed it) +if [ -z "${BINDGEN_GOBLEY_INSTALLED:-}" ]; then + echo "Installing gobley-uniffi-bindgen fork..." + cargo install --git https://github.com/ovitrif/gobley.git --branch fix-v0.2.0 gobley-uniffi-bindgen --force +fi +UNIFFI_BINDGEN_BIN="gobley-uniffi-bindgen" if [[ "$OSTYPE" == "linux-gnu"* ]]; then + echo "Building for Linux x86_64..." rustup target add x86_64-unknown-linux-gnu || exit 1 - cargo build --release --target x86_64-unknown-linux-gnu --features uniffi || exit 1 - DYNAMIC_LIB_PATH="target/x86_64-unknown-linux-gnu/release/libldk_node.so" - RES_DIR="$BINDINGS_DIR/$PROJECT_DIR/lib/src/main/resources/linux-x86-64/" + cargo build --profile release-smaller --target x86_64-unknown-linux-gnu --features uniffi || exit 1 + DYNAMIC_LIB_PATH="$TARGET_DIR/x86_64-unknown-linux-gnu/release-smaller/libldk_node.so" + RES_DIR="$JVM_LIB_DIR/lib/src/main/resources/linux-x86-64/" mkdir -p $RES_DIR || exit 1 cp $DYNAMIC_LIB_PATH $RES_DIR || exit 1 else + echo "Building for macOS x86_64..." rustup target add x86_64-apple-darwin || exit 1 - cargo build --release --target x86_64-apple-darwin --features uniffi || exit 1 - DYNAMIC_LIB_PATH="target/x86_64-apple-darwin/release/libldk_node.dylib" - RES_DIR="$BINDINGS_DIR/$PROJECT_DIR/lib/src/main/resources/darwin-x86-64/" + cargo build --profile release-smaller --target x86_64-apple-darwin --features uniffi || exit 1 + DYNAMIC_LIB_PATH="$TARGET_DIR/x86_64-apple-darwin/release-smaller/libldk_node.dylib" + RES_DIR="$JVM_LIB_DIR/lib/src/main/resources/darwin-x86-64/" mkdir -p $RES_DIR || exit 1 cp $DYNAMIC_LIB_PATH $RES_DIR || exit 1 + echo "Building for macOS aarch64..." rustup target add aarch64-apple-darwin || exit 1 - cargo build --release --target aarch64-apple-darwin --features uniffi || exit 1 - DYNAMIC_LIB_PATH="target/aarch64-apple-darwin/release/libldk_node.dylib" - RES_DIR="$BINDINGS_DIR/$PROJECT_DIR/lib/src/main/resources/darwin-aarch64/" + cargo build --profile release-smaller --target aarch64-apple-darwin --features uniffi || exit 1 + DYNAMIC_LIB_PATH_ARM="$TARGET_DIR/aarch64-apple-darwin/release-smaller/libldk_node.dylib" + RES_DIR="$JVM_LIB_DIR/lib/src/main/resources/darwin-aarch64/" mkdir -p $RES_DIR || exit 1 - cp $DYNAMIC_LIB_PATH $RES_DIR || exit 1 + cp $DYNAMIC_LIB_PATH_ARM $RES_DIR || exit 1 fi -mkdir -p "$BINDINGS_DIR"/"$PROJECT_DIR"/lib/src/main/kotlin/"$PACKAGE_DIR" || exit 1 -$UNIFFI_BINDGEN_BIN generate bindings/ldk_node.udl --language kotlin -o "$TARGET_DIR" || exit 1 +# Clean old bindings and generate new ones +echo "Cleaning old Kotlin bindings..." +rm -f "$JVM_LIB_DIR/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.kt" + +echo "Generating Kotlin bindings..." +$UNIFFI_BINDGEN_BIN bindings/ldk_node.udl --lib-file $DYNAMIC_LIB_PATH --config uniffi-jvm.toml -o "$JVM_LIB_DIR/lib/src" || exit 1 + +# Fix incorrect kotlinx.coroutines.IO import (removed in newer kotlinx.coroutines versions) +echo "Fixing Kotlin coroutines imports..." +KOTLIN_BINDINGS_DIR="$JVM_LIB_DIR/lib/src/main/kotlin/org/lightningdevkit/ldknode" +KOTLIN_BINDINGS_FILE="$KOTLIN_BINDINGS_DIR/ldk_node.jvm.kt" +if [ -f "$KOTLIN_BINDINGS_FILE" ]; then + sed -i.bak '/import kotlinx\.coroutines\.IO/d' "$KOTLIN_BINDINGS_FILE" + rm -f "$KOTLIN_BINDINGS_FILE.bak" +fi + +echo "Normalizing generated Kotlin whitespace..." +./scripts/normalize_generated_whitespace.sh \ + "$KOTLIN_BINDINGS_DIR/ldk_node.common.kt" \ + "$KOTLIN_BINDINGS_DIR/ldk_node.jvm.kt" || exit 1 + +# Sync version from Cargo.toml +echo "Syncing version from Cargo.toml..." +CARGO_VERSION=$(grep '^version = ' Cargo.toml | sed 's/version = "\(.*\)"/\1/' | head -1) +sed -i.bak "s/^version=.*/version=$CARGO_VERSION/" "$JVM_LIB_DIR/gradle.properties" +rm -f "$JVM_LIB_DIR/gradle.properties.bak" +echo "JVM version synced: $CARGO_VERSION" + +# Verify JVM library build (skip tests - they require bitcoind) +echo "Testing JVM library build..." +$JVM_LIB_DIR/gradlew --project-dir "$JVM_LIB_DIR" clean build -x test || exit 1 + +# Verify JVM library publish task graph +echo "Verifying JVM library publish task graph..." +$JVM_LIB_DIR/gradlew --project-dir "$JVM_LIB_DIR" clean publish --dry-run || exit 1 -cp "$TARGET_DIR"/"$PACKAGE_DIR"/ldk_node.kt "$BINDINGS_DIR"/"$PROJECT_DIR"/lib/src/main/kotlin/"$PACKAGE_DIR"/ || exit 1 +echo "JVM build process completed successfully!" diff --git a/scripts/uniffi_bindgen_generate_kotlin_android.sh b/scripts/uniffi_bindgen_generate_kotlin_android.sh index c87db59242..36543fca16 100755 --- a/scripts/uniffi_bindgen_generate_kotlin_android.sh +++ b/scripts/uniffi_bindgen_generate_kotlin_android.sh @@ -1,9 +1,20 @@ #!/bin/bash +set -e + BINDINGS_DIR="bindings/kotlin" TARGET_DIR="target" PROJECT_DIR="ldk-node-android" -UNIFFI_BINDGEN_BIN="cargo run --manifest-path bindings/uniffi-bindgen/Cargo.toml" +ANDROID_LIB_DIR="$BINDINGS_DIR/$PROJECT_DIR" +NATIVE_DEBUG_SYMBOLS_ZIP="$ANDROID_LIB_DIR/native-debug-symbols.zip" + +# Install gobley-uniffi-bindgen from fork (skip if orchestrator already installed it) +if [ -z "${BINDGEN_GOBLEY_INSTALLED:-}" ]; then + echo "Installing gobley-uniffi-bindgen fork..." + GOBLEY_REV="36730a4219b2e8d06aa2c073936d6fc6a7f60e0f" + cargo install --git https://github.com/ovitrif/gobley.git --rev "$GOBLEY_REV" gobley-uniffi-bindgen --force +fi +UNIFFI_BINDGEN_BIN="gobley-uniffi-bindgen" export_variable_if_not_present() { local name="$1" @@ -34,16 +45,272 @@ case "$OSTYPE" in PATH="$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/$LLVM_ARCH_PATH/bin:$PATH" +# Install the cargo-ndk version used by the mobile release scripts. +CARGO_NDK_VERSION="3.5.4" +if ! command -v cargo-ndk &> /dev/null || ! cargo ndk --version | grep "cargo-ndk $CARGO_NDK_VERSION" >/dev/null; then + echo "Installing cargo-ndk $CARGO_NDK_VERSION..." + cargo install cargo-ndk --version "$CARGO_NDK_VERSION" --locked --force +fi + +# Add Android targets +echo "Adding Android targets..." rustup target add x86_64-linux-android aarch64-linux-android armv7-linux-androideabi -RUSTFLAGS="-C link-args=-Wl,-z,max-page-size=16384,-z,common-page-size=16384" CFLAGS="-D__ANDROID_MIN_SDK_VERSION__=21" AR=llvm-ar CARGO_TARGET_X86_64_LINUX_ANDROID_LINKER="x86_64-linux-android21-clang" CC="x86_64-linux-android21-clang" cargo build --profile release-smaller --features uniffi --target x86_64-linux-android || exit 1 -RUSTFLAGS="-C link-args=-Wl,-z,max-page-size=16384,-z,common-page-size=16384" CFLAGS="-D__ANDROID_MIN_SDK_VERSION__=21" AR=llvm-ar CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER="armv7a-linux-androideabi21-clang" CC="armv7a-linux-androideabi21-clang" cargo build --profile release-smaller --features uniffi --target armv7-linux-androideabi || exit 1 -RUSTFLAGS="-C link-args=-Wl,-z,max-page-size=16384,-z,common-page-size=16384" CFLAGS="-D__ANDROID_MIN_SDK_VERSION__=21" AR=llvm-ar CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER="aarch64-linux-android21-clang" CC="aarch64-linux-android21-clang" cargo build --profile release-smaller --features uniffi --target aarch64-linux-android || exit 1 -$UNIFFI_BINDGEN_BIN generate bindings/ldk_node.udl --language kotlin --config uniffi-android.toml -o "$BINDINGS_DIR"/"$PROJECT_DIR"/lib/src/main/kotlin || exit 1 - -JNI_LIB_DIR="$BINDINGS_DIR"/"$PROJECT_DIR"/lib/src/main/jniLibs/ -mkdir -p $JNI_LIB_DIR/x86_64 || exit 1 -mkdir -p $JNI_LIB_DIR/armeabi-v7a || exit 1 -mkdir -p $JNI_LIB_DIR/arm64-v8a || exit 1 -cp $TARGET_DIR/x86_64-linux-android/release-smaller/libldk_node.so $JNI_LIB_DIR/x86_64/ || exit 1 -cp $TARGET_DIR/armv7-linux-androideabi/release-smaller/libldk_node.so $JNI_LIB_DIR/armeabi-v7a/ || exit 1 -cp $TARGET_DIR/aarch64-linux-android/release-smaller/libldk_node.so $JNI_LIB_DIR/arm64-v8a/ || exit 1 + +# Build for all Android architectures with page size optimizations +echo "Building for Android architectures..." +JNI_LIB_DIR="$ANDROID_LIB_DIR/lib/src/main/jniLibs" +export CARGO_PROFILE_RELEASE_SMALLER_STRIP=false +export CARGO_PROFILE_RELEASE_SMALLER_DEBUG=2 +export RUSTFLAGS="-C link-arg=-Wl,--build-id=sha1 -C link-args=-Wl,-z,max-page-size=16384,-z,common-page-size=16384" +export CFLAGS="-D__ANDROID_MIN_SDK_VERSION__=21" + +find_readelf() { + if command -v llvm-readelf >/dev/null 2>&1; then + command -v llvm-readelf + return + fi + + if command -v readelf >/dev/null 2>&1; then + command -v readelf + return + fi + + for ndk_dir in "${ANDROID_NDK_ROOT:-}" "${ANDROID_NDK_HOME:-}" "${NDK_HOME:-}"; do + if [ -z "$ndk_dir" ] || [ ! -d "$ndk_dir/toolchains/llvm/prebuilt" ]; then + continue + fi + + ndk_readelf=$(find "$ndk_dir/toolchains/llvm/prebuilt" -path '*/bin/llvm-readelf' | head -n 1) + if [ -n "$ndk_readelf" ]; then + echo "$ndk_readelf" + return + fi + done + + echo "Error: llvm-readelf or readelf is required to validate Android native debug symbols" + exit 1 +} + +find_strip() { + if command -v llvm-strip >/dev/null 2>&1; then + command -v llvm-strip + return + fi + + for ndk_dir in "${ANDROID_NDK_ROOT:-}" "${ANDROID_NDK_HOME:-}" "${NDK_HOME:-}"; do + if [ -z "$ndk_dir" ] || [ ! -d "$ndk_dir/toolchains/llvm/prebuilt" ]; then + continue + fi + + ndk_strip=$(find "$ndk_dir/toolchains/llvm/prebuilt" -path '*/bin/llvm-strip' | head -n 1) + if [ -n "$ndk_strip" ]; then + echo "$ndk_strip" + return + fi + done + + echo "Error: llvm-strip is required to strip Android native release libraries" + exit 1 +} + +has_dwarf_debug_metadata() { + for attempt in 1 2 3; do + if "$READELF_BIN" -S "$1" | grep -E '\.debug_info' >/dev/null; then + return 0 + fi + + sleep "$attempt" + done + + "$READELF_BIN" -S "$1" | grep -E '\.debug_info' || true + return 1 +} + +has_dwarf_sections() { + "$READELF_BIN" -S "$1" | grep -E '\.debug_' >/dev/null +} + +readelf_program_headers() { + if "$READELF_BIN" -W -l "$1" >/dev/null 2>&1; then + "$READELF_BIN" -W -l "$1" + return + fi + + "$READELF_BIN" -l "$1" +} + +has_16kb_load_alignment() { + alignments=$(readelf_program_headers "$1" | awk '$1 == "LOAD" { print $NF }') + if [ -z "$alignments" ]; then + return 1 + fi + + while read -r alignment; do + if [ -z "$alignment" ]; then + continue + fi + + if [ "$((alignment))" -lt 16384 ]; then + return 1 + fi + done </dev/null; then + rm -rf "$tmp_dir" + exit 1 + fi + rm -rf "$tmp_dir" +} + +strip_android_libraries() { + STRIP_BIN=$(find_strip) + + for abi in armeabi-v7a arm64-v8a x86_64; do + "$STRIP_BIN" --strip-unneeded "$JNI_LIB_DIR/$abi/libldk_node.so" + done +} + +validate_stripped_android_symbols() { + READELF_BIN=$(find_readelf) + + for abi in armeabi-v7a arm64-v8a x86_64; do + validate_stripped_android_library "$JNI_LIB_DIR/$abi/libldk_node.so" + done +} + +validate_android_aar_symbols() { + READELF_BIN=$(find_readelf) + aar=$(find "$ANDROID_LIB_DIR" -path '*/build/outputs/aar/*release.aar' -print | head -n 1) + if [ -z "$aar" ]; then + echo "Error: Android release AAR missing under $ANDROID_LIB_DIR" + exit 1 + fi + + tmp_dir=$(mktemp -d) + unzip -q "$aar" -d "$tmp_dir" + + for abi in armeabi-v7a arm64-v8a x86_64; do + lib="$tmp_dir/jni/$abi/libldk_node.so" + if [ ! -f "$lib" ]; then + echo "Error: Android release AAR native library missing at $lib" + rm -rf "$tmp_dir" + exit 1 + fi + + validate_stripped_android_library "$lib" + done + + rm -rf "$tmp_dir" +} + +cargo ndk \ + -o "$JNI_LIB_DIR" \ + --no-strip \ + -t armeabi-v7a \ + -t arm64-v8a \ + -t x86_64 \ + build --profile release-smaller --features uniffi || exit 1 + +validate_android_symbols +create_native_debug_symbols_archive +strip_android_libraries +validate_stripped_android_symbols + +# Clean up exported flags so they don't leak into subsequent scripts +# (e.g. the -z linker flags are Linux-only and break macOS builds) +unset CARGO_PROFILE_RELEASE_SMALLER_STRIP +unset CARGO_PROFILE_RELEASE_SMALLER_DEBUG +unset RUSTFLAGS +unset CFLAGS + +# Generate Kotlin bindings +echo "Generating Kotlin bindings..." +$UNIFFI_BINDGEN_BIN bindings/ldk_node.udl --lib-file $TARGET_DIR/aarch64-linux-android/release-smaller/libldk_node.so --config uniffi-android.toml -o "$ANDROID_LIB_DIR/lib/src" || exit 1 + +# Fix incorrect kotlinx.coroutines.IO import (removed in newer kotlinx.coroutines versions) +echo "Fixing Kotlin coroutines imports..." +KOTLIN_BINDINGS_DIR="$ANDROID_LIB_DIR/lib/src/main/kotlin/org/lightningdevkit/ldknode" +KOTLIN_BINDINGS_FILE="$KOTLIN_BINDINGS_DIR/ldk_node.android.kt" +sed -i.bak '/import kotlinx\.coroutines\.IO/d' "$KOTLIN_BINDINGS_FILE" +rm -f "$KOTLIN_BINDINGS_FILE.bak" + +echo "Normalizing generated Kotlin whitespace..." +./scripts/normalize_generated_whitespace.sh \ + "$KOTLIN_BINDINGS_DIR/ldk_node.android.kt" \ + "$KOTLIN_BINDINGS_DIR/ldk_node.common.kt" + +# Sync version from Cargo.toml +echo "Syncing version from Cargo.toml..." +CARGO_VERSION=$(grep '^version = ' Cargo.toml | sed 's/version = "\(.*\)"/\1/' | head -1) +sed -i.bak "s/^version=.*/version=$CARGO_VERSION/" "$ANDROID_LIB_DIR/gradle.properties" +rm -f "$ANDROID_LIB_DIR/gradle.properties.bak" +echo "Version synced: $CARGO_VERSION" + +# Verify android library publish task graph +echo "Testing android library publish to Maven Local..." +$ANDROID_LIB_DIR/gradlew --project-dir "$ANDROID_LIB_DIR" clean publishToMavenLocal +validate_android_aar_symbols + +echo "Android build process completed successfully!" diff --git a/scripts/uniffi_bindgen_generate_python.sh b/scripts/uniffi_bindgen_generate_python.sh index 14e7b4f86f..7349426668 100755 --- a/scripts/uniffi_bindgen_generate_python.sh +++ b/scripts/uniffi_bindgen_generate_python.sh @@ -11,5 +11,8 @@ fi cargo build --profile release-smaller --features uniffi || exit 1 $UNIFFI_BINDGEN_BIN generate bindings/ldk_node.udl --language python -o "$BINDINGS_DIR" || exit 1 +echo "Normalizing generated Python whitespace..." +./scripts/normalize_generated_whitespace.sh "$BINDINGS_DIR/ldk_node.py" || exit 1 + mkdir -p $BINDINGS_DIR cp "$DYNAMIC_LIB_PATH" "$BINDINGS_DIR" || exit 1 diff --git a/scripts/uniffi_bindgen_generate_swift.sh b/scripts/uniffi_bindgen_generate_swift.sh index ce1151a3bd..3cb582c074 100755 --- a/scripts/uniffi_bindgen_generate_swift.sh +++ b/scripts/uniffi_bindgen_generate_swift.sh @@ -4,9 +4,6 @@ set -eox pipefail BINDINGS_DIR="./bindings/swift" UNIFFI_BINDGEN_BIN="cargo run --manifest-path bindings/uniffi-bindgen/Cargo.toml" -cargo build --release || exit 1 -$UNIFFI_BINDGEN_BIN generate bindings/ldk_node.udl --language swift -o "$BINDINGS_DIR" || exit 1 - mkdir -p $BINDINGS_DIR # Install rust target toolchains @@ -20,18 +17,32 @@ rustup target add aarch64-apple-darwin x86_64-apple-darwin --toolchain stable cargo build --profile release-smaller --features uniffi || exit 1 cargo build --profile release-smaller --features uniffi --target x86_64-apple-darwin || exit 1 cargo build --profile release-smaller --features uniffi --target aarch64-apple-darwin || exit 1 -cargo build --profile release-smaller --features uniffi --target x86_64-apple-ios || exit 1 + +# Build iOS device targets +export SDKROOT=$(xcrun --sdk iphoneos --show-sdk-path) cargo build --profile release-smaller --features uniffi --target aarch64-apple-ios || exit 1 -cargo +stable build --release --features uniffi --target aarch64-apple-ios-sim || exit 1 + +# Build iOS simulator targets +export SDKROOT=$(xcrun --sdk iphonesimulator --show-sdk-path) +cargo build --profile release-smaller --features uniffi --target x86_64-apple-ios || exit 1 + +# For aarch64 simulator, set the additional environment variable +export SDKROOT=$(xcrun --sdk iphonesimulator --show-sdk-path) +export BINDGEN_EXTRA_CLANG_ARGS="--target=arm64-apple-ios-simulator" +cargo +stable build --profile release-smaller --features uniffi --target aarch64-apple-ios-sim || exit 1 # Combine ios-sim and apple-darwin (macos) libs for x86_64 and aarch64 (m1) mkdir -p target/lipo-ios-sim/release-smaller || exit 1 -lipo target/aarch64-apple-ios-sim/release/libldk_node.a target/x86_64-apple-ios/release-smaller/libldk_node.a -create -output target/lipo-ios-sim/release-smaller/libldk_node.a || exit 1 +lipo target/aarch64-apple-ios-sim/release-smaller/libldk_node.a target/x86_64-apple-ios/release-smaller/libldk_node.a -create -output target/lipo-ios-sim/release-smaller/libldk_node.a || exit 1 mkdir -p target/lipo-macos/release-smaller || exit 1 lipo target/aarch64-apple-darwin/release-smaller/libldk_node.a target/x86_64-apple-darwin/release-smaller/libldk_node.a -create -output target/lipo-macos/release-smaller/libldk_node.a || exit 1 $UNIFFI_BINDGEN_BIN generate bindings/ldk_node.udl --language swift -o "$BINDINGS_DIR" || exit 1 +# Reset SDKROOT for macOS compilation +unset SDKROOT +unset BINDGEN_EXTRA_CLANG_ARGS + swiftc -module-name LDKNode -emit-library -o "$BINDINGS_DIR"/libldk_node.dylib -emit-module -emit-module-path "$BINDINGS_DIR" -parse-as-library -L ./target/release-smaller -lldk_node -Xcc -fmodule-map-file="$BINDINGS_DIR"/LDKNodeFFI.modulemap "$BINDINGS_DIR"/LDKNode.swift -v || exit 1 # Create xcframework from bindings Swift file and libs diff --git a/src/balance.rs b/src/balance.rs index d96278daeb..fa4d6b6456 100644 --- a/src/balance.rs +++ b/src/balance.rs @@ -13,6 +13,15 @@ use lightning::sign::SpendableOutputDescriptor; use lightning::util::sweep::{OutputSpendStatus, TrackedSpendableOutput}; use lightning_types::payment::{PaymentHash, PaymentPreimage}; +/// Balance details for a specific address type wallet. +#[derive(Debug, Clone)] +pub struct AddressTypeBalance { + /// The total balance of the wallet for this address type. + pub total_sats: u64, + /// The currently spendable balance of the wallet for this address type. + pub spendable_sats: u64, +} + /// Details of the known available balances returned by [`Node::list_balances`]. /// /// [`Node::list_balances`]: crate::Node::list_balances diff --git a/src/builder.rs b/src/builder.rs index 63e84db378..0fcc8d536d 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -5,59 +5,72 @@ // http://opensource.org/licenses/MIT>, at your option. You may not use this file except in // accordance with one or both of these licenses. -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::convert::TryInto; use std::default::Default; use std::path::PathBuf; +use std::sync::atomic::AtomicU32; use std::sync::{Arc, Mutex, Once, RwLock}; use std::time::SystemTime; use std::{fmt, fs}; -use bdk_wallet::template::Bip84; -use bdk_wallet::{KeychainKind, Wallet as BdkWallet}; +use bdk_wallet::template::{Bip44, Bip49, Bip84, Bip86, P2Pkh, P2Wpkh, P2Wpkh_P2Sh, P2TR}; +use bdk_wallet::{KeychainKind, PersistedWallet, Wallet as BdkWallet}; use bip39::Mnemonic; -use bitcoin::bip32::{ChildNumber, Xpriv}; -use bitcoin::secp256k1::PublicKey; +use bitcoin::bip32::{ChildNumber, DerivationPath, Xpriv, Xpub}; +use bitcoin::secp256k1::{PublicKey, Secp256k1}; use bitcoin::{BlockHash, Network}; +use lightning::chain::channelmonitor::ChannelMonitor; use lightning::chain::{chainmonitor, BestBlock, Watch}; use lightning::io::Cursor; use lightning::ln::channelmanager::{self, ChainParameters, ChannelManagerReadArgs}; use lightning::ln::msgs::{RoutingMessageHandler, SocketAddress}; use lightning::ln::peer_handler::{IgnoringMessageHandler, MessageHandler}; -use lightning::log_trace; use lightning::routing::gossip::NodeAlias; use lightning::routing::router::DefaultRouter; use lightning::routing::scoring::{ - CombinedScorer, ProbabilisticScorer, ProbabilisticScoringDecayParameters, + ChannelLiquidities, CombinedScorer, ProbabilisticScorer, ProbabilisticScoringDecayParameters, ProbabilisticScoringFeeParameters, }; -use lightning::sign::{EntropySource, NodeSigner}; +use lightning::sign::{EntropySource, InMemorySigner, NodeSigner, SignerProvider}; use lightning::util::persist::{ - KVStoreSync, CHANNEL_MANAGER_PERSISTENCE_KEY, CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE, - CHANNEL_MANAGER_PERSISTENCE_SECONDARY_NAMESPACE, + KVStore, KVStoreSync, CHANNEL_MANAGER_PERSISTENCE_KEY, + CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE, CHANNEL_MANAGER_PERSISTENCE_SECONDARY_NAMESPACE, + CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE, CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE, + OUTPUT_SWEEPER_PERSISTENCE_KEY, OUTPUT_SWEEPER_PERSISTENCE_PRIMARY_NAMESPACE, + OUTPUT_SWEEPER_PERSISTENCE_SECONDARY_NAMESPACE, SCORER_PERSISTENCE_KEY, + SCORER_PERSISTENCE_PRIMARY_NAMESPACE, SCORER_PERSISTENCE_SECONDARY_NAMESPACE, }; -use lightning::util::ser::ReadableArgs; +use lightning::util::ser::{Readable, ReadableArgs}; use lightning::util::sweep::OutputSweeper; +use lightning::{log_info, log_trace, log_warn}; use lightning_persister::fs_store::FilesystemStore; use vss_client::headers::{FixedHeaders, LnurlAuthToJwtProvider, VssHeaderProvider}; use crate::chain::ChainSource; use crate::config::{ - default_user_config, may_announce_channel, AnnounceError, AsyncPaymentsRole, - BitcoindRestClientConfig, Config, ElectrumSyncConfig, EsploraSyncConfig, - DEFAULT_ESPLORA_SERVER_URL, DEFAULT_LOG_FILENAME, DEFAULT_LOG_LEVEL, WALLET_KEYS_SEED_LEN, + default_user_config, may_announce_channel, AddressType, AddressTypeRuntimeConfig, + AnnounceError, AsyncPaymentsRole, BitcoindRestClientConfig, Config, ElectrumSyncConfig, + EsploraSyncConfig, OnchainWalletAccount, RuntimeSyncIntervals, ScoringDecayParameters, + ScoringFeeParameters, BDK_CLIENT_STOP_GAP, DEFAULT_ESPLORA_SERVER_URL, DEFAULT_LOG_FILENAME, + DEFAULT_LOG_LEVEL, MAX_ONCHAIN_WALLET_ACCOUNT_INDEX, WALLET_KEYS_SEED_LEN, }; use crate::connection::ConnectionManager; use crate::event::EventQueue; use crate::fee_estimator::OnchainFeeEstimator; use crate::gossip::GossipSource; +use crate::io::local_graph_store::read_local_graph_cache; use crate::io::sqlite_store::SqliteStore; use crate::io::utils::{ - read_external_pathfinding_scores_from_cache, read_node_metrics, write_node_metrics, + read_network_graph, read_node_metrics, read_payments_async, write_node_metrics, + EXTERNAL_PATHFINDING_SCORES_CACHE_KEY, }; use crate::io::vss_store::VssStore; use crate::io::{ - self, PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE, PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE, + self, EVENT_QUEUE_PERSISTENCE_KEY, EVENT_QUEUE_PERSISTENCE_PRIMARY_NAMESPACE, + EVENT_QUEUE_PERSISTENCE_SECONDARY_NAMESPACE, PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE, + PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE, PEER_INFO_PERSISTENCE_KEY, + PEER_INFO_PERSISTENCE_PRIMARY_NAMESPACE, PEER_INFO_PERSISTENCE_SECONDARY_NAMESPACE, }; use crate::liquidity::{ LSPS1ClientConfig, LSPS2ClientConfig, LSPS2ServiceConfig, LiquiditySourceBuilder, @@ -65,15 +78,16 @@ use crate::liquidity::{ use crate::logger::{log_error, LdkLogger, LogLevel, LogWriter, Logger}; use crate::message_handler::NodeCustomMessageHandler; use crate::payment::asynchronous::om_mailbox::OnionMessageMailbox; -use crate::peer_store::PeerStore; +use crate::peer_store::{persist_missing_channel_peers, PeerStore}; use crate::runtime::Runtime; use crate::tx_broadcaster::TransactionBroadcaster; use crate::types::{ ChainMonitor, ChannelManager, DynStore, GossipSync, Graph, KeysManager, MessageRouter, - OnionMessenger, PaymentStore, PeerManager, Persister, + OnionMessenger, PaymentStore, PeerManager, Persister, Sweeper, }; use crate::wallet::persist::KVStoreWalletPersister; use crate::wallet::Wallet; +use crate::RgsPeerRecoveryExclusions; use crate::{Node, NodeMetrics}; const VSS_HARDENED_CHILD_INDEX: u32 = 877; @@ -101,6 +115,18 @@ enum ChainDataSourceConfig { }, } +fn derived_account_lookahead(chain_data_source_config: Option<&ChainDataSourceConfig>) -> u32 { + match chain_data_source_config { + Some(ChainDataSourceConfig::Electrum { sync_config, .. }) => { + sync_config.unwrap_or_default().additional_wallet_full_scan_stop_gap.max(1) + }, + Some(ChainDataSourceConfig::Bitcoind { .. }) => { + bdk_chain::keychain_txout::DEFAULT_LOOKAHEAD + }, + Some(ChainDataSourceConfig::Esplora { .. }) | None => BDK_CLIENT_STOP_GAP as u32, + } +} + #[derive(Debug, Clone)] enum EntropySourceConfig { SeedFile(String), @@ -136,6 +162,19 @@ enum LogWriterConfig { Custom(Arc), } +/// Channel data to migrate from an external LDK implementation (e.g., react-native-ldk). +/// +/// The data is written to the configured kv_store (including VSS) during the build process, +/// before channel monitors are read. The storage key for each monitor is derived by +/// deserializing the monitor and extracting the funding outpoint. +#[derive(Debug, Clone, Default)] +pub struct ChannelDataMigration { + /// Serialized ChannelManager bytes. + pub channel_manager: Option>, + /// Serialized channel monitor bytes. + pub channel_monitors: Vec>, +} + impl std::fmt::Debug for LogWriterConfig { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { @@ -157,7 +196,7 @@ impl std::fmt::Debug for LogWriterConfig { /// [`Node`]: crate::Node #[derive(Debug, Clone, PartialEq)] pub enum BuildError { - /// The given seed bytes are invalid, e.g., have invalid length. + /// The seed bytes or a seed-derived wallet configuration are invalid. InvalidSeedBytes, /// The given seed file is invalid, e.g., has invalid length, or could not be read. InvalidSeedFile, @@ -177,6 +216,9 @@ pub enum BuildError { /// /// [`KVStore`]: lightning::util::persist::KVStoreSync ReadFailed, + /// The deserialized channel data would be dangerous to use, typically because + /// channel monitors are stale compared to the channel manager. + DangerousValue, /// We failed to write data to the [`KVStore`]. /// /// [`KVStore`]: lightning::util::persist::KVStoreSync @@ -200,7 +242,9 @@ pub enum BuildError { impl fmt::Display for BuildError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - Self::InvalidSeedBytes => write!(f, "Given seed bytes are invalid."), + Self::InvalidSeedBytes => { + write!(f, "Given seed bytes or seed-derived wallet configuration are invalid.") + }, Self::InvalidSeedFile => write!(f, "Given seed file is invalid or could not be read."), Self::InvalidSystemTime => { write!(f, "System time is invalid. Clocks might have gone back in time.") @@ -214,6 +258,9 @@ impl fmt::Display for BuildError { }, Self::RuntimeSetupFailed => write!(f, "Failed to setup a runtime."), Self::ReadFailed => write!(f, "Failed to read from store."), + Self::DangerousValue => { + write!(f, "Deserialized channel data is dangerous to use (stale channel monitors).") + }, Self::WriteFailed => write!(f, "Failed to write to store."), Self::StoragePathAccessFailed => write!(f, "Failed to access the given storage path."), Self::KVStoreSetupFailed => write!(f, "Failed to setup KVStore."), @@ -253,6 +300,7 @@ pub struct NodeBuilder { async_payments_role: Option, runtime_handle: Option, pathfinding_scores_sync_config: Option, + channel_data_migration: Option, } impl NodeBuilder { @@ -271,6 +319,7 @@ impl NodeBuilder { let log_writer_config = None; let runtime_handle = None; let pathfinding_scores_sync_config = None; + let channel_data_migration = None; Self { config, entropy_source_config, @@ -281,6 +330,7 @@ impl NodeBuilder { runtime_handle, async_payments_role: None, pathfinding_scores_sync_config, + channel_data_migration, } } @@ -321,6 +371,18 @@ impl NodeBuilder { self } + /// Sets channel data to migrate from an external LDK implementation. + /// + /// Used when migrating from react-native-ldk or similar. The channel data is + /// written to the configured kv_store (including VSS) during build, before + /// channel monitors are read. Storage keys are derived from the monitor data. + /// + /// **Note:** The serialized data must be compatible with the current LDK version. + pub fn set_channel_data_migration(&mut self, migration: ChannelDataMigration) -> &mut Self { + self.channel_data_migration = Some(migration); + self + } + /// Configures the [`Node`] instance to source its chain data from the given Esplora server. /// /// If no `sync_config` is given, default values are used. See [`EsploraSyncConfig`] for more @@ -431,6 +493,18 @@ impl NodeBuilder { self } + /// Sets scorer fee parameters used for pathfinding penalties. + pub fn set_scoring_fee_params(&mut self, params: ScoringFeeParameters) -> &mut Self { + self.config.scoring_fee_params = Some(params); + self + } + + /// Sets scorer decay parameters used for liquidity estimate decay. + pub fn set_scoring_decay_params(&mut self, params: ScoringDecayParameters) -> &mut Self { + self.config.scoring_decay_params = Some(params); + self + } + /// Configures the [`Node`] instance to source inbound liquidity from the given /// [bLIP-51 / LSPS1] service. /// @@ -528,6 +602,30 @@ impl NodeBuilder { self } + /// Sets the primary address type for the on-chain wallet. + /// + /// This determines what type of addresses will be generated for new receiving and change + /// addresses. Default is [`AddressType::NativeSegwit`]. + pub fn set_address_type(&mut self, address_type: AddressType) -> &mut Self { + self.config.address_type = address_type; + self + } + + /// Sets additional address types to monitor for existing funds. + /// + /// These address types will be scanned alongside the primary address type during chain + /// synchronization. Useful when migrating from one address type to another — for example, + /// if switching from Legacy to NativeSegwit, add `Legacy` here to continue monitoring + /// old Legacy addresses. + /// + /// Default is empty (only the primary address type is monitored). + pub fn set_address_types_to_monitor( + &mut self, address_types_to_monitor: Vec, + ) -> &mut Self { + self.config.address_types_to_monitor = address_types_to_monitor; + self + } + /// Sets the IP address and TCP port on which [`Node`] will listen for incoming network connections. pub fn set_listening_addresses( &mut self, listening_addresses: Vec, @@ -748,6 +846,7 @@ impl NodeBuilder { runtime, logger, Arc::new(vss_store), + self.channel_data_migration.as_ref(), ) } @@ -782,6 +881,7 @@ impl NodeBuilder { runtime, logger, kv_store, + self.channel_data_migration.as_ref(), ) } } @@ -844,6 +944,13 @@ impl ArcedNodeBuilder { self.inner.write().unwrap().set_entropy_bip39_mnemonic(mnemonic, passphrase); } + /// Sets channel data to migrate from an external LDK implementation. + /// + /// See [`NodeBuilder::set_channel_data_migration`] for details. + pub fn set_channel_data_migration(&self, migration: ChannelDataMigration) { + self.inner.write().unwrap().set_channel_data_migration(migration); + } + /// Configures the [`Node`] instance to source its chain data from the given Esplora server. /// /// If no `sync_config` is given, default values are used. See [`EsploraSyncConfig`] for more @@ -943,6 +1050,16 @@ impl ArcedNodeBuilder { self.inner.write().unwrap().set_pathfinding_scores_source(url); } + /// Sets scorer fee parameters used for pathfinding penalties. + pub fn set_scoring_fee_params(&self, params: ScoringFeeParameters) { + self.inner.write().unwrap().set_scoring_fee_params(params); + } + + /// Sets scorer decay parameters used for liquidity estimate decay. + pub fn set_scoring_decay_params(&self, params: ScoringDecayParameters) { + self.inner.write().unwrap().set_scoring_decay_params(params); + } + /// Configures the [`Node`] instance to source inbound liquidity from the given /// [bLIP-51 / LSPS1] service. /// @@ -1016,6 +1133,16 @@ impl ArcedNodeBuilder { self.inner.write().unwrap().set_network(network); } + /// Sets the primary address type for the on-chain wallet. + pub fn set_address_type(&self, address_type: AddressType) { + self.inner.write().unwrap().set_address_type(address_type); + } + + /// Sets additional address types to monitor for existing funds. + pub fn set_address_types_to_monitor(&self, address_types_to_monitor: Vec) { + self.inner.write().unwrap().set_address_types_to_monitor(address_types_to_monitor); + } + /// Sets the IP address and TCP port on which [`Node`] will listen for incoming network connections. pub fn set_listening_addresses( &self, listening_addresses: Vec, @@ -1138,7 +1265,461 @@ impl ArcedNodeBuilder { } } -/// Builds a [`Node`] instance according to the options previously configured. +/// BIP coin type: `0'` for mainnet, `1'` for test networks. +pub(crate) fn bip_coin_type(network: Network) -> u32 { + match network { + Network::Bitcoin => 0, + _ => 1, + } +} + +/// Derives the account-level xprv at `m/purpose'/coin_type'/account_index'` and the +/// master fingerprint used in BIP descriptor origin metadata. +pub(crate) fn derive_account_xprv( + master_xprv: Xpriv, network: Network, address_type: AddressType, account_index: u32, +) -> Result<(Xpriv, bitcoin::bip32::Fingerprint), BuildError> { + let secp = Secp256k1::new(); + let master_fingerprint = master_xprv.fingerprint(&secp); + let account_path = account_derivation_path(address_type, network, account_index)?; + let account_xprv = + master_xprv.derive_priv(&secp, &account_path).map_err(|_| BuildError::InvalidSeedBytes)?; + Ok((account_xprv, master_fingerprint)) +} + +/// Derives the account-level xpub string for `(address_type, account_index)`. +pub(crate) fn derive_account_xpub_string( + master_xprv: Xpriv, network: Network, address_type: AddressType, account_index: u32, +) -> Result { + let secp = Secp256k1::new(); + let (account_xprv, _) = derive_account_xprv(master_xprv, network, address_type, account_index)?; + let account_xpub = Xpub::from_priv(&secp, &account_xprv); + Ok(account_xpub.to_string()) +} + +fn account_derivation_path( + address_type: AddressType, network: Network, account_index: u32, +) -> Result { + if account_index > MAX_ONCHAIN_WALLET_ACCOUNT_INDEX { + return Err(BuildError::InvalidSeedBytes); + } + let purpose = address_type.bip_purpose(); + let coin_type = bip_coin_type(network); + Ok(DerivationPath::from(vec![ + ChildNumber::from_hardened_idx(purpose).map_err(|_| BuildError::InvalidSeedBytes)?, + ChildNumber::from_hardened_idx(coin_type).map_err(|_| BuildError::InvalidSeedBytes)?, + ChildNumber::from_hardened_idx(account_index).map_err(|_| BuildError::InvalidSeedBytes)?, + ])) +} + +fn account_keychain_derivation_path( + address_type: AddressType, network: Network, account_index: u32, keychain: KeychainKind, +) -> Result { + let mut path = account_derivation_path(address_type, network, account_index)? + .into_iter() + .copied() + .collect::>(); + let keychain_index = match keychain { + KeychainKind::External => 0, + KeychainKind::Internal => 1, + }; + path.push( + ChildNumber::from_normal_idx(keychain_index).map_err(|_| BuildError::InvalidSeedBytes)?, + ); + Ok(path.into()) +} + +/// Loads or creates a BDK wallet for `wallet_account`. +/// +/// Returns `(wallet, loaded_from_store)` where `loaded_from_store` is `true` when an existing +/// persisted wallet was restored. +pub(crate) fn get_or_create_wallet_for_account( + wallet_account: OnchainWalletAccount, master_xprv: Xpriv, network: Network, + persister: &mut KVStoreWalletPersister, lookahead: Option, +) -> Result<(PersistedWallet, bool), BuildError> { + macro_rules! load_or_create { + ($ext:expr, $int:expr) => {{ + let mut load_params = BdkWallet::load() + .descriptor(KeychainKind::External, Some($ext)) + .descriptor(KeychainKind::Internal, Some($int)) + .extract_keys() + .check_network(network); + if let Some(lookahead) = lookahead { + load_params = load_params.lookahead(lookahead); + } + let wallet_opt = load_params.load_wallet(persister).map_err(|e| match e { + bdk_wallet::LoadWithPersistError::InvalidChangeSet( + bdk_wallet::LoadError::Mismatch(bdk_wallet::LoadMismatch::Network { + loaded, + expected, + }), + ) => { + log::error!( + "Failed to setup wallet: Networks do not match. Expected {} but got {}", + expected, + loaded + ); + BuildError::NetworkMismatch + }, + _ => { + log::error!("Failed to set up wallet: {}", e); + BuildError::WalletSetupFailed + }, + })?; + match wallet_opt { + Some(w) => Ok((w, true)), + None => { + let mut create_params = BdkWallet::create($ext, $int).network(network); + if let Some(lookahead) = lookahead { + create_params = create_params.lookahead(lookahead); + } + create_params + .create_wallet(persister) + .map(|w| (w, false)) + .map_err(|_| BuildError::WalletSetupFailed) + }, + } + }}; + } + + // Account 0 keeps the historical BipXX(master) templates for descriptor compatibility. + if wallet_account.account_index == 0 { + return match wallet_account.address_type { + AddressType::Legacy => load_or_create!( + Bip44(master_xprv, KeychainKind::External), + Bip44(master_xprv, KeychainKind::Internal) + ), + AddressType::NestedSegwit => load_or_create!( + Bip49(master_xprv, KeychainKind::External), + Bip49(master_xprv, KeychainKind::Internal) + ), + AddressType::NativeSegwit => load_or_create!( + Bip84(master_xprv, KeychainKind::External), + Bip84(master_xprv, KeychainKind::Internal) + ), + AddressType::Taproot => load_or_create!( + Bip86(master_xprv, KeychainKind::External), + Bip86(master_xprv, KeychainKind::Internal) + ), + }; + } + + if wallet_account.account_index > MAX_ONCHAIN_WALLET_ACCOUNT_INDEX { + return Err(BuildError::InvalidSeedBytes); + } + + // Use full master→account keychain paths so descriptor origin metadata includes the real + // account index (Bip*Public templates hard-code account `0'`). + let external_key = ( + master_xprv, + account_keychain_derivation_path( + wallet_account.address_type, + network, + wallet_account.account_index, + KeychainKind::External, + )?, + ); + let internal_key = ( + master_xprv, + account_keychain_derivation_path( + wallet_account.address_type, + network, + wallet_account.account_index, + KeychainKind::Internal, + )?, + ); + + match wallet_account.address_type { + AddressType::Legacy => { + load_or_create!(P2Pkh(external_key.clone()), P2Pkh(internal_key.clone())) + }, + AddressType::NestedSegwit => { + load_or_create!(P2Wpkh_P2Sh(external_key.clone()), P2Wpkh_P2Sh(internal_key.clone())) + }, + AddressType::NativeSegwit => { + load_or_create!(P2Wpkh(external_key.clone()), P2Wpkh(internal_key.clone())) + }, + AddressType::Taproot => { + load_or_create!(P2TR(external_key.clone()), P2TR(internal_key.clone())) + }, + } +} + +fn validate_configured_onchain_wallet_accounts( + config: &Config, xprv: Xpriv, +) -> Result, BuildError> { + let mut seen = HashSet::new(); + let mut accounts = Vec::new(); + for configured_account in &config.onchain_wallet_accounts { + let account_index = configured_account.account_index; + if account_index == 0 || account_index > MAX_ONCHAIN_WALLET_ACCOUNT_INDEX { + return Err(BuildError::InvalidSeedBytes); + } + + let account = + OnchainWalletAccount { address_type: configured_account.address_type, account_index }; + let expected_xpub = derive_account_xpub_string( + xprv, + config.network, + configured_account.address_type, + account_index, + )?; + if configured_account.xpub.trim() != expected_xpub { + return Err(BuildError::InvalidSeedBytes); + } + if seen.insert(account) { + accounts.push(account); + } + } + Ok(accounts) +} + +fn build_wallet_for_account( + config: &Config, wallet_account: OnchainWalletAccount, xprv: Xpriv, kv_store: Arc, + logger: Arc, chain_tip_opt: Option<&BestBlock>, lookahead: Option, +) -> Result< + (OnchainWalletAccount, PersistedWallet, KVStoreWalletPersister), + BuildError, +> { + let mut persister = + KVStoreWalletPersister::new(Arc::clone(&kv_store), Arc::clone(&logger), wallet_account); + + let (mut wallet, loaded_from_store) = get_or_create_wallet_for_account( + wallet_account, + xprv, + config.network, + &mut persister, + lookahead, + ) + .map_err(|e| { + log_error!(logger, "Failed to setup wallet for {:?}: {}", wallet_account, e); + e + })?; + + // Re-loaded wallets keep their persisted tip so chain backends can catch up. New wallets start + // at the known tip; Esplora and Electrum recover history independently with a full scan, while + // Bitcoind cannot recover confirmed pre-registration history. + if !loaded_from_store { + if let Some(best_block) = chain_tip_opt { + let mut checkpoint = wallet.latest_checkpoint(); + let block_id = + bdk_chain::BlockId { height: best_block.height, hash: best_block.block_hash }; + checkpoint = checkpoint.insert(block_id); + let update = bdk_wallet::Update { chain: Some(checkpoint), ..Default::default() }; + wallet.apply_update(update).map_err(|e| { + log_error!(logger, "Failed to apply checkpoint for {:?}: {}", wallet_account, e); + BuildError::WalletSetupFailed + })?; + } + } + + Ok((wallet_account, wallet, persister)) +} + +fn build_additional_wallets( + config: &Config, configured_accounts: &[OnchainWalletAccount], xprv: Xpriv, + kv_store: Arc, logger: Arc, chain_tip_opt: Option<&BestBlock>, + derived_account_lookahead: u32, +) -> Result< + Vec<(OnchainWalletAccount, PersistedWallet, KVStoreWalletPersister)>, + BuildError, +> { + let mut additional_wallets = Vec::new(); + + for address_type in config.additional_address_types() { + let wallet_account = OnchainWalletAccount::account_zero(address_type); + match build_wallet_for_account( + config, + wallet_account, + xprv, + Arc::clone(&kv_store), + Arc::clone(&logger), + chain_tip_opt, + None, + ) { + Ok(tuple) => { + log_info!(logger, "Created additional wallet for {:?}", tuple.0); + additional_wallets.push(tuple); + }, + Err(e) => { + log_error!( + logger, + "Failed to create additional wallet for {:?}: {}. Continuing without it.", + wallet_account, + e + ); + }, + } + } + + for &wallet_account in configured_accounts { + let wallet = build_wallet_for_account( + config, + wallet_account, + xprv, + Arc::clone(&kv_store), + Arc::clone(&logger), + chain_tip_opt, + Some(derived_account_lookahead), + )?; + log_info!(logger, "Loaded configured wallet for {:?}", wallet_account); + additional_wallets.push(wallet); + } + + Ok(additional_wallets) +} + +fn apply_channel_data_migration( + migration: &ChannelDataMigration, kv_store: &Arc, keys_manager: &K, + logger: &Arc, runtime: &Arc, +) -> Result<(), BuildError> +where + K: EntropySource + SignerProvider, +{ + if let Some(manager_bytes) = &migration.channel_manager { + // Skip if KV store already has a channel manager (existence-only check). + let should_write = match runtime.block_on(KVStore::read( + &**kv_store, + CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE, + CHANNEL_MANAGER_PERSISTENCE_SECONDARY_NAMESPACE, + CHANNEL_MANAGER_PERSISTENCE_KEY, + )) { + Ok(_existing_data) => { + log_warn!( + logger, + "Skipping channel manager migration: store already contains a channel manager" + ); + false + }, + Err(e) if e.kind() == lightning::io::ErrorKind::NotFound => true, + Err(e) => { + log_error!( + logger, + "Failed to read existing channel manager, refusing migration write \ + to avoid overwriting potentially newer state: {}", + e + ); + return Err(BuildError::ReadFailed); + }, + }; + + if should_write { + runtime + .block_on(async { + KVStore::write( + &**kv_store, + CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE, + CHANNEL_MANAGER_PERSISTENCE_SECONDARY_NAMESPACE, + CHANNEL_MANAGER_PERSISTENCE_KEY, + manager_bytes.clone(), + ) + .await + }) + .map_err(|e| { + log_error!(logger, "Failed to write migrated channel_manager: {}", e); + BuildError::WriteFailed + })?; + } + } + + for monitor_data in &migration.channel_monitors { + let mut reader = lightning::io::Cursor::new(monitor_data); + let (_, channel_monitor) = match <(BlockHash, ChannelMonitor)>::read( + &mut reader, + (keys_manager, keys_manager), + ) { + Ok(monitor) => monitor, + Err(e) => { + log_error!(logger, "Failed to deserialize channel_monitor: {:?}", e); + return Err(BuildError::ReadFailed); + }, + }; + + let funding_txo = channel_monitor.get_funding_txo(); + let monitor_key = format!("{}_{}", funding_txo.txid, funding_txo.index); + let migrated_update_id = channel_monitor.get_latest_update_id(); + log_info!( + logger, + "Migrating channel monitor: {} (update_id={})", + monitor_key, + migrated_update_id + ); + + // Check if the store already has a newer monitor to avoid overwriting + // current state with stale migration data. + let should_write = match runtime.block_on(KVStore::read( + &**kv_store, + CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE, + CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE, + &monitor_key, + )) { + Ok(existing_data) => { + let mut existing_reader = Cursor::new(&existing_data); + match <(BlockHash, ChannelMonitor)>::read( + &mut existing_reader, + (keys_manager, keys_manager), + ) { + Ok((_, existing_monitor)) => { + let existing_update_id = existing_monitor.get_latest_update_id(); + if existing_update_id >= migrated_update_id { + log_warn!( + logger, + "Skipping migration for monitor {}: existing update_id {} is newer than or equal to migrated update_id {}", + monitor_key, + existing_update_id, + migrated_update_id + ); + false + } else { + true + } + }, + Err(e) => { + log_warn!( + logger, + "Failed to deserialize existing monitor {}, skipping migration to avoid overwriting potentially newer state: {:?}", + monitor_key, + e + ); + false + }, + } + }, + Err(e) if e.kind() == lightning::io::ErrorKind::NotFound => true, + Err(e) => { + log_error!( + logger, + "Failed to read existing monitor {}, refusing migration write to avoid overwriting potentially newer state: {}", + monitor_key, + e + ); + return Err(BuildError::ReadFailed); + }, + }; + + if should_write { + runtime + .block_on(async { + KVStore::write( + &**kv_store, + CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE, + CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE, + &monitor_key, + monitor_data.clone(), + ) + .await + }) + .map_err(|e| { + log_error!(logger, "Failed to write channel_monitor {}: {}", monitor_key, e); + BuildError::WriteFailed + })?; + } + } + + log_info!(logger, "Applied channel migration: {} monitors", migration.channel_monitors.len()); + + Ok(()) +} + fn build_with_store_internal( config: Arc, chain_data_source_config: Option<&ChainDataSourceConfig>, gossip_source_config: Option<&GossipSourceConfig>, @@ -1146,6 +1727,7 @@ fn build_with_store_internal( pathfinding_scores_sync_config: Option<&PathfindingScoresSyncConfig>, async_payments_role: Option, seed_bytes: [u8; 64], runtime: Arc, logger: Arc, kv_store: Arc, + channel_data_migration: Option<&ChannelDataMigration>, ) -> Result { optionally_install_rustls_cryptoprovider(); @@ -1166,10 +1748,56 @@ fn build_with_store_internal( } } - // Initialize the status fields. - let node_metrics = match read_node_metrics(Arc::clone(&kv_store), Arc::clone(&logger)) { - Ok(metrics) => Arc::new(RwLock::new(metrics)), - Err(e) => { + // Prepare wallet components (instant operations) before parallel VSS reads + let xprv = bitcoin::bip32::Xpriv::new_master(config.network, &seed_bytes).map_err(|e| { + log_error!(logger, "Failed to derive master secret: {}", e); + BuildError::InvalidSeedBytes + })?; + let configured_accounts = validate_configured_onchain_wallet_accounts(&config, xprv)?; + let derived_account_lookahead = derived_account_lookahead(chain_data_source_config); + + let tx_broadcaster = Arc::new(TransactionBroadcaster::new(Arc::clone(&logger))); + let fee_estimator = Arc::new(OnchainFeeEstimator::new()); + + // Execute VSS reads in parallel: node_metrics, payments, and wallet + let (node_metrics_result, payments_result, wallet_result) = runtime.block_on(async { + let metrics_store = Arc::clone(&kv_store); + let metrics_logger = Arc::clone(&logger); + + let payments_store = Arc::clone(&kv_store); + let payments_logger = Arc::clone(&logger); + + let wallet_store = Arc::clone(&kv_store); + let wallet_logger: Arc = Arc::clone(&logger); + + tokio::join!( + tokio::task::spawn_blocking(move || read_node_metrics(metrics_store, metrics_logger)), + read_payments_async(payments_store, payments_logger), + tokio::task::spawn_blocking({ + let network = config.network; + let address_type = config.address_type; + move || { + let wallet_account = OnchainWalletAccount::account_zero(address_type); + let mut persister = + KVStoreWalletPersister::new(wallet_store, wallet_logger, wallet_account); + let result = get_or_create_wallet_for_account( + wallet_account, + xprv, + network, + &mut persister, + None, + ) + .map(|(wallet, _loaded)| wallet); + (result, persister) + } + }) + ) + }); + + // Process node_metrics result + let node_metrics = match node_metrics_result { + Ok(Ok(metrics)) => Arc::new(RwLock::new(metrics)), + Ok(Err(e)) => { if e.kind() == std::io::ErrorKind::NotFound { Arc::new(RwLock::new(NodeMetrics::default())) } else { @@ -1177,11 +1805,14 @@ fn build_with_store_internal( return Err(BuildError::ReadFailed); } }, + Err(e) => { + log_error!(logger, "Task join error reading node metrics: {}", e); + return Err(BuildError::ReadFailed); + }, }; - let tx_broadcaster = Arc::new(TransactionBroadcaster::new(Arc::clone(&logger))); - let fee_estimator = Arc::new(OnchainFeeEstimator::new()); - let payment_store = match io::utils::read_payments(Arc::clone(&kv_store), Arc::clone(&logger)) { + // Process payments result + let payment_store = match payments_result { Ok(payments) => Arc::new(PaymentStore::new( payments, PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE.to_string(), @@ -1195,6 +1826,22 @@ fn build_with_store_internal( }, }; + // Process wallet result + let (wallet_load_result, wallet_persister) = match wallet_result { + Ok(result) => result, + Err(e) => { + log_error!(logger, "Task join error loading wallet: {}", e); + return Err(BuildError::WalletSetupFailed); + }, + }; + let bdk_wallet_loaded = wallet_load_result?; + + let address_type_runtime_config = Arc::new(RwLock::new(AddressTypeRuntimeConfig::from_config( + &config, + configured_accounts.clone(), + ))); + + // Chain source setup let (chain_source, chain_tip_opt) = match chain_data_source_config { Some(ChainDataSourceConfig::Esplora { server_url, headers, sync_config }) => { let sync_config = sync_config.unwrap_or(EsploraSyncConfig::default()); @@ -1206,6 +1853,7 @@ fn build_with_store_internal( Arc::clone(&tx_broadcaster), Arc::clone(&kv_store), Arc::clone(&config), + Arc::clone(&address_type_runtime_config), Arc::clone(&logger), Arc::clone(&node_metrics), ) @@ -1219,6 +1867,7 @@ fn build_with_store_internal( Arc::clone(&tx_broadcaster), Arc::clone(&kv_store), Arc::clone(&config), + Arc::clone(&address_type_runtime_config), Arc::clone(&logger), Arc::clone(&node_metrics), ) @@ -1275,6 +1924,7 @@ fn build_with_store_internal( Arc::clone(&tx_broadcaster), Arc::clone(&kv_store), Arc::clone(&config), + Arc::clone(&address_type_runtime_config), Arc::clone(&logger), Arc::clone(&node_metrics), ) @@ -1282,79 +1932,43 @@ fn build_with_store_internal( }; let chain_source = Arc::new(chain_source); - // Initialize the on-chain wallet and chain access - let xprv = bitcoin::bip32::Xpriv::new_master(config.network, &seed_bytes).map_err(|e| { - log_error!(logger, "Failed to derive master secret: {}", e); - BuildError::InvalidSeedBytes - })?; - - let descriptor = Bip84(xprv, KeychainKind::External); - let change_descriptor = Bip84(xprv, KeychainKind::Internal); - let mut wallet_persister = - KVStoreWalletPersister::new(Arc::clone(&kv_store), Arc::clone(&logger)); - let wallet_opt = BdkWallet::load() - .descriptor(KeychainKind::External, Some(descriptor.clone())) - .descriptor(KeychainKind::Internal, Some(change_descriptor.clone())) - .extract_keys() - .check_network(config.network) - .load_wallet(&mut wallet_persister) - .map_err(|e| match e { - bdk_wallet::LoadWithPersistError::InvalidChangeSet( - bdk_wallet::LoadError::Mismatch(bdk_wallet::LoadMismatch::Network { - loaded, - expected, - }), - ) => { - log_error!( - logger, - "Failed to setup wallet: Networks do not match. Expected {} but got {}", - expected, - loaded - ); - BuildError::NetworkMismatch - }, - _ => { - log_error!(logger, "Failed to set up wallet: {}", e); - BuildError::WalletSetupFailed - }, + let mut bdk_wallet = bdk_wallet_loaded; + if let Some(best_block) = chain_tip_opt { + let mut latest_checkpoint = bdk_wallet.latest_checkpoint(); + let block_id = + bdk_chain::BlockId { height: best_block.height, hash: best_block.block_hash }; + latest_checkpoint = latest_checkpoint.insert(block_id); + let update = bdk_wallet::Update { chain: Some(latest_checkpoint), ..Default::default() }; + bdk_wallet.apply_update(update).map_err(|e| { + log_error!(logger, "Failed to apply checkpoint during wallet setup: {}", e); + BuildError::WalletSetupFailed })?; - let bdk_wallet = match wallet_opt { - Some(wallet) => wallet, - None => { - let mut wallet = BdkWallet::create(descriptor, change_descriptor) - .network(config.network) - .create_wallet(&mut wallet_persister) - .map_err(|e| { - log_error!(logger, "Failed to set up wallet: {}", e); - BuildError::WalletSetupFailed - })?; + } - if let Some(best_block) = chain_tip_opt { - // Insert the first checkpoint if we have it, to avoid resyncing from genesis. - // TODO: Use a proper wallet birthday once BDK supports it. - let mut latest_checkpoint = wallet.latest_checkpoint(); - let block_id = - bdk_chain::BlockId { height: best_block.height, hash: best_block.block_hash }; - latest_checkpoint = latest_checkpoint.insert(block_id); - let update = - bdk_wallet::Update { chain: Some(latest_checkpoint), ..Default::default() }; - wallet.apply_update(update).map_err(|e| { - log_error!(logger, "Failed to apply checkpoint during wallet setup: {}", e); - BuildError::WalletSetupFailed - })?; - } - wallet - }, - }; + let additional_wallets = build_additional_wallets( + &config, + &configured_accounts, + xprv, + Arc::clone(&kv_store), + Arc::clone(&logger), + chain_tip_opt.as_ref(), + derived_account_lookahead, + )?; let wallet = Arc::new(Wallet::new( bdk_wallet, wallet_persister, + additional_wallets, + seed_bytes, Arc::clone(&tx_broadcaster), Arc::clone(&fee_estimator), Arc::clone(&payment_store), Arc::clone(&config), + Arc::clone(&kv_store), + Arc::clone(&address_type_runtime_config), + Arc::clone(&node_metrics), Arc::clone(&logger), + derived_account_lookahead, )); // Initialize the KeysManager @@ -1383,10 +1997,100 @@ fn build_with_store_internal( Arc::clone(&fee_estimator), )); - // Read ChannelMonitor state from store - let channel_monitors = match persister.read_all_channel_monitors_with_updates() { - Ok(monitors) => monitors, - Err(e) => { + if let Some(migration) = channel_data_migration { + apply_channel_data_migration(migration, &kv_store, &*keys_manager, &logger, &runtime)?; + } + + // Initialize the network graph from local cache, with VSS fallback for migration. + let (network_graph, local_rgs_timestamp) = + match read_local_graph_cache(&config.storage_dir_path, Arc::clone(&logger)) { + Ok(cache_data) => { + log_trace!( + logger, + "Loaded network graph from local cache with RGS timestamp {}", + cache_data.rgs_timestamp + ); + (Arc::new(cache_data.graph), Arc::new(AtomicU32::new(cache_data.rgs_timestamp))) + }, + Err(e) if e.kind() == std::io::ErrorKind::NotFound => { + // Local cache doesn't exist, try VSS as fallback for migration. + log_trace!( + logger, + "Local graph cache not found, trying VSS fallback for migration" + ); + match read_network_graph(Arc::clone(&kv_store), Arc::clone(&logger)) { + Ok(graph) => { + let timestamp = + node_metrics.read().unwrap().latest_rgs_snapshot_timestamp.unwrap_or(0); + log_info!( + logger, + "Migrated network graph from VSS to local cache (RGS timestamp: {})", + timestamp + ); + (Arc::new(graph), Arc::new(AtomicU32::new(timestamp))) + }, + Err(e) if e.kind() == std::io::ErrorKind::NotFound => { + // New user, create empty graph. RGS will download full snapshot. + log_trace!(logger, "No network graph found, creating empty graph"); + ( + Arc::new(Graph::new(config.network.into(), Arc::clone(&logger))), + Arc::new(AtomicU32::new(0)), + ) + }, + Err(e) => { + log_error!(logger, "Failed to read network graph from VSS: {}", e); + return Err(BuildError::ReadFailed); + }, + } + }, + Err(e) => { + // Local cache is invalid. Start fresh to avoid graph/timestamp mismatch. + log_error!( + logger, + "Local graph cache invalid: {}, starting fresh with empty graph", + e + ); + ( + Arc::new(Graph::new(config.network.into(), Arc::clone(&logger))), + Arc::new(AtomicU32::new(0)), + ) + }, + }; + + // Read channel monitors and scorer data in parallel + let (monitors_result, scorer_data_res, external_scores_data_res) = { + let persister_clone = Arc::clone(&persister); + let store1 = Arc::clone(&kv_store); + let store2 = Arc::clone(&kv_store); + + runtime.block_on(async { + tokio::join!( + // Task 1: read channel monitors (blocking) + tokio::task::spawn_blocking(move || { + persister_clone.read_all_channel_monitors_with_updates() + }), + // Task 2: read scorer (async) + KVStore::read( + &*store1, + SCORER_PERSISTENCE_PRIMARY_NAMESPACE, + SCORER_PERSISTENCE_SECONDARY_NAMESPACE, + SCORER_PERSISTENCE_KEY, + ), + // Task 3: read external scores (async) + KVStore::read( + &*store2, + SCORER_PERSISTENCE_PRIMARY_NAMESPACE, + SCORER_PERSISTENCE_SECONDARY_NAMESPACE, + EXTERNAL_PATHFINDING_SCORES_CACHE_KEY, + ), + ) + }) + }; + + // Process channel monitors result + let channel_monitors = match monitors_result { + Ok(Ok(monitors)) => monitors, + Ok(Err(e)) => { if e.kind() == lightning::io::ErrorKind::NotFound { Vec::new() } else { @@ -1394,6 +2098,10 @@ fn build_with_store_internal( return Err(BuildError::ReadFailed); } }, + Err(e) => { + log_error!(logger, "Channel monitors read task failed: {}", e); + return Err(BuildError::ReadFailed); + }, }; // Initialize the ChainMonitor @@ -1407,54 +2115,64 @@ fn build_with_store_internal( peer_storage_key, )); - // Initialize the network graph, scorer, and router - let network_graph = - match io::utils::read_network_graph(Arc::clone(&kv_store), Arc::clone(&logger)) { - Ok(graph) => Arc::new(graph), - Err(e) => { - if e.kind() == std::io::ErrorKind::NotFound { - Arc::new(Graph::new(config.network.into(), Arc::clone(&logger))) - } else { - log_error!(logger, "Failed to read network graph from store: {}", e); + // Deserialize scorer + let scoring_decay_params = config + .scoring_decay_params + .clone() + .map(ProbabilisticScoringDecayParameters::from) + .unwrap_or_else(ProbabilisticScoringDecayParameters::default); + let local_scorer = match scorer_data_res { + Ok(data) => { + let mut reader = Cursor::new(data); + let args = (scoring_decay_params, Arc::clone(&network_graph), Arc::clone(&logger)); + match ProbabilisticScorer::read(&mut reader, args) { + Ok(scorer) => scorer, + Err(e) => { + log_error!(logger, "Failed to deserialize scorer: {}", e); return Err(BuildError::ReadFailed); - } - }, - }; - - let local_scorer = match io::utils::read_scorer( - Arc::clone(&kv_store), - Arc::clone(&network_graph), - Arc::clone(&logger), - ) { - Ok(scorer) => scorer, - Err(e) => { - if e.kind() == std::io::ErrorKind::NotFound { - let params = ProbabilisticScoringDecayParameters::default(); - ProbabilisticScorer::new(params, Arc::clone(&network_graph), Arc::clone(&logger)) - } else { - log_error!(logger, "Failed to read scoring data from store: {}", e); - return Err(BuildError::ReadFailed); + }, } }, + Err(e) if e.kind() == lightning::io::ErrorKind::NotFound => ProbabilisticScorer::new( + scoring_decay_params, + Arc::clone(&network_graph), + Arc::clone(&logger), + ), + Err(e) => { + log_error!(logger, "Failed to read scoring data from store: {}", e); + return Err(BuildError::ReadFailed); + }, }; let scorer = Arc::new(Mutex::new(CombinedScorer::new(local_scorer))); - // Restore external pathfinding scores from cache if possible. - match read_external_pathfinding_scores_from_cache(Arc::clone(&kv_store), Arc::clone(&logger)) { - Ok(external_scores) => { - scorer.lock().unwrap().merge(external_scores, cur_time); - log_trace!(logger, "External scores from cache merged successfully"); + // Deserialize and merge external pathfinding scores + match external_scores_data_res { + Ok(data) => { + let mut reader = Cursor::new(data); + match ChannelLiquidities::read(&mut reader) { + Ok(external_scores) => { + scorer.lock().unwrap().merge(external_scores, cur_time); + log_trace!(logger, "External scores from cache merged successfully"); + }, + Err(e) => { + log_error!(logger, "Failed to deserialize external scores: {}", e); + return Err(BuildError::ReadFailed); + }, + } }, + Err(e) if e.kind() == lightning::io::ErrorKind::NotFound => {}, Err(e) => { - if e.kind() != std::io::ErrorKind::NotFound { - log_error!(logger, "Error while reading external scores from cache: {}", e); - return Err(BuildError::ReadFailed); - } + log_error!(logger, "Error while reading external scores from cache: {}", e); + return Err(BuildError::ReadFailed); }, } - let scoring_fee_params = ProbabilisticScoringFeeParameters::default(); + let scoring_fee_params = config + .scoring_fee_params + .clone() + .map(ProbabilisticScoringFeeParameters::from) + .unwrap_or_else(ProbabilisticScoringFeeParameters::default); let router = Arc::new(DefaultRouter::new( Arc::clone(&network_graph), Arc::clone(&logger), @@ -1518,8 +2236,18 @@ fn build_with_store_internal( ); let (_hash, channel_manager) = <(BlockHash, ChannelManager)>::read(&mut reader, read_args).map_err(|e| { - log_error!(logger, "Failed to read channel manager from store: {}", e); - BuildError::ReadFailed + if matches!(e, lightning::ln::msgs::DecodeError::DangerousValue) { + log_error!( + logger, + "Channel manager deserialization returned DangerousValue \ + (stale channel monitors): {}", + e + ); + BuildError::DangerousValue + } else { + log_error!(logger, "Failed to read channel manager from store: {}", e); + BuildError::ReadFailed + } })?; channel_manager } else { @@ -1610,16 +2338,12 @@ fn build_with_store_internal( } p2p_source }, - GossipSourceConfig::RapidGossipSync(rgs_server) => { - let latest_sync_timestamp = - node_metrics.read().unwrap().latest_rgs_snapshot_timestamp.unwrap_or(0); - Arc::new(GossipSource::new_rgs( - rgs_server.clone(), - latest_sync_timestamp, - Arc::clone(&network_graph), - Arc::clone(&logger), - )) - }, + GossipSourceConfig::RapidGossipSync(rgs_server) => Arc::new(GossipSource::new_rgs( + rgs_server.clone(), + Arc::clone(&local_rgs_timestamp), + Arc::clone(&network_graph), + Arc::clone(&logger), + )), }; let (liquidity_source, custom_message_handler) = @@ -1722,17 +2446,59 @@ fn build_with_store_internal( let connection_manager = Arc::new(ConnectionManager::new(Arc::clone(&peer_manager), Arc::clone(&logger))); - let output_sweeper = match io::utils::read_output_sweeper( - Arc::clone(&tx_broadcaster), - Arc::clone(&fee_estimator), - Arc::clone(&chain_source), - Arc::clone(&keys_manager), - Arc::clone(&kv_store), - Arc::clone(&logger), - ) { - Ok(output_sweeper) => Arc::new(output_sweeper), + // Read output_sweeper, event_queue, and peer_store in parallel + let (output_sweeper_res, event_queue_res, peer_store_res) = { + let store1 = Arc::clone(&kv_store); + let store2 = Arc::clone(&kv_store); + let store3 = Arc::clone(&kv_store); + + runtime.block_on(async { + let sweeper_fut = KVStore::read( + &*store1, + OUTPUT_SWEEPER_PERSISTENCE_PRIMARY_NAMESPACE, + OUTPUT_SWEEPER_PERSISTENCE_SECONDARY_NAMESPACE, + OUTPUT_SWEEPER_PERSISTENCE_KEY, + ); + let event_queue_fut = KVStore::read( + &*store2, + EVENT_QUEUE_PERSISTENCE_PRIMARY_NAMESPACE, + EVENT_QUEUE_PERSISTENCE_SECONDARY_NAMESPACE, + EVENT_QUEUE_PERSISTENCE_KEY, + ); + let peer_store_fut = KVStore::read( + &*store3, + PEER_INFO_PERSISTENCE_PRIMARY_NAMESPACE, + PEER_INFO_PERSISTENCE_SECONDARY_NAMESPACE, + PEER_INFO_PERSISTENCE_KEY, + ); + + tokio::join!(sweeper_fut, event_queue_fut, peer_store_fut) + }) + }; + + // Process output_sweeper result + let output_sweeper = match output_sweeper_res { + Ok(data) => { + let mut reader = lightning::io::Cursor::new(data); + let args = ( + Arc::clone(&tx_broadcaster), + Arc::clone(&fee_estimator), + Some(Arc::clone(&chain_source)), + Arc::clone(&keys_manager), + Arc::clone(&keys_manager), + Arc::clone(&kv_store), + Arc::clone(&logger), + ); + match <(_, Sweeper)>::read(&mut reader, args) { + Ok((_, sweeper)) => Arc::new(sweeper), + Err(e) => { + log_error!(logger, "Failed to deserialize OutputSweeper: {}", e); + return Err(BuildError::ReadFailed); + }, + } + }, Err(e) => { - if e.kind() == std::io::ErrorKind::NotFound { + if e.kind() == lightning::io::ErrorKind::NotFound { Arc::new(OutputSweeper::new( channel_manager.current_best_block(), Arc::clone(&tx_broadcaster), @@ -1750,11 +2516,20 @@ fn build_with_store_internal( }, }; - let event_queue = match io::utils::read_event_queue(Arc::clone(&kv_store), Arc::clone(&logger)) - { - Ok(event_queue) => Arc::new(event_queue), + // Process event_queue result + let event_queue = match event_queue_res { + Ok(data) => { + let mut reader = lightning::io::Cursor::new(data); + match EventQueue::read(&mut reader, (Arc::clone(&kv_store), Arc::clone(&logger))) { + Ok(queue) => Arc::new(queue), + Err(e) => { + log_error!(logger, "Failed to deserialize EventQueue: {}", e); + return Err(BuildError::ReadFailed); + }, + } + }, Err(e) => { - if e.kind() == std::io::ErrorKind::NotFound { + if e.kind() == lightning::io::ErrorKind::NotFound { Arc::new(EventQueue::new(Arc::clone(&kv_store), Arc::clone(&logger))) } else { log_error!(logger, "Failed to read event queue from store: {}", e); @@ -1763,10 +2538,20 @@ fn build_with_store_internal( }, }; - let peer_store = match io::utils::read_peer_info(Arc::clone(&kv_store), Arc::clone(&logger)) { - Ok(peer_store) => Arc::new(peer_store), + // Process peer_store result + let peer_store = match peer_store_res { + Ok(data) => { + let mut reader = lightning::io::Cursor::new(data); + match PeerStore::read(&mut reader, (Arc::clone(&kv_store), Arc::clone(&logger))) { + Ok(store) => Arc::new(store), + Err(e) => { + log_error!(logger, "Failed to deserialize PeerStore: {}", e); + return Err(BuildError::ReadFailed); + }, + } + }, Err(e) => { - if e.kind() == std::io::ErrorKind::NotFound { + if e.kind() == lightning::io::ErrorKind::NotFound { Arc::new(PeerStore::new(Arc::clone(&kv_store), Arc::clone(&logger))) } else { log_error!(logger, "Failed to read peer data from store: {}", e); @@ -1775,6 +2560,13 @@ fn build_with_store_internal( }, }; + runtime.block_on(persist_missing_channel_peers( + channel_manager.list_channels().into_iter().map(|channel| channel.counterparty.node_id), + &network_graph, + &peer_store, + Arc::clone(&logger), + )); + let om_mailbox = if let Some(AsyncPaymentsRole::Server) = async_payments_role { Some(Arc::new(OnionMessageMailbox::new())) } else { @@ -1813,11 +2605,14 @@ fn build_with_store_internal( _router: router, scorer, peer_store, + rgs_peer_recovery_exclusions: Arc::new(RgsPeerRecoveryExclusions::default()), payment_store, is_running, node_metrics, om_mailbox, async_payments_role, + runtime_sync_intervals: Arc::new(RwLock::new(RuntimeSyncIntervals::default())), + local_rgs_timestamp, }) } @@ -1926,7 +2721,37 @@ pub(crate) fn sanitize_alias(alias_str: &str) -> Result { #[cfg(test)] mod tests { - use super::{sanitize_alias, BuildError, NodeAlias}; + use std::future::Future; + use std::pin::Pin; + use std::sync::Arc; + + use bitcoin::bip32::Xpriv; + use bitcoin::Network; + use lightning::io; + use lightning::ln::functional_test_utils::{ + create_announced_chan_between_nodes, create_chanmon_cfgs, create_network, create_node_cfgs, + create_node_chanmgrs, + }; + use lightning::sign::KeysManager as LdkKeysManager; + use lightning::util::persist::{ + KVStore, KVStoreSync, CHANNEL_MANAGER_PERSISTENCE_KEY, + CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE, + CHANNEL_MANAGER_PERSISTENCE_SECONDARY_NAMESPACE, + CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE, + CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE, + }; + use lightning::util::ser::Writeable; + + use super::{ + apply_channel_data_migration, derive_account_xpub_string, sanitize_alias, + validate_configured_onchain_wallet_accounts, BuildError, ChannelDataMigration, Config, + NodeAlias, NodeBuilder, ScoringDecayParameters, ScoringFeeParameters, + }; + use crate::config::{AddressType, OnchainWalletAccountConfig}; + use crate::io::test_utils::InMemoryStore; + use crate::logger::Logger; + use crate::runtime::Runtime; + use crate::types::DynStore; #[test] fn sanitize_empty_node_alias() { @@ -1963,4 +2788,544 @@ mod tests { let node = sanitize_alias(alias); assert_eq!(node.err().unwrap(), BuildError::InvalidNodeAlias); } + + #[test] + fn validates_and_deduplicates_configured_onchain_wallet_accounts() { + let xprv = Xpriv::new_master(Network::Regtest, &[42; 64]).unwrap(); + let xpub = + derive_account_xpub_string(xprv, Network::Regtest, AddressType::Taproot, 1).unwrap(); + let configured = OnchainWalletAccountConfig { + address_type: AddressType::Taproot, + account_index: 1, + xpub, + }; + let mut config = Config::default(); + config.network = Network::Regtest; + config.onchain_wallet_accounts = vec![configured.clone(), configured]; + + let accounts = validate_configured_onchain_wallet_accounts(&config, xprv).unwrap(); + assert_eq!(accounts.len(), 1); + assert_eq!(accounts[0].address_type, AddressType::Taproot); + assert_eq!(accounts[0].account_index, 1); + + config.onchain_wallet_accounts[0].xpub = "wrong xpub".to_string(); + assert_eq!( + validate_configured_onchain_wallet_accounts(&config, xprv), + Err(BuildError::InvalidSeedBytes) + ); + + config.onchain_wallet_accounts[0].account_index = 0; + assert_eq!( + validate_configured_onchain_wallet_accounts(&config, xprv), + Err(BuildError::InvalidSeedBytes) + ); + } + + #[test] + fn build_rejects_configured_account_xpub_from_another_seed() { + let foreign_xprv = Xpriv::new_master(Network::Regtest, &[43; 64]).unwrap(); + let foreign_xpub = derive_account_xpub_string( + foreign_xprv, + Network::Regtest, + AddressType::NativeSegwit, + 1, + ) + .unwrap(); + let mut config = Config::default(); + config.network = Network::Regtest; + config.onchain_wallet_accounts = vec![OnchainWalletAccountConfig { + address_type: AddressType::NativeSegwit, + account_index: 1, + xpub: foreign_xpub, + }]; + let mut builder = NodeBuilder::from_config(config); + builder.set_entropy_seed_bytes([42; 64]); + builder.set_log_facade_logger(); + let store: Arc = Arc::new(InMemoryStore::new()); + + assert!(matches!(builder.build_with_store(store), Err(BuildError::InvalidSeedBytes))); + } + + #[test] + fn set_scoring_params_updates_builder_config() { + let mut builder = NodeBuilder::from_config(Config::default()); + let fee_params = ScoringFeeParameters { + base_penalty_msat: 2_000, + base_penalty_amount_multiplier_msat: 200_000, + liquidity_penalty_multiplier_msat: 1, + liquidity_penalty_amount_multiplier_msat: 2, + historical_liquidity_penalty_multiplier_msat: 20_000, + historical_liquidity_penalty_amount_multiplier_msat: 2_500, + anti_probing_penalty_msat: 500, + considered_impossible_penalty_msat: 999_999, + linear_success_probability: true, + probing_diversity_penalty_msat: 321, + }; + let decay_params = ScoringDecayParameters { + historical_no_updates_half_life_secs: 1_234, + liquidity_offset_half_life_secs: 567, + }; + + builder.set_scoring_fee_params(fee_params.clone()); + builder.set_scoring_decay_params(decay_params.clone()); + + assert_eq!( + builder.config.scoring_fee_params.as_ref().unwrap().base_penalty_msat, + fee_params.base_penalty_msat + ); + assert_eq!( + builder.config.scoring_fee_params.as_ref().unwrap().linear_success_probability, + fee_params.linear_success_probability + ); + assert_eq!( + builder + .config + .scoring_decay_params + .as_ref() + .unwrap() + .historical_no_updates_half_life_secs, + decay_params.historical_no_updates_half_life_secs + ); + } + + /// Creates valid serialized (BlockHash, ChannelMonitor) bytes for testing. + /// + /// Uses LDK's functional test utilities to create a real channel between two + /// nodes, then serializes one of the resulting channel monitors. Returns the + /// seed used for node 0's KeysManager so callers can create a matching + /// KeysManager for deserialization. + /// + /// Returns (monitor_bytes, monitor_key, update_id, seed). + fn create_test_monitor_bytes() -> (Vec, String, u64, [u8; 32]) { + let chanmon_cfgs = create_chanmon_cfgs(2); + let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); + let nodes = create_network(2, &node_cfgs, &node_chanmgrs); + + let _ = create_announced_chan_between_nodes(&nodes, 0, 1); + + let channel_id = nodes[0].node.list_channels()[0].channel_id; + let monitor = nodes[0].chain_monitor.chain_monitor.get_monitor(channel_id).unwrap(); + + let funding_txo = monitor.get_funding_txo(); + let monitor_key = format!("{}_{}", funding_txo.txid, funding_txo.index); + let update_id = monitor.get_latest_update_id(); + + let seed = nodes[0].node_seed; + let mut serialized = Vec::new(); + monitor.write(&mut serialized).unwrap(); + + (serialized, monitor_key, update_id, seed) + } + + fn make_test_deps( + seed: &[u8; 32], + ) -> (Arc, LdkKeysManager, Arc, Arc) { + let store: Arc = Arc::new(InMemoryStore::new()); + let keys_manager = LdkKeysManager::new(seed, 0, 0, false); + let logger = Arc::new(Logger::new_log_facade()); + let runtime = Arc::new(Runtime::new(Arc::clone(&logger)).unwrap()); + (store, keys_manager, logger, runtime) + } + + /// A KVStore wrapper that returns IO errors for reads from the channel + /// monitor namespace, simulating a storage backend failure. + struct FailingReadStore; + + impl KVStore for FailingReadStore { + fn read( + &self, _primary_namespace: &str, _secondary_namespace: &str, _key: &str, + ) -> Pin, io::Error>> + 'static + Send>> { + Box::pin(async { + Err(io::Error::new(io::ErrorKind::ConnectionReset, "simulated IO error")) + }) + } + + fn write( + &self, _primary_namespace: &str, _secondary_namespace: &str, _key: &str, _buf: Vec, + ) -> Pin> + 'static + Send>> { + Box::pin(async { Ok(()) }) + } + + fn remove( + &self, _primary_namespace: &str, _secondary_namespace: &str, _key: &str, _lazy: bool, + ) -> Pin> + 'static + Send>> { + Box::pin(async { Ok(()) }) + } + + fn list( + &self, _primary_namespace: &str, _secondary_namespace: &str, + ) -> Pin, io::Error>> + 'static + Send>> { + Box::pin(async { Ok(Vec::new()) }) + } + } + + impl KVStoreSync for FailingReadStore { + fn read( + &self, _primary_namespace: &str, _secondary_namespace: &str, _key: &str, + ) -> io::Result> { + Err(io::Error::new(io::ErrorKind::ConnectionReset, "simulated IO error")) + } + + fn write( + &self, _primary_namespace: &str, _secondary_namespace: &str, _key: &str, _buf: Vec, + ) -> io::Result<()> { + Ok(()) + } + + fn remove( + &self, _primary_namespace: &str, _secondary_namespace: &str, _key: &str, _lazy: bool, + ) -> io::Result<()> { + Ok(()) + } + + fn list( + &self, _primary_namespace: &str, _secondary_namespace: &str, + ) -> io::Result> { + Ok(Vec::new()) + } + } + + unsafe impl Sync for FailingReadStore {} + unsafe impl Send for FailingReadStore {} + + #[test] + fn test_migration_invalid_monitor_data_returns_read_failed() { + let (store, keys_manager, logger, runtime) = make_test_deps(&[42u8; 32]); + let migration = ChannelDataMigration { + channel_manager: None, + channel_monitors: vec![vec![0xDE, 0xAD, 0xBE, 0xEF]], + }; + + let result = + apply_channel_data_migration(&migration, &store, &keys_manager, &logger, &runtime); + assert_eq!(result, Err(BuildError::ReadFailed)); + } + + #[test] + fn test_migration_empty_monitors_succeeds() { + let (store, keys_manager, logger, runtime) = make_test_deps(&[42u8; 32]); + let migration = + ChannelDataMigration { channel_manager: None, channel_monitors: Vec::new() }; + + let result = + apply_channel_data_migration(&migration, &store, &keys_manager, &logger, &runtime); + assert!(result.is_ok()); + } + + #[test] + fn test_migration_fresh_write_to_empty_store() { + let (monitor_bytes, monitor_key, _, seed) = create_test_monitor_bytes(); + let (store, keys_manager, logger, runtime) = make_test_deps(&seed); + + let migration = ChannelDataMigration { + channel_manager: None, + channel_monitors: vec![monitor_bytes.clone()], + }; + + let result = + apply_channel_data_migration(&migration, &store, &keys_manager, &logger, &runtime); + assert!(result.is_ok()); + + // Verify the monitor was written to the store. + let stored = runtime.block_on(KVStore::read( + &*store, + CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE, + CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE, + &monitor_key, + )); + assert!(stored.is_ok()); + assert_eq!(stored.unwrap(), monitor_bytes); + } + + #[test] + fn test_migration_skips_when_existing_is_newer_or_equal() { + let (monitor_bytes, monitor_key, _, seed) = create_test_monitor_bytes(); + let (store, keys_manager, logger, runtime) = make_test_deps(&seed); + + // Pre-populate the store with valid monitor data (update_id=0). + // Migration data also has update_id=0. Since existing >= migrated, + // the function should skip the redundant write and succeed. + runtime + .block_on(KVStore::write( + &*store, + CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE, + CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE, + &monitor_key, + monitor_bytes.clone(), + )) + .unwrap(); + + let migration = ChannelDataMigration { + channel_manager: None, + channel_monitors: vec![monitor_bytes.clone()], + }; + + let result = + apply_channel_data_migration(&migration, &store, &keys_manager, &logger, &runtime); + assert!(result.is_ok()); + } + + #[test] + fn test_migration_skips_on_corrupt_existing_data() { + let (monitor_bytes, monitor_key, _, seed) = create_test_monitor_bytes(); + let (store, keys_manager, logger, runtime) = make_test_deps(&seed); + + let corrupt_data = vec![0xFF, 0xFE, 0xFD, 0xFC]; + + // Pre-populate the store with garbage data for this monitor key. + runtime + .block_on(KVStore::write( + &*store, + CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE, + CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE, + &monitor_key, + corrupt_data.clone(), + )) + .unwrap(); + + // Migration should skip (not fail) when existing data can't be deserialized, + // to avoid blocking node startup while still not overwriting existing state. + let migration = + ChannelDataMigration { channel_manager: None, channel_monitors: vec![monitor_bytes] }; + + let result = + apply_channel_data_migration(&migration, &store, &keys_manager, &logger, &runtime); + assert_eq!(result, Ok(())); + + // Verify the corrupt data was NOT overwritten — existing state preserved. + let stored = runtime + .block_on(KVStore::read( + &*store, + CHANNEL_MONITOR_PERSISTENCE_PRIMARY_NAMESPACE, + CHANNEL_MONITOR_PERSISTENCE_SECONDARY_NAMESPACE, + &monitor_key, + )) + .unwrap(); + assert_eq!(stored, corrupt_data); + } + + #[test] + fn test_migration_fails_on_store_read_error() { + let (monitor_bytes, _, _, seed) = create_test_monitor_bytes(); + + let store: Arc = Arc::new(FailingReadStore); + let keys_manager = LdkKeysManager::new(&seed, 0, 0, false); + let logger = Arc::new(Logger::new_log_facade()); + let runtime = Arc::new(Runtime::new(Arc::clone(&logger)).unwrap()); + + // Migration should fail because the store returns an IO error on read + // (fail-closed: non-NotFound errors refuse migration). + let migration = + ChannelDataMigration { channel_manager: None, channel_monitors: vec![monitor_bytes] }; + + let result = + apply_channel_data_migration(&migration, &store, &keys_manager, &logger, &runtime); + assert_eq!(result, Err(BuildError::ReadFailed)); + } + + #[test] + fn test_channel_manager_migration_fresh_write_to_empty_store() { + let (store, keys_manager, logger, runtime) = make_test_deps(&[42u8; 32]); + let manager_bytes = vec![0x01, 0x02, 0x03, 0x04]; + + let migration = ChannelDataMigration { + channel_manager: Some(manager_bytes.clone()), + channel_monitors: Vec::new(), + }; + + let result = + apply_channel_data_migration(&migration, &store, &keys_manager, &logger, &runtime); + assert!(result.is_ok()); + + // Verify the channel manager was written to the store. + let stored = runtime.block_on(KVStore::read( + &*store, + CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE, + CHANNEL_MANAGER_PERSISTENCE_SECONDARY_NAMESPACE, + CHANNEL_MANAGER_PERSISTENCE_KEY, + )); + assert!(stored.is_ok()); + assert_eq!(stored.unwrap(), manager_bytes); + } + + #[test] + fn test_channel_manager_migration_skips_when_existing_data_present() { + let (store, keys_manager, logger, runtime) = make_test_deps(&[42u8; 32]); + + // Pre-populate the store with existing channel manager data. + let existing_data = vec![0xAA, 0xBB, 0xCC]; + runtime + .block_on(KVStore::write( + &*store, + CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE, + CHANNEL_MANAGER_PERSISTENCE_SECONDARY_NAMESPACE, + CHANNEL_MANAGER_PERSISTENCE_KEY, + existing_data.clone(), + )) + .unwrap(); + + // Attempt migration with different data. + let migration_bytes = vec![0x01, 0x02, 0x03]; + let migration = ChannelDataMigration { + channel_manager: Some(migration_bytes), + channel_monitors: Vec::new(), + }; + + let result = + apply_channel_data_migration(&migration, &store, &keys_manager, &logger, &runtime); + assert!(result.is_ok()); + + // Verify the original data is preserved (migration was skipped). + let stored = runtime + .block_on(KVStore::read( + &*store, + CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE, + CHANNEL_MANAGER_PERSISTENCE_SECONDARY_NAMESPACE, + CHANNEL_MANAGER_PERSISTENCE_KEY, + )) + .unwrap(); + assert_eq!(stored, existing_data); + } + + #[test] + fn test_channel_manager_migration_skips_even_when_existing_data_is_corrupt() { + let (store, keys_manager, logger, runtime) = make_test_deps(&[42u8; 32]); + + // Pre-populate the store with corrupt/garbage data. + let corrupt_data = vec![0xDE, 0xAD, 0xBE, 0xEF]; + runtime + .block_on(KVStore::write( + &*store, + CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE, + CHANNEL_MANAGER_PERSISTENCE_SECONDARY_NAMESPACE, + CHANNEL_MANAGER_PERSISTENCE_KEY, + corrupt_data.clone(), + )) + .unwrap(); + + // Migration should skip (existence-only check, no deserialization). + // This is intentional: overwriting potentially valid data with stale + // FS bytes risks fund loss; a node that fails to start on corrupt + // data can be recovered by clearing the KV store. + let migration = ChannelDataMigration { + channel_manager: Some(vec![0x01, 0x02, 0x03]), + channel_monitors: Vec::new(), + }; + + let result = + apply_channel_data_migration(&migration, &store, &keys_manager, &logger, &runtime); + assert!(result.is_ok()); + + // Verify the corrupt data is preserved (migration was skipped). + let stored = runtime + .block_on(KVStore::read( + &*store, + CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE, + CHANNEL_MANAGER_PERSISTENCE_SECONDARY_NAMESPACE, + CHANNEL_MANAGER_PERSISTENCE_KEY, + )) + .unwrap(); + assert_eq!(stored, corrupt_data); + } + + #[test] + fn test_channel_manager_migration_fails_on_store_read_error() { + let store: Arc = Arc::new(FailingReadStore); + let keys_manager = LdkKeysManager::new(&[42u8; 32], 0, 0, false); + let logger = Arc::new(Logger::new_log_facade()); + let runtime = Arc::new(Runtime::new(Arc::clone(&logger)).unwrap()); + + let migration = ChannelDataMigration { + channel_manager: Some(vec![0x01, 0x02, 0x03]), + channel_monitors: Vec::new(), + }; + + let result = + apply_channel_data_migration(&migration, &store, &keys_manager, &logger, &runtime); + assert_eq!(result, Err(BuildError::ReadFailed)); + } + + #[test] + fn derived_account_xpub_differs_from_account_zero() { + use bitcoin::bip32::Xpriv; + use bitcoin::Network; + + use super::{derive_account_xpub_string, AddressType}; + + let seed = [7u8; 64]; + let master = Xpriv::new_master(Network::Regtest, &seed).unwrap(); + let xpub0 = + derive_account_xpub_string(master, Network::Regtest, AddressType::NativeSegwit, 0) + .unwrap(); + let xpub1 = + derive_account_xpub_string(master, Network::Regtest, AddressType::NativeSegwit, 1) + .unwrap(); + assert_ne!(xpub0, xpub1); + assert!(xpub1.starts_with('t') || xpub1.starts_with('x')); + } + + #[test] + fn derived_account_descriptors_include_account_index_in_origin() { + use std::str::FromStr; + use std::sync::Arc; + + use bitcoin::bip32::{DerivationPath, Xpriv}; + use bitcoin::secp256k1::Secp256k1; + use bitcoin::Network; + + use super::{ + get_or_create_wallet_for_account, AddressType, KeychainKind, OnchainWalletAccount, + }; + use crate::io::test_utils::InMemoryStore; + use crate::logger::Logger; + use crate::types::DynStore; + use crate::wallet::persist::KVStoreWalletPersister; + + let store: Arc = Arc::new(InMemoryStore::new()); + let logger = Arc::new(Logger::new_log_facade()); + let network = Network::Regtest; + let master = Xpriv::new_master(network, &[42u8; 64]).unwrap(); + let account = + OnchainWalletAccount { address_type: AddressType::NativeSegwit, account_index: 7 }; + let mut persister = + KVStoreWalletPersister::new(Arc::clone(&store), Arc::clone(&logger), account); + let (wallet, loaded) = + get_or_create_wallet_for_account(account, master, network, &mut persister, None) + .unwrap(); + assert!(!loaded); + + let descriptor = wallet.public_descriptor(KeychainKind::External).to_string(); + assert!( + descriptor.contains("/84'/1'/7'"), + "descriptor origin must include account 7, got {}", + descriptor + ); + + let expected_path = DerivationPath::from_str("m/84'/1'/7'").unwrap(); + let expected_xpub = bitcoin::bip32::Xpub::from_priv( + &Secp256k1::new(), + &master.derive_priv(&Secp256k1::new(), &expected_path).unwrap(), + ); + assert!(descriptor.contains(&expected_xpub.to_string())); + assert!(wallet.peek_address(KeychainKind::External, 0).address.script_pubkey().is_p2wpkh()); + } + + #[test] + fn derived_account_xpub_rejects_different_seed() { + use bitcoin::bip32::Xpriv; + use bitcoin::Network; + + use super::{derive_account_xpub_string, AddressType}; + + let master_a = Xpriv::new_master(Network::Regtest, &[1u8; 64]).unwrap(); + let master_b = Xpriv::new_master(Network::Regtest, &[2u8; 64]).unwrap(); + let xpub_a = + derive_account_xpub_string(master_a, Network::Regtest, AddressType::NativeSegwit, 1) + .unwrap(); + let xpub_b = + derive_account_xpub_string(master_b, Network::Regtest, AddressType::NativeSegwit, 1) + .unwrap(); + assert_ne!(xpub_a, xpub_b); + } } diff --git a/src/chain/bitcoind.rs b/src/chain/bitcoind.rs index b3d7880d61..7467af86f7 100644 --- a/src/chain/bitcoind.rs +++ b/src/chain/bitcoind.rs @@ -19,18 +19,18 @@ use lightning::util::ser::Writeable; use lightning_block_sync::gossip::UtxoSource; use lightning_block_sync::http::{HttpEndpoint, JsonResponse}; use lightning_block_sync::init::{synchronize_listeners, validate_best_block_header}; -use lightning_block_sync::poll::{ChainPoller, ChainTip, ValidatedBlockHeader}; +use lightning_block_sync::poll::ValidatedBlockHeader; use lightning_block_sync::rest::RestClient; use lightning_block_sync::rpc::{RpcClient, RpcError}; use lightning_block_sync::{ - AsyncBlockSourceResult, BlockData, BlockHeaderData, BlockSource, BlockSourceErrorKind, Cache, - SpvClient, + AsyncBlockSourceResult, BlockData, BlockHeaderData, BlockSource, Cache, }; use serde::Serialize; use super::{periodically_archive_fully_resolved_monitors, WalletSyncStatus}; use crate::config::{ - BitcoindRestClientConfig, Config, FEE_RATE_CACHE_UPDATE_TIMEOUT_SECS, TX_BROADCAST_TIMEOUT_SECS, + BitcoindRestClientConfig, Config, OnchainWalletAccount, FEE_RATE_CACHE_UPDATE_TIMEOUT_SECS, + TX_BROADCAST_TIMEOUT_SECS, }; use crate::fee_estimator::{ apply_post_estimation_adjustments, get_all_conf_targets, get_num_block_defaults_for_target, @@ -43,17 +43,24 @@ use crate::{Error, NodeMetrics}; const CHAIN_POLLING_INTERVAL_SECS: u64 = 2; const CHAIN_POLLING_TIMEOUT_SECS: u64 = 10; +const MAX_ACCOUNT_SET_CHANGE_RETRIES: u8 = 3; +const ACCOUNT_SET_CHANGE_RETRY_DELAY: Duration = Duration::from_millis(100); + +enum ListenerSyncOutcome { + Complete(u64), + AccountSetChanged, +} pub(super) struct BitcoindChainSource { api_client: Arc, header_cache: tokio::sync::Mutex, - latest_chain_tip: RwLock>, wallet_polling_status: Mutex, + last_mempool_account_generation: AtomicU64, fee_estimator: Arc, - kv_store: Arc, - config: Arc, + pub(super) kv_store: Arc, + pub(super) config: Arc, logger: Arc, - node_metrics: Arc>, + pub(super) node_metrics: Arc>, } impl BitcoindChainSource { @@ -70,13 +77,12 @@ impl BitcoindChainSource { )); let header_cache = tokio::sync::Mutex::new(BoundedHeaderCache::new()); - let latest_chain_tip = RwLock::new(None); let wallet_polling_status = Mutex::new(WalletSyncStatus::Completed); Self { api_client, header_cache, - latest_chain_tip, wallet_polling_status, + last_mempool_account_generation: AtomicU64::new(u64::MAX), fee_estimator, kv_store, config, @@ -101,14 +107,13 @@ impl BitcoindChainSource { )); let header_cache = tokio::sync::Mutex::new(BoundedHeaderCache::new()); - let latest_chain_tip = RwLock::new(None); let wallet_polling_status = Mutex::new(WalletSyncStatus::Completed); Self { api_client, header_cache, - latest_chain_tip, wallet_polling_status, + last_mempool_account_generation: AtomicU64::new(u64::MAX), fee_estimator, kv_store, config, @@ -143,130 +148,66 @@ impl BitcoindChainSource { let mut backoff = CHAIN_POLLING_INTERVAL_SECS; const MAX_BACKOFF_SECS: u64 = 300; + // Use the same chain+mempool path as periodic polling. `sync_wallets` waits on this + // initial sync, so returning after headers alone would leave persisted unconfirmed + // transactions in place when Bitcoind's mempool is empty after restart. loop { - // if the stop_sync_sender has been dropped, we should just exit if stop_sync_receiver.has_changed().unwrap_or(true) { log_trace!(self.logger, "Stopping initial chain sync."); return; } - let channel_manager_best_block_hash = channel_manager.current_best_block().block_hash; - let sweeper_best_block_hash = output_sweeper.current_best_block().block_hash; - let onchain_wallet_best_block_hash = onchain_wallet.current_best_block().block_hash; - - let mut chain_listeners = vec![ - (onchain_wallet_best_block_hash, &*onchain_wallet as &(dyn Listen + Send + Sync)), - (channel_manager_best_block_hash, &*channel_manager as &(dyn Listen + Send + Sync)), - (sweeper_best_block_hash, &*output_sweeper as &(dyn Listen + Send + Sync)), - ]; - - // TODO: Eventually we might want to see if we can synchronize `ChannelMonitor`s - // before giving them to `ChainMonitor` it the first place. However, this isn't - // trivial as we load them on initialization (in the `Builder`) and only gain - // network access during `start`. For now, we just make sure we get the worst known - // block hash and sychronize them via `ChainMonitor`. - if let Some(worst_channel_monitor_block_hash) = chain_monitor - .list_monitors() - .iter() - .flat_map(|channel_id| chain_monitor.get_monitor(*channel_id)) - .map(|m| m.current_best_block()) - .min_by_key(|b| b.height) - .map(|b| b.block_hash) - { - chain_listeners.push(( - worst_channel_monitor_block_hash, - &*chain_monitor as &(dyn Listen + Send + Sync), - )); - } - - let mut locked_header_cache = self.header_cache.lock().await; - let now = SystemTime::now(); - match synchronize_listeners( - self.api_client.as_ref(), - self.config.network, - &mut *locked_header_cache, - chain_listeners.clone(), - ) - .await + match self + .poll_and_update_listeners_inner( + Arc::clone(&onchain_wallet), + Arc::clone(&channel_manager), + Arc::clone(&chain_monitor), + Arc::clone(&output_sweeper), + ) + .await { - Ok(chain_tip) => { - { + Ok(ListenerSyncOutcome::AccountSetChanged) => continue, + Ok(ListenerSyncOutcome::Complete(account_generation)) => { + let account_operation = onchain_wallet.lock_account_operations(); + if onchain_wallet.account_generation() != account_generation { log_info!( self.logger, - "Finished synchronizing listeners in {}ms", - now.elapsed().unwrap().as_millis() + "On-chain account set changed during initial sync; retrying." ); - *self.latest_chain_tip.write().unwrap() = Some(chain_tip); - let unix_time_secs_opt = - SystemTime::now().duration_since(UNIX_EPOCH).ok().map(|d| d.as_secs()); - let mut locked_node_metrics = self.node_metrics.write().unwrap(); - locked_node_metrics.latest_lightning_wallet_sync_timestamp = - unix_time_secs_opt; - locked_node_metrics.latest_onchain_wallet_sync_timestamp = - unix_time_secs_opt; - write_node_metrics( - &*locked_node_metrics, - Arc::clone(&self.kv_store), - Arc::clone(&self.logger), - ) - .unwrap_or_else(|e| { - log_error!(self.logger, "Failed to persist node metrics: {}", e); - }); + drop(account_operation); + continue; } + self.wallet_polling_status + .lock() + .unwrap() + .propagate_result_to_subscribers(Ok(())); + drop(account_operation); break; }, - Err(e) => { - log_error!(self.logger, "Failed to synchronize chain listeners: {:?}", e); - if e.kind() == BlockSourceErrorKind::Transient { - log_info!( - self.logger, - "Transient error syncing chain listeners: {:?}. Retrying in {} seconds.", - e, - backoff - ); - // Sleep with stop signal check to allow immediate shutdown - tokio::select! { - biased; - _ = stop_sync_receiver.changed() => { - log_trace!( - self.logger, - "Stopping initial chain sync.", - ); - return; - } - _ = tokio::time::sleep(Duration::from_secs(backoff)) => {} - } - backoff = std::cmp::min(backoff * 2, MAX_BACKOFF_SECS); - } else { - log_error!( - self.logger, - "Persistent error syncing chain listeners: {:?}. Retrying in {} seconds.", - e, - MAX_BACKOFF_SECS - ); - // Sleep with stop signal check to allow immediate shutdown - tokio::select! { - biased; - _ = stop_sync_receiver.changed() => { - log_trace!( - self.logger, - "Stopping initial chain sync during backoff.", - ); - return; - } - _ = tokio::time::sleep(Duration::from_secs(MAX_BACKOFF_SECS)) => {} + log_error!( + self.logger, + "Failed initial chain/mempool sync: {:?}. Retrying in {} seconds.", + e, + backoff + ); + tokio::select! { + biased; + _ = stop_sync_receiver.changed() => { + log_trace!(self.logger, "Stopping initial chain sync."); + return; } + _ = tokio::time::sleep(Duration::from_secs(backoff)) => {} } + backoff = (backoff * 2).min(MAX_BACKOFF_SECS); }, } } - // Now propagate the initial result to unblock waiting subscribers. - self.wallet_polling_status.lock().unwrap().propagate_result_to_subscribers(Ok(())); - let mut chain_polling_interval = tokio::time::interval(Duration::from_secs(CHAIN_POLLING_INTERVAL_SECS)); + // Initial sync already ran chain+mempool; skip the immediate first tick. + chain_polling_interval.reset(); chain_polling_interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip); let mut fee_rate_update_interval = @@ -346,10 +287,7 @@ impl BitcoindChainSource { })?; match validate_res { - Ok(tip) => { - *self.latest_chain_tip.write().unwrap() = Some(tip); - Ok(tip) - }, + Ok(tip) => Ok(tip), Err(e) => { log_error!(self.logger, "Failed to poll for chain data: {:?}", e); return Err(Error::TxSyncFailed); @@ -375,106 +313,216 @@ impl BitcoindChainSource { })?; } - let res = self - .poll_and_update_listeners_inner( - onchain_wallet, - channel_manager, - chain_monitor, - output_sweeper, - ) - .await; - - self.wallet_polling_status.lock().unwrap().propagate_result_to_subscribers(res); + let mut account_set_change_retries = 0; + loop { + match self + .poll_and_update_listeners_inner( + Arc::clone(&onchain_wallet), + Arc::clone(&channel_manager), + Arc::clone(&chain_monitor), + Arc::clone(&output_sweeper), + ) + .await + { + Ok(ListenerSyncOutcome::AccountSetChanged) => {}, + Ok(ListenerSyncOutcome::Complete(account_generation)) => { + let _account_operation = onchain_wallet.lock_account_operations(); + if onchain_wallet.account_generation() != account_generation { + log_info!( + self.logger, + "On-chain account set changed during sync; retrying." + ); + } else { + self.wallet_polling_status + .lock() + .unwrap() + .propagate_result_to_subscribers(Ok(())); + return Ok(()); + } + }, + Err(e) => { + self.wallet_polling_status + .lock() + .unwrap() + .propagate_result_to_subscribers(Err(e)); + return Err(e); + }, + } - res + if account_set_change_retries == MAX_ACCOUNT_SET_CHANGE_RETRIES { + log_error!( + self.logger, + "On-chain account set kept changing during wallet sync; giving up." + ); + let error = Error::WalletOperationFailed; + self.wallet_polling_status + .lock() + .unwrap() + .propagate_result_to_subscribers(Err(error.clone())); + return Err(error); + } + account_set_change_retries += 1; + tokio::time::sleep(ACCOUNT_SET_CHANGE_RETRY_DELAY).await; + } } async fn poll_and_update_listeners_inner( &self, onchain_wallet: Arc, channel_manager: Arc, chain_monitor: Arc, output_sweeper: Arc, - ) -> Result<(), Error> { - let latest_chain_tip_opt = self.latest_chain_tip.read().unwrap().clone(); - let chain_tip = - if let Some(tip) = latest_chain_tip_opt { tip } else { self.poll_chain_tip().await? }; + ) -> Result { + onchain_wallet.finish_pending_sync(false)?; + + let previous_lightning_tip = channel_manager.current_best_block(); + let (account_generation, account_tips) = onchain_wallet.account_sync_snapshot(); + let account_listeners: Vec = account_tips + .iter() + .map(|(account, _)| AccountChainListener::new(Arc::clone(&onchain_wallet), *account)) + .collect(); + let mut chain_listeners: Vec<(BlockHash, &(dyn Listen + Send + Sync))> = account_tips + .iter() + .zip(account_listeners.iter()) + .map(|((_, tip), listener)| (tip.block_hash, listener as &(dyn Listen + Send + Sync))) + .collect(); + chain_listeners.push(( + previous_lightning_tip.block_hash, + &*channel_manager as &(dyn Listen + Send + Sync), + )); + chain_listeners.push(( + output_sweeper.current_best_block().block_hash, + &*output_sweeper as &(dyn Listen + Send + Sync), + )); + if let Some(worst_channel_monitor_block_hash) = chain_monitor + .list_monitors() + .iter() + .flat_map(|channel_id| chain_monitor.get_monitor(*channel_id)) + .map(|monitor| monitor.current_best_block()) + .min_by_key(|block| block.height) + .map(|block| block.block_hash) + { + chain_listeners.push(( + worst_channel_monitor_block_hash, + &*chain_monitor as &(dyn Listen + Send + Sync), + )); + } let mut locked_header_cache = self.header_cache.lock().await; - let chain_poller = ChainPoller::new(Arc::clone(&self.api_client), self.config.network); - let chain_listener = ChainListener { - onchain_wallet: Arc::clone(&onchain_wallet), - channel_manager: Arc::clone(&channel_manager), - chain_monitor: Arc::clone(&chain_monitor), - output_sweeper, - }; - let mut spv_client = - SpvClient::new(chain_tip, chain_poller, &mut *locked_header_cache, &chain_listener); - let now = SystemTime::now(); - match spv_client.poll_best_tip().await { - Ok((ChainTip::Better(tip), true)) => { - log_trace!( - self.logger, - "Finished polling best tip in {}ms", - now.elapsed().unwrap().as_millis() - ); - *self.latest_chain_tip.write().unwrap() = Some(tip); + synchronize_listeners( + self.api_client.as_ref(), + self.config.network, + &mut *locked_header_cache, + chain_listeners, + ) + .await + .map_err(|e| { + log_error!(self.logger, "Failed to synchronize chain listeners: {:?}", e); + Error::TxSyncFailed + })?; + drop(locked_header_cache); + + for listener in &account_listeners { + match listener.finish(account_generation) { + Ok(AccountChainListenerOutcome::Complete) => {}, + Ok(AccountChainListenerOutcome::AccountSetChanged) => { + log_info!(self.logger, "On-chain account set changed during sync; retrying."); + return Ok(ListenerSyncOutcome::AccountSetChanged); + }, + Err(err) => { + log_error!( + self.logger, + "Per-account wallet sync apply failed for {:?}: {}", + listener.account(), + err + ); + return Err(err); + }, + } + } + onchain_wallet.finish_pending_sync(false)?; - periodically_archive_fully_resolved_monitors( - Arc::clone(&channel_manager), - chain_monitor, - Arc::clone(&self.kv_store), - Arc::clone(&self.logger), - Arc::clone(&self.node_metrics), - )?; - }, - Ok(_) => {}, - Err(e) => { - log_error!(self.logger, "Failed to poll for chain data: {:?}", e); - return Err(Error::TxSyncFailed); - }, + log_trace!( + self.logger, + "Finished synchronizing chain listeners in {}ms", + now.elapsed().unwrap().as_millis() + ); + // Archival and metrics persistence are best-effort: chain/mempool sync already + // succeeded, and failing these must not block `sync_wallets` (especially during + // initial sync, which subscribers wait on). + if let Err(e) = periodically_archive_fully_resolved_monitors( + Arc::clone(&channel_manager), + Arc::clone(&chain_monitor), + Arc::clone(&self.kv_store), + Arc::clone(&self.logger), + Arc::clone(&self.node_metrics), + ) { + log_error!( + self.logger, + "Failed to archive fully resolved channel monitors after sync: {}", + e + ); } let cur_height = channel_manager.current_best_block().height; let now = SystemTime::now(); - let bdk_unconfirmed_txids = onchain_wallet.get_unconfirmed_txids(); - match self + let bdk_unconfirmed_txids = onchain_wallet.get_unconfirmed_txids_with_last_seen(); + // A newly loaded account must see transactions emitted before it joined the aggregate. + let replay_mempool = + self.last_mempool_account_generation.load(Ordering::Acquire) != account_generation; + let mempool_update = match self .api_client - .get_updated_mempool_transactions(cur_height, bdk_unconfirmed_txids) + .get_updated_mempool_transactions(cur_height, bdk_unconfirmed_txids, replay_mempool) .await { - Ok((unconfirmed_txs, evicted_txids)) => { + Ok(update) => { log_trace!( self.logger, "Finished polling mempool of size {} and {} evicted transactions in {}ms", - unconfirmed_txs.len(), - evicted_txids.len(), + update.transactions.len(), + update.evicted_txids.len(), now.elapsed().unwrap().as_millis() ); - onchain_wallet.apply_mempool_txs(unconfirmed_txs, evicted_txids).unwrap_or_else( - |e| { - log_error!(self.logger, "Failed to apply mempool transactions: {:?}", e); - }, - ); + update }, Err(e) => { log_error!(self.logger, "Failed to poll for mempool transactions: {:?}", e); return Err(Error::TxSyncFailed); }, + }; + + { + let _account_operation = onchain_wallet.lock_account_operations(); + if onchain_wallet.account_generation() != account_generation { + log_info!(self.logger, "On-chain account set changed during sync; retrying."); + return Ok(ListenerSyncOutcome::AccountSetChanged); + } + onchain_wallet + .apply_mempool_txs(mempool_update.transactions, mempool_update.evicted_txids) + .map_err(|e| { + log_error!(self.logger, "Failed to apply mempool transactions: {:?}", e); + e + })?; + self.api_client.commit_mempool_timestamp(mempool_update.next_timestamp); + self.last_mempool_account_generation.store(account_generation, Ordering::Release); } let unix_time_secs_opt = SystemTime::now().duration_since(UNIX_EPOCH).ok().map(|d| d.as_secs()); - let mut locked_node_metrics = self.node_metrics.write().unwrap(); - locked_node_metrics.latest_lightning_wallet_sync_timestamp = unix_time_secs_opt; - locked_node_metrics.latest_onchain_wallet_sync_timestamp = unix_time_secs_opt; + { + let mut locked_node_metrics = self.node_metrics.write().unwrap(); + locked_node_metrics.latest_lightning_wallet_sync_timestamp = unix_time_secs_opt; + locked_node_metrics.latest_onchain_wallet_sync_timestamp = unix_time_secs_opt; - write_node_metrics( - &*locked_node_metrics, - Arc::clone(&self.kv_store), - Arc::clone(&self.logger), - )?; + if let Err(e) = write_node_metrics( + &*locked_node_metrics, + Arc::clone(&self.kv_store), + Arc::clone(&self.logger), + ) { + log_error!(self.logger, "Failed to persist node metrics after sync: {}", e); + } + } - Ok(()) + Ok(ListenerSyncOutcome::Complete(account_generation)) } pub(super) async fn update_fee_rate_estimates(&self) -> Result<(), Error> { @@ -639,6 +687,19 @@ impl BitcoindChainSource { } } +struct MempoolUpdate { + transactions: Vec<(Transaction, u64)>, + evicted_txids: Vec<(Txid, u64)>, + next_timestamp: Option, +} + +fn should_emit_mempool_entry( + entry_time: u64, entry_height: u32, best_processed_height: u32, watermark: u64, + replay_all: bool, +) -> bool { + replay_all || entry_height > best_processed_height || entry_time >= watermark +} + pub enum BitcoindClient { Rpc { rpc_client: Arc, @@ -1029,17 +1090,24 @@ impl BitcoindClient { Ok(()) } - /// Returns two `Vec`s: - /// - mempool transactions, alongside their first-seen unix timestamps. - /// - transactions that have been evicted from the mempool, alongside the last time they were seen absent. - pub(crate) async fn get_updated_mempool_transactions( - &self, best_processed_height: u32, bdk_unconfirmed_txids: Vec, - ) -> std::io::Result<(Vec<(Transaction, u64)>, Vec<(Txid, u64)>)> { - let mempool_txs = - self.get_mempool_transactions_and_timestamp_at_height(best_processed_height).await?; - let evicted_txids = - self.get_evicted_mempool_txids_and_timestamp(bdk_unconfirmed_txids).await?; - Ok((mempool_txs, evicted_txids)) + /// Collects mempool changes without advancing the committed emission timestamp. + async fn get_updated_mempool_transactions( + &self, best_processed_height: u32, bdk_unconfirmed_txids: Vec<(Txid, u64)>, + replay_all: bool, + ) -> std::io::Result { + let (transactions, next_timestamp) = self + .get_mempool_transactions_and_timestamp_at_height(best_processed_height, replay_all) + .await?; + let sync_timestamp = SystemTime::now() + .duration_since(UNIX_EPOCH) + .map(|duration| duration.as_secs()) + .unwrap_or_else(|_| self.mempool_timestamp()); + let eviction_timestamp = + next_timestamp.unwrap_or_else(|| self.mempool_timestamp()).max(sync_timestamp); + let evicted_txids = self + .get_evicted_mempool_txids_and_timestamp(bdk_unconfirmed_txids, eviction_timestamp) + .await?; + Ok(MempoolUpdate { transactions, evicted_txids, next_timestamp }) } /// Get mempool transactions, alongside their first-seen unix timestamps. @@ -1047,9 +1115,9 @@ impl BitcoindClient { /// This method is an adapted version of `bdk_bitcoind_rpc::Emitter::mempool`. It emits each /// transaction only once, unless we cannot assume the transaction's ancestors are already /// emitted. - pub(crate) async fn get_mempool_transactions_and_timestamp_at_height( - &self, best_processed_height: u32, - ) -> std::io::Result> { + async fn get_mempool_transactions_and_timestamp_at_height( + &self, best_processed_height: u32, replay_all: bool, + ) -> std::io::Result<(Vec<(Transaction, u64)>, Option)> { match self { BitcoindClient::Rpc { latest_mempool_timestamp, @@ -1062,6 +1130,7 @@ impl BitcoindClient { mempool_entries_cache, mempool_txs_cache, best_processed_height, + replay_all, ) .await }, @@ -1076,6 +1145,7 @@ impl BitcoindClient { mempool_entries_cache, mempool_txs_cache, best_processed_height, + replay_all, ) .await }, @@ -1086,8 +1156,8 @@ impl BitcoindClient { &self, latest_mempool_timestamp: &AtomicU64, mempool_entries_cache: &tokio::sync::Mutex>, mempool_txs_cache: &tokio::sync::Mutex>, - best_processed_height: u32, - ) -> std::io::Result> { + best_processed_height: u32, replay_all: bool, + ) -> std::io::Result<(Vec<(Transaction, u64)>, Option)> { let prev_mempool_time = latest_mempool_timestamp.load(Ordering::Relaxed); let mut latest_time = prev_mempool_time; @@ -1114,9 +1184,14 @@ impl BitcoindClient { // provides us with the block height that the tx is introduced to the mempool. // If we have already emitted the block of height, we can assume that all // ancestor txs have been processed by the receiver. - let ancestor_within_height = entry.height <= best_processed_height; - let is_already_emitted = entry.time <= prev_mempool_time; - if is_already_emitted && ancestor_within_height { + // Re-emit the watermark boundary because Bitcoin Core timestamps entries to the second. + if !should_emit_mempool_entry( + entry.time, + entry.height, + best_processed_height, + prev_mempool_time, + replay_all, + ) { continue; } @@ -1137,10 +1212,8 @@ impl BitcoindClient { }; } - if !txs_to_emit.is_empty() { - latest_mempool_timestamp.store(latest_time, Ordering::Release); - } - Ok(txs_to_emit) + let next_timestamp = (!txs_to_emit.is_empty()).then_some(latest_time); + Ok((txs_to_emit, next_timestamp)) } // Retrieve a list of Txids that have been evicted from the mempool. @@ -1148,22 +1221,22 @@ impl BitcoindClient { // To this end, we first update our local mempool_entries_cache and then return all unconfirmed // wallet `Txid`s that don't appear in the mempool still. async fn get_evicted_mempool_txids_and_timestamp( - &self, bdk_unconfirmed_txids: Vec, + &self, bdk_unconfirmed_txids: Vec<(Txid, u64)>, timestamp: u64, ) -> std::io::Result> { match self { - BitcoindClient::Rpc { latest_mempool_timestamp, mempool_entries_cache, .. } => { + BitcoindClient::Rpc { mempool_entries_cache, .. } => { Self::get_evicted_mempool_txids_and_timestamp_inner( - latest_mempool_timestamp, mempool_entries_cache, bdk_unconfirmed_txids, + timestamp, ) .await }, - BitcoindClient::Rest { latest_mempool_timestamp, mempool_entries_cache, .. } => { + BitcoindClient::Rest { mempool_entries_cache, .. } => { Self::get_evicted_mempool_txids_and_timestamp_inner( - latest_mempool_timestamp, mempool_entries_cache, bdk_unconfirmed_txids, + timestamp, ) .await }, @@ -1171,19 +1244,38 @@ impl BitcoindClient { } async fn get_evicted_mempool_txids_and_timestamp_inner( - latest_mempool_timestamp: &AtomicU64, mempool_entries_cache: &tokio::sync::Mutex>, - bdk_unconfirmed_txids: Vec, + bdk_unconfirmed_txids: Vec<(Txid, u64)>, timestamp: u64, ) -> std::io::Result> { - let latest_mempool_timestamp = latest_mempool_timestamp.load(Ordering::Relaxed); let mempool_entries_cache = mempool_entries_cache.lock().await; let evicted_txids = bdk_unconfirmed_txids .into_iter() - .filter(|txid| !mempool_entries_cache.contains_key(txid)) - .map(|txid| (txid, latest_mempool_timestamp)) + .filter(|(txid, _)| !mempool_entries_cache.contains_key(txid)) + .map(|(txid, last_seen)| (txid, timestamp.max(last_seen))) .collect(); Ok(evicted_txids) } + + fn mempool_timestamp(&self) -> u64 { + match self { + Self::Rpc { latest_mempool_timestamp, .. } + | Self::Rest { latest_mempool_timestamp, .. } => { + latest_mempool_timestamp.load(Ordering::Acquire) + }, + } + } + + fn commit_mempool_timestamp(&self, timestamp: Option) { + let Some(timestamp) = timestamp else { + return; + }; + match self { + Self::Rpc { latest_mempool_timestamp, .. } + | Self::Rest { latest_mempool_timestamp, .. } => { + latest_mempool_timestamp.fetch_max(timestamp, Ordering::AcqRel); + }, + } + } } impl BlockSource for BitcoindClient { @@ -1423,35 +1515,70 @@ impl Cache for BoundedHeaderCache { } } -pub(crate) struct ChainListener { - pub(crate) onchain_wallet: Arc, - pub(crate) channel_manager: Arc, - pub(crate) chain_monitor: Arc, - pub(crate) output_sweeper: Arc, +/// Listen adapter that synchronizes one aggregate account from its own checkpoint. +struct AccountChainListener { + wallet: Arc, + account: OnchainWalletAccount, + apply_error: Mutex>, } -impl Listen for ChainListener { +#[derive(Debug, PartialEq, Eq)] +enum AccountChainListenerOutcome { + Complete, + AccountSetChanged, +} + +impl AccountChainListener { + fn new(wallet: Arc, account: OnchainWalletAccount) -> Self { + Self { wallet, account, apply_error: Mutex::new(None) } + } + + fn account(&self) -> OnchainWalletAccount { + self.account + } + + fn finish(&self, account_generation: u64) -> Result { + if let Some(error) = self.apply_error.lock().unwrap().take() { + let account_was_removed = self.wallet.account_generation() != account_generation + && !self.wallet.has_onchain_wallet_account(self.account); + if account_was_removed { + return Ok(AccountChainListenerOutcome::AccountSetChanged); + } + return Err(error); + } + Ok(AccountChainListenerOutcome::Complete) + } + + fn record_apply_result(&self, result: Result<(), Error>) { + if let Err(error) = result { + let mut apply_error = self.apply_error.lock().unwrap(); + if apply_error.is_none() { + *apply_error = Some(error); + } + } + } +} + +impl Listen for AccountChainListener { fn filtered_block_connected( - &self, header: &bitcoin::block::Header, - txdata: &lightning::chain::transaction::TransactionData, height: u32, + &self, _header: &bitcoin::block::Header, + _txdata: &lightning::chain::transaction::TransactionData, _height: u32, ) { - self.onchain_wallet.filtered_block_connected(header, txdata, height); - self.channel_manager.filtered_block_connected(header, txdata, height); - self.chain_monitor.filtered_block_connected(header, txdata, height); - self.output_sweeper.filtered_block_connected(header, txdata, height); + self.record_apply_result(Err(Error::WalletOperationFailed)); } + fn block_connected(&self, block: &bitcoin::Block, height: u32) { - self.onchain_wallet.block_connected(block, height); - self.channel_manager.block_connected(block, height); - self.chain_monitor.block_connected(block, height); - self.output_sweeper.block_connected(block, height); + if self.apply_error.lock().unwrap().is_some() { + return; + } + self.record_apply_result(self.wallet.apply_block_to_account(self.account, block, height)); } - fn blocks_disconnected(&self, fork_point_block: lightning::chain::BestBlock) { - self.onchain_wallet.blocks_disconnected(fork_point_block); - self.channel_manager.blocks_disconnected(fork_point_block); - self.chain_monitor.blocks_disconnected(fork_point_block); - self.output_sweeper.blocks_disconnected(fork_point_block); + fn blocks_disconnected(&self, fork_point: BestBlock) { + if self.apply_error.lock().unwrap().is_some() { + return; + } + self.record_apply_result(self.wallet.rewind_wallet_account(self.account, fork_point)); } } @@ -1480,18 +1607,165 @@ impl std::fmt::Display for HttpError { #[cfg(test)] mod tests { + use std::sync::Arc; + + use bitcoin::blockdata::constants::genesis_block; use bitcoin::hashes::Hash; - use bitcoin::{FeeRate, OutPoint, ScriptBuf, Transaction, TxIn, TxOut, Txid, Witness}; + use bitcoin::{FeeRate, Network, OutPoint, ScriptBuf, Transaction, TxIn, TxOut, Txid, Witness}; + use lightning::chain::{BestBlock, Listen}; use lightning_block_sync::http::JsonResponse; use proptest::arbitrary::any; use proptest::collection::vec; use proptest::{prop_assert_eq, prop_compose, proptest}; use serde_json::json; + use crate::builder::NodeBuilder; use crate::chain::bitcoind::{ - FeeResponse, GetMempoolEntryResponse, GetRawMempoolResponse, GetRawTransactionResponse, - MempoolMinFeeResponse, + should_emit_mempool_entry, AccountChainListener, AccountChainListenerOutcome, + BitcoindClient, FeeResponse, GetMempoolEntryResponse, GetRawMempoolResponse, + GetRawTransactionResponse, MempoolMinFeeResponse, MempoolUpdate, }; + use crate::config::{AddressType, Config, OnchainWalletAccount}; + use crate::io::test_utils::InMemoryStore; + use crate::types::DynStore; + use crate::Error; + + fn test_node() -> (crate::Node, [u8; 64]) { + let seed = [42u8; 64]; + let mut config = Config::default(); + config.network = Network::Regtest; + let mut builder = NodeBuilder::from_config(config); + builder.set_chain_source_esplora("http://127.0.0.1:1".to_string(), None); + builder.set_entropy_seed_bytes(seed); + builder.set_log_facade_logger(); + let store: Arc = Arc::new(InMemoryStore::new()); + (builder.build_with_store(store).unwrap(), seed) + } + + fn child_block(parent: &bitcoin::Block, nonce: u32) -> bitcoin::Block { + let mut header = parent.header; + header.prev_blockhash = parent.block_hash(); + header.time = header.time.saturating_add(1); + header.nonce = nonce; + bitcoin::Block { header, txdata: Vec::new() } + } + + #[test] + fn account_listener_retries_stale_membership_but_preserves_apply_errors() { + let (node, seed) = test_node(); + + node.wallet.add_monitored_address_type(AddressType::Legacy, &seed).unwrap(); + let generation = node.wallet.account_generation(); + let account = OnchainWalletAccount::account_zero(AddressType::Legacy); + let stale_listener = AccountChainListener::new(Arc::clone(&node.wallet), account); + node.wallet.remove_monitored_address_type(AddressType::Legacy).unwrap(); + stale_listener.block_connected(&genesis_block(Network::Regtest), 0); + assert_eq!( + stale_listener.finish(generation), + Ok(AccountChainListenerOutcome::AccountSetChanged) + ); + + let listener_generation = node.wallet.account_generation(); + let primary = OnchainWalletAccount::account_zero(AddressType::NativeSegwit); + let failed_listener = AccountChainListener::new(Arc::clone(&node.wallet), primary); + *failed_listener.apply_error.lock().unwrap() = Some(Error::PersistenceFailed); + node.wallet.add_monitored_address_type(AddressType::Legacy, &seed).unwrap(); + assert!(matches!( + failed_listener.finish(listener_generation), + Err(Error::PersistenceFailed) + )); + } + + #[test] + fn account_listener_streams_replacement_blocks_after_rewind() { + let (node, _) = test_node(); + let account = OnchainWalletAccount::account_zero(AddressType::NativeSegwit); + let generation = node.wallet.account_generation(); + let listener = AccountChainListener::new(Arc::clone(&node.wallet), account); + let genesis = genesis_block(Network::Regtest); + listener.blocks_disconnected(BestBlock::new(genesis.block_hash(), 0)); + + let block1 = child_block(&genesis, 1); + listener.block_connected(&block1, 1); + let tip_after_first = node + .wallet + .account_sync_snapshot() + .1 + .into_iter() + .find(|(candidate, _)| *candidate == account) + .unwrap() + .1; + assert_eq!(tip_after_first.block_hash, block1.block_hash()); + + let block2 = child_block(&block1, 2); + listener.block_connected(&block2, 2); + assert_eq!(listener.finish(generation), Ok(AccountChainListenerOutcome::Complete)); + let tip_after_second = node + .wallet + .account_sync_snapshot() + .1 + .into_iter() + .find(|(candidate, _)| *candidate == account) + .unwrap() + .1; + assert_eq!(tip_after_second.block_hash, block2.block_hash()); + } + + #[test] + fn account_listener_rejects_filtered_blocks() { + let (node, _) = test_node(); + let account = OnchainWalletAccount::account_zero(AddressType::NativeSegwit); + let generation = node.wallet.account_generation(); + let listener = AccountChainListener::new(Arc::clone(&node.wallet), account); + let genesis = genesis_block(Network::Regtest); + + listener.filtered_block_connected(&genesis.header, &[], 0); + assert!(matches!(listener.finish(generation), Err(Error::WalletOperationFailed))); + } + + #[test] + fn mempool_timestamp_advances_only_after_commit() { + let client = BitcoindClient::new_rpc( + "127.0.0.1".to_string(), + 18443, + "user".to_string(), + "password".to_string(), + ); + let update = MempoolUpdate { + transactions: Vec::new(), + evicted_txids: Vec::new(), + next_timestamp: Some(42), + }; + + assert_eq!(client.mempool_timestamp(), 0); + client.commit_mempool_timestamp(update.next_timestamp); + assert_eq!(client.mempool_timestamp(), 42); + client.commit_mempool_timestamp(Some(21)); + assert_eq!(client.mempool_timestamp(), 42); + } + + #[test] + fn mempool_watermark_replays_same_second_entries() { + assert!(should_emit_mempool_entry(42, 100, 100, 42, false)); + assert!(!should_emit_mempool_entry(41, 100, 100, 42, false)); + assert!(should_emit_mempool_entry(41, 101, 100, 42, false)); + assert!(should_emit_mempool_entry(41, 100, 100, 42, true)); + } + + #[tokio::test] + async fn mempool_eviction_never_predates_last_seen() { + let txid = Txid::from_byte_array([42; 32]); + let entries = tokio::sync::Mutex::new(std::collections::HashMap::new()); + let evicted = BitcoindClient::get_evicted_mempool_txids_and_timestamp_inner( + &entries, + vec![(txid, 42)], + 0, + ) + .await + .unwrap(); + + assert_eq!(evicted, vec![(txid, 42)]); + } prop_compose! { fn arbitrary_witness()( diff --git a/src/chain/electrum.rs b/src/chain/electrum.rs index 9e05dfaeed..4e994f6176 100644 --- a/src/chain/electrum.rs +++ b/src/chain/electrum.rs @@ -11,7 +11,8 @@ use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; use bdk_chain::bdk_core::spk_client::{ FullScanRequest as BdkFullScanRequest, FullScanResponse as BdkFullScanResponse, - SyncRequest as BdkSyncRequest, SyncResponse as BdkSyncResponse, + SyncProgress as BdkSyncProgress, SyncRequest as BdkSyncRequest, + SyncResponse as BdkSyncResponse, }; use bdk_electrum::BdkElectrumClient; use bdk_wallet::{KeychainKind as BdkKeyChainKind, Update as BdkUpdate}; @@ -20,13 +21,17 @@ use electrum_client::{ Batch, Client as ElectrumClient, ConfigBuilder as ElectrumConfigBuilder, ElectrumApi, }; use lightning::chain::{Confirm, Filter, WatchedOutput}; +use lightning::log_warn; use lightning::util::ser::Writeable; use lightning_transaction_sync::ElectrumSyncClient; +use tokio::runtime::Handle; use super::{periodically_archive_fully_resolved_monitors, WalletSyncStatus}; use crate::config::{ - Config, ElectrumSyncConfig, BDK_CLIENT_STOP_GAP, BDK_WALLET_SYNC_TIMEOUT_SECS, - FEE_RATE_CACHE_UPDATE_TIMEOUT_SECS, LDK_WALLET_SYNC_TIMEOUT_SECS, TX_BROADCAST_TIMEOUT_SECS, + AddressTypeRuntimeConfig, Config, ElectrumSyncConfig, BDK_CLIENT_STOP_GAP, + BDK_ELECTRUM_CLIENT_BATCH_SIZE, BDK_WALLET_SYNC_TIMEOUT_SECS, + DEFAULT_ELECTRUM_CONNECTION_TIMEOUT_SECS, FEE_RATE_CACHE_UPDATE_TIMEOUT_SECS, + LDK_WALLET_SYNC_TIMEOUT_SECS, TX_BROADCAST_TIMEOUT_SECS, }; use crate::error::Error; use crate::fee_estimator::{ @@ -35,13 +40,81 @@ use crate::fee_estimator::{ }; use crate::io::utils::write_node_metrics; use crate::logger::{log_bytes, log_error, log_info, log_trace, LdkLogger, Logger}; -use crate::runtime::Runtime; use crate::types::{ChainMonitor, ChannelManager, DynStore, Sweeper, Wallet}; use crate::NodeMetrics; -const BDK_ELECTRUM_CLIENT_BATCH_SIZE: usize = 5; const ELECTRUM_CLIENT_NUM_RETRIES: u8 = 3; -const ELECTRUM_CLIENT_TIMEOUT_SECS: u8 = 10; + +fn effective_connection_timeout_secs(configured_timeout_secs: u64, logger: &Logger) -> u8 { + let requested_timeout = if configured_timeout_secs == 0 { + log_warn!( + logger, + "Electrum connection_timeout_secs is 0; using the safe default of {} seconds.", + DEFAULT_ELECTRUM_CONNECTION_TIMEOUT_SECS, + ); + DEFAULT_ELECTRUM_CONNECTION_TIMEOUT_SECS + } else { + configured_timeout_secs + }; + let capped_timeout = requested_timeout.min(u8::MAX as u64) as u8; + if capped_timeout as u64 != requested_timeout { + log_warn!( + logger, + "Electrum connection_timeout_secs ({}) exceeds maximum of {}; capping to {}.", + requested_timeout, + u8::MAX, + capped_timeout, + ); + } + capped_timeout +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +struct FullScanSettings { + stop_gap: usize, + batch_size: usize, +} + +const PRIMARY_WALLET_FULL_SCAN_SETTINGS: FullScanSettings = + FullScanSettings { stop_gap: BDK_CLIENT_STOP_GAP, batch_size: BDK_ELECTRUM_CLIENT_BATCH_SIZE }; + +fn additional_wallet_full_scan_settings(config: &ElectrumSyncConfig) -> FullScanSettings { + FullScanSettings { + stop_gap: config.additional_wallet_full_scan_stop_gap.max(1) as usize, + batch_size: config.additional_wallet_full_scan_batch_size.max(1) as usize, + } +} + +fn additional_wallet_full_scan_timeout( + settings: FullScanSettings, keychain_count: usize, +) -> Duration { + let request_count = + settings.stop_gap.div_ceil(settings.batch_size).saturating_mul(keychain_count); + let request_count = u64::try_from(request_count).unwrap_or(u64::MAX); + Duration::from_secs(BDK_WALLET_SYNC_TIMEOUT_SECS.saturating_add(request_count)) +} + +fn additional_wallet_incremental_batch_size( + account_index: u32, full_scan_settings: FullScanSettings, +) -> usize { + if account_index == 0 { + BDK_ELECTRUM_CLIENT_BATCH_SIZE + } else { + full_scan_settings.batch_size + } +} + +fn derived_wallet_incremental_sync_timeout( + progress: BdkSyncProgress, batch_size: usize, +) -> Duration { + let request_count = progress + .spks_remaining + .div_ceil(batch_size) + .saturating_add(progress.txids_remaining) + .saturating_add(progress.outpoints_remaining); + let request_count = u64::try_from(request_count).unwrap_or(u64::MAX); + Duration::from_secs(BDK_WALLET_SYNC_TIMEOUT_SECS.saturating_add(request_count)) +} pub(super) struct ElectrumChainSource { server_url: String, @@ -50,17 +123,19 @@ pub(super) struct ElectrumChainSource { onchain_wallet_sync_status: Mutex, lightning_wallet_sync_status: Mutex, fee_estimator: Arc, - kv_store: Arc, - config: Arc, + pub(super) kv_store: Arc, + pub(super) config: Arc, + address_type_runtime_config: Arc>, logger: Arc, - node_metrics: Arc>, + pub(super) node_metrics: Arc>, } impl ElectrumChainSource { pub(super) fn new( server_url: String, sync_config: ElectrumSyncConfig, fee_estimator: Arc, kv_store: Arc, config: Arc, - logger: Arc, node_metrics: Arc>, + address_type_runtime_config: Arc>, logger: Arc, + node_metrics: Arc>, ) -> Self { let electrum_runtime_status = RwLock::new(ElectrumRuntimeStatus::new()); let onchain_wallet_sync_status = Mutex::new(WalletSyncStatus::Completed); @@ -74,17 +149,19 @@ impl ElectrumChainSource { fee_estimator, kv_store, config, + address_type_runtime_config, logger: Arc::clone(&logger), node_metrics, } } - pub(super) fn start(&self, runtime: Arc) -> Result<(), Error> { + pub(super) fn start(&self, runtime_handle: Handle) -> Result<(), Error> { self.electrum_runtime_status.write().unwrap().start( self.server_url.clone(), - Arc::clone(&runtime), + runtime_handle, Arc::clone(&self.config), Arc::clone(&self.logger), + self.sync_config.connection_timeout_secs, ) } @@ -94,28 +171,40 @@ impl ElectrumChainSource { pub(crate) async fn sync_onchain_wallet( &self, onchain_wallet: Arc, - ) -> Result<(), Error> { + ) -> super::WalletSyncOutcome { let receiver_res = { let mut status_lock = self.onchain_wallet_sync_status.lock().unwrap(); status_lock.register_or_subscribe_pending_sync() }; if let Some(mut sync_receiver) = receiver_res { log_info!(self.logger, "Sync in progress, skipping."); - return sync_receiver.recv().await.map_err(|e| { - debug_assert!(false, "Failed to receive wallet sync result: {:?}", e); - log_error!(self.logger, "Failed to receive wallet sync result: {:?}", e); - Error::WalletOperationFailed - })?; + match sync_receiver.recv().await { + Ok(Ok(())) => return super::WalletSyncOutcome::new(Vec::new(), None), + Ok(Err(e)) => return super::WalletSyncOutcome::failed(e), + Err(e) => { + debug_assert!(false, "Failed to receive wallet sync result: {:?}", e); + log_error!(self.logger, "Failed to receive wallet sync result: {:?}", e); + return super::WalletSyncOutcome::failed(Error::WalletOperationFailed); + }, + } } - let res = self.sync_onchain_wallet_inner(onchain_wallet).await; + let outcome = self + .sync_onchain_wallet_inner(onchain_wallet) + .await + .unwrap_or_else(super::WalletSyncOutcome::failed); - self.onchain_wallet_sync_status.lock().unwrap().propagate_result_to_subscribers(res); + self.onchain_wallet_sync_status + .lock() + .unwrap() + .propagate_result_to_subscribers(outcome.result()); - res + outcome } - async fn sync_onchain_wallet_inner(&self, onchain_wallet: Arc) -> Result<(), Error> { + async fn sync_onchain_wallet_inner( + &self, onchain_wallet: Arc, + ) -> Result { let electrum_client: Arc = if let Some(client) = self.electrum_runtime_status.read().unwrap().client().as_ref() { Arc::clone(client) @@ -126,60 +215,189 @@ impl ElectrumChainSource { ); return Err(Error::FeerateEstimationUpdateFailed); }; - // If this is our first sync, do a full scan with the configured gap limit. - // Otherwise just do an incremental sync. - let incremental_sync = + + let primary_incremental = self.node_metrics.read().unwrap().latest_onchain_wallet_sync_timestamp.is_some(); - let apply_wallet_update = - |update_res: Result, now: Instant| match update_res { - Ok(update) => match onchain_wallet.apply_update(update) { - Ok(()) => { - log_info!( - self.logger, - "{} of on-chain wallet finished in {}ms.", - if incremental_sync { "Incremental sync" } else { "Sync" }, - now.elapsed().as_millis() - ); - let unix_time_secs_opt = - SystemTime::now().duration_since(UNIX_EPOCH).ok().map(|d| d.as_secs()); - { - let mut locked_node_metrics = self.node_metrics.write().unwrap(); - locked_node_metrics.latest_onchain_wallet_sync_timestamp = - unix_time_secs_opt; - write_node_metrics( - &*locked_node_metrics, - Arc::clone(&self.kv_store), - Arc::clone(&self.logger), - )?; - } - Ok(()) - }, - Err(e) => Err(e), + let additional_accounts = + self.address_type_runtime_config.read().unwrap().additional_wallet_accounts(); + let additional_sync_requests = super::collect_additional_sync_requests( + &additional_accounts, + &onchain_wallet, + &self.node_metrics, + &self.logger, + )?; + let additional_full_scan_settings = additional_wallet_full_scan_settings(&self.sync_config); + + let primary_request: super::WalletSyncRequest = if primary_incremental { + super::WalletSyncRequest::Incremental(onchain_wallet.get_incremental_sync_request()) + } else { + super::WalletSyncRequest::FullScan(onchain_wallet.get_full_scan_request()) + }; + + // Collect cached transactions once and share via Arc to avoid cloning + // the entire Vec for each spawned task. + let cached_txs = Arc::new(onchain_wallet.get_cached_txs()); + + // Primary wallet is identified by address_type = None in the JoinSet results. + let now = Instant::now(); + let mut join_set: tokio::task::JoinSet<( + Option, + Result, + )> = tokio::task::JoinSet::new(); + + { + let client = Arc::clone(&electrum_client); + let txs = Arc::clone(&cached_txs); + match primary_request { + super::WalletSyncRequest::Incremental(req) => { + join_set.spawn(async move { + let result: Result = client + .get_incremental_sync_wallet_update( + req, + txs.iter().cloned(), + BDK_ELECTRUM_CLIENT_BATCH_SIZE, + Duration::from_secs(BDK_WALLET_SYNC_TIMEOUT_SECS), + ) + .await + .map(|u| u.into()); + (None, result) + }); + }, + super::WalletSyncRequest::FullScan(req) => { + join_set.spawn(async move { + let result: Result = client + .get_full_scan_wallet_update( + req, + txs.iter().cloned(), + PRIMARY_WALLET_FULL_SCAN_SETTINGS, + Duration::from_secs(BDK_WALLET_SYNC_TIMEOUT_SECS), + ) + .await + .map(|u| u.into()); + (None, result) + }); + }, + } + } + + for (wallet_account, sync_req) in additional_sync_requests { + let client = Arc::clone(&electrum_client); + let txs = Arc::clone(&cached_txs); + let incremental_batch_size = additional_wallet_incremental_batch_size( + wallet_account.account_index, + additional_full_scan_settings, + ); + match sync_req { + super::WalletSyncRequest::Incremental(req) => { + let timeout = if wallet_account.account_index == 0 { + Duration::from_secs(BDK_WALLET_SYNC_TIMEOUT_SECS) + } else { + derived_wallet_incremental_sync_timeout( + req.progress(), + incremental_batch_size, + ) + }; + join_set.spawn(async move { + let result: Result = client + .get_incremental_sync_wallet_update( + req, + txs.iter().cloned(), + incremental_batch_size, + timeout, + ) + .await + .map(|u| u.into()); + (Some(wallet_account), result) + }); + }, + super::WalletSyncRequest::FullScan(req) => { + let timeout = additional_wallet_full_scan_timeout( + additional_full_scan_settings, + req.keychains().len(), + ); + join_set.spawn(async move { + let result: Result = client + .get_full_scan_wallet_update( + req, + txs.iter().cloned(), + additional_full_scan_settings, + timeout, + ) + .await + .map(|u| u.into()); + (Some(wallet_account), result) + }); + }, + } + } + + let mut primary_update: Option = None; + let mut primary_error: Option = None; + let mut additional_results = Vec::new(); + let mut task_error = None; + + while let Some(join_result) = join_set.join_next().await { + match join_result { + Ok((None, Ok(update))) => { + primary_update = Some(update); + }, + Ok((None, Err(e))) => { + primary_error = Some(e); + }, + Ok((Some(wallet_account), Ok(update))) => { + additional_results.push((wallet_account, Ok(update))); + }, + Ok((Some(wallet_account), Err(e))) => { + log_warn!(self.logger, "Failed to sync wallet {:?}: {}", wallet_account, e); + additional_results.push((wallet_account, Err(e))); + }, + Err(e) => { + log_warn!(self.logger, "Wallet sync task panicked: {}", e); + task_error = Some(Error::WalletOperationFailed); }, - Err(e) => Err(e), }; + } - let cached_txs = onchain_wallet.get_cached_txs(); + if primary_update.is_none() && primary_error.is_none() { + log_error!(self.logger, "Primary wallet sync task failed unexpectedly"); + primary_error = Some(Error::WalletOperationFailed); + } + let mut outcome = super::apply_wallet_sync_results( + primary_update, + primary_error, + task_error, + additional_results, + &onchain_wallet, + &self.node_metrics, + &self.logger, + ); + if outcome.primary_applied { + log_info!( + self.logger, + "{} of primary on-chain wallet finished in {}ms.", + if primary_incremental { "Incremental sync" } else { "Full sync" }, + now.elapsed().as_millis() + ); + } - let res = if incremental_sync { - let incremental_sync_request = onchain_wallet.get_incremental_sync_request(); - let incremental_sync_fut = electrum_client - .get_incremental_sync_wallet_update(incremental_sync_request, cached_txs); + if outcome.any_applied { + if let Err(e) = onchain_wallet.update_payment_store_for_all_transactions() { + log_error!(self.logger, "Failed to update payment store after wallet syncs: {}", e); + outcome.error.get_or_insert(e); + } - let now = Instant::now(); - let update_res = incremental_sync_fut.await.map(|u| u.into()); - apply_wallet_update(update_res, now) - } else { - let full_scan_request = onchain_wallet.get_full_scan_request(); - let full_scan_fut = - electrum_client.get_full_scan_wallet_update(full_scan_request, cached_txs); - let now = Instant::now(); - let update_res = full_scan_fut.await.map(|u| u.into()); - apply_wallet_update(update_res, now) - }; + let locked_node_metrics = self.node_metrics.read().unwrap(); + if let Err(e) = write_node_metrics( + &*locked_node_metrics, + Arc::clone(&self.kv_store), + Arc::clone(&self.logger), + ) { + log_error!(self.logger, "Failed to persist node metrics: {}", e); + } + } - res + Ok(super::WalletSyncOutcome::new(outcome.events, outcome.error)) } pub(crate) async fn sync_lightning_wallet( @@ -307,6 +525,16 @@ impl ElectrumChainSource { electrum_client.broadcast(tx).await; } } + + pub(super) async fn get_address_balance(&self, address: &bitcoin::Address) -> Option { + let electrum_client: Arc = + if let Some(client) = self.electrum_runtime_status.read().unwrap().client().as_ref() { + Arc::clone(client) + } else { + return None; + }; + electrum_client.get_address_balance(address).await + } } impl Filter for ElectrumChainSource { @@ -334,16 +562,17 @@ impl ElectrumRuntimeStatus { } pub(super) fn start( - &mut self, server_url: String, runtime: Arc, config: Arc, - logger: Arc, + &mut self, server_url: String, runtime_handle: Handle, config: Arc, + logger: Arc, connection_timeout_secs: u64, ) -> Result<(), Error> { match self { Self::Stopped { pending_registered_txs, pending_registered_outputs } => { let client = Arc::new(ElectrumRuntimeClient::new( server_url.clone(), - runtime, + runtime_handle, config, logger, + connection_timeout_secs, )?); // Apply any pending `Filter` entries @@ -398,34 +627,75 @@ struct ElectrumRuntimeClient { electrum_client: Arc, bdk_electrum_client: Arc>>, tx_sync: Arc>>, - runtime: Arc, + runtime_handle: Handle, config: Arc, logger: Arc, } impl ElectrumRuntimeClient { fn new( - server_url: String, runtime: Arc, config: Arc, logger: Arc, + server_url: String, runtime_handle: Handle, config: Arc, logger: Arc, + connection_timeout_secs: u64, ) -> Result { + // Every socket operation needs a finite bound so a cancelled blocking job eventually + // completes and cannot hold owned-runtime shutdown open indefinitely. + let timeout = effective_connection_timeout_secs(connection_timeout_secs, logger.as_ref()); + let electrum_config = ElectrumConfigBuilder::new() .retry(ELECTRUM_CLIENT_NUM_RETRIES) - .timeout(Some(ELECTRUM_CLIENT_TIMEOUT_SECS)) + .timeout(Some(timeout)) .build(); let electrum_client = Arc::new( ElectrumClient::from_config(&server_url, electrum_config.clone()).map_err(|e| { - log_error!(logger, "Failed to connect to electrum server: {}", e); + log_error!(logger, "Failed to connect to Electrum server: {}", e); Error::ConnectionFailed })?, ); let bdk_electrum_client = Arc::new(BdkElectrumClient::new(Arc::clone(&electrum_client))); - let tx_sync = Arc::new( - ElectrumSyncClient::new(server_url.clone(), Arc::clone(&logger)).map_err(|e| { - log_error!(logger, "Failed to connect to electrum server: {}", e); + + // The LDK tx-sync client needs its own TCP connection, configured with the same + // timeout so that its blocking reads are bounded and Tokio's blocking thread pool + // is not exhausted by threads stuck on dead sockets. + let ldk_electrum_client = + Arc::new(ElectrumClient::from_config(&server_url, electrum_config).map_err(|e| { + log_error!(logger, "Failed to connect to Electrum server for tx sync: {}", e); Error::ConnectionFailed - })?, + })?); + let tx_sync = Arc::new( + ElectrumSyncClient::from_client(ldk_electrum_client, Arc::clone(&logger)).map_err( + |e| { + log_error!(logger, "Failed to initialize Electrum tx sync client: {}", e); + Error::ConnectionFailed + }, + )?, ); - Ok(Self { electrum_client, bdk_electrum_client, tx_sync, runtime, config, logger }) + Ok(Self { electrum_client, bdk_electrum_client, tx_sync, runtime_handle, config, logger }) + } + + pub(crate) async fn get_address_balance(&self, address: &bitcoin::Address) -> Option { + use electrum_client::ElectrumApi; + + let script = address.script_pubkey(); + let electrum_client = Arc::clone(&self.electrum_client); + let script_clone = script.clone(); + let balance_result = self + .runtime_handle + .spawn_blocking(move || { + electrum_client + .script_get_balance(&script_clone) + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("{}", e))) + }) + .await; + + match balance_result { + Ok(Ok(balance)) => { + let confirmed = balance.confirmed.max(0) as u64; + let unconfirmed = balance.unconfirmed.max(0) as u64; + Some(confirmed + unconfirmed) + }, + _ => None, + } } async fn sync_confirmables( @@ -434,7 +704,7 @@ impl ElectrumRuntimeClient { let now = Instant::now(); let tx_sync = Arc::clone(&self.tx_sync); - let spawn_fut = self.runtime.spawn_blocking(move || tx_sync.sync(confirmables)); + let spawn_fut = self.runtime_handle.spawn_blocking(move || tx_sync.sync(confirmables)); let timeout_fut = tokio::time::timeout(Duration::from_secs(LDK_WALLET_SYNC_TIMEOUT_SECS), spawn_fut); @@ -465,20 +735,15 @@ impl ElectrumRuntimeClient { async fn get_full_scan_wallet_update( &self, request: BdkFullScanRequest, cached_txs: impl IntoIterator>>, + settings: FullScanSettings, timeout: Duration, ) -> Result, Error> { let bdk_electrum_client = Arc::clone(&self.bdk_electrum_client); bdk_electrum_client.populate_tx_cache(cached_txs); - let spawn_fut = self.runtime.spawn_blocking(move || { - bdk_electrum_client.full_scan( - request, - BDK_CLIENT_STOP_GAP, - BDK_ELECTRUM_CLIENT_BATCH_SIZE, - true, - ) + let spawn_fut = self.runtime_handle.spawn_blocking(move || { + bdk_electrum_client.full_scan(request, settings.stop_gap, settings.batch_size, true) }); - let wallet_sync_timeout_fut = - tokio::time::timeout(Duration::from_secs(BDK_WALLET_SYNC_TIMEOUT_SECS), spawn_fut); + let wallet_sync_timeout_fut = tokio::time::timeout(timeout, spawn_fut); wallet_sync_timeout_fut .await @@ -498,16 +763,16 @@ impl ElectrumRuntimeClient { async fn get_incremental_sync_wallet_update( &self, request: BdkSyncRequest<(BdkKeyChainKind, u32)>, - cached_txs: impl IntoIterator>>, + cached_txs: impl IntoIterator>>, batch_size: usize, + timeout: Duration, ) -> Result { let bdk_electrum_client = Arc::clone(&self.bdk_electrum_client); bdk_electrum_client.populate_tx_cache(cached_txs); - let spawn_fut = self.runtime.spawn_blocking(move || { - bdk_electrum_client.sync(request, BDK_ELECTRUM_CLIENT_BATCH_SIZE, true) - }); - let wallet_sync_timeout_fut = - tokio::time::timeout(Duration::from_secs(BDK_WALLET_SYNC_TIMEOUT_SECS), spawn_fut); + let spawn_fut = self + .runtime_handle + .spawn_blocking(move || bdk_electrum_client.sync(request, batch_size, true)); + let wallet_sync_timeout_fut = tokio::time::timeout(timeout, spawn_fut); wallet_sync_timeout_fut .await @@ -532,7 +797,7 @@ impl ElectrumRuntimeClient { let tx_bytes = tx.encode(); let spawn_fut = - self.runtime.spawn_blocking(move || electrum_client.transaction_broadcast(&tx)); + self.runtime_handle.spawn_blocking(move || electrum_client.transaction_broadcast(&tx)); let timeout_fut = tokio::time::timeout(Duration::from_secs(TX_BROADCAST_TIMEOUT_SECS), spawn_fut); @@ -578,7 +843,8 @@ impl ElectrumRuntimeClient { batch.estimate_fee(num_blocks); } - let spawn_fut = self.runtime.spawn_blocking(move || electrum_client.batch_call(&batch)); + let spawn_fut = + self.runtime_handle.spawn_blocking(move || electrum_client.batch_call(&batch)); let timeout_fut = tokio::time::timeout( Duration::from_secs(FEE_RATE_CACHE_UPDATE_TIMEOUT_SECS), @@ -658,3 +924,181 @@ impl Filter for ElectrumRuntimeClient { self.tx_sync.register_output(output) } } + +#[cfg(test)] +mod tests { + use std::net::TcpListener; + use std::process::Command; + use std::sync::mpsc::sync_channel; + use std::thread; + + use super::*; + use crate::runtime::Runtime; + + const RUNTIME_SELF_DROP_CHILD_ENV: &str = "LDK_NODE_ELECTRUM_RUNTIME_SELF_DROP_CHILD"; + + #[test] + fn inflight_electrum_worker_does_not_own_runtime_lifecycle() { + if std::env::var_os(RUNTIME_SELF_DROP_CHILD_ENV).is_some() { + run_inflight_electrum_worker_drop(); + return; + } + + let status = Command::new(std::env::current_exe().unwrap()) + .args([ + "--exact", + "chain::electrum::tests::inflight_electrum_worker_does_not_own_runtime_lifecycle", + "--nocapture", + ]) + .env(RUNTIME_SELF_DROP_CHILD_ENV, "1") + .status() + .unwrap(); + + assert!(status.success(), "in-flight Electrum worker aborted during runtime teardown"); + } + + fn run_inflight_electrum_worker_drop() { + std::panic::set_hook(Box::new(|panic_info| { + eprintln!("{panic_info}"); + std::process::exit(101); + })); + + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let server_url = format!("tcp://{}", listener.local_addr().unwrap()); + let (release_server_tx, release_server_rx) = sync_channel(0); + let server_thread = thread::spawn(move || { + let connections = [listener.accept().unwrap().0, listener.accept().unwrap().0]; + let _ = release_server_rx.recv(); + drop(connections); + }); + + let logger = Arc::new(Logger::new_log_facade()); + let runtime = Arc::new(Runtime::new(Arc::clone(&logger)).unwrap()); + let client = Arc::new( + ElectrumRuntimeClient::new( + server_url, + runtime.handle().clone(), + Arc::new(Config::default()), + logger, + 1, + ) + .unwrap(), + ); + let (worker_started_tx, worker_started_rx) = sync_channel(0); + let (release_worker_tx, release_worker_rx) = tokio::sync::oneshot::channel(); + + runtime.spawn_background_task(async move { + worker_started_tx.send(()).unwrap(); + let _ = release_worker_rx.await; + drop(client); + }); + worker_started_rx.recv_timeout(Duration::from_secs(1)).unwrap(); + + let release_thread = thread::spawn(move || { + thread::sleep(Duration::from_millis(100)); + let _ = release_worker_tx.send(()); + }); + + // A runtime handle lets this drop cancel the in-flight worker from the caller thread. An + // Arc stored by the Electrum client would instead defer the last runtime drop to + // the worker itself and abort the subprocess. + drop(runtime); + release_thread.join().unwrap(); + let _ = release_server_tx.send(()); + server_thread.join().unwrap(); + thread::sleep(Duration::from_millis(500)); + } + + #[test] + fn additional_full_scan_settings_do_not_change_primary_defaults() { + let default_config = ElectrumSyncConfig::default(); + let config = ElectrumSyncConfig { + additional_wallet_full_scan_batch_size: 100, + additional_wallet_full_scan_stop_gap: 1_000, + ..Default::default() + }; + + assert_eq!( + PRIMARY_WALLET_FULL_SCAN_SETTINGS, + FullScanSettings { stop_gap: 20, batch_size: 5 } + ); + assert_eq!( + additional_wallet_full_scan_settings(&default_config), + PRIMARY_WALLET_FULL_SCAN_SETTINGS + ); + assert_eq!( + additional_wallet_full_scan_settings(&config), + FullScanSettings { stop_gap: 1_000, batch_size: 100 } + ); + } + + #[test] + fn electrum_connection_timeout_is_always_finite_and_bounded() { + let logger = Logger::new_log_facade(); + + assert_eq!( + effective_connection_timeout_secs(0, &logger), + DEFAULT_ELECTRUM_CONNECTION_TIMEOUT_SECS as u8 + ); + assert_eq!(effective_connection_timeout_secs(1, &logger), 1); + assert_eq!(effective_connection_timeout_secs(300, &logger), u8::MAX); + } + + #[test] + fn additional_full_scan_settings_are_never_zero() { + let config = ElectrumSyncConfig { + additional_wallet_full_scan_batch_size: 0, + additional_wallet_full_scan_stop_gap: 0, + ..Default::default() + }; + + assert_eq!( + additional_wallet_full_scan_settings(&config), + FullScanSettings { stop_gap: 1, batch_size: 1 } + ); + } + + #[test] + fn additional_full_scan_timeout_scales_with_request_batches() { + assert_eq!( + additional_wallet_full_scan_timeout( + FullScanSettings { stop_gap: 20, batch_size: 5 }, + 2, + ), + Duration::from_secs(28) + ); + assert_eq!( + additional_wallet_full_scan_timeout( + FullScanSettings { stop_gap: 1_000, batch_size: 100 }, + 2, + ), + Duration::from_secs(40) + ); + } + + #[test] + fn derived_incremental_sync_uses_the_configured_batch_size() { + let settings = FullScanSettings { stop_gap: 1_000, batch_size: 100 }; + + assert_eq!(additional_wallet_incremental_batch_size(0, settings), 5); + assert_eq!(additional_wallet_incremental_batch_size(1, settings), 100); + } + + #[test] + fn derived_incremental_timeout_scales_with_request_batches() { + let settings = FullScanSettings { stop_gap: 1_000, batch_size: 100 }; + let progress = BdkSyncProgress { + spks_consumed: 0, + spks_remaining: 2_000, + txids_consumed: 0, + txids_remaining: 0, + outpoints_consumed: 0, + outpoints_remaining: 0, + }; + + assert_eq!( + derived_wallet_incremental_sync_timeout(progress, settings.batch_size), + Duration::from_secs(40) + ); + } +} diff --git a/src/chain/esplora.rs b/src/chain/esplora.rs index f6f313955c..8de1a23962 100644 --- a/src/chain/esplora.rs +++ b/src/chain/esplora.rs @@ -13,13 +13,14 @@ use bdk_esplora::EsploraAsyncExt; use bitcoin::{FeeRate, Network, Script, Transaction, Txid}; use esplora_client::AsyncClient as EsploraAsyncClient; use lightning::chain::{Confirm, Filter, WatchedOutput}; +use lightning::log_warn; use lightning::util::ser::Writeable; use lightning_transaction_sync::EsploraSyncClient; use super::{periodically_archive_fully_resolved_monitors, WalletSyncStatus}; use crate::config::{ - Config, EsploraSyncConfig, BDK_CLIENT_CONCURRENCY, BDK_CLIENT_STOP_GAP, - BDK_WALLET_SYNC_TIMEOUT_SECS, DEFAULT_ESPLORA_CLIENT_TIMEOUT_SECS, + AddressTypeRuntimeConfig, Config, EsploraSyncConfig, BDK_CLIENT_CONCURRENCY, + BDK_CLIENT_STOP_GAP, BDK_WALLET_SYNC_TIMEOUT_SECS, DEFAULT_ESPLORA_CLIENT_TIMEOUT_SECS, FEE_RATE_CACHE_UPDATE_TIMEOUT_SECS, LDK_WALLET_SYNC_TIMEOUT_SECS, TX_BROADCAST_TIMEOUT_SECS, }; use crate::fee_estimator::{ @@ -38,17 +39,19 @@ pub(super) struct EsploraChainSource { tx_sync: Arc>>, lightning_wallet_sync_status: Mutex, fee_estimator: Arc, - kv_store: Arc, - config: Arc, + pub(super) kv_store: Arc, + pub(super) config: Arc, + address_type_runtime_config: Arc>, logger: Arc, - node_metrics: Arc>, + pub(super) node_metrics: Arc>, } impl EsploraChainSource { pub(crate) fn new( server_url: String, headers: HashMap, sync_config: EsploraSyncConfig, fee_estimator: Arc, kv_store: Arc, config: Arc, - logger: Arc, node_metrics: Arc>, + address_type_runtime_config: Arc>, logger: Arc, + node_metrics: Arc>, ) -> Self { let mut client_builder = esplora_client::Builder::new(&server_url); client_builder = client_builder.timeout(DEFAULT_ESPLORA_CLIENT_TIMEOUT_SECS); @@ -72,6 +75,7 @@ impl EsploraChainSource { fee_estimator, kv_store, config, + address_type_runtime_config, logger, node_metrics, } @@ -79,126 +83,238 @@ impl EsploraChainSource { pub(super) async fn sync_onchain_wallet( &self, onchain_wallet: Arc, - ) -> Result<(), Error> { + ) -> super::WalletSyncOutcome { let receiver_res = { let mut status_lock = self.onchain_wallet_sync_status.lock().unwrap(); status_lock.register_or_subscribe_pending_sync() }; if let Some(mut sync_receiver) = receiver_res { log_info!(self.logger, "Sync in progress, skipping."); - return sync_receiver.recv().await.map_err(|e| { - debug_assert!(false, "Failed to receive wallet sync result: {:?}", e); - log_error!(self.logger, "Failed to receive wallet sync result: {:?}", e); - Error::WalletOperationFailed - })?; + match sync_receiver.recv().await { + Ok(Ok(())) => return super::WalletSyncOutcome::new(Vec::new(), None), + Ok(Err(e)) => return super::WalletSyncOutcome::failed(e), + Err(e) => { + debug_assert!(false, "Failed to receive wallet sync result: {:?}", e); + log_error!(self.logger, "Failed to receive wallet sync result: {:?}", e); + return super::WalletSyncOutcome::failed(Error::WalletOperationFailed); + }, + } } - let res = self.sync_onchain_wallet_inner(onchain_wallet).await; + let outcome = self + .sync_onchain_wallet_inner(onchain_wallet) + .await + .unwrap_or_else(super::WalletSyncOutcome::failed); - self.onchain_wallet_sync_status.lock().unwrap().propagate_result_to_subscribers(res); + self.onchain_wallet_sync_status + .lock() + .unwrap() + .propagate_result_to_subscribers(outcome.result()); - res + outcome } - async fn sync_onchain_wallet_inner(&self, onchain_wallet: Arc) -> Result<(), Error> { - // If this is our first sync, do a full scan with the configured gap limit. - // Otherwise just do an incremental sync. - let incremental_sync = + async fn sync_onchain_wallet_inner( + &self, onchain_wallet: Arc, + ) -> Result { + let primary_incremental = self.node_metrics.read().unwrap().latest_onchain_wallet_sync_timestamp.is_some(); - macro_rules! get_and_apply_wallet_update { - ($sync_future: expr) => {{ - let now = Instant::now(); - match $sync_future.await { - Ok(res) => match res { - Ok(update) => match onchain_wallet.apply_update(update) { - Ok(()) => { - log_info!( + let additional_accounts = + self.address_type_runtime_config.read().unwrap().additional_wallet_accounts(); + let additional_sync_requests = super::collect_additional_sync_requests( + &additional_accounts, + &onchain_wallet, + &self.node_metrics, + &self.logger, + )?; + + let primary_request: super::WalletSyncRequest = if primary_incremental { + super::WalletSyncRequest::Incremental(onchain_wallet.get_incremental_sync_request()) + } else { + super::WalletSyncRequest::FullScan(onchain_wallet.get_full_scan_request()) + }; + + // Primary wallet is identified by address_type = None in the JoinSet results. + let now = Instant::now(); + type EsploraSyncResult = ( + Option, + Result< + Result>, + tokio::time::error::Elapsed, + >, + ); + let mut join_set: tokio::task::JoinSet = tokio::task::JoinSet::new(); + + let client = self.esplora_client.clone(); + match primary_request { + super::WalletSyncRequest::Incremental(req) => { + join_set.spawn(async move { + let result = tokio::time::timeout( + Duration::from_secs(BDK_WALLET_SYNC_TIMEOUT_SECS), + client.sync(req, BDK_CLIENT_CONCURRENCY), + ) + .await + .map(|r| r.map(|u| bdk_wallet::Update::from(u))); + (None, result) + }); + }, + super::WalletSyncRequest::FullScan(req) => { + join_set.spawn(async move { + let result = tokio::time::timeout( + Duration::from_secs(BDK_WALLET_SYNC_TIMEOUT_SECS), + client.full_scan(req, BDK_CLIENT_STOP_GAP, BDK_CLIENT_CONCURRENCY), + ) + .await + .map(|r| r.map(|u| bdk_wallet::Update::from(u))); + (None, result) + }); + }, + } + + for (wallet_account, sync_req) in additional_sync_requests { + let client = self.esplora_client.clone(); + match sync_req { + super::WalletSyncRequest::Incremental(req) => { + join_set.spawn(async move { + let result = tokio::time::timeout( + Duration::from_secs(BDK_WALLET_SYNC_TIMEOUT_SECS), + client.sync(req, BDK_CLIENT_CONCURRENCY), + ) + .await + .map(|r| r.map(|u| bdk_wallet::Update::from(u))); + (Some(wallet_account), result) + }); + }, + super::WalletSyncRequest::FullScan(req) => { + join_set.spawn(async move { + let result = tokio::time::timeout( + Duration::from_secs(BDK_WALLET_SYNC_TIMEOUT_SECS), + client.full_scan(req, BDK_CLIENT_STOP_GAP, BDK_CLIENT_CONCURRENCY), + ) + .await + .map(|r| r.map(|u| bdk_wallet::Update::from(u))); + (Some(wallet_account), result) + }); + }, + } + } + + let mut primary_update: Option = None; + let mut primary_error: Option = None; + let mut additional_results = Vec::new(); + let mut task_error = None; + + while let Some(join_result) = join_set.join_next().await { + match join_result { + Ok((None, Ok(Ok(update)))) => { + primary_update = Some(update); + }, + Ok((None, Ok(Err(e)))) => { + match *e { + esplora_client::Error::Reqwest(ref he) => { + if let Some(status_code) = he.status() { + log_error!( self.logger, - "{} of on-chain wallet finished in {}ms.", - if incremental_sync { "Incremental sync" } else { "Sync" }, - now.elapsed().as_millis() + "{} of primary on-chain wallet failed due to HTTP {} error: {}", + if primary_incremental { + "Incremental sync" + } else { + "Full sync" + }, + status_code, + he, ); - let unix_time_secs_opt = SystemTime::now() - .duration_since(UNIX_EPOCH) - .ok() - .map(|d| d.as_secs()); - { - let mut locked_node_metrics = self.node_metrics.write().unwrap(); - locked_node_metrics.latest_onchain_wallet_sync_timestamp = unix_time_secs_opt; - write_node_metrics( - &*locked_node_metrics, - Arc::clone(&self.kv_store), - Arc::clone(&self.logger) - )?; - } - Ok(()) - }, - Err(e) => Err(e), - }, - Err(e) => match *e { - esplora_client::Error::Reqwest(he) => { - if let Some(status_code) = he.status() { - log_error!( - self.logger, - "{} of on-chain wallet failed due to HTTP {} error: {}", - if incremental_sync { "Incremental sync" } else { "Sync" }, - status_code, - he, - ); - } else { - log_error!( - self.logger, - "{} of on-chain wallet failed due to HTTP error: {}", - if incremental_sync { "Incremental sync" } else { "Sync" }, - he, - ); - } - Err(Error::WalletOperationFailed) - }, - _ => { + } else { log_error!( self.logger, - "{} of on-chain wallet failed due to Esplora error: {}", - if incremental_sync { "Incremental sync" } else { "Sync" }, - e + "{} of primary on-chain wallet failed due to HTTP error: {}", + if primary_incremental { + "Incremental sync" + } else { + "Full sync" + }, + he, ); - Err(Error::WalletOperationFailed) - }, + } }, - }, - Err(e) => { - log_error!( - self.logger, - "{} of on-chain wallet timed out: {}", - if incremental_sync { "Incremental sync" } else { "Sync" }, - e - ); - Err(Error::WalletOperationTimeout) - }, - } - }} + _ => { + log_error!( + self.logger, + "{} of primary on-chain wallet failed due to Esplora error: {}", + if primary_incremental { "Incremental sync" } else { "Full sync" }, + e + ); + }, + } + primary_error = Some(Error::WalletOperationFailed); + }, + Ok((None, Err(e))) => { + log_error!( + self.logger, + "{} of primary on-chain wallet timed out: {}", + if primary_incremental { "Incremental sync" } else { "Full sync" }, + e + ); + primary_error = Some(Error::WalletOperationTimeout); + }, + Ok((Some(wallet_account), Ok(Ok(update)))) => { + additional_results.push((wallet_account, Ok(update))); + }, + Ok((Some(wallet_account), Ok(Err(e)))) => { + log_warn!(self.logger, "Failed to sync wallet {:?}: {}", wallet_account, e); + additional_results.push((wallet_account, Err(Error::WalletOperationFailed))); + }, + Ok((Some(wallet_account), Err(_))) => { + log_warn!(self.logger, "Sync timeout for wallet {:?}", wallet_account); + additional_results.push((wallet_account, Err(Error::WalletOperationTimeout))); + }, + Err(e) => { + log_warn!(self.logger, "Wallet sync task panicked: {}", e); + task_error = Some(Error::WalletOperationFailed); + }, + }; } - if incremental_sync { - let sync_request = onchain_wallet.get_incremental_sync_request(); - let wallet_sync_timeout_fut = tokio::time::timeout( - Duration::from_secs(BDK_WALLET_SYNC_TIMEOUT_SECS), - self.esplora_client.sync(sync_request, BDK_CLIENT_CONCURRENCY), - ); - get_and_apply_wallet_update!(wallet_sync_timeout_fut) - } else { - let full_scan_request = onchain_wallet.get_full_scan_request(); - let wallet_sync_timeout_fut = tokio::time::timeout( - Duration::from_secs(BDK_WALLET_SYNC_TIMEOUT_SECS), - self.esplora_client.full_scan( - full_scan_request, - BDK_CLIENT_STOP_GAP, - BDK_CLIENT_CONCURRENCY, - ), + if primary_update.is_none() && primary_error.is_none() { + log_error!(self.logger, "Primary wallet sync task failed unexpectedly"); + primary_error = Some(Error::WalletOperationFailed); + } + let mut outcome = super::apply_wallet_sync_results( + primary_update, + primary_error, + task_error, + additional_results, + &onchain_wallet, + &self.node_metrics, + &self.logger, + ); + if outcome.primary_applied { + log_info!( + self.logger, + "{} of primary on-chain wallet finished in {}ms.", + if primary_incremental { "Incremental sync" } else { "Full sync" }, + now.elapsed().as_millis() ); - get_and_apply_wallet_update!(wallet_sync_timeout_fut) } + + if outcome.any_applied { + if let Err(e) = onchain_wallet.update_payment_store_for_all_transactions() { + log_error!(self.logger, "Failed to update payment store after wallet syncs: {}", e); + outcome.error.get_or_insert(e); + } + + let locked_node_metrics = self.node_metrics.read().unwrap(); + if let Err(e) = write_node_metrics( + &*locked_node_metrics, + Arc::clone(&self.kv_store), + Arc::clone(&self.logger), + ) { + log_error!(self.logger, "Failed to persist node metrics: {}", e); + } + } + + Ok(super::WalletSyncOutcome::new(outcome.events, outcome.error)) } pub(super) async fn sync_lightning_wallet( @@ -433,6 +549,31 @@ impl EsploraChainSource { } } } + + pub(super) async fn get_address_balance(&self, address: &bitcoin::Address) -> Option { + let script = address.script_pubkey(); + match self.esplora_client.scripthash_txs(&script, None).await { + Ok(txs) => { + let mut balance = 0i64; + for tx in txs { + for output in &tx.vout { + if output.scriptpubkey == script { + balance += output.value as i64; + } + } + for input in &tx.vin { + if let Some(prevout) = &input.prevout { + if prevout.scriptpubkey == script { + balance -= prevout.value as i64; + } + } + } + } + Some(balance.max(0) as u64) + }, + Err(_) => None, + } + } } impl Filter for EsploraChainSource { diff --git a/src/chain/mod.rs b/src/chain/mod.rs index 2cd98e20d8..07aaf62527 100644 --- a/src/chain/mod.rs +++ b/src/chain/mod.rs @@ -10,26 +10,37 @@ mod electrum; mod esplora; use std::collections::HashMap; -use std::sync::{Arc, RwLock}; -use std::time::Duration; +use std::ops::Deref; +use std::sync::{Arc, Mutex, RwLock}; +use std::time::{Duration, SystemTime, UNIX_EPOCH}; +use bdk_chain::spk_client::{FullScanRequest, SyncRequest}; +use bdk_wallet::event::WalletEvent as BdkWalletEvent; +use bdk_wallet::{KeychainKind, Update as BdkUpdate}; use bitcoin::{Script, Txid}; use lightning::chain::{BestBlock, Filter}; +use lightning::log_warn; use lightning_block_sync::gossip::UtxoSource; use crate::chain::bitcoind::BitcoindChainSource; use crate::chain::electrum::ElectrumChainSource; use crate::chain::esplora::EsploraChainSource; use crate::config::{ - BackgroundSyncConfig, BitcoindRestClientConfig, Config, ElectrumSyncConfig, EsploraSyncConfig, + AddressTypeRuntimeConfig, BackgroundSyncConfig, BitcoindRestClientConfig, Config, + ElectrumSyncConfig, EsploraSyncConfig, OnchainWalletAccount, RESOLVED_CHANNEL_MONITOR_ARCHIVAL_INTERVAL, WALLET_SYNC_INTERVAL_MINIMUM_SECS, }; +use crate::event::{Event, EventQueue, SyncType, TransactionDetails}; use crate::fee_estimator::OnchainFeeEstimator; use crate::io::utils::write_node_metrics; -use crate::logger::{log_debug, log_info, log_trace, LdkLogger, Logger}; -use crate::runtime::Runtime; +use crate::logger::{log_debug, log_error, log_info, log_trace, LdkLogger, Logger}; use crate::types::{Broadcaster, ChainMonitor, ChannelManager, DynStore, Sweeper, Wallet}; -use crate::{Error, NodeMetrics}; +use crate::{check_and_emit_balance_update, Error, NodeMetrics}; + +pub(super) enum WalletSyncRequest { + FullScan(FullScanRequest), + Incremental(SyncRequest<(KeychainKind, u32)>), +} pub(crate) enum WalletSyncStatus { Completed, @@ -88,6 +99,9 @@ pub(crate) struct ChainSource { kind: ChainSourceKind, tx_broadcaster: Arc, logger: Arc, + onchain_wallet: Arc>>>, + event_queue: Arc>>>>>, + sync_config_sender: Option>, } enum ChainSourceKind { @@ -96,13 +110,478 @@ enum ChainSourceKind { Bitcoind(BitcoindChainSource), } +// Check for evicted transactions by comparing unconfirmed txids before and after sync. +// Returns a list of txids that were unconfirmed before but are no longer unconfirmed +// and are not confirmed in the wallet. +fn check_evicted_transactions( + prev_unconfirmed_txids: Vec, wallet: &crate::wallet::Wallet, logger: &Logger, +) -> Vec { + let current_unconfirmed_txids: std::collections::HashSet = + wallet.get_unconfirmed_txids().into_iter().collect(); + let transaction_confirmations = wallet.transaction_confirmations(); + + let mut evicted_txids = Vec::new(); + for txid in prev_unconfirmed_txids { + // If transaction is still unconfirmed, skip it + if current_unconfirmed_txids.contains(&txid) { + continue; + } + + // Check if transaction is confirmed in wallet + // If it's confirmed, it wasn't evicted - it was included in a block + if transaction_confirmations.contains_key(&txid) { + continue; + } + + // Transaction is not unconfirmed and not confirmed in wallet + // This means it was evicted from the mempool + // (We don't need to check via chain source since the wallet state after sync + // should be up-to-date - if it were confirmed, it would be in the wallet) + log_info!(logger, "Transaction {} was evicted from the mempool", txid); + evicted_txids.push(txid); + } + + evicted_txids +} + +// Check for evicted transactions and emit events for them. +async fn check_and_emit_evicted_transactions( + prev_unconfirmed_txids: Vec, wallet: &crate::wallet::Wallet, + event_queue: &EventQueue, logger: &Logger, +) where + L2::Target: LdkLogger, +{ + let evicted_txids = check_evicted_transactions(prev_unconfirmed_txids, wallet, logger); + + for txid in evicted_txids { + if let Err(e) = event_queue.add_event(Event::OnchainTransactionEvicted { txid }).await { + log_error!(logger, "Failed to push evicted transaction event to queue: {}", e); + } + } +} + +// Get transaction details including inputs and outputs. +fn get_transaction_details( + txid: &bitcoin::Txid, wallet: &crate::wallet::Wallet, + _channel_manager: Option<&Arc>, +) -> Option { + // Get transaction details from wallet + let (amount_sats, inputs, outputs) = wallet.get_tx_details(txid)?; + + Some(TransactionDetails { amount_sats, inputs, outputs }) +} + +pub(super) fn collect_additional_sync_requests( + additional_accounts: &[OnchainWalletAccount], onchain_wallet: &Wallet, + node_metrics: &Arc>, logger: &Arc, +) -> Result, Error> { + additional_accounts + .iter() + .copied() + .map(|wallet_account| { + let do_incremental = + should_use_incremental_sync(wallet_account, onchain_wallet, node_metrics); + let request = if do_incremental { + onchain_wallet + .get_wallet_incremental_sync_request(wallet_account) + .map(WalletSyncRequest::Incremental) + } else { + onchain_wallet + .get_wallet_full_scan_request(wallet_account) + .map(WalletSyncRequest::FullScan) + }; + request.map(|request| (wallet_account, request)).map_err(|e| { + log_warn!(logger, "Failed to build sync request for {:?}: {}", wallet_account, e); + Error::WalletOperationFailed + }) + }) + .collect() +} + +fn should_use_incremental_sync( + wallet_account: OnchainWalletAccount, onchain_wallet: &Wallet, + node_metrics: &Arc>, +) -> bool { + if wallet_account.account_index == 0 { + node_metrics.read().unwrap().get_wallet_sync_timestamp(wallet_account).is_some() + } else { + onchain_wallet.has_synced_derived_account(wallet_account) + } +} + +pub(super) struct AdditionalSyncOutcome { + pub(super) events: Vec, + pub(super) any_applied: bool, + pub(super) error: Option, +} + +pub(super) struct WalletSyncOutcome { + pub(super) events: Vec, + pub(super) error: Option, +} + +impl WalletSyncOutcome { + pub(super) fn new(events: Vec, error: Option) -> Self { + Self { events, error } + } + + pub(super) fn failed(error: Error) -> Self { + Self { events: Vec::new(), error: Some(error) } + } + + pub(super) fn result(&self) -> Result<(), Error> { + self.error.map_or(Ok(()), Err) + } +} + +pub(super) struct AppliedWalletSyncOutcome { + pub(super) events: Vec, + pub(super) any_applied: bool, + pub(super) primary_applied: bool, + pub(super) error: Option, +} + +pub(super) fn apply_additional_sync_results( + results: Vec<(OnchainWalletAccount, Result)>, onchain_wallet: &Wallet, + node_metrics: &Arc>, logger: &Arc, +) -> AdditionalSyncOutcome { + let mut events = Vec::new(); + let mut any_applied = false; + let mut error = None; + for (wallet_account, result) in results { + let update = match result { + Ok(update) => update, + Err(e) => { + log_warn!(logger, "Failed to sync wallet {:?}: {}", wallet_account, e); + error.get_or_insert(e); + continue; + }, + }; + + match onchain_wallet.apply_update_for_wallet_account(wallet_account, update) { + Ok(Some(wallet_events)) => { + any_applied = true; + if let Some(ts) = + SystemTime::now().duration_since(UNIX_EPOCH).ok().map(|d| d.as_secs()) + { + node_metrics.write().unwrap().set_wallet_sync_timestamp(wallet_account, ts); + } + if wallet_account.account_index != 0 { + onchain_wallet.mark_derived_account_synced(wallet_account); + } + events.extend(wallet_events); + }, + Ok(None) => { + log_debug!(logger, "Ignoring sync result for unloaded wallet {:?}", wallet_account); + }, + Err(e) => { + log_warn!(logger, "Failed to apply update to wallet {:?}: {}", wallet_account, e); + error.get_or_insert(e); + }, + } + } + + AdditionalSyncOutcome { events, any_applied, error } +} + +pub(super) fn apply_wallet_sync_results( + primary_update: Option, primary_error: Option, task_error: Option, + additional_results: Vec<(OnchainWalletAccount, Result)>, + onchain_wallet: &Wallet, node_metrics: &Arc>, logger: &Arc, +) -> AppliedWalletSyncOutcome { + let mut events = Vec::new(); + let mut primary_applied = false; + let mut error = primary_error; + + if let Some(update) = primary_update { + match onchain_wallet.apply_update(update) { + Ok(wallet_events) => { + primary_applied = true; + node_metrics.write().unwrap().latest_onchain_wallet_sync_timestamp = + SystemTime::now().duration_since(UNIX_EPOCH).ok().map(|d| d.as_secs()); + events.extend(wallet_events); + }, + Err(e) => { + log_warn!(logger, "Failed to apply primary wallet update: {}", e); + error.get_or_insert(e); + }, + } + } + + error = error.or(task_error); + let additional_outcome = + apply_additional_sync_results(additional_results, onchain_wallet, node_metrics, logger); + events.extend(additional_outcome.events); + error = error.or(additional_outcome.error); + + AppliedWalletSyncOutcome { + events, + any_applied: primary_applied || additional_outcome.any_applied, + primary_applied, + error, + } +} + +#[cfg(test)] +mod sync_tests { + use std::sync::Arc; + + use bdk_chain::{BlockId, CheckPoint}; + use bitcoin::blockdata::constants::genesis_block; + use bitcoin::{hashes::Hash as _, Network}; + + use super::*; + use crate::builder::NodeBuilder; + use crate::config::{AddressType, Config}; + use crate::io::test_utils::InMemoryStore; + use crate::types::DynStore; + + #[test] + fn successful_primary_update_is_applied_when_a_secondary_fetch_fails() { + let mut config = Config::default(); + config.network = Network::Regtest; + let mut builder = NodeBuilder::from_config(config); + builder.set_chain_source_esplora("http://127.0.0.1:1".to_string(), None); + builder.set_entropy_seed_bytes([42u8; 64]); + builder.set_log_facade_logger(); + let store: Arc = Arc::new(InMemoryStore::new()); + let node = builder.build_with_store(store).unwrap(); + let secondary = + OnchainWalletAccount { address_type: AddressType::NativeSegwit, account_index: 1 }; + let genesis = genesis_block(Network::Regtest); + let next_block = BlockId { height: 1, hash: bitcoin::BlockHash::from_byte_array([1; 32]) }; + let checkpoint = CheckPoint::new(BlockId { height: 0, hash: genesis.block_hash() }) + .push(next_block) + .unwrap(); + let primary_update = BdkUpdate { chain: Some(checkpoint), ..Default::default() }; + + let outcome = apply_wallet_sync_results( + Some(primary_update), + None, + None, + vec![(secondary, Err(Error::WalletOperationTimeout))], + &node.wallet, + &node.node_metrics, + &node.logger, + ); + + assert!(outcome.primary_applied); + assert!(outcome.any_applied); + assert!(matches!(outcome.events.as_slice(), [BdkWalletEvent::ChainTipChanged { .. }])); + assert_eq!(outcome.error, Some(Error::WalletOperationTimeout)); + assert_eq!(node.wallet.current_best_block().height, 1); + assert!(node.node_metrics.read().unwrap().latest_onchain_wallet_sync_timestamp.is_some()); + } + + #[test] + fn wallet_sync_outcome_preserves_events_on_failure() { + let block = bitcoin::BlockHash::all_zeros(); + let event = BdkWalletEvent::ChainTipChanged { + old_tip: bdk_chain::BlockId { height: 0, hash: block }, + new_tip: bdk_chain::BlockId { height: 1, hash: block }, + }; + let outcome = WalletSyncOutcome::new(vec![event], Some(Error::WalletOperationTimeout)); + + assert_eq!(outcome.events.len(), 1); + assert_eq!(outcome.result(), Err(Error::WalletOperationTimeout)); + } + + #[test] + fn late_sync_result_for_removed_account_is_ignored() { + let mut config = Config::default(); + config.network = Network::Regtest; + let mut builder = NodeBuilder::from_config(config); + builder.set_chain_source_esplora("http://127.0.0.1:1".to_string(), None); + builder.set_entropy_seed_bytes([42u8; 64]); + builder.set_log_facade_logger(); + let store: Arc = Arc::new(InMemoryStore::new()); + let node = builder.build_with_store(store).unwrap(); + let account = + OnchainWalletAccount { address_type: AddressType::NativeSegwit, account_index: 1 }; + let xpub = node + .export_onchain_wallet_account_xpub(account.address_type, account.account_index) + .unwrap(); + node.add_onchain_wallet_account(account.address_type, account.account_index, xpub).unwrap(); + node.remove_onchain_wallet_account(account.address_type, account.account_index).unwrap(); + + let outcome = apply_additional_sync_results( + vec![(account, Ok(BdkUpdate::default()))], + &node.wallet, + &node.node_metrics, + &node.logger, + ); + + assert!(!outcome.any_applied); + assert!(outcome.events.is_empty()); + assert_eq!(outcome.error, None); + assert_eq!( + node.remove_onchain_wallet_account(account.address_type, account.account_index), + Err(Error::OnchainWalletAccountNotRegistered) + ); + } +} + +// Process BDK wallet events and emit corresponding ldk-node events via the event queue. +// When a transaction touches multiple wallet accounts, each wallet emits its own +// BdkWalletEvent, so we deduplicate by txid before forwarding to the event queue. +async fn process_wallet_events( + wallet_events: Vec, wallet: &crate::wallet::Wallet, + event_queue: &EventQueue, logger: &Arc, + channel_manager: Option<&Arc>, _chain_monitor: Option<&Arc>, +) -> Result<(), Error> +where + L2::Target: LdkLogger, +{ + // Use per-type sets so that two wallets with different prior state can each contribute + // their event type for the same txid without suppressing the other. + let mut seen_received_txids = std::collections::HashSet::new(); + let mut seen_confirmed_txids = std::collections::HashSet::new(); + let mut seen_reorged_txids = std::collections::HashSet::new(); + let mut seen_replaced_txids = std::collections::HashSet::new(); + let transaction_confirmations = wallet.transaction_confirmations(); + + for wallet_event in wallet_events { + match wallet_event { + BdkWalletEvent::TxConfirmed { txid, .. } => { + let Some(block_time) = transaction_confirmations.get(&txid).copied() else { + log_trace!( + logger, + "Deferring confirmation event for {} until tracked wallets agree", + txid + ); + continue; + }; + if !seen_confirmed_txids.insert(txid) { + continue; + } + let details = get_transaction_details(&txid, wallet, channel_manager) + .unwrap_or_else(|| { + log_error!(logger, "Transaction {} not found in wallet", txid); + TransactionDetails { + amount_sats: 0, + inputs: Vec::new(), + outputs: Vec::new(), + } + }); + + log_info!( + logger, + "Onchain transaction {} confirmed at height {}", + txid, + block_time.block_id.height + ); + + let event = Event::OnchainTransactionConfirmed { + txid, + block_hash: block_time.block_id.hash, + block_height: block_time.block_id.height, + confirmation_time: block_time.confirmation_time, + details, + }; + event_queue.add_event(event).await.map_err(|e| { + log_error!(logger, "Failed to push onchain event to queue: {}", e); + e + })?; + }, + BdkWalletEvent::TxUnconfirmed { txid, old_block_time, .. } => { + match old_block_time { + Some(_) => { + if !seen_reorged_txids.insert(txid) { + continue; + } + // Transaction was previously confirmed but is now unconfirmed (reorg) + log_info!( + logger, + "Onchain transaction {} became unconfirmed (reorg)", + txid + ); + let event = Event::OnchainTransactionReorged { txid }; + event_queue.add_event(event).await.map_err(|e| { + log_error!(logger, "Failed to push onchain event to queue: {}", e); + e + })?; + }, + None => { + if !seen_received_txids.insert(txid) { + continue; + } + // New unconfirmed transaction detected in mempool + let details = get_transaction_details(&txid, wallet, channel_manager) + .unwrap_or_else(|| { + log_error!(logger, "Transaction {} not found in wallet", txid); + TransactionDetails { + amount_sats: 0, + inputs: Vec::new(), + outputs: Vec::new(), + } + }); + + log_info!( + logger, + "New unconfirmed transaction {} detected in mempool (amount: {} sats)", + txid, + details.amount_sats + ); + + let event = Event::OnchainTransactionReceived { txid, details }; + event_queue.add_event(event).await.map_err(|e| { + log_error!(logger, "Failed to push onchain event to queue: {}", e); + e + })?; + }, + } + }, + BdkWalletEvent::ChainTipChanged { old_tip, new_tip } => { + log_trace!( + logger, + "Chain tip changed from block {} at height {} to block {} at height {}", + old_tip.hash, + old_tip.height, + new_tip.hash, + new_tip.height + ); + // We don't emit an event for chain tip changes as this is too noisy + }, + BdkWalletEvent::TxReplaced { txid, conflicts, .. } => { + if !seen_replaced_txids.insert(txid) { + continue; + } + let conflict_txids: Vec = + conflicts.iter().map(|(_, conflict_txid)| *conflict_txid).collect(); + log_info!( + logger, + "Onchain transaction {} was replaced by {} transaction(s)", + txid, + conflict_txids.len() + ); + let event = Event::OnchainTransactionReplaced { txid, conflicts: conflict_txids }; + event_queue.add_event(event).await.map_err(|e| { + log_error!(logger, "Failed to push onchain event to queue: {}", e); + e + })?; + }, + _ => { + // TxDropped is handled via check_and_emit_evicted_transactions; skip here. + }, + } + } + Ok(()) +} + impl ChainSource { pub(crate) fn new_esplora( server_url: String, headers: HashMap, sync_config: EsploraSyncConfig, fee_estimator: Arc, tx_broadcaster: Arc, - kv_store: Arc, config: Arc, logger: Arc, + kv_store: Arc, config: Arc, + address_type_runtime_config: Arc>, logger: Arc, node_metrics: Arc>, ) -> (Self, Option) { + // Create watch channel for runtime sync config updates if background sync is enabled + let sync_config_sender = sync_config.background_sync_config.as_ref().map(|cfg| { + let (tx, _) = tokio::sync::watch::channel(cfg.clone()); + tx + }); + let esplora_chain_source = EsploraChainSource::new( server_url, headers, @@ -110,30 +589,59 @@ impl ChainSource { fee_estimator, kv_store, config, + address_type_runtime_config, Arc::clone(&logger), node_metrics, ); let kind = ChainSourceKind::Esplora(esplora_chain_source); - (Self { kind, tx_broadcaster, logger }, None) + ( + Self { + kind, + tx_broadcaster, + logger, + onchain_wallet: Arc::new(Mutex::new(None)), + event_queue: Arc::new(Mutex::new(None)), + sync_config_sender, + }, + None, + ) } pub(crate) fn new_electrum( server_url: String, sync_config: ElectrumSyncConfig, fee_estimator: Arc, tx_broadcaster: Arc, - kv_store: Arc, config: Arc, logger: Arc, + kv_store: Arc, config: Arc, + address_type_runtime_config: Arc>, logger: Arc, node_metrics: Arc>, ) -> (Self, Option) { + // Create watch channel for runtime sync config updates if background sync is enabled + let sync_config_sender = sync_config.background_sync_config.as_ref().map(|cfg| { + let (tx, _) = tokio::sync::watch::channel(cfg.clone()); + tx + }); + let electrum_chain_source = ElectrumChainSource::new( server_url, sync_config, fee_estimator, kv_store, config, + address_type_runtime_config, Arc::clone(&logger), node_metrics, ); let kind = ChainSourceKind::Electrum(electrum_chain_source); - (Self { kind, tx_broadcaster, logger }, None) + ( + Self { + kind, + tx_broadcaster, + logger, + onchain_wallet: Arc::new(Mutex::new(None)), + event_queue: Arc::new(Mutex::new(None)), + sync_config_sender, + }, + None, + ) } pub(crate) async fn new_bitcoind_rpc( @@ -155,7 +663,17 @@ impl ChainSource { ); let best_block = bitcoind_chain_source.poll_best_block().await.ok(); let kind = ChainSourceKind::Bitcoind(bitcoind_chain_source); - (Self { kind, tx_broadcaster, logger }, best_block) + ( + Self { + kind, + tx_broadcaster, + logger, + onchain_wallet: Arc::new(Mutex::new(None)), + event_queue: Arc::new(Mutex::new(None)), + sync_config_sender: None, + }, + best_block, + ) } pub(crate) async fn new_bitcoind_rest( @@ -178,13 +696,23 @@ impl ChainSource { ); let best_block = bitcoind_chain_source.poll_best_block().await.ok(); let kind = ChainSourceKind::Bitcoind(bitcoind_chain_source); - (Self { kind, tx_broadcaster, logger }, best_block) + ( + Self { + kind, + tx_broadcaster, + logger, + onchain_wallet: Arc::new(Mutex::new(None)), + event_queue: Arc::new(Mutex::new(None)), + sync_config_sender: None, + }, + best_block, + ) } - pub(crate) fn start(&self, runtime: Arc) -> Result<(), Error> { + pub(crate) fn start(&self, runtime_handle: tokio::runtime::Handle) -> Result<(), Error> { match &self.kind { ChainSourceKind::Electrum(electrum_chain_source) => { - electrum_chain_source.start(runtime)? + electrum_chain_source.start(runtime_handle)? }, _ => { // Nothing to do for other chain sources. @@ -214,8 +742,8 @@ impl ChainSource { pub(crate) fn is_transaction_based(&self) -> bool { match &self.kind { ChainSourceKind::Esplora(_) => true, - ChainSourceKind::Electrum { .. } => true, - ChainSourceKind::Bitcoind { .. } => false, + ChainSourceKind::Electrum(_) => true, + ChainSourceKind::Bitcoind(_) => false, } } @@ -224,14 +752,25 @@ impl ChainSource { channel_manager: Arc, chain_monitor: Arc, output_sweeper: Arc, ) { + self.set_onchain_wallet(Arc::clone(&onchain_wallet)); + match &self.kind { ChainSourceKind::Esplora(esplora_chain_source) => { if let Some(background_sync_config) = esplora_chain_source.sync_config.background_sync_config.as_ref() { + // Get config receiver for runtime updates + let config_receiver = self + .sync_config_sender + .as_ref() + .expect( + "sync_config_sender should be set when background_sync_config is Some", + ) + .subscribe(); + self.start_tx_based_sync_loop( stop_sync_receiver, - onchain_wallet, + config_receiver, channel_manager, chain_monitor, output_sweeper, @@ -252,9 +791,18 @@ impl ChainSource { if let Some(background_sync_config) = electrum_chain_source.sync_config.background_sync_config.as_ref() { + // Get config receiver for runtime updates + let config_receiver = self + .sync_config_sender + .as_ref() + .expect( + "sync_config_sender should be set when background_sync_config is Some", + ) + .subscribe(); + self.start_tx_based_sync_loop( stop_sync_receiver, - onchain_wallet, + config_receiver, channel_manager, chain_monitor, output_sweeper, @@ -285,11 +833,53 @@ impl ChainSource { } } + // Synchronize the onchain wallet via transaction-based protocols (Esplora, Electrum). + // If event_queue is set, emits onchain events. + pub(crate) async fn sync_onchain_wallet( + &self, wallet: Arc, channel_manager: Option>, + chain_monitor: Option>, + ) -> Result<(), Error> { + let event_queue = self.event_queue.lock().unwrap().clone(); + if let Some(event_queue) = event_queue { + // Use event-emitting sync path + self.sync_onchain_wallet_with_events( + Some(&event_queue), + channel_manager.as_ref(), + chain_monitor.as_ref(), + self.config(), + ) + .await + } else { + // Simple sync without events (event_queue not set) + match &self.kind { + ChainSourceKind::Esplora(esplora_chain_source) => { + esplora_chain_source.sync_onchain_wallet(wallet).await.result() + }, + ChainSourceKind::Electrum(electrum_chain_source) => { + electrum_chain_source.sync_onchain_wallet(wallet).await.result() + }, + ChainSourceKind::Bitcoind(_) => { + // Bitcoind sync is handled differently + Ok(()) + }, + } + } + } + + fn config(&self) -> Option<&Arc> { + match &self.kind { + ChainSourceKind::Esplora(esplora_chain_source) => Some(&esplora_chain_source.config), + ChainSourceKind::Electrum(electrum_chain_source) => Some(&electrum_chain_source.config), + ChainSourceKind::Bitcoind(bitcoind_chain_source) => Some(&bitcoind_chain_source.config), + } + } + async fn start_tx_based_sync_loop( &self, mut stop_sync_receiver: tokio::sync::watch::Receiver<()>, - onchain_wallet: Arc, channel_manager: Arc, - chain_monitor: Arc, output_sweeper: Arc, - background_sync_config: &BackgroundSyncConfig, logger: Arc, + mut config_receiver: tokio::sync::watch::Receiver, + channel_manager: Arc, chain_monitor: Arc, + output_sweeper: Arc, background_sync_config: &BackgroundSyncConfig, + logger: Arc, ) { // Setup syncing intervals let onchain_wallet_sync_interval_secs = background_sync_config @@ -327,8 +917,50 @@ impl ChainSource { ); return; } + Ok(()) = config_receiver.changed() => { + let new_config = config_receiver.borrow().clone(); + log_info!( + logger, + "Background sync intervals updated: onchain={}s, lightning={}s, fee_rate={}s", + new_config.onchain_wallet_sync_interval_secs, + new_config.lightning_wallet_sync_interval_secs, + new_config.fee_rate_cache_update_interval_secs, + ); + + // Reset intervals with new durations (enforce minimum) + let new_onchain_secs = new_config + .onchain_wallet_sync_interval_secs + .max(WALLET_SYNC_INTERVAL_MINIMUM_SECS); + onchain_wallet_sync_interval = + tokio::time::interval(Duration::from_secs(new_onchain_secs)); + onchain_wallet_sync_interval + .set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip); + + let new_fee_rate_secs = new_config + .fee_rate_cache_update_interval_secs + .max(WALLET_SYNC_INTERVAL_MINIMUM_SECS); + fee_rate_update_interval = + tokio::time::interval(Duration::from_secs(new_fee_rate_secs)); + fee_rate_update_interval + .set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip); + + let new_lightning_secs = new_config + .lightning_wallet_sync_interval_secs + .max(WALLET_SYNC_INTERVAL_MINIMUM_SECS); + lightning_wallet_sync_interval = + tokio::time::interval(Duration::from_secs(new_lightning_secs)); + lightning_wallet_sync_interval + .set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip); + } _ = onchain_wallet_sync_interval.tick() => { - let _ = self.sync_onchain_wallet(Arc::clone(&onchain_wallet)).await; + // Access event_queue from struct for event emission + let event_queue = self.event_queue.lock().unwrap().clone(); + let _ = self.sync_onchain_wallet_with_events( + event_queue.as_ref(), + Some(&channel_manager), + Some(&chain_monitor), + self.config(), + ).await; } _ = fee_rate_update_interval.tick() => { let _ = self.update_fee_rate_estimates().await; @@ -344,17 +976,234 @@ impl ChainSource { } } + pub(crate) fn set_onchain_wallet(&self, wallet: Arc) { + *self.onchain_wallet.lock().unwrap() = Some(wallet); + } + + pub(crate) fn set_event_queue(&self, event_queue: Arc>>) { + *self.event_queue.lock().unwrap() = Some(event_queue); + } + + /// Update the background sync configuration at runtime. + /// + /// This allows changing sync intervals while the node is running. + /// Returns an error if background syncing was disabled at build time. + pub(crate) fn set_background_sync_config( + &self, config: BackgroundSyncConfig, + ) -> Result<(), Error> { + if let Some(ref sender) = self.sync_config_sender { + // Send will only fail if there are no receivers, which shouldn't happen + // while the sync loop is running + let _ = sender.send(config); + Ok(()) + } else { + Err(Error::BackgroundSyncNotEnabled) + } + } + // Synchronize the onchain wallet via transaction-based protocols (i.e., Esplora, Electrum, - // etc.) - pub(crate) async fn sync_onchain_wallet( - &self, onchain_wallet: Arc, + // etc.) with event emission support. + async fn sync_onchain_wallet_with_events( + &self, event_queue: Option<&Arc>>>, + channel_manager: Option<&Arc>, chain_monitor: Option<&Arc>, + config: Option<&Arc>, ) -> Result<(), Error> { + let wallet = self.onchain_wallet.lock().unwrap().clone(); + let wallet = wallet.ok_or(Error::WalletOperationFailed)?; + match &self.kind { ChainSourceKind::Esplora(esplora_chain_source) => { - esplora_chain_source.sync_onchain_wallet(onchain_wallet).await + // Track unconfirmed transactions before sync to detect evictions + let prev_unconfirmed_txids = wallet.get_unconfirmed_txids(); + + let WalletSyncOutcome { events: wallet_events, error: sync_error } = + esplora_chain_source.sync_onchain_wallet(Arc::clone(&wallet)).await; + + // Process wallet events if event queue is provided + if let Some(event_queue) = event_queue { + process_wallet_events( + wallet_events, + &wallet, + event_queue, + &self.logger, + channel_manager, + chain_monitor, + ) + .await?; + } + + if let Some(error) = sync_error { + return Err(error); + } + + if let Some(event_queue) = event_queue { + // Check for evicted transactions + check_and_emit_evicted_transactions( + prev_unconfirmed_txids, + &wallet, + event_queue, + &self.logger, + ) + .await; + + // Emit SyncCompleted event + let synced_height = wallet.current_best_block().height; + event_queue + .add_event(Event::SyncCompleted { + sync_type: SyncType::OnchainWallet, + synced_block_height: synced_height, + }) + .await?; + // Check for balance changes and emit BalanceChanged event if needed + if let (Some(cm), Some(chain_mon), Some(cfg)) = + (channel_manager, chain_monitor, config) + { + let cur_anchor_reserve_sats = + crate::total_anchor_channels_reserve_sats(cm, cfg); + let (total_onchain_balance_sats, spendable_onchain_balance_sats) = + wallet.get_balances(cur_anchor_reserve_sats).unwrap_or((0, 0)); + + let mut total_lightning_balance_sats = 0; + for channel_id in chain_mon.list_monitors() { + if let Ok(monitor) = chain_mon.get_monitor(channel_id) { + for ldk_balance in monitor.get_claimable_balances() { + total_lightning_balance_sats += + ldk_balance.claimable_amount_satoshis(); + } + } + } + + let balance_details = crate::BalanceDetails { + total_onchain_balance_sats, + spendable_onchain_balance_sats, + total_anchor_channels_reserve_sats: std::cmp::min( + cur_anchor_reserve_sats, + total_onchain_balance_sats, + ), + total_lightning_balance_sats, + lightning_balances: Vec::new(), + pending_balances_from_channel_closures: Vec::new(), + }; + + let node_metrics = match &self.kind { + ChainSourceKind::Esplora(es) => Arc::clone(&es.node_metrics), + ChainSourceKind::Electrum(el) => Arc::clone(&el.node_metrics), + ChainSourceKind::Bitcoind(bd) => Arc::clone(&bd.node_metrics), + }; + let kv_store = match &self.kind { + ChainSourceKind::Esplora(es) => Arc::clone(&es.kv_store), + ChainSourceKind::Electrum(el) => Arc::clone(&el.kv_store), + ChainSourceKind::Bitcoind(bd) => Arc::clone(&bd.kv_store), + }; + + check_and_emit_balance_update( + &node_metrics, + &balance_details, + event_queue, + &kv_store, + &self.logger, + ) + .await?; + } + } + Ok(()) }, ChainSourceKind::Electrum(electrum_chain_source) => { - electrum_chain_source.sync_onchain_wallet(onchain_wallet).await + // Track unconfirmed transactions before sync to detect evictions + let prev_unconfirmed_txids = wallet.get_unconfirmed_txids(); + + let WalletSyncOutcome { events: wallet_events, error: sync_error } = + electrum_chain_source.sync_onchain_wallet(Arc::clone(&wallet)).await; + + // Process wallet events if event queue is provided + if let Some(event_queue) = event_queue { + process_wallet_events( + wallet_events, + &wallet, + event_queue, + &self.logger, + channel_manager, + chain_monitor, + ) + .await?; + } + + if let Some(error) = sync_error { + return Err(error); + } + + if let Some(event_queue) = event_queue { + // Check for evicted transactions + check_and_emit_evicted_transactions( + prev_unconfirmed_txids, + &wallet, + event_queue, + &self.logger, + ) + .await; + + // Emit SyncCompleted event + let synced_height = wallet.current_best_block().height; + event_queue + .add_event(Event::SyncCompleted { + sync_type: SyncType::OnchainWallet, + synced_block_height: synced_height, + }) + .await?; + + // Check for balance changes and emit BalanceChanged event if needed + if let (Some(cm), Some(chain_mon), Some(cfg)) = + (channel_manager, chain_monitor, config) + { + let cur_anchor_reserve_sats = + crate::total_anchor_channels_reserve_sats(cm, cfg); + let (total_onchain_balance_sats, spendable_onchain_balance_sats) = + wallet.get_balances(cur_anchor_reserve_sats).unwrap_or((0, 0)); + + let mut total_lightning_balance_sats = 0; + for channel_id in chain_mon.list_monitors() { + if let Ok(monitor) = chain_mon.get_monitor(channel_id) { + for ldk_balance in monitor.get_claimable_balances() { + total_lightning_balance_sats += + ldk_balance.claimable_amount_satoshis(); + } + } + } + + let balance_details = crate::BalanceDetails { + total_onchain_balance_sats, + spendable_onchain_balance_sats, + total_anchor_channels_reserve_sats: std::cmp::min( + cur_anchor_reserve_sats, + total_onchain_balance_sats, + ), + total_lightning_balance_sats, + lightning_balances: Vec::new(), + pending_balances_from_channel_closures: Vec::new(), + }; + + let node_metrics = match &self.kind { + ChainSourceKind::Esplora(es) => Arc::clone(&es.node_metrics), + ChainSourceKind::Electrum(el) => Arc::clone(&el.node_metrics), + ChainSourceKind::Bitcoind(bd) => Arc::clone(&bd.node_metrics), + }; + let kv_store = match &self.kind { + ChainSourceKind::Esplora(es) => Arc::clone(&es.kv_store), + ChainSourceKind::Electrum(el) => Arc::clone(&el.kv_store), + ChainSourceKind::Bitcoind(bd) => Arc::clone(&bd.kv_store), + }; + + check_and_emit_balance_update( + &node_metrics, + &balance_details, + event_queue, + &kv_store, + &self.logger, + ) + .await?; + } + } + Ok(()) }, ChainSourceKind::Bitcoind { .. } => { // In BitcoindRpc mode we sync lightning and onchain wallet in one go via @@ -488,6 +1337,23 @@ impl Filter for ChainSource { } } +impl ChainSource { + pub(crate) async fn get_address_balance(&self, address: &bitcoin::Address) -> Option { + match &self.kind { + ChainSourceKind::Esplora(esplora_chain_source) => { + esplora_chain_source.get_address_balance(address).await + }, + ChainSourceKind::Electrum(electrum_chain_source) => { + electrum_chain_source.get_address_balance(address).await + }, + ChainSourceKind::Bitcoind(_) => { + // BitcoindRpc doesn't have a direct address balance query API + None + }, + } + } +} + fn periodically_archive_fully_resolved_monitors( channel_manager: Arc, chain_monitor: Arc, kv_store: Arc, logger: Arc, node_metrics: Arc>, @@ -506,3 +1372,92 @@ fn periodically_archive_fully_resolved_monitors( } Ok(()) } + +#[cfg(test)] +mod tests { + use std::sync::Arc; + + use bitcoin::Network; + + use super::{collect_additional_sync_requests, WalletSyncRequest}; + use crate::builder::NodeBuilder; + use crate::config::{AddressType, Config, ElectrumSyncConfig, OnchainWalletAccount}; + use crate::io::test_utils::InMemoryStore; + use crate::types::DynStore; + + #[test] + fn derived_accounts_switch_to_incremental_sync_after_initial_scan() { + let seed = [42u8; 64]; + let mut config = Config::default(); + config.network = Network::Regtest; + let mut builder = NodeBuilder::from_config(config); + builder.set_chain_source_esplora("http://127.0.0.1:1".to_string(), None); + builder.set_entropy_seed_bytes(seed); + builder.set_log_facade_logger(); + let store: Arc = Arc::new(InMemoryStore::new()); + let node = builder.build_with_store(store).unwrap(); + let account = + OnchainWalletAccount { address_type: AddressType::NativeSegwit, account_index: 1 }; + let xpub = node + .export_onchain_wallet_account_xpub(account.address_type, account.account_index) + .unwrap(); + node.add_onchain_wallet_account(account.address_type, account.account_index, xpub).unwrap(); + + let requests = collect_additional_sync_requests( + &[account], + &node.wallet, + &node.node_metrics, + &node.logger, + ) + .unwrap(); + assert!(matches!(requests[0].1, WalletSyncRequest::FullScan(_))); + + node.wallet.mark_derived_account_synced(account); + let requests = collect_additional_sync_requests( + &[account], + &node.wallet, + &node.node_metrics, + &node.logger, + ) + .unwrap(); + assert!(matches!(requests[0].1, WalletSyncRequest::Incremental(_))); + } + + #[test] + fn electrum_stop_gap_sets_derived_account_incremental_lookahead() { + let mut config = Config::default(); + config.network = Network::Regtest; + let sync_config = ElectrumSyncConfig { + background_sync_config: None, + additional_wallet_full_scan_stop_gap: 1_000, + ..ElectrumSyncConfig::default() + }; + let mut builder = NodeBuilder::from_config(config); + builder.set_chain_source_electrum("ssl://127.0.0.1:1".to_string(), Some(sync_config)); + builder.set_entropy_seed_bytes([42u8; 64]); + builder.set_log_facade_logger(); + let store: Arc = Arc::new(InMemoryStore::new()); + let node = builder.build_with_store(store).unwrap(); + let account = + OnchainWalletAccount { address_type: AddressType::NativeSegwit, account_index: 1 }; + let xpub = node + .export_onchain_wallet_account_xpub(account.address_type, account.account_index) + .unwrap(); + node.add_onchain_wallet_account(account.address_type, account.account_index, xpub).unwrap(); + node.wallet.mark_derived_account_synced(account); + + let mut requests = collect_additional_sync_requests( + &[account], + &node.wallet, + &node.node_metrics, + &node.logger, + ) + .unwrap(); + match requests.pop().unwrap().1 { + WalletSyncRequest::Incremental(request) => { + assert_eq!(request.progress().spks_remaining, 1_000); + }, + WalletSyncRequest::FullScan(_) => panic!("expected incremental sync request"), + } + } +} diff --git a/src/config.rs b/src/config.rs index 510bcc875e..c271b71200 100644 --- a/src/config.rs +++ b/src/config.rs @@ -15,6 +15,9 @@ use bitcoin::Network; use lightning::ln::msgs::SocketAddress; use lightning::routing::gossip::NodeAlias; use lightning::routing::router::RouteParametersConfig; +use lightning::routing::scoring::{ + ProbabilisticScoringDecayParameters, ProbabilisticScoringFeeParameters, +}; use lightning::util::config::{ ChannelConfig as LdkChannelConfig, MaxDustHTLCExposure as LdkMaxDustHTLCExposure, UserConfig, }; @@ -44,6 +47,12 @@ pub(crate) const DEFAULT_ESPLORA_SERVER_URL: &str = "https://blockstream.info/ap // The default Esplora client timeout we're using. pub(crate) const DEFAULT_ESPLORA_CLIENT_TIMEOUT_SECS: u64 = 10; +// The default Electrum connection/read timeout we're using. +pub(crate) const DEFAULT_ELECTRUM_CONNECTION_TIMEOUT_SECS: u64 = 10; + +// The default number of scripts queried in each Electrum batch. +pub(crate) const BDK_ELECTRUM_CLIENT_BATCH_SIZE: usize = 5; + // The 'stop gap' parameter used by BDK's wallet sync. This seems to configure the threshold // number of derivation indexes after which BDK stops looking for new scripts belonging to the wallet. pub(crate) const BDK_CLIENT_STOP_GAP: usize = 20; @@ -85,10 +94,10 @@ pub(crate) const LDK_EVENT_HANDLER_SHUTDOWN_TIMEOUT_SECS: u64 = 30; pub(crate) const BACKGROUND_TASK_SHUTDOWN_TIMEOUT_SECS: u64 = 5; // The timeout after which we abort a fee rate cache update operation. -pub(crate) const FEE_RATE_CACHE_UPDATE_TIMEOUT_SECS: u64 = 5; +pub(crate) const FEE_RATE_CACHE_UPDATE_TIMEOUT_SECS: u64 = 15; // The timeout after which we abort a transaction broadcast operation. -pub(crate) const TX_BROADCAST_TIMEOUT_SECS: u64 = 5; +pub(crate) const TX_BROADCAST_TIMEOUT_SECS: u64 = 15; // The timeout after which we abort a RGS sync operation. pub(crate) const RGS_SYNC_TIMEOUT_SECS: u64 = 5; @@ -96,9 +105,204 @@ pub(crate) const RGS_SYNC_TIMEOUT_SECS: u64 = 5; /// The length in bytes of our wallets' keys seed. pub const WALLET_KEYS_SEED_LEN: usize = 64; +/// Maximum BIP32 account index that can be registered as a derived on-chain wallet. +/// +/// Hardened derivation only allows indices in `0..2^31`, so account indexes above this value +/// cannot be encoded as a hardened child number. +pub const MAX_ONCHAIN_WALLET_ACCOUNT_INDEX: u32 = (1 << 31) - 1; + // The timeout after which we abort a external scores sync operation. pub(crate) const EXTERNAL_PATHFINDING_SCORES_SYNC_TIMEOUT_SECS: u64 = 5; +/// Supported Bitcoin address types for the on-chain wallet. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum AddressType { + /// Legacy addresses (P2PKH) - BIP 44. + Legacy, + /// Nested SegWit addresses (P2SH-wrapped P2WPKH) - BIP 49. + NestedSegwit, + /// Native SegWit addresses (P2WPKH) - BIP 84. + NativeSegwit, + /// Taproot addresses (P2TR) - BIP 86. + Taproot, +} + +impl AddressType { + /// Returns `true` for address types with a native witness `scriptPubKey` + /// (`NativeSegwit` and `Taproot`). Required by BOLT 2 for channel scripts. + pub fn is_native_witness(&self) -> bool { + matches!(self, AddressType::NativeSegwit | AddressType::Taproot) + } + + /// Returns a stable string suffix used for namespacing persisted wallet data. + pub(crate) fn storage_suffix(&self) -> &'static str { + match self { + AddressType::Legacy => "legacy", + AddressType::NestedSegwit => "nested_segwit", + AddressType::NativeSegwit => "native_segwit", + AddressType::Taproot => "taproot", + } + } + + /// BIP purpose number for this address type (44/49/84/86). + pub(crate) fn bip_purpose(&self) -> u32 { + match self { + AddressType::Legacy => 44, + AddressType::NestedSegwit => 49, + AddressType::NativeSegwit => 84, + AddressType::Taproot => 86, + } + } +} + +/// Identifies an on-chain wallet by [`AddressType`] and BIP44 account index. +/// +/// Account `0` is the main account ([`Config::address_type`] / +/// [`crate::Node::set_primary_address_type`]). Accounts `1+` are derived accounts +/// loaded from [`Config::onchain_wallet_accounts`] or registered at runtime via +/// [`crate::Node::add_onchain_wallet_account`]. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct OnchainWalletAccount { + /// The script/address type of this wallet account. + pub address_type: AddressType, + /// BIP44 account index. `0` is the main account; `1+` are derived accounts. + pub account_index: u32, +} + +impl OnchainWalletAccount { + /// Creates an account-0 (main) wallet identity for `address_type`. + pub const fn account_zero(address_type: AddressType) -> Self { + Self { address_type, account_index: 0 } + } + + /// Returns `true` when this is a derived account (`account_index >= 1`). + pub fn is_derived(&self) -> bool { + self.account_index >= 1 + } + + /// KV-store secondary-namespace suffix for this wallet's BDK data. + /// + /// Account `0` keeps the historical address-type-only suffix (e.g. `native_segwit`). + /// Derived accounts use `{suffix}_{account_index}` (e.g. `native_segwit_1`). + pub(crate) fn storage_suffix(&self) -> String { + if self.account_index == 0 { + self.address_type.storage_suffix().to_string() + } else { + format!("{}_{}", self.address_type.storage_suffix(), self.account_index) + } + } +} + +/// Configures a derived on-chain wallet account to load when the node is built. +/// +/// The xpub must match the account derived from the node's seed. Account `0` is reserved for +/// [`Config::address_type`] and [`Config::address_types_to_monitor`]. +/// Esplora and Electrum recover confirmed history with a full scan. Bitcoind cannot recover +/// confirmed transactions from before a brand-new account's first load. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct OnchainWalletAccountConfig { + /// The script/address type of this wallet account. + pub address_type: AddressType, + /// BIP44 account index between `1` and [`MAX_ONCHAIN_WALLET_ACCOUNT_INDEX`], inclusive. + /// + /// [`MAX_ONCHAIN_WALLET_ACCOUNT_INDEX`]: crate::config::MAX_ONCHAIN_WALLET_ACCOUNT_INDEX + pub account_index: u32, + /// Account-level extended public key derived from the node's seed. + pub xpub: String, +} + +impl Default for AddressType { + fn default() -> Self { + AddressType::NativeSegwit + } +} + +impl lightning::util::ser::Writeable for AddressType { + fn write( + &self, writer: &mut W, + ) -> Result<(), bitcoin::io::Error> { + match self { + AddressType::Legacy => 0u8.write(writer), + AddressType::NestedSegwit => 1u8.write(writer), + AddressType::NativeSegwit => 2u8.write(writer), + AddressType::Taproot => 3u8.write(writer), + } + } +} + +impl lightning::util::ser::Readable for AddressType { + fn read( + reader: &mut R, + ) -> Result { + let discriminant: u8 = lightning::util::ser::Readable::read(reader)?; + match discriminant { + 0 => Ok(AddressType::Legacy), + 1 => Ok(AddressType::NestedSegwit), + 2 => Ok(AddressType::NativeSegwit), + 3 => Ok(AddressType::Taproot), + _ => Err(lightning::ln::msgs::DecodeError::InvalidValue), + } + } +} + +impl Config { + /// Returns the additional address types to monitor, excluding the primary. + pub fn additional_address_types(&self) -> Vec { + let mut seen = std::collections::HashSet::new(); + self.address_types_to_monitor + .iter() + .copied() + .filter(|&at| at != self.address_type && seen.insert(at)) + .collect() + } +} + +/// Runtime wallet configuration, initialized from [`Config`] and updated at runtime. +#[derive(Debug, Clone)] +pub(crate) struct AddressTypeRuntimeConfig { + /// The primary address type for account 0 (new addresses and change outputs). + pub(crate) primary: AddressType, + /// Additional account-0 address types to monitor for existing funds. + pub(crate) monitored: Vec, + /// Loaded derived accounts (`account_index >= 1`). + pub(crate) derived_accounts: Vec, +} + +impl AddressTypeRuntimeConfig { + pub(crate) fn from_config( + config: &Config, derived_accounts: Vec, + ) -> Self { + let monitored = config + .address_types_to_monitor + .iter() + .copied() + .filter(|&at| at != config.address_type) + .collect(); + Self { primary: config.address_type, monitored, derived_accounts } + } + + /// Returns the additional account-0 address types to monitor, deduplicating. + pub(crate) fn additional_address_types(&self) -> Vec { + let mut seen = std::collections::HashSet::new(); + self.monitored.iter().copied().filter(|&at| seen.insert(at)).collect() + } + + /// Returns non-primary wallet identities to chain-sync. + pub(crate) fn additional_wallet_accounts(&self) -> Vec { + let mut accounts: Vec = self + .additional_address_types() + .into_iter() + .map(OnchainWalletAccount::account_zero) + .collect(); + for account in &self.derived_accounts { + if !accounts.contains(account) { + accounts.push(*account); + } + } + accounts + } +} + #[derive(Debug, Clone)] /// Represents the configuration of an [`Node`] instance. /// @@ -184,6 +388,36 @@ pub struct Config { /// **Note:** If unset, default parameters will be used, and you will be able to override the /// parameters on a per-payment basis in the corresponding method calls. pub route_parameters: Option, + /// Optional parameters for configuring routing scorer fee penalties. + /// + /// If unset, defaults from [`ProbabilisticScoringFeeParameters::default`] are used. + pub scoring_fee_params: Option, + /// Optional parameters for configuring routing scorer decay behavior. + /// + /// If unset, defaults from [`ProbabilisticScoringDecayParameters::default`] are used. + pub scoring_decay_params: Option, + /// Whether to include unconfirmed funds from external sources in spendable balance. + /// + /// If `true`, [`BalanceDetails::spendable_onchain_balance_sats`] will include + /// unconfirmed UTXOs received from external wallets (`untrusted_pending` in BDK terms). + /// + /// Default is `false`, meaning only confirmed funds and unconfirmed change from your own + /// transactions are considered spendable. + /// + /// **Warning:** Spending unconfirmed external funds is risky as the sender could + /// double-spend, causing your transaction to fail. + /// + /// [`BalanceDetails::spendable_onchain_balance_sats`]: crate::BalanceDetails::spendable_onchain_balance_sats + pub include_untrusted_pending_in_spendable: bool, + /// The address type for the primary (account `0`) on-chain wallet. Default is `NativeSegwit`. + pub address_type: AddressType, + /// Additional account-`0` address types to monitor for existing funds. + pub address_types_to_monitor: Vec, + /// Derived on-chain wallet accounts to load when the node is built. + /// + /// Registrations are validated against the node's seed. Runtime additions and removals do not + /// mutate this list or persist registration changes. + pub onchain_wallet_accounts: Vec, } impl Default for Config { @@ -197,7 +431,121 @@ impl Default for Config { probing_liquidity_limit_multiplier: DEFAULT_PROBING_LIQUIDITY_LIMIT_MULTIPLIER, anchor_channels_config: Some(AnchorChannelsConfig::default()), route_parameters: None, + scoring_fee_params: None, + scoring_decay_params: None, node_alias: None, + include_untrusted_pending_in_spendable: false, + address_type: AddressType::default(), + address_types_to_monitor: Vec::new(), + onchain_wallet_accounts: Vec::new(), + } + } +} + +/// Configuration options for [`ProbabilisticScoringFeeParameters`]. +#[derive(Debug, Clone)] +pub struct ScoringFeeParameters { + /// See [`ProbabilisticScoringFeeParameters::base_penalty_msat`]. + pub base_penalty_msat: u64, + /// See [`ProbabilisticScoringFeeParameters::base_penalty_amount_multiplier_msat`]. + pub base_penalty_amount_multiplier_msat: u64, + /// See [`ProbabilisticScoringFeeParameters::liquidity_penalty_multiplier_msat`]. + pub liquidity_penalty_multiplier_msat: u64, + /// See [`ProbabilisticScoringFeeParameters::liquidity_penalty_amount_multiplier_msat`]. + pub liquidity_penalty_amount_multiplier_msat: u64, + /// See [`ProbabilisticScoringFeeParameters::historical_liquidity_penalty_multiplier_msat`]. + pub historical_liquidity_penalty_multiplier_msat: u64, + /// See [`ProbabilisticScoringFeeParameters::historical_liquidity_penalty_amount_multiplier_msat`]. + pub historical_liquidity_penalty_amount_multiplier_msat: u64, + /// See [`ProbabilisticScoringFeeParameters::anti_probing_penalty_msat`]. + pub anti_probing_penalty_msat: u64, + /// See [`ProbabilisticScoringFeeParameters::considered_impossible_penalty_msat`]. + pub considered_impossible_penalty_msat: u64, + /// See [`ProbabilisticScoringFeeParameters::linear_success_probability`]. + pub linear_success_probability: bool, + /// See [`ProbabilisticScoringFeeParameters::probing_diversity_penalty_msat`]. + pub probing_diversity_penalty_msat: u64, +} + +impl Default for ScoringFeeParameters { + fn default() -> Self { + let params = ProbabilisticScoringFeeParameters::default(); + Self::from(params) + } +} + +impl From for ScoringFeeParameters { + fn from(value: ProbabilisticScoringFeeParameters) -> Self { + Self { + base_penalty_msat: value.base_penalty_msat, + base_penalty_amount_multiplier_msat: value.base_penalty_amount_multiplier_msat, + liquidity_penalty_multiplier_msat: value.liquidity_penalty_multiplier_msat, + liquidity_penalty_amount_multiplier_msat: value + .liquidity_penalty_amount_multiplier_msat, + historical_liquidity_penalty_multiplier_msat: value + .historical_liquidity_penalty_multiplier_msat, + historical_liquidity_penalty_amount_multiplier_msat: value + .historical_liquidity_penalty_amount_multiplier_msat, + anti_probing_penalty_msat: value.anti_probing_penalty_msat, + considered_impossible_penalty_msat: value.considered_impossible_penalty_msat, + linear_success_probability: value.linear_success_probability, + probing_diversity_penalty_msat: value.probing_diversity_penalty_msat, + } + } +} + +impl From for ProbabilisticScoringFeeParameters { + fn from(value: ScoringFeeParameters) -> Self { + let mut params = ProbabilisticScoringFeeParameters::default(); + params.base_penalty_msat = value.base_penalty_msat; + params.base_penalty_amount_multiplier_msat = value.base_penalty_amount_multiplier_msat; + params.liquidity_penalty_multiplier_msat = value.liquidity_penalty_multiplier_msat; + params.liquidity_penalty_amount_multiplier_msat = + value.liquidity_penalty_amount_multiplier_msat; + params.historical_liquidity_penalty_multiplier_msat = + value.historical_liquidity_penalty_multiplier_msat; + params.historical_liquidity_penalty_amount_multiplier_msat = + value.historical_liquidity_penalty_amount_multiplier_msat; + params.anti_probing_penalty_msat = value.anti_probing_penalty_msat; + params.considered_impossible_penalty_msat = value.considered_impossible_penalty_msat; + params.linear_success_probability = value.linear_success_probability; + params.probing_diversity_penalty_msat = value.probing_diversity_penalty_msat; + params + } +} + +/// Configuration options for [`ProbabilisticScoringDecayParameters`]. +#[derive(Debug, Clone)] +pub struct ScoringDecayParameters { + /// See [`ProbabilisticScoringDecayParameters::historical_no_updates_half_life`]. + pub historical_no_updates_half_life_secs: u64, + /// See [`ProbabilisticScoringDecayParameters::liquidity_offset_half_life`]. + pub liquidity_offset_half_life_secs: u64, +} + +impl Default for ScoringDecayParameters { + fn default() -> Self { + let params = ProbabilisticScoringDecayParameters::default(); + Self::from(params) + } +} + +impl From for ScoringDecayParameters { + fn from(value: ProbabilisticScoringDecayParameters) -> Self { + Self { + historical_no_updates_half_life_secs: value.historical_no_updates_half_life.as_secs(), + liquidity_offset_half_life_secs: value.liquidity_offset_half_life.as_secs(), + } + } +} + +impl From for ProbabilisticScoringDecayParameters { + fn from(value: ScoringDecayParameters) -> Self { + Self { + historical_no_updates_half_life: Duration::from_secs( + value.historical_no_updates_half_life_secs, + ), + liquidity_offset_half_life: Duration::from_secs(value.liquidity_offset_half_life_secs), } } } @@ -373,6 +721,86 @@ impl Default for BackgroundSyncConfig { } } +/// Runtime-adjustable sync intervals for background wallet syncing. +/// +/// This struct allows updating sync intervals after `node.start()` has been called, +/// which is useful for mobile apps that want to reduce battery usage when in the background. +/// +/// ### Defaults +/// +/// | Parameter | Value (secs) | +/// |----------------------------------------|--------------| +/// | `onchain_wallet_sync_interval_secs` | 80 | +/// | `lightning_wallet_sync_interval_secs` | 30 | +/// | `fee_rate_cache_update_interval_secs` | 600 | +/// +/// [`Node::update_sync_intervals`]: crate::Node::update_sync_intervals +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct RuntimeSyncIntervals { + /// Interval for on-chain wallet sync, in seconds. + /// + /// **Note:** A minimum of 10 seconds is enforced. + pub onchain_wallet_sync_interval_secs: u64, + + /// Interval for Lightning wallet sync, in seconds. + /// + /// **Note:** A minimum of 10 seconds is enforced. + pub lightning_wallet_sync_interval_secs: u64, + + /// Interval for fee rate cache updates, in seconds. + /// + /// **Note:** A minimum of 10 seconds is enforced. + pub fee_rate_cache_update_interval_secs: u64, +} + +impl Default for RuntimeSyncIntervals { + fn default() -> Self { + Self { + onchain_wallet_sync_interval_secs: DEFAULT_BDK_WALLET_SYNC_INTERVAL_SECS, + lightning_wallet_sync_interval_secs: DEFAULT_LDK_WALLET_SYNC_INTERVAL_SECS, + fee_rate_cache_update_interval_secs: DEFAULT_FEE_RATE_CACHE_UPDATE_INTERVAL_SECS, + } + } +} + +impl RuntimeSyncIntervals { + /// Returns intervals optimized for battery saving in background operation. + /// + /// This preset uses longer intervals to reduce CPU and network usage: + /// - On-chain wallet sync: 5 minutes (was 80 seconds) + /// - Lightning wallet sync: 2 minutes (was 30 seconds) + /// - Fee rate cache: 30 minutes (was 10 minutes) + /// + /// Ideal for Android foreground services when the app goes to background. + pub fn battery_saving() -> Self { + Self { + onchain_wallet_sync_interval_secs: 300, // 5 minutes + lightning_wallet_sync_interval_secs: 120, // 2 minutes + fee_rate_cache_update_interval_secs: 1800, // 30 minutes + } + } +} + +impl From for BackgroundSyncConfig { + fn from(intervals: RuntimeSyncIntervals) -> Self { + Self { + onchain_wallet_sync_interval_secs: intervals.onchain_wallet_sync_interval_secs, + lightning_wallet_sync_interval_secs: intervals.lightning_wallet_sync_interval_secs, + fee_rate_cache_update_interval_secs: intervals.fee_rate_cache_update_interval_secs, + } + } +} + +/// Returns a [`RuntimeSyncIntervals`] object with battery-saving presets. +/// +/// See the documentation of [`RuntimeSyncIntervals::battery_saving`] for more information. +/// +/// This is mostly meant for use in bindings, in Rust this is synonymous with +/// [`RuntimeSyncIntervals::battery_saving()`]. +pub fn battery_saving_sync_intervals() -> RuntimeSyncIntervals { + RuntimeSyncIntervals::battery_saving() +} + /// Configuration for syncing with an Esplora backend. /// /// Background syncing is enabled by default, using the default values specified in @@ -407,11 +835,40 @@ pub struct ElectrumSyncConfig { /// /// [`Node::sync_wallets`]: crate::Node::sync_wallets pub background_sync_config: Option, + /// Timeout in seconds for each Electrum socket operation (connect, read, write). + /// + /// **Note:** Without a per-socket timeout, threads spawned by `sync_wallets` can block + /// indefinitely under total packet loss, eventually exhausting Tokio's blocking thread pool + /// and causing subsequent `sync_wallets` calls to block indefinitely. + /// + /// Set to `0` to use the safe 10-second default. The effective maximum is 255 seconds (the + /// underlying `electrum_client` crate uses a `u8`); larger values are capped with a warning. + /// Note that two TCP connections are opened at node start (on-chain and Lightning sync), so + /// budget accordingly when tuning this value. Defaults to 10 seconds. + pub connection_timeout_secs: u64, + /// Batch size for Electrum full scans of non-primary wallets. + /// + /// This applies to full scans of monitored account-`0` address types and derived accounts, and to + /// rolling incremental scans of derived accounts. It does not affect primary or account-`0` + /// incremental sync. Values below `1` are treated as `1`. Defaults to `5`. + pub additional_wallet_full_scan_batch_size: u32, + /// Stop gap for Electrum full scans of non-primary wallets. + /// + /// This applies to monitored account-`0` address types and derived accounts. It does not affect + /// the primary wallet. For derived accounts, it also sets the incremental lookahead beyond the + /// highest revealed index. Activity within that window advances and replenishes it. Values below + /// `1` are treated as `1`. Defaults to `20`. + pub additional_wallet_full_scan_stop_gap: u32, } impl Default for ElectrumSyncConfig { fn default() -> Self { - Self { background_sync_config: Some(BackgroundSyncConfig::default()) } + Self { + background_sync_config: Some(BackgroundSyncConfig::default()), + connection_timeout_secs: DEFAULT_ELECTRUM_CONNECTION_TIMEOUT_SECS, + additional_wallet_full_scan_batch_size: BDK_ELECTRUM_CLIENT_BATCH_SIZE as u32, + additional_wallet_full_scan_stop_gap: BDK_CLIENT_STOP_GAP as u32, + } } } @@ -604,4 +1061,19 @@ mod tests { } assert!(may_announce_channel(&node_config).is_ok()); } + + #[test] + fn onchain_wallet_account_helpers() { + use super::{AddressType, OnchainWalletAccount, MAX_ONCHAIN_WALLET_ACCOUNT_INDEX}; + + let main = OnchainWalletAccount::account_zero(AddressType::Taproot); + assert!(!main.is_derived()); + assert_eq!(main.storage_suffix(), "taproot"); + + let derived = + OnchainWalletAccount { address_type: AddressType::NestedSegwit, account_index: 3 }; + assert!(derived.is_derived()); + assert_eq!(derived.storage_suffix(), "nested_segwit_3"); + assert_eq!(MAX_ONCHAIN_WALLET_ACCOUNT_INDEX, (1 << 31) - 1); + } } diff --git a/src/data_store.rs b/src/data_store.rs index 87bd831c9b..de73e2c4c1 100644 --- a/src/data_store.rs +++ b/src/data_store.rs @@ -77,16 +77,18 @@ where let updated; match locked_objects.entry(object.id()) { - hash_map::Entry::Occupied(mut e) => { + hash_map::Entry::Occupied(mut entry) => { let update = object.to_update(); - updated = e.get_mut().update(&update); + let mut updated_object = entry.get().clone(); + updated = updated_object.update(&update); if updated { - self.persist(&e.get())?; + self.persist(&updated_object)?; + entry.insert(updated_object); } }, - hash_map::Entry::Vacant(e) => { - e.insert(object.clone()); + hash_map::Entry::Vacant(entry) => { self.persist(&object)?; + entry.insert(object); updated = true; }, } @@ -172,7 +174,7 @@ where #[cfg(test)] mod tests { use lightning::impl_writeable_tlv_based; - use lightning::util::test_utils::TestLogger; + use lightning::util::test_utils::{TestLogger, TestStore}; use super::*; use crate::hex_utils; @@ -296,4 +298,30 @@ mod tests { new_iou_object.data[0] += 1; assert_eq!(Ok(true), data_store.insert_or_update(new_iou_object)); } + + #[test] + fn insert_or_update_remains_retryable_after_write_failure() { + let store: Arc = Arc::new(TestStore::new(true)); + let logger = Arc::new(TestLogger::new()); + let id = TestObjectId { id: [42u8; 4] }; + let original = TestObject { id, data: [1u8; 3] }; + let data_store = DataStore::new( + vec![original], + "datastore_retry_primary".to_string(), + "datastore_retry_secondary".to_string(), + store, + logger, + ); + + let updated = TestObject { id, data: [2u8; 3] }; + assert_eq!(Err(Error::PersistenceFailed), data_store.insert_or_update(updated)); + assert_eq!(Some(original), data_store.get(&id)); + assert_eq!(Err(Error::PersistenceFailed), data_store.insert_or_update(updated)); + + let new_id = TestObjectId { id: [84u8; 4] }; + let new_object = TestObject { id: new_id, data: [3u8; 3] }; + assert_eq!(Err(Error::PersistenceFailed), data_store.insert_or_update(new_object)); + assert_eq!(None, data_store.get(&new_id)); + assert_eq!(Err(Error::PersistenceFailed), data_store.insert_or_update(new_object)); + } } diff --git a/src/error.rs b/src/error.rs index 20b1cceab1..c285162ca6 100644 --- a/src/error.rs +++ b/src/error.rs @@ -39,6 +39,8 @@ pub enum Error { InvalidCustomTlvs, /// Sending a payment probe has failed. ProbeSendingFailed, + /// A route could not be found for fee estimation. + RouteNotFound, /// A channel could not be opened. ChannelCreationFailed, /// A channel could not be closed. @@ -127,6 +129,33 @@ pub enum Error { InvalidBlindedPaths, /// Asynchronous payment services are disabled. AsyncPaymentServicesDisabled, + /// Cannot RBF a channel funding transaction. + CannotRbfFundingTransaction, + /// The transaction was not found in the wallet. + TransactionNotFound, + /// The transaction is already confirmed and cannot be modified. + TransactionAlreadyConfirmed, + /// The transaction has no spendable outputs. + NoSpendableOutputs, + /// Coin selection failed to find suitable UTXOs. + CoinSelectionFailed, + /// The given mnemonic is invalid. + InvalidMnemonic, + /// Background syncing is not enabled. + /// + /// This error is returned when attempting to update sync intervals but background + /// syncing was disabled at build time by setting `background_sync_config` to `None`. + BackgroundSyncNotEnabled, + /// The address type is already being monitored. + AddressTypeAlreadyMonitored, + /// The address type is the current primary and cannot be added as a monitored type or removed. + AddressTypeIsPrimary, + /// The address type is not currently being monitored. + AddressTypeNotMonitored, + /// The derived on-chain wallet account is not currently registered. + OnchainWalletAccountNotRegistered, + /// The seed bytes or a seed-derived wallet account are invalid. + InvalidSeedBytes, } impl fmt::Display for Error { @@ -145,6 +174,7 @@ impl fmt::Display for Error { Self::PaymentSendingFailed => write!(f, "Failed to send the given payment."), Self::InvalidCustomTlvs => write!(f, "Failed to construct payment with custom TLVs."), Self::ProbeSendingFailed => write!(f, "Failed to send the given payment probe."), + Self::RouteNotFound => write!(f, "Failed to find a route for fee estimation."), Self::ChannelCreationFailed => write!(f, "Failed to create channel."), Self::ChannelClosingFailed => write!(f, "Failed to close channel."), Self::ChannelSplicingFailed => write!(f, "Failed to splice channel."), @@ -205,6 +235,35 @@ impl fmt::Display for Error { Self::AsyncPaymentServicesDisabled => { write!(f, "Asynchronous payment services are disabled.") }, + Self::CannotRbfFundingTransaction => { + write!(f, "Cannot RBF a channel funding transaction.") + }, + Self::TransactionNotFound => write!(f, "The transaction was not found in the wallet."), + Self::TransactionAlreadyConfirmed => { + write!(f, "The transaction is already confirmed and cannot be modified.") + }, + Self::NoSpendableOutputs => write!(f, "The transaction has no spendable outputs."), + Self::CoinSelectionFailed => write!(f, "Coin selection failed to find suitable UTXOs."), + Self::InvalidMnemonic => write!(f, "The given mnemonic is invalid."), + Self::BackgroundSyncNotEnabled => write!(f, "Background syncing is not enabled."), + Self::AddressTypeAlreadyMonitored => { + write!(f, "The address type is already being monitored.") + }, + Self::AddressTypeIsPrimary => { + write!( + f, + "The address type is the current primary and cannot be added as monitored or removed." + ) + }, + Self::AddressTypeNotMonitored => { + write!(f, "The address type is not currently being monitored.") + }, + Self::OnchainWalletAccountNotRegistered => { + write!(f, "The on-chain wallet account is not currently registered.") + }, + Self::InvalidSeedBytes => { + write!(f, "The seed bytes or seed-derived wallet account are invalid.") + }, } } } diff --git a/src/event.rs b/src/event.rs index 41f76f216d..8398ad7a75 100644 --- a/src/event.rs +++ b/src/event.rs @@ -13,12 +13,11 @@ use std::sync::{Arc, Mutex}; use bitcoin::blockdata::locktime::absolute::LockTime; use bitcoin::secp256k1::PublicKey; -use bitcoin::{Amount, OutPoint}; +use bitcoin::{Amount, OutPoint, TxIn, TxOut}; use lightning::events::bump_transaction::BumpTransactionEvent; use lightning::events::{ ClosureReason, Event as LdkEvent, PaymentFailureReason, PaymentPurpose, ReplayEvent, }; -use lightning::impl_writeable_tlv_based_enum; use lightning::ln::channelmanager::PaymentId; use lightning::ln::types::ChannelId; use lightning::routing::gossip::NodeId; @@ -28,6 +27,7 @@ use lightning::util::config::{ use lightning::util::errors::APIError; use lightning::util::persist::KVStore; use lightning::util::ser::{Readable, ReadableArgs, Writeable, Writer}; +use lightning::{impl_writeable_tlv_based, impl_writeable_tlv_based_enum}; use lightning_liquidity::lsps2::utils::compute_opening_fee; use lightning_types::payment::{PaymentHash, PaymentPreimage}; use rand::{rng, Rng}; @@ -47,16 +47,249 @@ use crate::payment::asynchronous::static_invoice_store::StaticInvoiceStore; use crate::payment::store::{ PaymentDetails, PaymentDetailsUpdate, PaymentDirection, PaymentKind, PaymentStatus, }; +use crate::peer_store::persist_missing_channel_peers; use crate::runtime::Runtime; use crate::types::{CustomTlvRecord, DynStore, OnionMessenger, PaymentStore, Sweeper, Wallet}; use crate::{ - hex_utils, BumpTransactionEventHandler, ChannelManager, Error, Graph, PeerInfo, PeerStore, - UserChannelId, + hex_utils, BumpTransactionEventHandler, ChannelManager, Error, Graph, PeerStore, UserChannelId, }; +/// Details about a transaction input. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TxInput { + /// The transaction ID of the previous output being spent. + pub txid: bitcoin::Txid, + /// The output index of the previous output being spent. + pub vout: u32, + /// The script signature (hex-encoded). + pub scriptsig: String, + /// The witness stack (hex-encoded strings). + pub witness: Vec, + /// The sequence number. + pub sequence: u32, +} + +/// Details about a transaction output. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TxOutput { + /// The script public key (hex-encoded). + pub scriptpubkey: String, + /// The script public key type (e.g., "p2pkh", "p2sh", "p2wpkh", "p2wsh", "p2tr"). + pub scriptpubkey_type: Option, + /// The address corresponding to this script (if decodable). + pub scriptpubkey_address: Option, + /// The value in satoshis. + pub value: i64, + /// The output index in the transaction. + pub n: u32, +} + +/// Details about an onchain transaction. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TransactionDetails { + /// The net amount in this transaction (in satoshis). + /// + /// This is calculated as: (received - sent). For incoming payments, + /// this will be positive. For outgoing payments, this will be negative. + /// + /// Note: This amount does NOT include transaction fees. + pub amount_sats: i64, + /// The transaction inputs with full details. + pub inputs: Vec, + /// The transaction outputs with full details. + pub outputs: Vec, +} + +impl_writeable_tlv_based!(TxInput, { + (0, txid, required), + (2, vout, required), + (4, scriptsig, required), + (6, witness, required_vec), + (8, sequence, required), +}); + +impl_writeable_tlv_based!(TxOutput, { + (0, scriptpubkey, required), + (2, scriptpubkey_type, option), + (4, scriptpubkey_address, option), + (6, value, required), + (8, n, required), +}); + +impl_writeable_tlv_based!(TransactionDetails, { + (0, amount_sats, required), + (2, inputs, required_vec), + (4, outputs, required_vec), +}); + +impl TxInput { + pub(crate) fn from_tx_input(tx_input: &TxIn) -> Self { + let scriptsig = hex_utils::to_string(tx_input.script_sig.as_bytes()); + let witness: Vec = + tx_input.witness.iter().map(|w| hex_utils::to_string(w)).collect(); + + Self { + txid: tx_input.previous_output.txid, + vout: tx_input.previous_output.vout, + scriptsig, + witness, + sequence: tx_input.sequence.to_consensus_u32(), + } + } +} + +impl TxOutput { + pub(crate) fn from_tx_output(tx_output: &TxOut, index: u32, network: bitcoin::Network) -> Self { + let scriptpubkey = hex_utils::to_string(tx_output.script_pubkey.as_bytes()); + let (scriptpubkey_type, scriptpubkey_address) = + Self::parse_script_type_and_address(&tx_output.script_pubkey, network); + + Self { + scriptpubkey, + scriptpubkey_type, + scriptpubkey_address, + value: tx_output.value.to_sat() as i64, + n: index, + } + } + + fn parse_script_type_and_address( + script: &bitcoin::Script, network: bitcoin::Network, + ) -> (Option, Option) { + bitcoin::Address::from_script(script, network) + .map(|addr| { + let script_type = match addr.address_type() { + Some(bitcoin::address::AddressType::P2pkh) => Some("p2pkh".to_string()), + Some(bitcoin::address::AddressType::P2sh) => Some("p2sh".to_string()), + Some(bitcoin::address::AddressType::P2wpkh) => Some("p2wpkh".to_string()), + Some(bitcoin::address::AddressType::P2wsh) => Some("p2wsh".to_string()), + Some(bitcoin::address::AddressType::P2tr) => Some("p2tr".to_string()), + _ => None, + }; + (script_type, Some(addr.to_string())) + }) + .unwrap_or((None, None)) + } +} + +/// Describes what component is being synchronized. +/// +/// Note: Currently, only `OnchainWallet` sync completion events are emitted. +/// `LightningWallet` and `FeeRateCache` variants are reserved for future use. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum SyncType { + /// Synchronizing the onchain wallet (checking for new transactions and confirmations). + OnchainWallet, + /// Synchronizing the Lightning wallet (updating channel states and commitments). + /// + /// Reserved for future use - not currently emitted. + LightningWallet, + /// Updating fee rate estimates from the blockchain. + /// + /// Reserved for future use - not currently emitted. + FeeRateCache, +} + +impl_writeable_tlv_based_enum!(SyncType, + (0, OnchainWallet) => {}, + (1, LightningWallet) => {}, + (2, FeeRateCache) => {}, +); + /// An event emitted by [`Node`], which should be handled by the user. /// +/// Events provide a reactive way to be notified about important state changes in the node, +/// including payment status updates, channel lifecycle events, and onchain transaction +/// confirmations. +/// +/// # Handling Events +/// +/// Events should be regularly retrieved and handled using [`Node::next_event`] or +/// [`Node::next_event_async`]. After processing an event, you must call [`Node::event_handled`] +/// to mark it as processed. +/// +/// # Onchain Transaction Events +/// +/// The onchain transaction events (`OnchainTransactionConfirmed`, `OnchainTransactionReceived`, +/// `OnchainTransactionReplaced`, `OnchainTransactionReorged`, and `OnchainTransactionEvicted`) +/// allow applications to reactively respond to onchain wallet activity without polling. +/// +/// ## Example: Monitoring Onchain Transactions (Reactive - No Polling!) +/// +/// ```no_run +/// use ldk_node::bitcoin::Network; +/// use ldk_node::{Builder, Event}; +/// +/// # fn main() -> Result<(), Box> { +/// // Build and start the node with background sync enabled (default) +/// let mut builder = Builder::new(); +/// builder.set_network(Network::Testnet); +/// builder.set_chain_source_esplora("https://blockstream.info/testnet/api".to_string(), None); +/// let node = builder.build()?; +/// node.start()?; // Background sync starts automatically! +/// +/// // Event handling loop (NOT a polling loop!) +/// // The loop is needed to process multiple events over time, but wait_next_event() +/// // BLOCKS (doesn't consume CPU) until an event arrives from background sync. +/// // This is fundamentally different from a polling loop with sleep(). +/// // +/// // WRONG (polling - consumes CPU, slow to react): +/// // loop { sync(); check_state(); sleep(30_seconds); } +/// // +/// // RIGHT (event-driven - zero CPU when idle, instant reaction): +/// // loop { event = wait_for_event(); handle(event); } +/// // +/// loop { +/// // This blocks until an event is available (pushed by background sync) +/// match node.wait_next_event() { +/// Event::OnchainTransactionConfirmed { txid, block_height, details, .. } => { +/// println!("Transaction {} confirmed at height {}", txid, block_height); +/// println!("Amount: {} sats", details.amount_sats); +/// // Update UI, send push notification, etc. - truly reactive! +/// node.event_handled()?; +/// }, +/// Event::OnchainTransactionReceived { txid, details } => { +/// println!("New transaction {} received", txid); +/// println!("Amount: {} sats", details.amount_sats); +/// node.event_handled()?; +/// }, +/// Event::OnchainTransactionReplaced { txid, conflicts } => { +/// println!( +/// "Transaction {} was replaced (RBF) by {} transaction(s)", +/// txid, +/// conflicts.len() +/// ); +/// node.event_handled()?; +/// }, +/// Event::OnchainTransactionReorged { txid } => { +/// println!("Transaction {} became unconfirmed due to a reorg", txid); +/// node.event_handled()?; +/// }, +/// Event::OnchainTransactionEvicted { txid } => { +/// println!("Transaction {} was evicted from the mempool", txid); +/// node.event_handled()?; +/// }, +/// Event::PaymentReceived { .. } => { +/// println!("Payment received!"); +/// node.event_handled()?; +/// }, +/// _ => { +/// node.event_handled()?; +/// }, +/// } +/// } +/// # } +/// ``` +/// +/// **Important**: With background sync enabled (default), wallet syncs happen automatically +/// every ~30 seconds in the background, and events are emitted automatically. You do NOT need +/// to call `sync_wallets()` in a loop. The example above uses `wait_next_event()` which blocks +/// (consumes zero CPU) until events arrive, making it truly reactive with instant notifications. +/// /// [`Node`]: [`crate::Node`] +/// [`Node::next_event`]: [`crate::Node::next_event`] +/// [`Node::next_event_async`]: [`crate::Node::next_event_async`] +/// [`Node::event_handled`]: [`crate::Node::event_handled`] #[derive(Debug, Clone, PartialEq, Eq)] pub enum Event { /// A sent payment was successful. @@ -185,6 +418,26 @@ pub enum Event { /// Custom TLV records attached to the payment custom_records: Vec, }, + /// A sent payment probe was successful. + ProbeSuccessful { + /// A local identifier used to track the probe. + payment_id: PaymentId, + /// The hash of the probe payment. + payment_hash: PaymentHash, + /// The total routing fee paid by the probe path, in thousandths of a satoshi. + route_fee_msat: Option, + }, + /// A sent payment probe has failed. + ProbeFailed { + /// A local identifier used to track the probe. + payment_id: PaymentId, + /// The hash of the probe payment. + payment_hash: PaymentHash, + /// The channel responsible for the failed probe, if known. + short_channel_id: Option, + /// The total routing fee for the failed probe path, in thousandths of a satoshi. + route_fee_msat: Option, + }, /// A channel has been created and is pending confirmation on-chain. ChannelPending { /// The `channel_id` of the channel. @@ -256,6 +509,353 @@ pub enum Event { /// The outpoint of the channel's splice funding transaction, if one was created. abandoned_funding_txo: Option, }, + /// An onchain transaction was confirmed. + /// + /// This event is emitted when the onchain wallet detects that a transaction has transitioned + /// from unconfirmed to confirmed during a wallet sync operation. This includes both incoming + /// and outgoing transactions. + /// + /// Note: This event is only emitted when a transaction's confirmation status changes + /// (unconfirmed → confirmed). Already-confirmed transactions will not trigger this event + /// on subsequent syncs unless they become unconfirmed first (due to a reorg). + /// + /// # Example + /// + /// ```no_run + /// # use ldk_node::{Builder, Event}; + /// # use ldk_node::bitcoin::Network; + /// # let mut builder = Builder::new(); + /// # builder.set_network(Network::Testnet); + /// # builder.set_chain_source_esplora("https://blockstream.info/testnet/api".to_string(), None); + /// # let node = builder.build().unwrap(); + /// # node.start().unwrap(); + /// // Sync the wallet + /// node.sync_wallets().unwrap(); + /// + /// // Check for onchain transaction events + /// if let Some(Event::OnchainTransactionConfirmed { txid, block_height, details, .. }) = + /// node.next_event() + /// { + /// println!("Transaction {} confirmed at height {}", txid, block_height); + /// println!("Amount: {} sats", details.amount_sats); + /// node.event_handled().unwrap(); + /// } + /// ``` + /// + /// ## Cross-Referencing Channel Events + /// + /// To determine if a transaction is channel-related, applications should cross-reference + /// with `ChannelPending` and `ChannelClosed` events: + /// + /// ```no_run + /// # use ldk_node::{Builder, Event, TransactionDetails}; + /// # use ldk_node::bitcoin::Network; + /// # use std::collections::HashMap; + /// # let mut builder = Builder::new(); + /// # builder.set_network(Network::Testnet); + /// # builder.set_chain_source_esplora("https://blockstream.info/testnet/api".to_string(), None); + /// # let node = builder.build().unwrap(); + /// # node.start().unwrap(); + /// // Track channel funding transactions + /// let mut channel_funding_txs = HashMap::new(); + /// + /// loop { + /// if let Some(event) = node.next_event() { + /// match event { + /// Event::ChannelPending { funding_txo, channel_id, .. } => { + /// channel_funding_txs.insert(funding_txo.txid, channel_id); + /// node.event_handled().unwrap(); + /// }, + /// Event::OnchainTransactionConfirmed { txid, .. } => { + /// // This event is only emitted once when the transaction confirms + /// if let Some(channel_id) = channel_funding_txs.get(&txid) { + /// println!("Channel {} funding confirmed!", channel_id); + /// } + /// node.event_handled().unwrap(); + /// }, + /// _ => { + /// node.event_handled().unwrap(); + /// }, + /// } + /// } + /// # break; + /// } + /// ``` + OnchainTransactionConfirmed { + /// The transaction ID. + txid: bitcoin::Txid, + /// The confirmation block hash. + block_hash: bitcoin::BlockHash, + /// The confirmation block height. + block_height: u32, + /// The confirmation timestamp (seconds since epoch). + confirmation_time: u64, + /// Details about the transaction including inputs and outputs. + details: TransactionDetails, + }, + /// A new onchain transaction was received (detected in the mempool). + /// + /// This event is emitted when a transaction is first seen in the mempool, before any + /// confirmations. This is useful for immediately showing incoming payments in the UI + /// or sending notifications to users. + /// + /// **Important**: Unconfirmed transactions can be replaced (RBF), double-spent, or may + /// never confirm. Wait for confirmations before considering funds as received. + /// + /// # Example + /// + /// ```no_run + /// # use ldk_node::{Builder, Event}; + /// # use ldk_node::bitcoin::Network; + /// # let mut builder = Builder::new(); + /// # builder.set_network(Network::Testnet); + /// # builder.set_chain_source_esplora("https://blockstream.info/testnet/api".to_string(), None); + /// # let node = builder.build().unwrap(); + /// # node.start().unwrap(); + /// // When someone sends sats to your wallet... + /// match node.wait_next_event() { + /// Event::OnchainTransactionReceived { txid, details } => { + /// println!("Incoming payment detected! Txid: {}", txid); + /// println!("Amount: {} sats", details.amount_sats); + /// println!("Waiting for confirmations..."); + /// node.event_handled().unwrap(); + /// }, + /// _ => {}, + /// } + /// ``` + OnchainTransactionReceived { + /// The transaction ID of the newly detected transaction. + txid: bitcoin::Txid, + /// Details about the transaction including inputs and outputs. + details: TransactionDetails, + }, + /// An onchain transaction was replaced via Replace-By-Fee (RBF). + /// + /// This event is emitted when a transaction is replaced by another transaction. + /// + /// Applications should handle this event by: + /// - Marking the original transaction as replaced + /// - Updating UI to reflect the replacement + /// - Potentially tracking the new replacement transaction + /// + /// # Example + /// + /// ```no_run + /// # use ldk_node::{Builder, Event}; + /// # use ldk_node::bitcoin::Network; + /// # let mut builder = Builder::new(); + /// # builder.set_network(Network::Testnet); + /// # builder.set_chain_source_esplora("https://blockstream.info/testnet/api".to_string(), None); + /// # let node = builder.build().unwrap(); + /// # node.start().unwrap(); + /// match node.wait_next_event() { + /// Event::OnchainTransactionReplaced { txid, conflicts } => { + /// println!("Transaction {} was replaced by {} transaction(s)", txid, conflicts.len()); + /// for conflict_txid in conflicts { + /// println!(" Replacement transaction: {}", conflict_txid); + /// } + /// node.event_handled().unwrap(); + /// }, + /// _ => {}, + /// } + /// ``` + OnchainTransactionReplaced { + /// The transaction ID that was replaced. + txid: bitcoin::Txid, + /// The transaction IDs that replaced this transaction (conflicts). + /// + /// These are the transactions that share inputs with the replaced transaction + /// and caused it to be replaced. Typically there will be one replacement transaction, + /// but multiple are possible. + conflicts: Vec, + }, + /// An onchain transaction became unconfirmed due to a chain reorganization. + /// + /// This event is emitted when a previously confirmed transaction is no longer + /// in the best chain due to a reorg. The transaction may re-confirm in a future block + /// or remain unconfirmed. + /// + /// **Note**: The reorged transaction may re-confirm in a future block or remain unconfirmed. + /// + /// Applications should handle this event by: + /// - Marking the transaction as pending again + /// - Updating UI to reflect the unconfirmed status + /// - Potentially re-evaluating fee requirements if needed + /// + /// # Example + /// + /// ```no_run + /// # use ldk_node::{Builder, Event}; + /// # use ldk_node::bitcoin::Network; + /// # let mut builder = Builder::new(); + /// # builder.set_network(Network::Testnet); + /// # builder.set_chain_source_esplora("https://blockstream.info/testnet/api".to_string(), None); + /// # let node = builder.build().unwrap(); + /// # node.start().unwrap(); + /// // After a chain reorg... + /// node.sync_wallets().unwrap(); + /// + /// if let Some(Event::OnchainTransactionReorged { txid }) = node.next_event() { + /// println!("Transaction {} became unconfirmed due to a reorg", txid); + /// node.event_handled().unwrap(); + /// } + /// ``` + OnchainTransactionReorged { + /// The transaction ID that became unconfirmed due to a reorg. + txid: bitcoin::Txid, + }, + /// An onchain transaction was evicted from the mempool. + /// + /// This event is emitted when a previously unconfirmed transaction is no longer + /// in the mempool and has not been confirmed in a block. Transactions can be + /// evicted from the mempool for various reasons, such as: + /// - Mempool size limits being exceeded + /// - Transaction expiry (typically 14 days) + /// - Conflicts with other transactions + /// + /// Applications should handle this event by: + /// - Marking the transaction as evicted + /// - Updating UI to reflect the evicted status + /// - Potentially rebroadcasting the transaction if needed + /// + /// # Example + /// + /// ```no_run + /// # use ldk_node::{Builder, Event}; + /// # use ldk_node::bitcoin::Network; + /// # let mut builder = Builder::new(); + /// # builder.set_network(Network::Testnet); + /// # builder.set_chain_source_esplora("https://blockstream.info/testnet/api".to_string(), None); + /// # let node = builder.build().unwrap(); + /// # node.start().unwrap(); + /// match node.wait_next_event() { + /// Event::OnchainTransactionEvicted { txid } => { + /// println!("Transaction {} was evicted from the mempool", txid); + /// node.event_handled().unwrap(); + /// }, + /// _ => {}, + /// } + /// ``` + OnchainTransactionEvicted { + /// The transaction ID that was evicted from the mempool. + txid: bitcoin::Txid, + }, + /// Synchronization progress update. + /// + /// This event is emitted periodically during sync operations to report progress. + /// It allows applications to show progress bars or status messages during lengthy + /// sync operations. + /// + /// # Example + /// + /// ```no_run + /// # use ldk_node::{Builder, Event, SyncType}; + /// # use ldk_node::bitcoin::Network; + /// # let mut builder = Builder::new(); + /// # builder.set_network(Network::Testnet); + /// # builder.set_chain_source_esplora("https://blockstream.info/testnet/api".to_string(), None); + /// # let node = builder.build().unwrap(); + /// # node.start().unwrap(); + /// match node.wait_next_event() { + /// Event::SyncProgress { sync_type, progress_percent, current_block_height, .. } => { + /// match sync_type { + /// SyncType::OnchainWallet => { + /// println!( + /// "Syncing wallet: {}% (block {})", + /// progress_percent, current_block_height + /// ); + /// }, + /// SyncType::LightningWallet => { + /// println!("Syncing Lightning: {}%", progress_percent); + /// }, + /// _ => {}, + /// } + /// node.event_handled().unwrap(); + /// }, + /// _ => {}, + /// } + /// ``` + SyncProgress { + /// The type of sync operation in progress. + sync_type: SyncType, + /// Progress percentage (0-100). + progress_percent: u8, + /// Current block height being processed. + current_block_height: u32, + /// Target block height to sync to. + target_block_height: u32, + }, + /// Wallet synchronization has completed. + /// + /// This event is emitted when a sync operation finishes successfully. + /// + /// # Example + /// + /// ```no_run + /// # use ldk_node::{Builder, Event, SyncType}; + /// # use ldk_node::bitcoin::Network; + /// # let mut builder = Builder::new(); + /// # builder.set_network(Network::Testnet); + /// # builder.set_chain_source_esplora("https://blockstream.info/testnet/api".to_string(), None); + /// # let node = builder.build().unwrap(); + /// # node.start().unwrap(); + /// match node.wait_next_event() { + /// Event::SyncCompleted { sync_type, synced_block_height, .. } => { + /// println!("Sync completed! Now at block {}", synced_block_height); + /// node.event_handled().unwrap(); + /// }, + /// _ => {}, + /// } + /// ``` + SyncCompleted { + /// The type of sync operation that completed. + sync_type: SyncType, + /// The block height that was synced to. + synced_block_height: u32, + }, + /// Wallet balance has changed. + /// + /// This event is emitted when either onchain or Lightning balances change, + /// allowing applications to update balance displays immediately without polling. + /// + /// # Example + /// + /// ```no_run + /// # use ldk_node::{Builder, Event}; + /// # use ldk_node::bitcoin::Network; + /// # let mut builder = Builder::new(); + /// # builder.set_network(Network::Testnet); + /// # builder.set_chain_source_esplora("https://blockstream.info/testnet/api".to_string(), None); + /// # let node = builder.build().unwrap(); + /// # node.start().unwrap(); + /// match node.wait_next_event() { + /// Event::BalanceChanged { + /// new_spendable_onchain_balance_sats, + /// new_total_lightning_balance_sats, + /// .. + /// } => { + /// println!("💰 Balance updated!"); + /// println!(" Onchain: {} sats", new_spendable_onchain_balance_sats); + /// println!(" Lightning: {} sats", new_total_lightning_balance_sats); + /// node.event_handled().unwrap(); + /// }, + /// _ => {}, + /// } + /// ``` + BalanceChanged { + /// Previous spendable onchain balance in satoshis. + old_spendable_onchain_balance_sats: u64, + /// New spendable onchain balance in satoshis. + new_spendable_onchain_balance_sats: u64, + /// Previous total onchain balance (including unconfirmed and reserved) in satoshis. + old_total_onchain_balance_sats: u64, + /// New total onchain balance (including unconfirmed and reserved) in satoshis. + new_total_onchain_balance_sats: u64, + /// Previous total Lightning balance in satoshis. + old_total_lightning_balance_sats: u64, + /// New total Lightning balance in satoshis. + new_total_lightning_balance_sats: u64, + }, } impl_writeable_tlv_based_enum!(Event, @@ -326,6 +926,56 @@ impl_writeable_tlv_based_enum!(Event, (5, user_channel_id, required), (7, abandoned_funding_txo, option), }, + (10, OnchainTransactionConfirmed) => { + (0, txid, required), + (2, block_hash, required), + (4, block_height, required), + (6, confirmation_time, required), + (8, details, required), + }, + (11, OnchainTransactionReceived) => { + (0, txid, required), + (2, details, required), + }, + (12, OnchainTransactionReplaced) => { + (0, txid, required), + (1, conflicts, required_vec), + }, + (13, OnchainTransactionReorged) => { + (0, txid, required), + }, + (14, OnchainTransactionEvicted) => { + (0, txid, required), + }, + (15, SyncProgress) => { + (0, sync_type, required), + (2, progress_percent, required), + (4, current_block_height, required), + (6, target_block_height, required), + }, + (16, SyncCompleted) => { + (0, sync_type, required), + (2, synced_block_height, required), + }, + (17, BalanceChanged) => { + (0, old_spendable_onchain_balance_sats, required), + (2, new_spendable_onchain_balance_sats, required), + (4, old_total_onchain_balance_sats, required), + (6, new_total_onchain_balance_sats, required), + (8, old_total_lightning_balance_sats, required), + (10, new_total_lightning_balance_sats, required), + }, + (18, ProbeSuccessful) => { + (0, payment_hash, required), + (2, payment_id, required), + (4, route_fee_msat, option), + }, + (19, ProbeFailed) => { + (0, payment_hash, required), + (1, short_channel_id, option), + (3, payment_id, required), + (5, route_fee_msat, option), + } ); pub struct EventQueue @@ -979,16 +1629,42 @@ where }; match self.payment_store.update(&update) { - Ok(DataStoreUpdateResult::Updated) | Ok(DataStoreUpdateResult::Unchanged) => ( - // No need to do anything if the idempotent update was applied, which might - // be the result of a replayed event. - ), + Ok(DataStoreUpdateResult::Updated) => { + // Payment was newly updated to Succeeded - emit PaymentReceived event + let event = Event::PaymentReceived { + payment_id: Some(payment_id), + payment_hash, + amount_msat, + custom_records: onion_fields + .map(|cf| { + cf.custom_tlvs().into_iter().map(|tlv| tlv.into()).collect() + }) + .unwrap_or_default(), + }; + match self.event_queue.add_event(event).await { + Ok(_) => return Ok(()), + Err(e) => { + log_error!(self.logger, "Failed to push to event queue: {}", e); + return Err(ReplayEvent()); + }, + }; + }, + Ok(DataStoreUpdateResult::Unchanged) => { + // Payment was already Succeeded - this is a replayed event, don't emit duplicate + log_debug!( + self.logger, + "Skipping duplicate PaymentReceived event for already-succeeded payment {}", + payment_id, + ); + return Ok(()); + }, Ok(DataStoreUpdateResult::NotFound) => { log_error!( self.logger, "Claimed payment with ID {} couldn't be found in store", payment_id, ); + return Ok(()); }, Err(e) => { log_error!( @@ -1000,22 +1676,6 @@ where return Err(ReplayEvent()); }, } - - let event = Event::PaymentReceived { - payment_id: Some(payment_id), - payment_hash, - amount_msat, - custom_records: onion_fields - .map(|cf| cf.custom_tlvs().into_iter().map(|tlv| tlv.into()).collect()) - .unwrap_or_default(), - }; - match self.event_queue.add_event(event).await { - Ok(_) => return Ok(()), - Err(e) => { - log_error!(self.logger, "Failed to push to event queue: {}", e); - return Err(ReplayEvent()); - }, - }; }, LdkEvent::PaymentSent { payment_id, @@ -1040,39 +1700,57 @@ where }; match self.payment_store.update(&update) { - Ok(_) => {}, - Err(e) => { - log_error!(self.logger, "Failed to access payment store: {}", e); - return Err(ReplayEvent()); - }, - }; - - self.payment_store.get(&payment_id).map(|payment| { - log_info!( - self.logger, - "Successfully sent payment of {}msat{} from \ - payment hash {:?} with preimage {:?}", - payment.amount_msat.unwrap(), - if let Some(fee) = fee_paid_msat { - format!(" (fee {} msat)", fee) - } else { - "".to_string() - }, - hex_utils::to_string(&payment_hash.0), - hex_utils::to_string(&payment_preimage.0) - ); - }); - let event = Event::PaymentSuccessful { - payment_id: Some(payment_id), - payment_hash, - payment_preimage: Some(payment_preimage), - fee_paid_msat, - }; + Ok(DataStoreUpdateResult::Updated) => { + // Payment was newly updated - emit PaymentSuccessful event + self.payment_store.get(&payment_id).map(|payment| { + log_info!( + self.logger, + "Successfully sent payment of {}msat{} from \ + payment hash {:?} with preimage {:?}", + payment.amount_msat.unwrap(), + if let Some(fee) = fee_paid_msat { + format!(" (fee {} msat)", fee) + } else { + "".to_string() + }, + hex_utils::to_string(&payment_hash.0), + hex_utils::to_string(&payment_preimage.0) + ); + }); + let event = Event::PaymentSuccessful { + payment_id: Some(payment_id), + payment_hash, + payment_preimage: Some(payment_preimage), + fee_paid_msat, + }; - match self.event_queue.add_event(event).await { - Ok(_) => return Ok(()), + match self.event_queue.add_event(event).await { + Ok(_) => return Ok(()), + Err(e) => { + log_error!(self.logger, "Failed to push to event queue: {}", e); + return Err(ReplayEvent()); + }, + }; + }, + Ok(DataStoreUpdateResult::Unchanged) => { + // Payment was already Succeeded - this is a replayed event + log_debug!( + self.logger, + "Skipping duplicate PaymentSuccessful event for already-succeeded payment {}", + payment_id, + ); + return Ok(()); + }, + Ok(DataStoreUpdateResult::NotFound) => { + log_error!( + self.logger, + "Sent payment with ID {} couldn't be found in store", + payment_id, + ); + return Ok(()); + }, Err(e) => { - log_error!(self.logger, "Failed to push to event queue: {}", e); + log_error!(self.logger, "Failed to access payment store: {}", e); return Err(ReplayEvent()); }, }; @@ -1091,28 +1769,74 @@ where ..PaymentDetailsUpdate::new(payment_id) }; match self.payment_store.update(&update) { - Ok(_) => {}, + Ok(DataStoreUpdateResult::Updated) => { + // Payment was newly updated to Failed - emit PaymentFailed event + let event = Event::PaymentFailed { + payment_id: Some(payment_id), + payment_hash, + reason, + }; + match self.event_queue.add_event(event).await { + Ok(_) => return Ok(()), + Err(e) => { + log_error!(self.logger, "Failed to push to event queue: {}", e); + return Err(ReplayEvent()); + }, + }; + }, + Ok(DataStoreUpdateResult::Unchanged) => { + // Payment was already Failed - this is a replayed event + log_debug!( + self.logger, + "Skipping duplicate PaymentFailed event for already-failed payment {}", + payment_id, + ); + return Ok(()); + }, + Ok(DataStoreUpdateResult::NotFound) => { + log_error!( + self.logger, + "Failed payment with ID {} couldn't be found in store", + payment_id, + ); + return Ok(()); + }, Err(e) => { log_error!(self.logger, "Failed to access payment store: {}", e); return Err(ReplayEvent()); }, }; + }, - let event = - Event::PaymentFailed { payment_id: Some(payment_id), payment_hash, reason }; + LdkEvent::PaymentPathSuccessful { .. } => {}, + LdkEvent::PaymentPathFailed { .. } => {}, + LdkEvent::ProbeSuccessful { payment_id, payment_hash, path, .. } => { + let route_fee_msat = Some(path.fee_msat()); + let event = Event::ProbeSuccessful { payment_id, payment_hash, route_fee_msat }; match self.event_queue.add_event(event).await { - Ok(_) => return Ok(()), + Ok(_) => {}, Err(e) => { - log_error!(self.logger, "Failed to push to event queue: {}", e); + log_error!(self.logger, "Failed to push probe event: {}", e); return Err(ReplayEvent()); }, + } + }, + LdkEvent::ProbeFailed { payment_id, payment_hash, short_channel_id, path, .. } => { + let route_fee_msat = Some(path.fee_msat()); + let event = Event::ProbeFailed { + payment_id, + payment_hash, + short_channel_id, + route_fee_msat, }; + match self.event_queue.add_event(event).await { + Ok(_) => {}, + Err(e) => { + log_error!(self.logger, "Failed to push probe event: {}", e); + return Err(ReplayEvent()); + }, + } }, - - LdkEvent::PaymentPathSuccessful { .. } => {}, - LdkEvent::PaymentPathFailed { .. } => {}, - LdkEvent::ProbeSuccessful { .. } => {}, - LdkEvent::ProbeFailed { .. } => {}, LdkEvent::HTLCHandlingFailed { failure_type, .. } => { if let Some(liquidity_source) = self.liquidity_source.as_ref() { liquidity_source.handle_htlc_handling_failed(failure_type).await; @@ -1411,35 +2135,19 @@ where }, }; - let network_graph = self.network_graph.read_only(); let channels = self.channel_manager.list_channels_with_counterparty(&counterparty_node_id); if let Some(pending_channel) = channels.into_iter().find(|c| c.channel_id == channel_id) { - if !pending_channel.is_outbound - && self.peer_store.get_peer(&counterparty_node_id).is_none() - { - if let Some(address) = network_graph - .nodes() - .get(&NodeId::from_pubkey(&counterparty_node_id)) - .and_then(|node_info| node_info.announcement_info.as_ref()) - .and_then(|ann_info| ann_info.addresses().first()) - { - let peer = PeerInfo { - node_id: counterparty_node_id, - address: address.clone(), - }; - - self.peer_store.add_peer(peer).unwrap_or_else(|e| { - log_error!( - self.logger, - "Failed to add peer {} to peer store: {}", - counterparty_node_id, - e - ); - }); - } + if !pending_channel.is_outbound { + persist_missing_channel_peers( + std::iter::once(counterparty_node_id), + &self.network_graph, + &self.peer_store, + self.logger.clone(), + ) + .await; } } }, @@ -1905,4 +2613,61 @@ mod tests { } assert_eq!(event_queue.next_event(), None); } + + #[tokio::test] + async fn probe_events_persistence_roundtrip() { + let events = [ + Event::ProbeSuccessful { + payment_id: PaymentId([1u8; 32]), + payment_hash: PaymentHash([2u8; 32]), + route_fee_msat: Some(1_234), + }, + Event::ProbeFailed { + payment_id: PaymentId([3u8; 32]), + payment_hash: PaymentHash([4u8; 32]), + short_channel_id: Some(42), + route_fee_msat: Some(5_678), + }, + Event::ProbeFailed { + payment_id: PaymentId([5u8; 32]), + payment_hash: PaymentHash([6u8; 32]), + short_channel_id: None, + route_fee_msat: None, + }, + ]; + + for expected_event in events { + assert_probe_event_persistence_roundtrip(expected_event).await; + } + } + + async fn assert_probe_event_persistence_roundtrip(expected_event: Event) { + let store: Arc = Arc::new(InMemoryStore::new()); + let logger = Arc::new(TestLogger::new()); + let event_queue = Arc::new(EventQueue::new(Arc::clone(&store), Arc::clone(&logger))); + + assert_eq!(event_queue.next_event(), None); + + event_queue.add_event(expected_event.clone()).await.unwrap(); + + // Check we get the expected event and that it is returned until handled. + assert_eq!(event_queue.next_event_async().await, expected_event); + assert_eq!(event_queue.next_event(), Some(expected_event.clone())); + + // Check we can read back what we persisted. + let persisted_bytes = KVStore::read( + &*store, + EVENT_QUEUE_PERSISTENCE_PRIMARY_NAMESPACE, + EVENT_QUEUE_PERSISTENCE_SECONDARY_NAMESPACE, + EVENT_QUEUE_PERSISTENCE_KEY, + ) + .await + .unwrap(); + let deser_event_queue = + EventQueue::read(&mut &persisted_bytes[..], (Arc::clone(&store), logger)).unwrap(); + assert_eq!(deser_event_queue.next_event_async().await, expected_event); + + event_queue.event_handled().await.unwrap(); + assert_eq!(event_queue.next_event(), None); + } } diff --git a/src/ffi/types.rs b/src/ffi/types.rs index 3c88a665fe..c2d7074f0a 100644 --- a/src/ffi/types.rs +++ b/src/ffi/types.rs @@ -42,19 +42,25 @@ pub use lightning_types::payment::{PaymentHash, PaymentPreimage, PaymentSecret}; pub use lightning_types::string::UntrustedString; pub use vss_client::headers::{VssHeaderProvider, VssHeaderProviderError}; +pub use crate::balance::AddressTypeBalance; use crate::builder::sanitize_alias; pub use crate::config::{ - default_config, AnchorChannelsConfig, BackgroundSyncConfig, ElectrumSyncConfig, - EsploraSyncConfig, MaxDustHTLCExposure, + battery_saving_sync_intervals, default_config, AddressType, AnchorChannelsConfig, + BackgroundSyncConfig, ElectrumSyncConfig, EsploraSyncConfig, MaxDustHTLCExposure, + OnchainWalletAccount, RuntimeSyncIntervals, ScoringDecayParameters, ScoringFeeParameters, }; use crate::error::Error; pub use crate::graph::{ChannelInfo, ChannelUpdateInfo, NodeAnnouncementInfo, NodeInfo}; +pub use crate::io::utils::derive_node_secret_from_mnemonic; pub use crate::liquidity::{LSPS1OrderStatus, LSPS2ServiceConfig}; pub use crate::logger::{LogLevel, LogRecord, LogWriter}; pub use crate::payment::store::{ ConfirmationStatus, LSPFeeLimits, PaymentDirection, PaymentKind, PaymentStatus, }; pub use crate::payment::QrPaymentResult; +#[allow(unused_imports)] +pub use crate::payment::{AddressInfo, KeychainKind}; +pub use crate::types::SpendableUtxo; use crate::{hex_utils, SocketAddress, UniffiCustomTypeConverter, UserChannelId}; impl UniffiCustomTypeConverter for PublicKey { diff --git a/src/gossip.rs b/src/gossip.rs index 01aff47425..04710e5033 100644 --- a/src/gossip.rs +++ b/src/gossip.rs @@ -27,7 +27,7 @@ pub(crate) enum GossipSource { RapidGossipSync { gossip_sync: Arc, server_url: String, - latest_sync_timestamp: AtomicU32, + latest_sync_timestamp: Arc, logger: Arc, }, } @@ -43,11 +43,10 @@ impl GossipSource { } pub fn new_rgs( - server_url: String, latest_sync_timestamp: u32, network_graph: Arc, + server_url: String, latest_sync_timestamp: Arc, network_graph: Arc, logger: Arc, ) -> Self { let gossip_sync = Arc::new(RapidGossipSync::new(network_graph, Arc::clone(&logger))); - let latest_sync_timestamp = AtomicU32::new(latest_sync_timestamp); Self::RapidGossipSync { gossip_sync, server_url, latest_sync_timestamp, logger } } diff --git a/src/io/local_graph_store.rs b/src/io/local_graph_store.rs new file mode 100644 index 0000000000..c4f05e533c --- /dev/null +++ b/src/io/local_graph_store.rs @@ -0,0 +1,276 @@ +// This file is Copyright its original authors, visible in version control history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license , at your option. You may not use this file except in +// accordance with one or both of these licenses. + +//! Local caching for the network graph to avoid slow VSS reads/writes. + +use std::fs; +use std::future::Future; +use std::ops::Deref; +use std::pin::Pin; +use std::sync::atomic::{AtomicU32, Ordering}; +use std::sync::Arc; + +use lightning::io; +use lightning::io::Cursor; +use lightning::routing::gossip::NetworkGraph; +use lightning::util::persist::{ + KVStore, KVStoreSync, NETWORK_GRAPH_PERSISTENCE_KEY, + NETWORK_GRAPH_PERSISTENCE_PRIMARY_NAMESPACE, NETWORK_GRAPH_PERSISTENCE_SECONDARY_NAMESPACE, +}; +use lightning::util::ser::ReadableArgs; + +use crate::logger::{log_error, LdkLogger}; +use crate::types::DynStore; + +const LOCAL_GRAPH_CACHE_MAGIC: &[u8; 4] = b"LGNC"; +const LOCAL_GRAPH_CACHE_VERSION: u8 = 1; +pub const NETWORK_GRAPH_LOCAL_CACHE_FILENAME: &str = "network_graph_cache"; + +/// Result of reading the local graph cache. +pub struct LocalGraphCacheData +where + L::Target: LdkLogger, +{ + pub graph: NetworkGraph, + pub rgs_timestamp: u32, +} + +/// Header: 4 bytes magic + 1 byte version + 4 bytes timestamp +const LOCAL_GRAPH_CACHE_HEADER_SIZE: usize = 9; + +/// Reads the network graph and RGS timestamp from the local cache. +pub fn read_local_graph_cache( + storage_dir_path: &str, logger: L, +) -> Result, std::io::Error> +where + L::Target: LdkLogger, +{ + let cache_path = format!("{}/{}", storage_dir_path, NETWORK_GRAPH_LOCAL_CACHE_FILENAME); + let data = fs::read(&cache_path)?; + + if data.len() < LOCAL_GRAPH_CACHE_HEADER_SIZE { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Local graph cache too small", + )); + } + + if &data[0..4] != LOCAL_GRAPH_CACHE_MAGIC { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Invalid local graph cache magic bytes", + )); + } + + if data[4] != LOCAL_GRAPH_CACHE_VERSION { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + format!("Unsupported local graph cache version: {}", data[4]), + )); + } + + let rgs_timestamp = u32::from_be_bytes([data[5], data[6], data[7], data[8]]); + let graph_data = &data[LOCAL_GRAPH_CACHE_HEADER_SIZE..]; + + let mut graph_cursor = Cursor::new(graph_data); + let graph = NetworkGraph::read(&mut graph_cursor, logger.clone()).map_err(|e| { + log_error!(logger, "Failed to deserialize NetworkGraph from local cache: {}", e); + std::io::Error::new(std::io::ErrorKind::InvalidData, "Failed to deserialize NetworkGraph") + })?; + + Ok(LocalGraphCacheData { graph, rgs_timestamp }) +} + +fn write_local_graph_cache_bytes( + storage_dir_path: &str, graph_bytes: &[u8], rgs_timestamp: u32, +) -> Result<(), std::io::Error> { + fs::create_dir_all(storage_dir_path)?; + + let cache_path = format!("{}/{}", storage_dir_path, NETWORK_GRAPH_LOCAL_CACHE_FILENAME); + + let mut cache_data = Vec::with_capacity(LOCAL_GRAPH_CACHE_HEADER_SIZE + graph_bytes.len()); + cache_data.extend_from_slice(LOCAL_GRAPH_CACHE_MAGIC); + cache_data.push(LOCAL_GRAPH_CACHE_VERSION); + cache_data.extend_from_slice(&rgs_timestamp.to_be_bytes()); + cache_data.extend_from_slice(graph_bytes); + + fs::write(&cache_path, cache_data) +} + +fn read_local_graph_cache_bytes(storage_dir_path: &str) -> Result, std::io::Error> { + let cache_path = format!("{}/{}", storage_dir_path, NETWORK_GRAPH_LOCAL_CACHE_FILENAME); + let data = fs::read(&cache_path)?; + + if data.len() < LOCAL_GRAPH_CACHE_HEADER_SIZE { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Local graph cache too small", + )); + } + + if &data[0..4] != LOCAL_GRAPH_CACHE_MAGIC { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Invalid local graph cache magic bytes", + )); + } + + if data[4] != LOCAL_GRAPH_CACHE_VERSION { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + format!("Unsupported local graph cache version: {}", data[4]), + )); + } + + Ok(data[LOCAL_GRAPH_CACHE_HEADER_SIZE..].to_vec()) +} + +/// A KVStore wrapper that redirects network graph operations to local storage. +pub struct LocalGraphStore { + inner: Arc, + storage_dir_path: String, + rgs_timestamp: Arc, +} + +impl LocalGraphStore { + pub fn new( + inner: Arc, storage_dir_path: String, rgs_timestamp: Arc, + ) -> Self { + Self { inner, storage_dir_path, rgs_timestamp } + } + + fn is_network_graph( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, + ) -> bool { + primary_namespace == NETWORK_GRAPH_PERSISTENCE_PRIMARY_NAMESPACE + && secondary_namespace == NETWORK_GRAPH_PERSISTENCE_SECONDARY_NAMESPACE + && key == NETWORK_GRAPH_PERSISTENCE_KEY + } +} + +impl KVStoreSync for LocalGraphStore { + fn read( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, + ) -> Result, io::Error> { + if self.is_network_graph(primary_namespace, secondary_namespace, key) { + read_local_graph_cache_bytes(&self.storage_dir_path).map_err(|e| { + if e.kind() == std::io::ErrorKind::NotFound { + io::Error::new(io::ErrorKind::NotFound, e) + } else { + io::Error::new(io::ErrorKind::Other, format!("Local cache read failed: {}", e)) + } + }) + } else { + KVStoreSync::read(&*self.inner, primary_namespace, secondary_namespace, key) + } + } + + fn write( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, buf: Vec, + ) -> Result<(), io::Error> { + if self.is_network_graph(primary_namespace, secondary_namespace, key) { + let timestamp = self.rgs_timestamp.load(Ordering::Acquire); + write_local_graph_cache_bytes(&self.storage_dir_path, &buf, timestamp).map_err(|e| { + io::Error::new(io::ErrorKind::Other, format!("Local cache write failed: {}", e)) + }) + } else { + KVStoreSync::write(&*self.inner, primary_namespace, secondary_namespace, key, buf) + } + } + + fn remove( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, lazy: bool, + ) -> Result<(), io::Error> { + if self.is_network_graph(primary_namespace, secondary_namespace, key) { + let cache_path = + format!("{}/{}", self.storage_dir_path, NETWORK_GRAPH_LOCAL_CACHE_FILENAME); + match std::fs::remove_file(&cache_path) { + Ok(()) => Ok(()), + Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(()), + Err(e) => Err(io::Error::new( + io::ErrorKind::Other, + format!("Failed to remove local cache: {}", e), + )), + } + } else { + KVStoreSync::remove(&*self.inner, primary_namespace, secondary_namespace, key, lazy) + } + } + + fn list( + &self, primary_namespace: &str, secondary_namespace: &str, + ) -> Result, io::Error> { + KVStoreSync::list(&*self.inner, primary_namespace, secondary_namespace) + } +} + +impl KVStore for LocalGraphStore { + fn read( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, + ) -> Pin, io::Error>> + 'static + Send>> { + if self.is_network_graph(primary_namespace, secondary_namespace, key) { + let storage_dir = self.storage_dir_path.clone(); + Box::pin(async move { + read_local_graph_cache_bytes(&storage_dir).map_err(|e| { + if e.kind() == std::io::ErrorKind::NotFound { + io::Error::new(io::ErrorKind::NotFound, e) + } else { + io::Error::new( + io::ErrorKind::Other, + format!("Local cache read failed: {}", e), + ) + } + }) + }) + } else { + KVStore::read(&*self.inner, primary_namespace, secondary_namespace, key) + } + } + + fn write( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, buf: Vec, + ) -> Pin> + 'static + Send>> { + if self.is_network_graph(primary_namespace, secondary_namespace, key) { + let storage_dir = self.storage_dir_path.clone(); + let timestamp = self.rgs_timestamp.load(Ordering::Acquire); + Box::pin(async move { + write_local_graph_cache_bytes(&storage_dir, &buf, timestamp).map_err(|e| { + io::Error::new(io::ErrorKind::Other, format!("Local cache write failed: {}", e)) + }) + }) + } else { + KVStore::write(&*self.inner, primary_namespace, secondary_namespace, key, buf) + } + } + + fn remove( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, lazy: bool, + ) -> Pin> + 'static + Send>> { + if self.is_network_graph(primary_namespace, secondary_namespace, key) { + let storage_dir = self.storage_dir_path.clone(); + Box::pin(async move { + let cache_path = format!("{}/{}", storage_dir, NETWORK_GRAPH_LOCAL_CACHE_FILENAME); + match std::fs::remove_file(&cache_path) { + Ok(()) => Ok(()), + Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(()), + Err(e) => Err(io::Error::new( + io::ErrorKind::Other, + format!("Failed to remove local cache: {}", e), + )), + } + }) + } else { + KVStore::remove(&*self.inner, primary_namespace, secondary_namespace, key, lazy) + } + } + + fn list( + &self, primary_namespace: &str, secondary_namespace: &str, + ) -> Pin, io::Error>> + 'static + Send>> { + KVStore::list(&*self.inner, primary_namespace, secondary_namespace) + } +} diff --git a/src/io/mod.rs b/src/io/mod.rs index 38fba5114f..611acc8362 100644 --- a/src/io/mod.rs +++ b/src/io/mod.rs @@ -7,6 +7,7 @@ //! Objects and traits for data persistence. +pub(crate) mod local_graph_store; pub mod sqlite_store; #[cfg(test)] pub(crate) mod test_utils; diff --git a/src/io/utils.rs b/src/io/utils.rs index 1b4b02a827..32f37b3fd4 100644 --- a/src/io/utils.rs +++ b/src/io/utils.rs @@ -18,38 +18,34 @@ use bdk_chain::tx_graph::ChangeSet as BdkTxGraphChangeSet; use bdk_chain::ConfirmationBlockTime; use bdk_wallet::ChangeSet as BdkWalletChangeSet; use bip39::Mnemonic; +use bitcoin::bip32::{ChildNumber, Xpriv}; +use bitcoin::secp256k1::Secp256k1; use bitcoin::Network; use lightning::io::Cursor; use lightning::ln::msgs::DecodeError; use lightning::routing::gossip::NetworkGraph; -use lightning::routing::scoring::{ - ChannelLiquidities, ProbabilisticScorer, ProbabilisticScoringDecayParameters, -}; +use lightning::routing::scoring::ChannelLiquidities; use lightning::util::persist::{ KVStore, KVStoreSync, KVSTORE_NAMESPACE_KEY_ALPHABET, KVSTORE_NAMESPACE_KEY_MAX_LEN, NETWORK_GRAPH_PERSISTENCE_KEY, NETWORK_GRAPH_PERSISTENCE_PRIMARY_NAMESPACE, - NETWORK_GRAPH_PERSISTENCE_SECONDARY_NAMESPACE, OUTPUT_SWEEPER_PERSISTENCE_KEY, - OUTPUT_SWEEPER_PERSISTENCE_PRIMARY_NAMESPACE, OUTPUT_SWEEPER_PERSISTENCE_SECONDARY_NAMESPACE, - SCORER_PERSISTENCE_KEY, SCORER_PERSISTENCE_PRIMARY_NAMESPACE, + NETWORK_GRAPH_PERSISTENCE_SECONDARY_NAMESPACE, SCORER_PERSISTENCE_PRIMARY_NAMESPACE, SCORER_PERSISTENCE_SECONDARY_NAMESPACE, }; use lightning::util::ser::{Readable, ReadableArgs, Writeable}; use lightning_types::string::PrintableString; use rand::rngs::OsRng; use rand::TryRngCore; +use tokio::task::JoinSet; use super::*; -use crate::chain::ChainSource; use crate::config::WALLET_KEYS_SEED_LEN; -use crate::fee_estimator::OnchainFeeEstimator; use crate::io::{ NODE_METRICS_KEY, NODE_METRICS_PRIMARY_NAMESPACE, NODE_METRICS_SECONDARY_NAMESPACE, }; use crate::logger::{log_error, LdkLogger, Logger}; -use crate::peer_store::PeerStore; -use crate::types::{Broadcaster, DynStore, KeysManager, Sweeper, WordCount}; +use crate::types::{DynStore, WordCount}; use crate::wallet::ser::{ChangeSetDeserWrapper, ChangeSetSerWrapper}; -use crate::{Error, EventQueue, NodeMetrics, PaymentDetails}; +use crate::{Error, NodeMetrics, PaymentDetails}; pub const EXTERNAL_PATHFINDING_SCORES_CACHE_KEY: &str = "external_pathfinding_scores_cache"; @@ -68,6 +64,38 @@ pub fn generate_entropy_mnemonic(word_count: Option) -> Mnemonic { Mnemonic::generate(word_count).expect("Failed to generate mnemonic") } +/// Derives the node secret key from a BIP39 mnemonic. +/// +/// This is the same key that would be used by a [`Node`] built with this mnemonic via +/// [`Builder::set_entropy_bip39_mnemonic`]. +/// +/// The derivation follows LDK's KeysManager behavior: +/// 1. BIP39 seed (64 bytes) → BIP32 master key (32 bytes) +/// 2. Those 32 bytes as new seed → BIP32 master → derive m/0' → node_secret +/// +/// [`Node`]: crate::Node +/// [`Builder::set_entropy_bip39_mnemonic`]: crate::Builder::set_entropy_bip39_mnemonic +pub fn derive_node_secret_from_mnemonic( + mnemonic: String, passphrase: Option, +) -> Result, Error> { + let parsed_mnemonic = Mnemonic::parse(&mnemonic).map_err(|_| Error::InvalidMnemonic)?; + let seed = parsed_mnemonic.to_seed(passphrase.as_deref().unwrap_or("")); + + let master_xpriv = + Xpriv::new_master(Network::Bitcoin, &seed).map_err(|_| Error::InvalidMnemonic)?; + + let ldk_seed_bytes: [u8; 32] = master_xpriv.private_key.secret_bytes(); + + let keys_manager_master = + Xpriv::new_master(Network::Bitcoin, &ldk_seed_bytes).map_err(|_| Error::InvalidMnemonic)?; + + let node_secret_xpriv = keys_manager_master + .derive_priv(&Secp256k1::new(), &[ChildNumber::from_hardened_idx(0).unwrap()]) + .map_err(|_| Error::InvalidMnemonic)?; + + Ok(node_secret_xpriv.private_key.secret_bytes().to_vec()) +} + pub(crate) fn read_or_generate_seed_file( keys_seed_path: &str, logger: L, ) -> std::io::Result<[u8; WALLET_KEYS_SEED_LEN]> @@ -151,46 +179,6 @@ where }) } -/// Read a previously persisted [`ProbabilisticScorer`] from the store. -pub(crate) fn read_scorer>, L: Deref + Clone>( - kv_store: Arc, network_graph: G, logger: L, -) -> Result, std::io::Error> -where - L::Target: LdkLogger, -{ - let params = ProbabilisticScoringDecayParameters::default(); - let mut reader = Cursor::new(KVStoreSync::read( - &*kv_store, - SCORER_PERSISTENCE_PRIMARY_NAMESPACE, - SCORER_PERSISTENCE_SECONDARY_NAMESPACE, - SCORER_PERSISTENCE_KEY, - )?); - let args = (params, network_graph, logger.clone()); - ProbabilisticScorer::read(&mut reader, args).map_err(|e| { - log_error!(logger, "Failed to deserialize scorer: {}", e); - std::io::Error::new(std::io::ErrorKind::InvalidData, "Failed to deserialize Scorer") - }) -} - -/// Read previously persisted external pathfinding scores from the cache. -pub(crate) fn read_external_pathfinding_scores_from_cache( - kv_store: Arc, logger: L, -) -> Result -where - L::Target: LdkLogger, -{ - let mut reader = Cursor::new(KVStoreSync::read( - &*kv_store, - SCORER_PERSISTENCE_PRIMARY_NAMESPACE, - SCORER_PERSISTENCE_SECONDARY_NAMESPACE, - EXTERNAL_PATHFINDING_SCORES_CACHE_KEY, - )?); - ChannelLiquidities::read(&mut reader).map_err(|e| { - log_error!(logger, "Failed to deserialize scorer: {}", e); - std::io::Error::new(std::io::ErrorKind::InvalidData, "Failed to deserialize Scorer") - }) -} - /// Persist external pathfinding scores to the cache. pub(crate) async fn write_external_pathfinding_scores_to_cache( kv_store: Arc, data: &ChannelLiquidities, logger: L, @@ -219,102 +207,72 @@ where }) } -/// Read previously persisted events from the store. -pub(crate) fn read_event_queue( - kv_store: Arc, logger: L, -) -> Result, std::io::Error> -where - L::Target: LdkLogger, -{ - let mut reader = Cursor::new(KVStoreSync::read( - &*kv_store, - EVENT_QUEUE_PERSISTENCE_PRIMARY_NAMESPACE, - EVENT_QUEUE_PERSISTENCE_SECONDARY_NAMESPACE, - EVENT_QUEUE_PERSISTENCE_KEY, - )?); - EventQueue::read(&mut reader, (kv_store, logger.clone())).map_err(|e| { - log_error!(logger, "Failed to deserialize event queue: {}", e); - std::io::Error::new(std::io::ErrorKind::InvalidData, "Failed to deserialize EventQueue") - }) -} - -/// Read previously persisted peer info from the store. -pub(crate) fn read_peer_info( - kv_store: Arc, logger: L, -) -> Result, std::io::Error> -where - L::Target: LdkLogger, -{ - let mut reader = Cursor::new(KVStoreSync::read( - &*kv_store, - PEER_INFO_PERSISTENCE_PRIMARY_NAMESPACE, - PEER_INFO_PERSISTENCE_SECONDARY_NAMESPACE, - PEER_INFO_PERSISTENCE_KEY, - )?); - PeerStore::read(&mut reader, (kv_store, logger.clone())).map_err(|e| { - log_error!(logger, "Failed to deserialize peer store: {}", e); - std::io::Error::new(std::io::ErrorKind::InvalidData, "Failed to deserialize PeerStore") - }) -} - -/// Read previously persisted payments information from the store. -pub(crate) fn read_payments( +/// Read previously persisted payments information from the store (async version). +/// +/// Uses parallel async reads to improve performance with remote stores like VSS. +pub(crate) async fn read_payments_async( kv_store: Arc, logger: L, ) -> Result, std::io::Error> where L::Target: LdkLogger, { - let mut res = Vec::new(); - - for stored_key in KVStoreSync::list( - &*kv_store, - PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE, - PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE, - )? { - let mut reader = Cursor::new(KVStoreSync::read( - &*kv_store, + // First, list all payment keys (single round trip) - spawn_blocking for sync operation + let kv_store_list = Arc::clone(&kv_store); + let keys = tokio::task::spawn_blocking(move || { + KVStoreSync::list( + &*kv_store_list, PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE, PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE, - &stored_key, - )?); - let payment = PaymentDetails::read(&mut reader).map_err(|e| { - log_error!(logger, "Failed to deserialize PaymentDetails: {}", e); - std::io::Error::new( - std::io::ErrorKind::InvalidData, - "Failed to deserialize PaymentDetails", + ) + }) + .await + .map_err(|e| { + std::io::Error::new(std::io::ErrorKind::Other, format!("Task join error: {}", e)) + })??; + + if keys.is_empty() { + return Ok(Vec::new()); + } + + // Execute all reads in parallel using JoinSet + let mut join_set: JoinSet> = JoinSet::new(); + + for key in keys { + let store = Arc::clone(&kv_store); + let log = logger.clone(); + join_set.spawn(async move { + let data = KVStore::read( + &*store, + PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE, + PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE, + &key, ) - })?; - res.push(payment); + .await?; + let mut reader = Cursor::new(data); + PaymentDetails::read(&mut reader).map_err(|e| { + log_error!(log, "Failed to deserialize PaymentDetails for key {}: {}", key, e); + std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Failed to deserialize PaymentDetails", + ) + }) + }); } - Ok(res) -} -/// Read `OutputSweeper` state from the store. -pub(crate) fn read_output_sweeper( - broadcaster: Arc, fee_estimator: Arc, - chain_data_source: Arc, keys_manager: Arc, kv_store: Arc, - logger: Arc, -) -> Result { - let mut reader = Cursor::new(KVStoreSync::read( - &*kv_store, - OUTPUT_SWEEPER_PERSISTENCE_PRIMARY_NAMESPACE, - OUTPUT_SWEEPER_PERSISTENCE_SECONDARY_NAMESPACE, - OUTPUT_SWEEPER_PERSISTENCE_KEY, - )?); - let args = ( - broadcaster, - fee_estimator, - Some(chain_data_source), - Arc::clone(&keys_manager), - keys_manager, - kv_store, - logger.clone(), - ); - let (_, sweeper) = <(_, Sweeper)>::read(&mut reader, args).map_err(|e| { - log_error!(logger, "Failed to deserialize OutputSweeper: {}", e); - std::io::Error::new(std::io::ErrorKind::InvalidData, "Failed to deserialize OutputSweeper") - })?; - Ok(sweeper) + let mut payments = Vec::with_capacity(join_set.len()); + while let Some(result) = join_set.join_next().await { + match result { + Ok(Ok(payment)) => payments.push(payment), + Ok(Err(e)) => return Err(e), + Err(e) => { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + format!("Task join error: {}", e), + )) + }, + } + } + Ok(payments) } pub(crate) fn read_node_metrics( @@ -463,24 +421,60 @@ macro_rules! impl_read_write_change_set_type { $key:expr ) => { pub(crate) fn $read_name( - kv_store: Arc, logger: L, + kv_store: Arc, logger: L, wallet_account: crate::config::OnchainWalletAccount, ) -> Result, std::io::Error> where L::Target: LdkLogger, { + let suffix = wallet_account.storage_suffix(); + let secondary_namespace = if $secondary_namespace.is_empty() { + suffix + } else { + format!("{}/{}", $secondary_namespace, suffix) + }; let bytes = - match KVStoreSync::read(&*kv_store, $primary_namespace, $secondary_namespace, $key) + match KVStoreSync::read(&*kv_store, $primary_namespace, &secondary_namespace, $key) { Ok(bytes) => bytes, Err(e) => { if e.kind() == lightning::io::ErrorKind::NotFound { - return Ok(None); + // Fallback: try the un-namespaced key for pre-multi-wallet data. + if wallet_account.address_type + == crate::config::AddressType::NativeSegwit + && wallet_account.account_index == 0 + { + match KVStoreSync::read( + &*kv_store, + $primary_namespace, + $secondary_namespace, + $key, + ) { + Ok(bytes) => bytes, + Err(e2) => { + if e2.kind() == lightning::io::ErrorKind::NotFound { + return Ok(None); + } else { + log_error!( + logger, + "Reading legacy data from key {}/{}/{} failed due to: {}", + $primary_namespace, + $secondary_namespace, + $key, + e2 + ); + return Err(e2.into()); + } + }, + } + } else { + return Ok(None); + } } else { log_error!( logger, "Reading data from key {}/{}/{} failed due to: {}", $primary_namespace, - $secondary_namespace, + secondary_namespace, $key, e ); @@ -506,18 +500,25 @@ macro_rules! impl_read_write_change_set_type { pub(crate) fn $write_name( value: &$change_set_type, kv_store: Arc, logger: L, + wallet_account: crate::config::OnchainWalletAccount, ) -> Result<(), std::io::Error> where L::Target: LdkLogger, { + let suffix = wallet_account.storage_suffix(); + let secondary_namespace = if $secondary_namespace.is_empty() { + suffix + } else { + format!("{}/{}", $secondary_namespace, suffix) + }; let data = ChangeSetSerWrapper(value).encode(); - KVStoreSync::write(&*kv_store, $primary_namespace, $secondary_namespace, $key, data) + KVStoreSync::write(&*kv_store, $primary_namespace, &secondary_namespace, $key, data) .map_err(|e| { log_error!( logger, "Writing data to key {}/{}/{} failed due to: {}", $primary_namespace, - $secondary_namespace, + secondary_namespace, $key, e ); @@ -584,12 +585,13 @@ impl_read_write_change_set_type!( // Reads the full BdkWalletChangeSet or returns default fields pub(crate) fn read_bdk_wallet_change_set( kv_store: Arc, logger: Arc, + wallet_account: crate::config::OnchainWalletAccount, ) -> Result, std::io::Error> { let mut change_set = BdkWalletChangeSet::default(); // We require a descriptor and return `None` to signal creation of a new wallet otherwise. if let Some(descriptor) = - read_bdk_wallet_descriptor(Arc::clone(&kv_store), Arc::clone(&logger))? + read_bdk_wallet_descriptor(Arc::clone(&kv_store), Arc::clone(&logger), wallet_account)? { change_set.descriptor = Some(descriptor); } else { @@ -597,32 +599,38 @@ pub(crate) fn read_bdk_wallet_change_set( } // We require a change_descriptor and return `None` to signal creation of a new wallet otherwise. - if let Some(change_descriptor) = - read_bdk_wallet_change_descriptor(Arc::clone(&kv_store), Arc::clone(&logger))? - { + if let Some(change_descriptor) = read_bdk_wallet_change_descriptor( + Arc::clone(&kv_store), + Arc::clone(&logger), + wallet_account, + )? { change_set.change_descriptor = Some(change_descriptor); } else { return Ok(None); } // We require a network and return `None` to signal creation of a new wallet otherwise. - if let Some(network) = read_bdk_wallet_network(Arc::clone(&kv_store), Arc::clone(&logger))? { + if let Some(network) = + read_bdk_wallet_network(Arc::clone(&kv_store), Arc::clone(&logger), wallet_account)? + { change_set.network = Some(network); } else { return Ok(None); } - read_bdk_wallet_local_chain(Arc::clone(&kv_store), Arc::clone(&logger))? + read_bdk_wallet_local_chain(Arc::clone(&kv_store), Arc::clone(&logger), wallet_account)? .map(|local_chain| change_set.local_chain = local_chain); - read_bdk_wallet_tx_graph(Arc::clone(&kv_store), Arc::clone(&logger))? + read_bdk_wallet_tx_graph(Arc::clone(&kv_store), Arc::clone(&logger), wallet_account)? .map(|tx_graph| change_set.tx_graph = tx_graph); - read_bdk_wallet_indexer(Arc::clone(&kv_store), Arc::clone(&logger))? + read_bdk_wallet_indexer(Arc::clone(&kv_store), Arc::clone(&logger), wallet_account)? .map(|indexer| change_set.indexer = indexer); Ok(Some(change_set)) } #[cfg(test)] mod tests { + use lightning::sign::KeysManager as LdkKeysManager; + use super::*; #[test] @@ -658,4 +666,45 @@ mod tests { assert_eq!(mnemonic.word_count(), expected_words); } } + + #[test] + fn derive_node_secret_matches_keys_manager() { + // Standard test mnemonic (BIP39 test vector) + let mnemonic = + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; + + // Derive using our function + let derived_secret = derive_node_secret_from_mnemonic(mnemonic.to_string(), None).unwrap(); + + // Derive using LDK's KeysManager (same flow as Builder) + let parsed = Mnemonic::parse(mnemonic).unwrap(); + let seed = parsed.to_seed(""); + let xpriv = Xpriv::new_master(Network::Bitcoin, &seed).unwrap(); + let ldk_seed: [u8; 32] = xpriv.private_key.secret_bytes(); + + let keys_manager = LdkKeysManager::new(&ldk_seed, 0, 0, false); + let expected_secret = keys_manager.get_node_secret_key(); + + assert_eq!(derived_secret, expected_secret.secret_bytes().to_vec()); + } + + #[test] + fn derive_node_secret_with_passphrase() { + let mnemonic = + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; + let passphrase = Some("test_passphrase".to_string()); + + let derived_secret = + derive_node_secret_from_mnemonic(mnemonic.to_string(), passphrase).unwrap(); + + let parsed = Mnemonic::parse(mnemonic).unwrap(); + let seed = parsed.to_seed("test_passphrase"); + let xpriv = Xpriv::new_master(Network::Bitcoin, &seed).unwrap(); + let ldk_seed: [u8; 32] = xpriv.private_key.secret_bytes(); + + let keys_manager = LdkKeysManager::new(&ldk_seed, 0, 0, false); + let expected_secret = keys_manager.get_node_secret_key(); + + assert_eq!(derived_secret, expected_secret.secret_bytes().to_vec()); + } } diff --git a/src/io/vss_store.rs b/src/io/vss_store.rs index 2906b89ca2..2fd1ab2cae 100644 --- a/src/io/vss_store.rs +++ b/src/io/vss_store.rs @@ -15,7 +15,6 @@ use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering}; use std::sync::{Arc, Mutex}; use std::time::Duration; -use bdk_chain::Merge; use bitcoin::hashes::{sha256, Hash, HashEngine, Hmac, HmacEngine}; use lightning::impl_writeable_tlv_based_enum; use lightning::io::{self, Error, ErrorKind}; @@ -244,11 +243,15 @@ impl KVStoreSync for VssStore { primary_namespace, secondary_namespace, key, - lazy, ) .await }; - tokio::task::block_in_place(move || internal_runtime.block_on(fut)) + if lazy { + internal_runtime.spawn(async { fut.await }); + Ok(()) + } else { + tokio::task::block_in_place(move || internal_runtime.block_on(fut)) + } } fn list(&self, primary_namespace: &str, secondary_namespace: &str) -> io::Result> { @@ -316,7 +319,7 @@ impl KVStore for VssStore { let secondary_namespace = secondary_namespace.to_string(); let key = key.to_string(); let inner = Arc::clone(&self.inner); - Box::pin(async move { + let fut = async move { inner .remove_internal( &inner.async_client, @@ -326,10 +329,15 @@ impl KVStore for VssStore { primary_namespace, secondary_namespace, key, - lazy, ) .await - }) + }; + if lazy { + tokio::task::spawn(async { fut.await }); + Box::pin(async { Ok(()) }) + } else { + Box::pin(async { fut.await }) + } } fn list( &self, primary_namespace: &str, secondary_namespace: &str, @@ -362,7 +370,6 @@ struct VssStoreInner { // Per-key locks that ensures that we don't have concurrent writes to the same namespace/key. // The lock also encapsulates the latest written version per key. locks: Mutex>>>, - pending_lazy_deletes: Mutex>, } impl VssStoreInner { @@ -372,7 +379,6 @@ impl VssStoreInner { data_encryption_key: [u8; 32], key_obfuscator: KeyObfuscator, ) -> Self { let locks = Mutex::new(HashMap::new()); - let pending_lazy_deletes = Mutex::new(Vec::new()); Self { schema_version, blocking_client, @@ -381,7 +387,6 @@ impl VssStoreInner { data_encryption_key, key_obfuscator, locks, - pending_lazy_deletes, } } @@ -520,12 +525,6 @@ impl VssStoreInner { "write", )?; - let delete_items = self - .pending_lazy_deletes - .try_lock() - .ok() - .and_then(|mut guard| guard.take()) - .unwrap_or_default(); let store_key = self.build_obfuscated_key(&primary_namespace, &secondary_namespace, &key); let vss_version = -1; let storable_builder = StorableBuilder::new(RandEntropySource); @@ -541,16 +540,11 @@ impl VssStoreInner { version: vss_version, value: storable.encode_to_vec(), }], - delete_items: delete_items.clone(), + delete_items: vec![], }; self.execute_locked_write(inner_lock_ref, locking_key, version, async move || { client.put_object(&request).await.map_err(|e| { - // Restore delete items so they'll be retried on next write. - if !delete_items.is_empty() { - self.pending_lazy_deletes.lock().unwrap().extend(delete_items); - } - let msg = format!( "Failed to write to key {}/{}/{}: {}", primary_namespace, secondary_namespace, key, e @@ -566,7 +560,7 @@ impl VssStoreInner { async fn remove_internal( &self, client: &VssClient, inner_lock_ref: Arc>, locking_key: String, version: u64, primary_namespace: String, secondary_namespace: String, - key: String, lazy: bool, + key: String, ) -> io::Result<()> { check_namespace_key_validity( &primary_namespace, @@ -579,12 +573,6 @@ impl VssStoreInner { self.build_obfuscated_key(&primary_namespace, &secondary_namespace, &key); let key_value = KeyValue { key: obfuscated_key, version: -1, value: vec![] }; - if lazy { - let mut pending_lazy_deletes = self.pending_lazy_deletes.lock().unwrap(); - pending_lazy_deletes.push(key_value); - return Ok(()); - } - self.execute_locked_write(inner_lock_ref, locking_key, version, async move || { let request = DeleteObjectRequest { store_id: self.store_id.clone(), key_value: Some(key_value) }; @@ -851,85 +839,4 @@ mod tests { do_read_write_remove_list_persist(&vss_store); drop(vss_store) } - - #[tokio::test(flavor = "multi_thread", worker_threads = 1)] - async fn vss_lazy_delete() { - let vss_base_url = std::env::var("TEST_VSS_BASE_URL").unwrap(); - let mut rng = rng(); - let rand_store_id: String = (0..7).map(|_| rng.sample(Alphanumeric) as char).collect(); - let mut vss_seed = [0u8; 32]; - rng.fill_bytes(&mut vss_seed); - let header_provider = Arc::new(FixedHeaders::new(HashMap::new())); - let vss_store = - VssStore::new(vss_base_url, rand_store_id, vss_seed, header_provider).unwrap(); - - let primary_namespace = "test_namespace"; - let secondary_namespace = ""; - let key_to_delete = "key_to_delete"; - let key_for_trigger = "key_for_trigger"; - let data_to_delete = b"data_to_delete".to_vec(); - let trigger_data = b"trigger_data".to_vec(); - - // Write the key that we'll later lazily delete - KVStore::write( - &vss_store, - primary_namespace, - secondary_namespace, - key_to_delete, - data_to_delete.clone(), - ) - .await - .unwrap(); - - // Verify the key exists - let read_data = - KVStore::read(&vss_store, primary_namespace, secondary_namespace, key_to_delete) - .await - .unwrap(); - assert_eq!(read_data, data_to_delete); - - // Perform a lazy delete - KVStore::remove(&vss_store, primary_namespace, secondary_namespace, key_to_delete, true) - .await - .unwrap(); - - // Verify the key still exists (lazy delete doesn't immediately remove it) - let read_data = - KVStore::read(&vss_store, primary_namespace, secondary_namespace, key_to_delete) - .await - .unwrap(); - assert_eq!(read_data, data_to_delete); - - // Verify the key is still in the list - let keys = KVStore::list(&vss_store, primary_namespace, secondary_namespace).await.unwrap(); - assert!(keys.contains(&key_to_delete.to_string())); - - // Trigger the actual deletion by performing a write operation - KVStore::write( - &vss_store, - primary_namespace, - secondary_namespace, - key_for_trigger, - trigger_data.clone(), - ) - .await - .unwrap(); - - // Now verify the key is actually deleted - let read_result = - KVStore::read(&vss_store, primary_namespace, secondary_namespace, key_to_delete).await; - assert!(read_result.is_err()); - assert_eq!(read_result.unwrap_err().kind(), ErrorKind::NotFound); - - // Verify the key is no longer in the list - let keys = KVStore::list(&vss_store, primary_namespace, secondary_namespace).await.unwrap(); - assert!(!keys.contains(&key_to_delete.to_string())); - - // Verify the trigger key still exists - let read_data = - KVStore::read(&vss_store, primary_namespace, secondary_namespace, key_for_trigger) - .await - .unwrap(); - assert_eq!(read_data, trigger_data); - } } diff --git a/src/lib.rs b/src/lib.rs index 8ac6780ed2..4d9d5ec529 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,7 +75,7 @@ #![deny(rustdoc::private_intra_doc_links)] #![allow(bare_trait_objects)] #![allow(ellipsis_inclusive_range_patterns)] -#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![cfg_attr(docsrs, feature(doc_cfg))] mod balance; mod builder; @@ -96,42 +96,49 @@ pub mod logger; mod message_handler; pub mod payment; mod peer_store; +mod probe_handle; mod runtime; mod scoring; mod tx_broadcaster; mod types; mod wallet; +use std::collections::{HashMap, HashSet}; use std::default::Default; use std::net::ToSocketAddrs; +use std::ops::Deref; +use std::sync::atomic::AtomicU32; use std::sync::{Arc, Mutex, RwLock}; use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; -pub use balance::{BalanceDetails, LightningBalance, PendingSweepBalance}; +pub use balance::{AddressTypeBalance, BalanceDetails, LightningBalance, PendingSweepBalance}; use bitcoin::secp256k1::PublicKey; use bitcoin::{Address, Amount}; #[cfg(feature = "uniffi")] pub use builder::ArcedNodeBuilder as Builder; -pub use builder::BuildError; #[cfg(not(feature = "uniffi"))] pub use builder::NodeBuilder as Builder; +pub use builder::{BuildError, ChannelDataMigration}; use chain::ChainSource; +pub use config::{battery_saving_sync_intervals, RuntimeSyncIntervals}; use config::{ - default_user_config, may_announce_channel, AsyncPaymentsRole, ChannelConfig, Config, - NODE_ANN_BCAST_INTERVAL, PEER_RECONNECTION_INTERVAL, RGS_SYNC_INTERVAL, + default_user_config, may_announce_channel, AsyncPaymentsRole, BackgroundSyncConfig, + ChannelConfig, Config, NODE_ANN_BCAST_INTERVAL, PEER_RECONNECTION_INTERVAL, RGS_SYNC_INTERVAL, }; +pub use config::{AddressType, OnchainWalletAccount, OnchainWalletAccountConfig}; use connection::ConnectionManager; pub use error::Error as NodeError; use error::Error; -pub use event::Event; +pub use event::{Event, SyncType, TransactionDetails, TxInput, TxOutput}; use event::{EventHandler, EventQueue}; use fee_estimator::{ConfirmationTarget, FeeEstimator, OnchainFeeEstimator}; #[cfg(feature = "uniffi")] use ffi::*; use gossip::GossipSource; use graph::NetworkGraph; -pub use io::utils::generate_entropy_mnemonic; use io::utils::write_node_metrics; +pub use io::utils::{derive_node_secret_from_mnemonic, generate_entropy_mnemonic}; +use lightning::chain::channelmonitor::Balance as LdkBalance; use lightning::chain::BestBlock; use lightning::events::bump_transaction::{Input, Wallet as LdkWallet}; use lightning::impl_writeable_tlv_based; @@ -140,6 +147,7 @@ use lightning::ln::channel_state::{ChannelDetails as LdkChannelDetails, ChannelS use lightning::ln::channelmanager::PaymentId; use lightning::ln::funding::SpliceContribution; use lightning::ln::msgs::SocketAddress; +use lightning::ln::types::ChannelId; use lightning::routing::gossip::NodeAlias; use lightning::util::persist::KVStoreSync; use lightning_background_processor::process_events_async; @@ -147,11 +155,13 @@ use liquidity::{LSPS1Liquidity, LiquiditySource}; use logger::{log_debug, log_error, log_info, log_trace, LdkLogger, Logger}; use payment::asynchronous::om_mailbox::OnionMessageMailbox; use payment::asynchronous::static_invoice_store::StaticInvoiceStore; +pub use payment::{AddressInfo, KeychainKind}; use payment::{ Bolt11Payment, Bolt12Payment, OnchainPayment, PaymentDetails, SpontaneousPayment, UnifiedQrPayment, }; -use peer_store::{PeerInfo, PeerStore}; +use peer_store::{persist_missing_channel_peers_excluding, PeerInfo, PeerStore}; +pub use probe_handle::ProbeHandle; use rand::Rng; use runtime::Runtime; use types::{ @@ -159,9 +169,10 @@ use types::{ OnionMessenger, PaymentStore, PeerManager, Router, Scorer, Sweeper, Wallet, }; pub use types::{ - ChannelDetails, CustomTlvRecord, DynStore, PeerDetails, SyncAndAsyncKVStore, UserChannelId, - WordCount, + ChannelDetails, CustomTlvRecord, DynStore, PeerDetails, SpendableUtxo, SyncAndAsyncKVStore, + UserChannelId, WordCount, }; +pub use wallet::CoinSelectionAlgorithm; pub use { bip39, bitcoin, lightning, lightning_invoice, lightning_liquidity, lightning_types, tokio, vss_client, @@ -201,11 +212,81 @@ pub struct Node { _router: Arc, scorer: Arc>, peer_store: Arc>>, + rgs_peer_recovery_exclusions: Arc, payment_store: Arc, is_running: Arc>, node_metrics: Arc>, om_mailbox: Option>, async_payments_role: Option, + runtime_sync_intervals: Arc>, + /// Shared RGS timestamp used by LocalGraphStore to persist the timestamp alongside the graph. + local_rgs_timestamp: Arc, +} + +#[derive(Default)] +pub(crate) struct RgsPeerRecoveryExclusions { + node_ids: tokio::sync::RwLock>, +} + +impl RgsPeerRecoveryExclusions { + async fn read(&self) -> tokio::sync::RwLockReadGuard<'_, HashSet> { + self.node_ids.read().await + } + + async fn write(&self) -> tokio::sync::RwLockWriteGuard<'_, HashSet> { + self.node_ids.write().await + } + + #[cfg(test)] + async fn exclude_after_disconnect(&self, node_id: PublicKey) { + self.write().await.insert(node_id); + } + + async fn remove_peer_and_exclude_after_disconnect( + &self, peer_store: &PeerStore, node_id: PublicKey, + ) -> Result<(), Error> + where + L: Deref, + L::Target: LdkLogger, + { + let mut excluded_node_ids = self.write().await; + peer_store.remove_peer(&node_id).await?; + excluded_node_ids.insert(node_id); + Ok(()) + } + + async fn exclude_after_last_channel_close(&self, node_id: PublicKey) { + self.write().await.insert(node_id); + } + + #[cfg(test)] + async fn clear_after_persistent_connect(&self, node_id: &PublicKey) { + self.write().await.remove(node_id); + } + + #[cfg(test)] + async fn clear_after_channel_open(&self, node_id: &PublicKey) { + self.write().await.remove(node_id); + } + + async fn add_peer_and_clear_exclusion( + &self, peer_store: &PeerStore, peer_info: PeerInfo, + ) -> Result<(), Error> + where + L: Deref, + L::Target: LdkLogger, + { + let mut excluded_node_ids = self.write().await; + let node_id = peer_info.node_id; + peer_store.add_peer(peer_info).await?; + excluded_node_ids.remove(&node_id); + Ok(()) + } + + #[cfg(test)] + async fn contains(&self, node_id: &PublicKey) -> bool { + self.read().await.contains(node_id) + } } impl Node { @@ -232,7 +313,9 @@ impl Node { ); // Start up any runtime-dependant chain sources (e.g. Electrum) - self.chain_source.start(Arc::clone(&self.runtime)).map_err(|e| { + // Electrum needs execution access without owning the runtime lifecycle. + let runtime_handle = self.runtime.handle().clone(); + self.chain_source.start(runtime_handle).map_err(|e| { log_error!(self.logger, "Failed to start chain syncing: {}", e); e })?; @@ -241,30 +324,20 @@ impl Node { let chain_source = Arc::clone(&self.chain_source); self.runtime.block_on(async move { chain_source.update_fee_rate_estimates().await })?; - // Spawn background task continuously syncing onchain, lightning, and fee rate cache. - let stop_sync_receiver = self.stop_sender.subscribe(); - let chain_source = Arc::clone(&self.chain_source); - let sync_wallet = Arc::clone(&self.wallet); - let sync_cman = Arc::clone(&self.channel_manager); - let sync_cmon = Arc::clone(&self.chain_monitor); - let sync_sweeper = Arc::clone(&self.output_sweeper); - self.runtime.spawn_background_task(async move { - chain_source - .continuously_sync_wallets( - stop_sync_receiver, - sync_wallet, - sync_cman, - sync_cmon, - sync_sweeper, - ) - .await; - }); + // Set event queue for onchain event emission + self.chain_source.set_event_queue(Arc::clone(&self.event_queue)); + + self.spawn_chain_sync_task(); if self.gossip_source.is_rgs() { let gossip_source = Arc::clone(&self.gossip_source); let gossip_sync_store = Arc::clone(&self.kv_store); let gossip_sync_logger = Arc::clone(&self.logger); let gossip_node_metrics = Arc::clone(&self.node_metrics); + let gossip_channel_manager = Arc::clone(&self.channel_manager); + let gossip_network_graph = Arc::clone(&self.network_graph); + let gossip_peer_store = Arc::clone(&self.peer_store); + let gossip_peer_recovery_exclusions = Arc::clone(&self.rgs_peer_recovery_exclusions); let mut stop_gossip_sync = self.stop_sender.subscribe(); self.runtime.spawn_cancellable_background_task(async move { let mut interval = tokio::time::interval(RGS_SYNC_INTERVAL); @@ -285,7 +358,20 @@ impl Node { gossip_sync_logger, "Background sync of RGS gossip data finished in {}ms.", now.elapsed().as_millis() - ); + ); + let peer_recovery_exclusions = + gossip_peer_recovery_exclusions.read().await; + persist_missing_channel_peers_excluding( + gossip_channel_manager + .list_channels() + .into_iter() + .map(|channel| channel.counterparty.node_id), + &gossip_network_graph, + &gossip_peer_store, + &peer_recovery_exclusions, + Arc::clone(&gossip_sync_logger), + ) + .await; { let mut locked_node_metrics = gossip_node_metrics.write().unwrap(); locked_node_metrics.latest_rgs_snapshot_timestamp = Some(updated_timestamp); @@ -560,7 +646,13 @@ impl Node { )); // Setup background processing - let background_persister = Arc::clone(&self.kv_store); + // Wrap the kv_store with LocalGraphStore to redirect network graph persistence to local storage + let background_persister: Arc = + Arc::new(io::local_graph_store::LocalGraphStore::new( + Arc::clone(&self.kv_store), + self.config.storage_dir_path.clone(), + Arc::clone(&self.local_rgs_timestamp), + )); let background_event_handler = Arc::clone(&event_handler); let background_chain_mon = Arc::clone(&self.chain_monitor); let background_chan_man = Arc::clone(&self.channel_manager); @@ -643,6 +735,32 @@ impl Node { Ok(()) } + fn spawn_chain_sync_task(&self) { + let stop_receiver = self.stop_sender.subscribe(); + self.spawn_chain_sync_task_with_receiver(stop_receiver); + } + + fn spawn_chain_sync_task_with_receiver( + &self, stop_sync_receiver: tokio::sync::watch::Receiver<()>, + ) { + let chain_source = Arc::clone(&self.chain_source); + let sync_wallet = Arc::clone(&self.wallet); + let sync_cman = Arc::clone(&self.channel_manager); + let sync_cmon = Arc::clone(&self.chain_monitor); + let sync_sweeper = Arc::clone(&self.output_sweeper); + self.runtime.spawn_background_task(async move { + chain_source + .continuously_sync_wallets( + stop_sync_receiver, + sync_wallet, + sync_cman, + sync_cmon, + sync_sweeper, + ) + .await; + }); + } + /// Disconnects all peers, stops all running background tasks, and shuts down [`Node`]. /// /// After this returns most API methods will return [`Error::NotRunning`]. @@ -841,6 +959,7 @@ impl Node { Arc::clone(&self.config), Arc::clone(&self.is_running), Arc::clone(&self.logger), + Arc::clone(&self._router), ) } @@ -859,6 +978,7 @@ impl Node { Arc::clone(&self.config), Arc::clone(&self.is_running), Arc::clone(&self.logger), + Arc::clone(&self._router), )) } @@ -942,6 +1062,40 @@ impl Node { )) } + /// Returns transaction details for the given transaction ID, if available in the wallet. + /// + /// Returns `None` if the transaction is not found in the wallet. + pub fn get_transaction_details(&self, txid: &bitcoin::Txid) -> Option { + let (amount_sats, inputs, outputs) = self.wallet.get_tx_details(txid)?; + Some(TransactionDetails { amount_sats, inputs, outputs }) + } + + /// Gets the current balance (in satoshis) for a Bitcoin address. + /// + /// This queries the chain source (Esplora or Electrum) to get the current balance of the + /// address. Returns 0 if the balance cannot be queried (e.g., chain source unavailable). + /// + /// Returns [`Error::InvalidAddress`] if the address string cannot be parsed or doesn't match + /// the node's network. + pub fn get_address_balance(&self, address_str: &str) -> Result { + use std::str::FromStr; + + use bitcoin::address::NetworkUnchecked; + + let addr_unchecked = bitcoin::Address::::from_str(address_str) + .map_err(|_| Error::InvalidAddress)?; + + let addr_checked = addr_unchecked + .require_network(self.config.network) + .map_err(|_| Error::InvalidAddress)?; + + let chain_source = Arc::clone(&self.chain_source); + let balance = self + .runtime + .block_on(async move { chain_source.get_address_balance(&addr_checked).await }); + Ok(balance.unwrap_or(0)) + } + /// Returns a payment handler allowing to create [BIP 21] URIs with an on-chain, [BOLT 11], /// and [BOLT 12] payment options. /// @@ -1006,7 +1160,37 @@ impl Node { /// Retrieve a list of known channels. pub fn list_channels(&self) -> Vec { - self.channel_manager.list_channels().into_iter().map(|c| c.into()).collect() + // Build channel_id -> claimable_on_close_sats map from monitors + let mut claimable_map: HashMap = HashMap::new(); + + for channel_id in self.chain_monitor.list_monitors() { + if let Ok(monitor) = self.chain_monitor.get_monitor(channel_id) { + for balance in monitor.get_claimable_balances() { + if let LdkBalance::ClaimableOnChannelClose { + balance_candidates, + confirmed_balance_candidate_index, + .. + } = &balance + { + if let Some(confirmed) = + balance_candidates.get(*confirmed_balance_candidate_index) + { + *claimable_map.entry(channel_id).or_insert(0) += + confirmed.amount_satoshis; + } + } + } + } + } + + self.channel_manager + .list_channels() + .into_iter() + .map(|c| { + let balance = claimable_map.get(&c.channel_id).copied(); + ChannelDetails::from_ldk_with_balance(c, balance) + }) + .collect() } /// Connect to a node on the peer-to-peer network. @@ -1021,6 +1205,15 @@ impl Node { let peer_info = PeerInfo { node_id, address }; + // Persist first so the address is updated even if the connection attempt + // races with an in-flight reconnection loop attempt at the old address. + if persist { + self.runtime.block_on( + self.rgs_peer_recovery_exclusions + .add_peer_and_clear_exclusion(self.peer_store.as_ref(), peer_info.clone()), + )?; + } + let con_node_id = peer_info.node_id; let con_addr = peer_info.address.clone(); let con_cm = Arc::clone(&self.connection_manager); @@ -1033,17 +1226,21 @@ impl Node { log_info!(self.logger, "Connected to peer {}@{}. ", peer_info.node_id, peer_info.address); - if persist { - self.peer_store.add_peer(peer_info)?; - } - Ok(()) } /// Disconnects the peer with the given node id. /// - /// Will also remove the peer from the peer store, i.e., after this has been called we won't - /// try to reconnect on restart. + /// Will also remove the peer from the peer store, i.e., the stored peer entry won't be used + /// by the reconnect loop. + /// + /// If an active channel with this peer is later restored and the peer has an announced address + /// in the network graph, startup may persist the peer again so the channel can reconnect. + /// Background RGS retries will not re-persist the peer during this node instance unless the + /// peer is explicitly connected with persistence enabled or a new channel is opened. + /// + /// Returns [`Error::PersistenceFailed`] without disconnecting the peer if removing the peer from + /// persistent storage fails. pub fn disconnect(&self, counterparty_node_id: PublicKey) -> Result<(), Error> { if !*self.is_running.read().unwrap() { return Err(Error::NotRunning); @@ -1051,12 +1248,12 @@ impl Node { log_info!(self.logger, "Disconnecting peer {}..", counterparty_node_id); - match self.peer_store.remove_peer(&counterparty_node_id) { - Ok(()) => {}, - Err(e) => { - log_error!(self.logger, "Failed to remove peer {}: {}", counterparty_node_id, e) - }, - } + self.runtime.block_on( + self.rgs_peer_recovery_exclusions.remove_peer_and_exclude_after_disconnect( + self.peer_store.as_ref(), + counterparty_node_id, + ), + )?; self.peer_manager.disconnect_by_node_id(counterparty_node_id); Ok(()) @@ -1115,7 +1312,10 @@ impl Node { "Initiated channel creation with peer {}. ", peer_info.node_id ); - self.peer_store.add_peer(peer_info)?; + self.runtime.block_on( + self.rgs_peer_recovery_exclusions + .add_peer_and_clear_exclusion(self.peer_store.as_ref(), peer_info), + )?; Ok(UserChannelId(user_channel_id)) }, Err(e) => { @@ -1130,8 +1330,9 @@ impl Node { ) -> Result<(), Error> { let cur_anchor_reserve_sats = total_anchor_channels_reserve_sats(&self.channel_manager, &self.config); + let spendable_amount_sats = - self.wallet.get_spendable_amount_sats(cur_anchor_reserve_sats).unwrap_or(0); + self.wallet.get_witness_spendable_amount_sats(cur_anchor_reserve_sats).unwrap_or(0); // Fail early if we have less than the channel value available. if spendable_amount_sats < amount_sats { @@ -1445,9 +1646,15 @@ impl Node { if chain_source.is_transaction_based() { chain_source.update_fee_rate_estimates().await?; chain_source - .sync_lightning_wallet(sync_cman, sync_cmon, Arc::clone(&sync_sweeper)) + .sync_lightning_wallet( + Arc::clone(&sync_cman), + Arc::clone(&sync_cmon), + Arc::clone(&sync_sweeper), + ) + .await?; + chain_source + .sync_onchain_wallet(sync_wallet, Some(sync_cman), Some(sync_cmon)) .await?; - chain_source.sync_onchain_wallet(sync_wallet).await?; } else { chain_source.update_fee_rate_estimates().await?; chain_source @@ -1529,7 +1736,11 @@ impl Node { // Check if this was the last open channel, if so, forget the peer. if open_channels.len() == 1 { - self.peer_store.remove_peer(&counterparty_node_id)?; + self.runtime.block_on( + self.rgs_peer_recovery_exclusions + .exclude_after_last_channel_close(counterparty_node_id), + ); + self.runtime.block_on(self.peer_store.remove_peer(&counterparty_node_id))?; } } @@ -1558,6 +1769,46 @@ impl Node { } } + /// Updates the intervals for background wallet sync tasks at runtime. + /// + /// This allows changing sync intervals while the node is running, which is useful + /// for mobile apps that want to reduce battery usage when in the background. + /// + /// See [`RuntimeSyncIntervals`] for available interval settings and the + /// [`RuntimeSyncIntervals::battery_saving`] preset. + /// + /// **Note:** Changes take effect on the next sync cycle. Currently running sync operations + /// will complete with their original interval. + /// + /// **Note:** A minimum of 10 seconds is enforced for wallet sync intervals. + /// Values below this minimum will be silently raised to 10 seconds. + /// + /// **Note:** If `background_sync_config` was set to `None` at build time (e.g., via + /// [`EsploraSyncConfig`] or [`ElectrumSyncConfig`]), the wallet sync intervals + /// cannot be updated at runtime and this method will return an error. + /// In that case, use [`Node::sync_wallets`] for manual syncing instead. + /// + /// [`EsploraSyncConfig`]: crate::config::EsploraSyncConfig + /// [`ElectrumSyncConfig`]: crate::config::ElectrumSyncConfig + pub fn update_sync_intervals(&self, intervals: RuntimeSyncIntervals) -> Result<(), Error> { + // Update the shared RuntimeSyncIntervals + *self.runtime_sync_intervals.write().unwrap() = intervals.clone(); + + // Update chain source wallet sync intervals + let wallet_config = BackgroundSyncConfig::from(intervals); + self.chain_source.set_background_sync_config(wallet_config)?; + + log_info!(self.logger, "Updated runtime sync intervals."); + Ok(()) + } + + /// Returns the current sync intervals for background wallet sync tasks. + /// + /// See [`RuntimeSyncIntervals`] for the meaning of each interval. + pub fn current_sync_intervals(&self) -> RuntimeSyncIntervals { + self.runtime_sync_intervals.read().unwrap().clone() + } + /// Retrieve the details of a specific payment with the given id. /// /// Returns `Some` if the payment was known and `None` otherwise. @@ -1571,6 +1822,9 @@ impl Node { } /// Retrieves an overview of all known balances. + /// + /// On-chain totals include all currently loaded derived accounts. Funds from unloaded accounts + /// are omitted until the account is loaded from configuration or registered at runtime. pub fn list_balances(&self) -> BalanceDetails { let cur_anchor_reserve_sats = total_anchor_channels_reserve_sats(&self.channel_manager, &self.config); @@ -1618,6 +1872,191 @@ impl Node { } } + /// Retrieves the on-chain balance for a specific address type on account `0`. + /// + /// See [`Node::get_balance_for_onchain_wallet_account`] for derived accounts. + pub fn get_balance_for_address_type( + &self, address_type: AddressType, + ) -> Result { + let (total_sats, spendable_sats) = + self.wallet.get_balance_for_address_type(address_type)?; + Ok(AddressTypeBalance { total_sats, spendable_sats }) + } + + /// Returns all address types currently loaded on account `0`. + pub fn list_monitored_address_types(&self) -> Vec { + self.wallet.get_loaded_address_types() + } + + /// Adds an address type to the monitored set. + /// + /// The wallet is created from `seed_bytes` (or loaded from the kv-store if previously + /// monitored) and included in subsequent sync cycles. The seed must be the same 64-byte + /// entropy used to build this node. + /// + /// Not persisted across restarts; re-apply on each start or update [`Config`]. + #[cfg(not(feature = "uniffi"))] + pub fn add_address_type_to_monitor( + &self, address_type: config::AddressType, seed_bytes: [u8; config::WALLET_KEYS_SEED_LEN], + ) -> Result<(), Error> { + self.wallet.add_monitored_address_type(address_type, &seed_bytes) + } + + /// Adds an address type to the monitored set. + /// + /// The wallet is created from `seed_bytes` (or loaded from the kv-store if previously + /// monitored) and included in subsequent sync cycles. The seed must be the same 64-byte + /// entropy used to build this node. + /// + /// Returns [`Error::InvalidSeedBytes`] if `seed_bytes` length differs from + /// [`config::WALLET_KEYS_SEED_LEN`]. + /// + /// Not persisted across restarts; re-apply on each start or update [`Config`]. + #[cfg(feature = "uniffi")] + pub fn add_address_type_to_monitor( + &self, address_type: config::AddressType, seed_bytes: Vec, + ) -> Result<(), Error> { + let seed = validate_seed_bytes(seed_bytes)?; + self.wallet.add_monitored_address_type(address_type, &seed) + } + + /// Removes an address type from the monitored set and unloads its wallet. + /// + /// Persisted state is retained in the kv-store; re-adding the type via + /// [`Node::add_address_type_to_monitor`] recovers all funds on the next sync. + /// + /// Not persisted across restarts; re-apply on each start or update [`Config`]. + pub fn remove_address_type_from_monitor( + &self, address_type: config::AddressType, + ) -> Result<(), Error> { + self.wallet.remove_monitored_address_type(address_type) + } + + /// Changes the primary address type used for new addresses and change outputs on account `0`. + /// + /// Creates the wallet from `seed_bytes` if not already loaded. The previous primary is + /// demoted to the monitored set. If the new primary has never been synced, a full scan + /// is triggered on the next sync cycle. + /// + /// Not persisted across restarts; re-apply on each start or update [`Config`]. + #[cfg(not(feature = "uniffi"))] + pub fn set_primary_address_type( + &self, address_type: config::AddressType, seed_bytes: [u8; config::WALLET_KEYS_SEED_LEN], + ) -> Result<(), Error> { + self.wallet.set_primary_address_type(address_type, &seed_bytes) + } + + /// Changes the primary address type used for new addresses and change outputs on account `0`. + /// + /// Creates the wallet from `seed_bytes` if not already loaded. The previous primary is + /// demoted to the monitored set. If the new primary has never been synced, a full scan + /// is triggered on the next sync cycle. + /// + /// Returns [`Error::InvalidSeedBytes`] if `seed_bytes` length differs from + /// [`config::WALLET_KEYS_SEED_LEN`]. + /// + /// Not persisted across restarts; re-apply on each start or update [`Config`]. + #[cfg(feature = "uniffi")] + pub fn set_primary_address_type( + &self, address_type: config::AddressType, seed_bytes: Vec, + ) -> Result<(), Error> { + let seed = validate_seed_bytes(seed_bytes)?; + self.wallet.set_primary_address_type(address_type, &seed) + } + + /// Adds an address type to the monitored set, deriving the wallet from a BIP39 mnemonic. + /// + /// Convenience wrapper around [`Node::add_address_type_to_monitor`]. The `mnemonic` and + /// `passphrase` must match the values used at build time. + /// + /// Not persisted across restarts. + pub fn add_address_type_to_monitor_with_mnemonic( + &self, address_type: config::AddressType, mnemonic: bip39::Mnemonic, + passphrase: Option, + ) -> Result<(), Error> { + let seed = mnemonic.to_seed(passphrase.as_deref().unwrap_or("")); + self.wallet.add_monitored_address_type(address_type, &seed) + } + + /// Changes the primary address type, deriving the wallet from a BIP39 mnemonic. + /// + /// Convenience wrapper around [`Node::set_primary_address_type`]. The `mnemonic` and + /// `passphrase` must match the values used at build time. + /// + /// Not persisted across restarts. + pub fn set_primary_address_type_with_mnemonic( + &self, address_type: config::AddressType, mnemonic: bip39::Mnemonic, + passphrase: Option, + ) -> Result<(), Error> { + let seed = mnemonic.to_seed(passphrase.as_deref().unwrap_or("")); + self.wallet.set_primary_address_type(address_type, &seed) + } + + /// Exports the account-level xpub for a derived (or main) on-chain wallet account. + /// + /// Store the returned xpub in [`Config::onchain_wallet_accounts`] to load a derived account on + /// future builds, or register it at runtime with [`Node::add_onchain_wallet_account`]. + pub fn export_onchain_wallet_account_xpub( + &self, address_type: AddressType, account_index: u32, + ) -> Result { + self.wallet.export_onchain_wallet_account_xpub(address_type, account_index) + } + + /// Registers a derived on-chain wallet account (`account_index >= 1`). + /// + /// Validates `xpub` against the node's master seed. Idempotent for the same xpub. + /// Account `0` and indexes above [`crate::config::MAX_ONCHAIN_WALLET_ACCOUNT_INDEX`] are + /// rejected with [`Error::InvalidQuantity`]. A mismatched xpub returns + /// [`Error::InvalidSeedBytes`]. + /// + /// Runtime registration is not persisted across restarts. BDK data remains persisted; use + /// [`Config::onchain_wallet_accounts`] to load the account on each build. + /// + /// Registered funds participate in normal wallet coin selection and signing. Change remains on + /// the configured primary account-`0` wallet. + /// + /// Esplora/Electrum perform a full scan after registration, then maintain a rolling lookahead for + /// derived accounts. Activity inside the lookahead advances and replenishes it. Use + /// [`OnchainPayment::reveal_receive_addresses_to_account`] when an external address issuer may + /// skip beyond the current lookahead. Bitcoind replays the current mempool but cannot scan + /// confirmed history from before a brand-new account's first registration. + pub fn add_onchain_wallet_account( + &self, address_type: AddressType, account_index: u32, xpub: String, + ) -> Result<(), Error> { + self.wallet.add_onchain_wallet_account(address_type, account_index, &xpub) + } + + /// Unloads a derived on-chain wallet account (`account_index >= 1`). + /// + /// Persisted BDK data is retained, so re-registering the account recovers its state on the next + /// sync. Accounts listed in [`Config::onchain_wallet_accounts`] are loaded again on restart. + /// Account `0` and out-of-range indexes return [`Error::InvalidQuantity`]; an unloaded account + /// returns [`Error::OnchainWalletAccountNotRegistered`]. + pub fn remove_onchain_wallet_account( + &self, address_type: AddressType, account_index: u32, + ) -> Result<(), Error> { + self.wallet.remove_onchain_wallet_account(address_type, account_index) + } + + /// Retrieves the on-chain balance for a specific wallet account. + /// + /// Funds in a registered account are available to normal wallet payments, whose change is sent to + /// the configured primary account-`0` wallet. + /// An unloaded derived account returns [`Error::OnchainWalletAccountNotRegistered`]. + pub fn get_balance_for_onchain_wallet_account( + &self, address_type: AddressType, account_index: u32, + ) -> Result { + let wallet_account = OnchainWalletAccount { address_type, account_index }; + let (total_sats, spendable_sats) = + self.wallet.get_balance_for_onchain_wallet_account(wallet_account)?; + Ok(AddressTypeBalance { total_sats, spendable_sats }) + } + + /// Returns all currently loaded on-chain wallet accounts, including derived accounts. + pub fn list_onchain_wallet_accounts(&self) -> Vec { + self.wallet.get_loaded_onchain_wallet_accounts() + } + /// Retrieves all payments that match the given predicate. /// /// For example, you could retrieve all stored outbound payments as follows: @@ -1740,6 +2179,16 @@ impl Drop for Node { } } +#[cfg(feature = "uniffi")] +fn validate_seed_bytes(seed_bytes: Vec) -> Result<[u8; config::WALLET_KEYS_SEED_LEN], Error> { + if seed_bytes.len() != config::WALLET_KEYS_SEED_LEN { + return Err(Error::InvalidSeedBytes); + } + let mut bytes = [0u8; config::WALLET_KEYS_SEED_LEN]; + bytes.copy_from_slice(&seed_bytes); + Ok(bytes) +} + /// Represents the status of the [`Node`]. #[derive(Clone, Debug, PartialEq, Eq)] pub struct NodeStatus { @@ -1790,6 +2239,11 @@ pub(crate) struct NodeMetrics { latest_pathfinding_scores_sync_timestamp: Option, latest_node_announcement_broadcast_timestamp: Option, latest_channel_monitor_archival_height: Option, + last_known_spendable_onchain_balance_sats: Option, + last_known_total_onchain_balance_sats: Option, + last_known_total_lightning_balance_sats: Option, + /// Sync timestamps for account-0 monitored address types (TLV type 18). + monitored_wallet_sync_timestamps: Vec<(AddressType, u64)>, } impl Default for NodeMetrics { @@ -1802,6 +2256,42 @@ impl Default for NodeMetrics { latest_pathfinding_scores_sync_timestamp: None, latest_node_announcement_broadcast_timestamp: None, latest_channel_monitor_archival_height: None, + last_known_spendable_onchain_balance_sats: None, + last_known_total_onchain_balance_sats: None, + last_known_total_lightning_balance_sats: None, + monitored_wallet_sync_timestamps: Vec::new(), + } + } +} + +impl NodeMetrics { + pub(crate) fn get_wallet_sync_timestamp( + &self, wallet_account: OnchainWalletAccount, + ) -> Option { + // Derived-account scan completion is runtime-only, so each registration after restart full-scans. + if wallet_account.account_index != 0 { + return None; + } + self.monitored_wallet_sync_timestamps + .iter() + .find(|(at, _)| *at == wallet_account.address_type) + .map(|(_, ts)| *ts) + } + + pub(crate) fn set_wallet_sync_timestamp( + &mut self, wallet_account: OnchainWalletAccount, timestamp: u64, + ) { + if wallet_account.account_index != 0 { + return; + } + if let Some(entry) = self + .monitored_wallet_sync_timestamps + .iter_mut() + .find(|(at, _)| *at == wallet_account.address_type) + { + entry.1 = timestamp; + } else { + self.monitored_wallet_sync_timestamps.push((wallet_account.address_type, timestamp)); } } } @@ -1814,8 +2304,77 @@ impl_writeable_tlv_based!(NodeMetrics, { (6, latest_rgs_snapshot_timestamp, option), (8, latest_node_announcement_broadcast_timestamp, option), (10, latest_channel_monitor_archival_height, option), + (12, last_known_spendable_onchain_balance_sats, option), + (14, last_known_total_onchain_balance_sats, option), + (16, last_known_total_lightning_balance_sats, option), + (18, monitored_wallet_sync_timestamps, optional_vec), }); +// Check if balances have changed and emit BalanceChanged event if so. +pub(crate) async fn check_and_emit_balance_update( + node_metrics: &Arc>, balance_details: &BalanceDetails, + event_queue: &EventQueue, kv_store: &Arc, logger: &Arc, +) -> Result<(), Error> +where + L::Target: LdkLogger, +{ + let new_spendable_onchain = balance_details.spendable_onchain_balance_sats; + let new_total_onchain = balance_details.total_onchain_balance_sats; + let new_total_lightning = balance_details.total_lightning_balance_sats; + + // Read old values while holding the lock (drop before await) + let (old_spendable_onchain, old_total_onchain, old_total_lightning) = { + let locked_metrics = node_metrics.read().unwrap(); + ( + locked_metrics.last_known_spendable_onchain_balance_sats.unwrap_or(0), + locked_metrics.last_known_total_onchain_balance_sats.unwrap_or(0), + locked_metrics.last_known_total_lightning_balance_sats.unwrap_or(0), + ) + }; + + // Check if any balance has changed + if old_spendable_onchain != new_spendable_onchain + || old_total_onchain != new_total_onchain + || old_total_lightning != new_total_lightning + { + log_info!( + logger, + "Balance changed: onchain {} -> {} (spendable), {} -> {} (total), lightning {} -> {}", + old_spendable_onchain, + new_spendable_onchain, + old_total_onchain, + new_total_onchain, + old_total_lightning, + new_total_lightning + ); + + // Emit balance changed event (lock dropped before await) + event_queue + .add_event(Event::BalanceChanged { + old_spendable_onchain_balance_sats: old_spendable_onchain, + new_spendable_onchain_balance_sats: new_spendable_onchain, + old_total_onchain_balance_sats: old_total_onchain, + new_total_onchain_balance_sats: new_total_onchain, + old_total_lightning_balance_sats: old_total_lightning, + new_total_lightning_balance_sats: new_total_lightning, + }) + .await?; + + // Update tracked balances (reacquire lock after await) + { + let mut locked_metrics = node_metrics.write().unwrap(); + locked_metrics.last_known_spendable_onchain_balance_sats = Some(new_spendable_onchain); + locked_metrics.last_known_total_onchain_balance_sats = Some(new_total_onchain); + locked_metrics.last_known_total_lightning_balance_sats = Some(new_total_lightning); + + // Persist updated metrics + write_node_metrics(&*locked_metrics, Arc::clone(kv_store), Arc::clone(logger))?; + } + } + + Ok(()) +} + pub(crate) fn total_anchor_channels_reserve_sats( channel_manager: &ChannelManager, config: &Config, ) -> u64 { @@ -1835,3 +2394,231 @@ pub(crate) fn total_anchor_channels_reserve_sats( * anchor_channels_config.per_channel_reserve_sats }) } + +#[cfg(test)] +mod tests { + use std::future::Future; + use std::pin::Pin; + use std::str::FromStr; + use std::sync::atomic::{AtomicBool, Ordering}; + use std::sync::Arc; + use std::time::Duration; + + use bitcoin::Network; + use lightning::io; + use lightning::util::persist::{KVStore, KVStoreSync}; + + use super::*; + use crate::builder::NodeBuilder; + use crate::config::Config; + use crate::io::test_utils::InMemoryStore; + + struct FailNextWriteStore { + inner: InMemoryStore, + fail_next_write: AtomicBool, + } + + impl FailNextWriteStore { + fn new() -> Self { + Self { inner: InMemoryStore::new(), fail_next_write: AtomicBool::new(false) } + } + + fn fail_next_write(&self) { + self.fail_next_write.store(true, Ordering::Relaxed); + } + } + + impl KVStore for FailNextWriteStore { + fn read( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, + ) -> Pin, io::Error>> + 'static + Send>> { + KVStore::read(&self.inner, primary_namespace, secondary_namespace, key) + } + + fn write( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, buf: Vec, + ) -> Pin> + 'static + Send>> { + if self.fail_next_write.swap(false, Ordering::Relaxed) { + return Box::pin(async { + Err(io::Error::new(io::ErrorKind::Other, "Injected write failure")) + }); + } + KVStore::write(&self.inner, primary_namespace, secondary_namespace, key, buf) + } + + fn remove( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, lazy: bool, + ) -> Pin> + 'static + Send>> { + KVStore::remove(&self.inner, primary_namespace, secondary_namespace, key, lazy) + } + + fn list( + &self, primary_namespace: &str, secondary_namespace: &str, + ) -> Pin, io::Error>> + 'static + Send>> { + KVStore::list(&self.inner, primary_namespace, secondary_namespace) + } + } + + impl KVStoreSync for FailNextWriteStore { + fn read( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, + ) -> io::Result> { + KVStoreSync::read(&self.inner, primary_namespace, secondary_namespace, key) + } + + fn write( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, buf: Vec, + ) -> io::Result<()> { + if self.fail_next_write.swap(false, Ordering::Relaxed) { + return Err(io::Error::new(io::ErrorKind::Other, "Injected write failure")); + } + KVStoreSync::write(&self.inner, primary_namespace, secondary_namespace, key, buf) + } + + fn remove( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, lazy: bool, + ) -> io::Result<()> { + KVStoreSync::remove(&self.inner, primary_namespace, secondary_namespace, key, lazy) + } + + fn list( + &self, primary_namespace: &str, secondary_namespace: &str, + ) -> io::Result> { + KVStoreSync::list(&self.inner, primary_namespace, secondary_namespace) + } + } + + fn test_node_id() -> PublicKey { + PublicKey::from_str("0276607124ebe6a6c9338517b6f485825b27c2dcc0b9fc2aa6a4c0df91194e5993") + .unwrap() + } + + fn other_test_node_id() -> PublicKey { + PublicKey::from_str("02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619") + .unwrap() + } + + fn test_peer_info(node_id: PublicKey, port: u16) -> PeerInfo { + PeerInfo { + node_id, + address: SocketAddress::from_str(&format!("127.0.0.1:{port}")).unwrap(), + } + } + + #[test] + fn disconnect_propagates_peer_removal_persistence_failure() { + let config = Config { network: Network::Regtest, ..Config::default() }; + let mut builder = NodeBuilder::from_config(config); + builder.set_chain_source_esplora("http://127.0.0.1:1".to_string(), None); + builder.set_entropy_seed_bytes([42u8; 64]); + builder.set_log_facade_logger(); + + let store = Arc::new(FailNextWriteStore::new()); + let dyn_store: Arc = store.clone(); + let node = builder.build_with_store(dyn_store).unwrap(); + let node_id = test_node_id(); + let peer_info = test_peer_info(node_id, 9738); + node.runtime.block_on(node.peer_store.add_peer(peer_info.clone())).unwrap(); + *node.is_running.write().unwrap() = true; + + store.fail_next_write(); + assert!(matches!(node.disconnect(node_id), Err(Error::PersistenceFailed))); + assert_eq!(node.peer_store.get_peer(&node_id), Some(peer_info)); + assert!(!node.runtime.block_on(node.rgs_peer_recovery_exclusions.contains(&node_id))); + + node.disconnect(node_id).unwrap(); + assert!(node.peer_store.get_peer(&node_id).is_none()); + assert!(node.runtime.block_on(node.rgs_peer_recovery_exclusions.contains(&node_id))); + *node.is_running.write().unwrap() = false; + } + + #[tokio::test] + async fn rgs_peer_recovery_exclusions_follow_disconnect_and_connect_transitions() { + let exclusions = RgsPeerRecoveryExclusions::default(); + let node_id = test_node_id(); + + exclusions.exclude_after_disconnect(node_id).await; + assert!(exclusions.contains(&node_id).await); + + exclusions.clear_after_persistent_connect(&node_id).await; + assert!(!exclusions.contains(&node_id).await); + + exclusions.exclude_after_last_channel_close(node_id).await; + assert!(exclusions.contains(&node_id).await); + + exclusions.clear_after_channel_open(&node_id).await; + assert!(!exclusions.contains(&node_id).await); + } + + #[tokio::test] + async fn rgs_peer_recovery_read_guard_serializes_disconnect_exclusion() { + let exclusions = Arc::new(RgsPeerRecoveryExclusions::default()); + let node_id = test_node_id(); + let recovery_read_guard = exclusions.read().await; + + let (attempting_write_tx, attempting_write_rx) = tokio::sync::oneshot::channel(); + let writer_exclusions = Arc::clone(&exclusions); + let mut writer = tokio::spawn(async move { + attempting_write_tx.send(()).unwrap(); + writer_exclusions.exclude_after_disconnect(node_id).await; + }); + + attempting_write_rx.await.unwrap(); + assert!( + tokio::time::timeout(Duration::from_millis(200), &mut writer).await.is_err(), + "disconnect exclusion must wait while RGS recovery holds the live read guard" + ); + assert!(!recovery_read_guard.contains(&node_id)); + + drop(recovery_read_guard); + writer.await.unwrap(); + assert!(exclusions.contains(&node_id).await); + } + + #[tokio::test] + async fn rgs_peer_recovery_persistent_peer_updates_take_exclusion_lock_first() { + let store: Arc = Arc::new(crate::io::test_utils::InMemoryStore::new()); + let logger = Arc::new(Logger::new_log_facade()); + let peer_store = Arc::new(PeerStore::new(store, logger)); + let exclusions = Arc::new(RgsPeerRecoveryExclusions::default()); + let node_id = test_node_id(); + let other_node_id = other_test_node_id(); + let peer_info = test_peer_info(node_id, 9738); + let other_peer_info = test_peer_info(other_node_id, 9739); + + exclusions.exclude_after_disconnect(node_id).await; + let recovery_read_guard = exclusions.read().await; + + let (attempting_clear_tx, attempting_clear_rx) = tokio::sync::oneshot::channel(); + let clear_exclusions = Arc::clone(&exclusions); + let clear_peer_store = Arc::clone(&peer_store); + let peer_info_for_clear = peer_info.clone(); + let mut clearer = tokio::spawn(async move { + attempting_clear_tx.send(()).unwrap(); + clear_exclusions + .add_peer_and_clear_exclusion(clear_peer_store.as_ref(), peer_info_for_clear) + .await + .unwrap(); + }); + + attempting_clear_rx.await.unwrap(); + assert!( + tokio::time::timeout(Duration::from_millis(200), &mut clearer).await.is_err(), + "persistent peer update must wait for the recovery read guard before taking peer_store" + ); + + tokio::time::timeout(Duration::from_secs(1), peer_store.add_peer(other_peer_info.clone())) + .await + .expect("peer store must remain available while exclusion acquisition is pending") + .unwrap(); + + assert_eq!(peer_store.get_peer(&other_node_id), Some(other_peer_info)); + assert!(peer_store.get_peer(&node_id).is_none()); + assert!(recovery_read_guard.contains(&node_id)); + + drop(recovery_read_guard); + clearer.await.unwrap(); + assert_eq!(peer_store.get_peer(&node_id), Some(peer_info)); + assert!(!exclusions.contains(&node_id).await); + } +} diff --git a/src/liquidity.rs b/src/liquidity.rs index 74e6098ddc..24d3f3d218 100644 --- a/src/liquidity.rs +++ b/src/liquidity.rs @@ -745,8 +745,10 @@ where let channel_amount_sats = (amt_to_forward_msat + over_provisioning_msat) / 1000; let cur_anchor_reserve_sats = total_anchor_channels_reserve_sats(&self.channel_manager, &self.config); - let spendable_amount_sats = - self.wallet.get_spendable_amount_sats(cur_anchor_reserve_sats).unwrap_or(0); + let spendable_amount_sats = self + .wallet + .get_witness_spendable_amount_sats(cur_anchor_reserve_sats) + .unwrap_or(0); let required_funds_sats = channel_amount_sats + self.config.anchor_channels_config.as_ref().map_or(0, |c| { if init_features.requires_anchors_zero_fee_htlc_tx() diff --git a/src/payment/bolt11.rs b/src/payment/bolt11.rs index 60c313381a..3670afc1c7 100644 --- a/src/payment/bolt11.rs +++ b/src/payment/bolt11.rs @@ -16,7 +16,9 @@ use bitcoin::hashes::Hash; use lightning::ln::channelmanager::{ Bolt11InvoiceParameters, Bolt11PaymentError, PaymentId, Retry, RetryableSendFailure, }; -use lightning::routing::router::{PaymentParameters, RouteParameters, RouteParametersConfig}; +use lightning::routing::router::{ + PaymentParameters, RouteParameters, RouteParametersConfig, Router as LdkRouter, +}; use lightning_invoice::{ Bolt11Invoice as LdkBolt11Invoice, Bolt11InvoiceDescription as LdkBolt11InvoiceDescription, }; @@ -35,8 +37,8 @@ use crate::payment::store::{ }; use crate::peer_store::{PeerInfo, PeerStore}; use crate::runtime::Runtime; -use crate::types::{ChannelManager, PaymentStore}; - +use crate::types::{ChannelManager, PaymentStore, Router}; +use crate::ProbeHandle; #[cfg(not(feature = "uniffi"))] type Bolt11Invoice = LdkBolt11Invoice; #[cfg(feature = "uniffi")] @@ -63,6 +65,7 @@ pub struct Bolt11Payment { config: Arc, is_running: Arc>, logger: Arc, + router: Arc, } impl Bolt11Payment { @@ -72,6 +75,7 @@ impl Bolt11Payment { liquidity_source: Option>>>, payment_store: Arc, peer_store: Arc>>, config: Arc, is_running: Arc>, logger: Arc, + router: Arc, ) -> Self { Self { runtime, @@ -83,6 +87,7 @@ impl Bolt11Payment { config, is_running, logger, + router, } } @@ -126,10 +131,22 @@ impl Bolt11Payment { let amt_msat = invoice.amount_milli_satoshis().unwrap(); log_info!(self.logger, "Initiated sending {}msat to {}", amt_msat, payee_pubkey); + // Extract description from the invoice + let description = match invoice.description() { + lightning_invoice::Bolt11InvoiceDescriptionRef::Direct(desc) => { + Some(desc.to_string()) + }, + lightning_invoice::Bolt11InvoiceDescriptionRef::Hash(hash) => { + Some(crate::hex_utils::to_string(hash.0.as_ref())) + }, + }; + let kind = PaymentKind::Bolt11 { hash: payment_hash, preimage: None, secret: payment_secret, + description, + bolt11: Some(invoice.to_string()), }; let payment = PaymentDetails::new( payment_id, @@ -155,10 +172,22 @@ impl Bolt11Payment { match e { RetryableSendFailure::DuplicatePayment => Err(Error::DuplicatePayment), _ => { + // Extract description from the invoice + let description = match invoice.description() { + lightning_invoice::Bolt11InvoiceDescriptionRef::Direct(desc) => { + Some(desc.to_string()) + }, + lightning_invoice::Bolt11InvoiceDescriptionRef::Hash(hash) => { + Some(crate::hex_utils::to_string(hash.0.as_ref())) + }, + }; + let kind = PaymentKind::Bolt11 { hash: payment_hash, preimage: None, secret: payment_secret, + description, + bolt11: Some(invoice.to_string()), }; let payment = PaymentDetails::new( payment_id, @@ -236,10 +265,22 @@ impl Bolt11Payment { payee_pubkey ); + // Extract description from the invoice + let description = match invoice.description() { + lightning_invoice::Bolt11InvoiceDescriptionRef::Direct(desc) => { + Some(desc.to_string()) + }, + lightning_invoice::Bolt11InvoiceDescriptionRef::Hash(hash) => { + Some(crate::hex_utils::to_string(hash.0.as_ref())) + }, + }; + let kind = PaymentKind::Bolt11 { hash: payment_hash, preimage: None, secret: payment_secret, + description, + bolt11: Some(invoice.to_string()), }; let payment = PaymentDetails::new( @@ -266,10 +307,22 @@ impl Bolt11Payment { match e { RetryableSendFailure::DuplicatePayment => Err(Error::DuplicatePayment), _ => { + // Extract description from the invoice + let description = match invoice.description() { + lightning_invoice::Bolt11InvoiceDescriptionRef::Direct(desc) => { + Some(desc.to_string()) + }, + lightning_invoice::Bolt11InvoiceDescriptionRef::Hash(hash) => { + Some(crate::hex_utils::to_string(hash.0.as_ref())) + }, + }; + let kind = PaymentKind::Bolt11 { hash: payment_hash, preimage: None, secret: payment_secret, + description, + bolt11: Some(invoice.to_string()), }; let payment = PaymentDetails::new( payment_id, @@ -509,10 +562,21 @@ impl Bolt11Payment { } else { None }; + + // Extract description from the invoice + let description = match invoice.description() { + lightning_invoice::Bolt11InvoiceDescriptionRef::Direct(desc) => Some(desc.to_string()), + lightning_invoice::Bolt11InvoiceDescriptionRef::Hash(hash) => { + Some(crate::hex_utils::to_string(hash.0.as_ref())) + }, + }; + let kind = PaymentKind::Bolt11 { hash: payment_hash, preimage, secret: Some(payment_secret.clone()), + description, + bolt11: Some(invoice.to_string()), }; let payment = PaymentDetails::new( id, @@ -721,12 +785,23 @@ impl Bolt11Payment { let id = PaymentId(payment_hash.0); let preimage = self.channel_manager.get_payment_preimage(payment_hash, payment_secret.clone()).ok(); + + // Extract description from the invoice + let description = match invoice.description() { + lightning_invoice::Bolt11InvoiceDescriptionRef::Direct(desc) => Some(desc.to_string()), + lightning_invoice::Bolt11InvoiceDescriptionRef::Hash(hash) => { + Some(crate::hex_utils::to_string(hash.0.as_ref())) + }, + }; + let kind = PaymentKind::Bolt11Jit { hash: payment_hash, preimage, secret: Some(payment_secret.clone()), counterparty_skimmed_fee_msat: None, lsp_fee_limits, + description, + bolt11: Some(invoice.to_string()), }; let payment = PaymentDetails::new( id, @@ -739,7 +814,7 @@ impl Bolt11Payment { self.payment_store.insert(payment)?; // Persist LSP peer to make sure we reconnect on restart. - self.peer_store.add_peer(peer_info)?; + self.runtime.block_on(self.peer_store.add_peer(peer_info))?; Ok(invoice) } @@ -760,9 +835,15 @@ impl Bolt11Payment { /// /// If `route_parameters` are provided they will override the default as well as the /// node-wide parameters configured via [`Config::route_parameters`] on a per-field basis. + /// + /// Returns one [`ProbeHandle`] per probe that LDK actually sends. LDK may skip route + /// paths before dispatch, for example if the path is too short to probe or would breach + /// [`Config::probing_liquidity_limit_multiplier`]. Use [`ProbeHandle::payment_id`] + /// (and/or [`ProbeHandle::payment_hash`]) to match [`crate::Event::ProbeSuccessful`] / + /// [`crate::Event::ProbeFailed`]. These values are **not** the invoice payment hash. pub fn send_probes( &self, invoice: &Bolt11Invoice, route_parameters: Option, - ) -> Result<(), Error> { + ) -> Result, Error> { if !*self.is_running.read().unwrap() { return Err(Error::NotRunning); } @@ -796,12 +877,16 @@ impl Bolt11Payment { self.channel_manager .send_preflight_probes(route_params, liquidity_limit_multiplier) + .map(|pairs| { + pairs + .into_iter() + .map(|(payment_hash, payment_id)| ProbeHandle { payment_hash, payment_id }) + .collect() + }) .map_err(|e| { log_error!(self.logger, "Failed to send payment probes: {:?}", e); Error::ProbeSendingFailed - })?; - - Ok(()) + }) } /// Sends payment probes over all paths of a route that would be used to pay the given @@ -813,11 +898,11 @@ impl Bolt11Payment { /// If `route_parameters` are provided they will override the default as well as the /// node-wide parameters configured via [`Config::route_parameters`] on a per-field basis. /// - /// See [`Self::send_probes`] for more information. + /// See [`Self::send_probes`] for return value semantics and correlation with probe events. pub fn send_probes_using_amount( &self, invoice: &Bolt11Invoice, amount_msat: u64, route_parameters: Option, - ) -> Result<(), Error> { + ) -> Result, Error> { if !*self.is_running.read().unwrap() { return Err(Error::NotRunning); } @@ -858,11 +943,105 @@ impl Bolt11Payment { self.channel_manager .send_preflight_probes(route_params, liquidity_limit_multiplier) + .map(|pairs| { + pairs + .into_iter() + .map(|(payment_hash, payment_id)| ProbeHandle { payment_hash, payment_id }) + .collect() + }) .map_err(|e| { log_error!(self.logger, "Failed to send payment probes: {:?}", e); Error::ProbeSendingFailed + }) + } + + /// Estimates the routing fees for a given invoice. + /// + /// This method calculates the routing fees that would be charged for paying the given invoice + /// without actually sending the payment. It uses the same routing logic as the actual payment + /// to provide an accurate estimation. + /// + /// Returns the estimated total routing fees in millisatoshis. + pub fn estimate_routing_fees(&self, invoice: &Bolt11Invoice) -> Result { + if !*self.is_running.read().unwrap() { + return Err(Error::NotRunning); + } + + let invoice = maybe_deref(invoice); + let payment_params = PaymentParameters::from_bolt11_invoice(invoice); + let amount_msat = invoice.amount_milli_satoshis().ok_or_else(|| { + log_error!(self.logger, "Failed to estimate routing fees due to the given invoice being \"zero-amount\". Please use estimate_routing_fees_using_amount instead."); + Error::InvalidInvoice + })?; + + let route_params = + RouteParameters::from_payment_params_and_value(payment_params, amount_msat); + + let first_hops = self.channel_manager.list_usable_channels(); + let inflight_htlcs = self.channel_manager.compute_inflight_htlcs(); + + let route = (&*self.router) + .find_route( + &self.channel_manager.get_our_node_id(), + &route_params, + Some(&first_hops.iter().collect::>()), + inflight_htlcs, + ) + .map_err(|e| { + log_error!(self.logger, "Failed to find route for fee estimation: {:?}", e); + Error::RouteNotFound })?; - Ok(()) + let total_fees = route.paths.iter().map(|path| path.fee_msat()).sum::(); + + Ok(total_fees) + } + + /// Estimates the routing fees for a given zero-amount invoice with a specific amount. + /// + /// This method calculates the routing fees that would be charged for paying the given + /// zero-amount invoice with the specified amount without actually sending the payment. + /// + /// Returns the estimated total routing fees in millisatoshis. + pub fn estimate_routing_fees_using_amount( + &self, invoice: &Bolt11Invoice, amount_msat: u64, + ) -> Result { + if !*self.is_running.read().unwrap() { + return Err(Error::NotRunning); + } + + let invoice = maybe_deref(invoice); + let payment_params = PaymentParameters::from_bolt11_invoice(invoice); + + if let Some(invoice_amount_msat) = invoice.amount_milli_satoshis() { + if amount_msat < invoice_amount_msat { + log_error!( + self.logger, + "Failed to estimate routing fees as the given amount needs to be at least the invoice amount: required {}msat, gave {}msat.", invoice_amount_msat, amount_msat); + return Err(Error::InvalidAmount); + } + } + + let route_params = + RouteParameters::from_payment_params_and_value(payment_params, amount_msat); + + let first_hops = self.channel_manager.list_usable_channels(); + let inflight_htlcs = self.channel_manager.compute_inflight_htlcs(); + + let route = (&*self.router) + .find_route( + &self.channel_manager.get_our_node_id(), + &route_params, + Some(&first_hops.iter().collect::>()), + inflight_htlcs, + ) + .map_err(|e| { + log_error!(self.logger, "Failed to find route for fee estimation: {:?}", e); + Error::RouteNotFound + })?; + + let total_fees = route.paths.iter().map(|path| path.fee_msat()).sum::(); + + Ok(total_fees) } } diff --git a/src/payment/mod.rs b/src/payment/mod.rs index f629960e1d..ba59aea06a 100644 --- a/src/payment/mod.rs +++ b/src/payment/mod.rs @@ -17,7 +17,7 @@ mod unified_qr; pub use bolt11::Bolt11Payment; pub use bolt12::Bolt12Payment; -pub use onchain::OnchainPayment; +pub use onchain::{AddressInfo, KeychainKind, OnchainPayment}; pub use spontaneous::SpontaneousPayment; pub use store::{ ConfirmationStatus, LSPFeeLimits, PaymentDetails, PaymentDirection, PaymentKind, PaymentStatus, diff --git a/src/payment/onchain.rs b/src/payment/onchain.rs index 695f96d435..ef30c0279a 100644 --- a/src/payment/onchain.rs +++ b/src/payment/onchain.rs @@ -11,11 +11,12 @@ use std::sync::{Arc, RwLock}; use bitcoin::{Address, Txid}; -use crate::config::Config; +use crate::config::{AddressType, Config, OnchainWalletAccount}; use crate::error::Error; +use crate::fee_estimator::ConfirmationTarget; use crate::logger::{log_info, LdkLogger, Logger}; -use crate::types::{ChannelManager, Wallet}; -use crate::wallet::OnchainSendAmount; +use crate::types::{ChannelManager, SpendableUtxo, Wallet}; +use crate::wallet::{CoinSelectionAlgorithm, OnchainSendAmount}; #[cfg(not(feature = "uniffi"))] type FeeRate = bitcoin::FeeRate; @@ -35,6 +36,61 @@ macro_rules! maybe_map_fee_rate_opt { }}; } +/// The keychain an address was derived from. +/// +/// Address derivation APIs can use [`KeychainKind::External`] for receive addresses or +/// [`KeychainKind::Internal`] for change addresses. APIs that generate or reveal new receive +/// addresses always operate on [`KeychainKind::External`]. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum KeychainKind { + /// External receive-address keychain. + External, + /// Internal change-address keychain. + Internal, +} + +impl From for KeychainKind { + fn from(keychain: bdk_wallet::KeychainKind) -> Self { + match keychain { + bdk_wallet::KeychainKind::External => Self::External, + bdk_wallet::KeychainKind::Internal => Self::Internal, + } + } +} + +impl From for bdk_wallet::KeychainKind { + fn from(keychain: KeychainKind) -> Self { + match keychain { + KeychainKind::External => Self::External, + KeychainKind::Internal => Self::Internal, + } + } +} + +/// Metadata for an address derived by the on-chain wallet. +/// +/// The `index` is the BIP32 child index within `keychain`. For receive addresses generated by +/// `new_address_info` methods, `keychain` is expected to be [`KeychainKind::External`]. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct AddressInfo { + /// Child index of this address within its keychain. + pub index: u32, + /// The derived Bitcoin address. + pub address: Address, + /// The keychain this address belongs to. + pub keychain: KeychainKind, +} + +impl From for AddressInfo { + fn from(address_info: bdk_wallet::AddressInfo) -> Self { + Self { + index: address_info.index, + address: address_info.address, + keychain: address_info.keychain.into(), + } + } +} + /// A payment handler allowing to send and receive on-chain payments. /// /// Should be retrieved by calling [`Node::onchain_payment`]. @@ -63,6 +119,417 @@ impl OnchainPayment { Ok(funding_address) } + /// Retrieve a new on-chain/funding address with derivation metadata. + /// + /// This uses the same default address type and receive cursor as [`new_address`]. + /// + /// [`new_address`]: Self::new_address + pub fn new_address_info(&self) -> Result { + let funding_address_info = AddressInfo::from(self.wallet.get_new_address_info()?); + log_info!(self.logger, "Generated new funding address: {}", funding_address_info.address); + Ok(funding_address_info) + } + + /// Retrieve a new on-chain address for a specific address type. + pub fn new_address_for_type(&self, address_type: AddressType) -> Result { + if !*self.is_running.read().unwrap() { + return Err(Error::NotRunning); + } + + let funding_address = self.wallet.get_new_address_for_type(address_type)?; + log_info!( + self.logger, + "Generated new funding address for {:?}: {}", + address_type, + funding_address + ); + Ok(funding_address) + } + + /// Retrieve a new on-chain address with derivation metadata for a specific address type. + pub fn new_address_info_for_type( + &self, address_type: AddressType, + ) -> Result { + if !*self.is_running.read().unwrap() { + return Err(Error::NotRunning); + } + + let funding_address_info = + AddressInfo::from(self.wallet.get_new_address_info_for_type(address_type)?); + log_info!( + self.logger, + "Generated new funding address for {:?}: {}", + address_type, + funding_address_info.address + ); + Ok(funding_address_info) + } + + /// Retrieve a new on-chain address for a specific wallet account. + /// + /// An unloaded derived account returns [`Error::OnchainWalletAccountNotRegistered`]. + pub fn new_address_for_account( + &self, address_type: AddressType, account_index: u32, + ) -> Result { + if !*self.is_running.read().unwrap() { + return Err(Error::NotRunning); + } + + let wallet_account = OnchainWalletAccount { address_type, account_index }; + let funding_address = self.wallet.get_new_address_for_account(wallet_account)?; + log_info!( + self.logger, + "Generated new funding address for {:?}: {}", + wallet_account, + funding_address + ); + Ok(funding_address) + } + + /// Retrieve a new on-chain address with derivation metadata for a specific wallet account. + /// + /// An unloaded derived account returns [`Error::OnchainWalletAccountNotRegistered`]. + pub fn new_address_info_for_account( + &self, address_type: AddressType, account_index: u32, + ) -> Result { + if !*self.is_running.read().unwrap() { + return Err(Error::NotRunning); + } + + let wallet_account = OnchainWalletAccount { address_type, account_index }; + let funding_address_info = + AddressInfo::from(self.wallet.get_new_address_info_for_account(wallet_account)?); + log_info!( + self.logger, + "Generated new funding address for {:?}: {}", + wallet_account, + funding_address_info.address + ); + Ok(funding_address_info) + } + + /// Derive address metadata for `address_type`, `keychain`, and `index` on account `0`. + /// + /// This does not reveal, reserve, or advance any wallet cursor. + pub fn address_info_for_type_at_index( + &self, address_type: AddressType, keychain: KeychainKind, index: u32, + ) -> Result { + if !*self.is_running.read().unwrap() { + return Err(Error::NotRunning); + } + + self.wallet + .get_address_info_for_type_at_index(address_type, keychain, index) + .map(Into::into) + } + + /// Derive address metadata for a wallet account without advancing its cursor. + /// + /// An unloaded derived account returns [`Error::OnchainWalletAccountNotRegistered`]. + pub fn address_info_for_account_at_index( + &self, address_type: AddressType, account_index: u32, keychain: KeychainKind, index: u32, + ) -> Result { + if !*self.is_running.read().unwrap() { + return Err(Error::NotRunning); + } + + let wallet_account = OnchainWalletAccount { address_type, account_index }; + self.wallet + .get_address_info_for_account_at_index(wallet_account, keychain, index) + .map(Into::into) + } + + /// Derive address metadata for a contiguous account-`0` range without advancing any wallet + /// cursor. + /// + /// The returned vector contains `count` addresses starting at `start_index`. Batch requests are + /// capped at 10,000 addresses per call. + pub fn address_infos_for_type( + &self, address_type: AddressType, keychain: KeychainKind, start_index: u32, count: u32, + ) -> Result, Error> { + if !*self.is_running.read().unwrap() { + return Err(Error::NotRunning); + } + + self.wallet + .get_address_infos_for_type(address_type, keychain, start_index, count) + .map(|infos| infos.into_iter().map(Into::into).collect()) + } + + /// Derive address metadata for a contiguous wallet-account range without advancing its cursor. + /// + /// Batch requests are capped at 10,000 addresses per call. + /// An unloaded derived account returns [`Error::OnchainWalletAccountNotRegistered`]. + pub fn address_infos_for_account( + &self, address_type: AddressType, account_index: u32, keychain: KeychainKind, + start_index: u32, count: u32, + ) -> Result, Error> { + if !*self.is_running.read().unwrap() { + return Err(Error::NotRunning); + } + + let wallet_account = OnchainWalletAccount { address_type, account_index }; + self.wallet + .get_address_infos_for_account(wallet_account, keychain, start_index, count) + .map(|infos| infos.into_iter().map(Into::into).collect()) + } + + /// Reveal external receive addresses for account-`0` `address_type` up to and including + /// `index`. + /// + /// After this returns successfully, normal address generation for `address_type` will not return + /// any receive address with an index at or below `index`. + pub fn reveal_receive_addresses_to( + &self, address_type: AddressType, index: u32, + ) -> Result<(), Error> { + if !*self.is_running.read().unwrap() { + return Err(Error::NotRunning); + } + + self.wallet.reveal_receive_addresses_to(address_type, index) + } + + /// Reveal external receive addresses through `index` for a specific wallet account. + /// + /// Apps issuing addresses from an exported account xpub should call this with the highest issued + /// index so wallet sync includes the corresponding scripts. + /// An unloaded derived account returns [`Error::OnchainWalletAccountNotRegistered`]. + pub fn reveal_receive_addresses_to_account( + &self, address_type: AddressType, account_index: u32, index: u32, + ) -> Result<(), Error> { + if !*self.is_running.read().unwrap() { + return Err(Error::NotRunning); + } + + let wallet_account = OnchainWalletAccount { address_type, account_index }; + self.wallet.reveal_receive_addresses_to_account(wallet_account, index) + } + + /// Returns a list of all UTXOs that are safe to spend. + /// + /// This excludes any outputs that are currently being used to fund Lightning channels. + /// + /// **Note:** This does not account for anchor channel reserves. When using these UTXOs + /// for transactions, ensure you maintain sufficient balance for any required reserves. + pub fn list_spendable_outputs(&self) -> Result, Error> { + if !*self.is_running.read().unwrap() { + return Err(Error::NotRunning); + } + + self.wallet + .get_spendable_utxos(&self.channel_manager) + .map(|outputs| outputs.into_iter().map(SpendableUtxo::from).collect()) + } + + /// Select UTXOs using a specific coin selection algorithm. + /// + /// This method allows you to choose which algorithm to use for selecting UTXOs + /// to meet a target amount. The selected UTXOs will be safe to spend (not funding channels). + /// + /// # Arguments + /// + /// * `target_amount_sats` - The target amount in satoshis + /// * `fee_rate` - The fee rate to use (or None to estimate) + /// * `algorithm` - The coin selection algorithm to use + /// * `utxos` - Optional list of UTXO outpoints to select from (or None to use all spendable UTXOs) + pub fn select_utxos_with_algorithm( + &self, target_amount_sats: u64, fee_rate: Option, + algorithm: CoinSelectionAlgorithm, utxos: Option>, + ) -> Result, Error> { + if !*self.is_running.read().unwrap() { + return Err(Error::NotRunning); + } + + // Get available UTXOs, optionally filtering by provided UTXOs + let available_utxos = match utxos { + Some(spendable_utxos) => { + // Get all spendable UTXOs and filter by the provided UTXOs + let wallet_outputs = self.wallet.get_spendable_utxos(&self.channel_manager)?; + let outpoint_set: std::collections::HashSet<_> = + spendable_utxos.iter().map(|u| u.outpoint).collect(); + wallet_outputs + .into_iter() + .filter(|output| outpoint_set.contains(&output.outpoint)) + .collect() + }, + None => self.wallet.get_spendable_utxos(&self.channel_manager)?, + }; + + if available_utxos.is_empty() { + return Err(Error::InsufficientFunds); + } + + // Use the set fee_rate or default to fee estimation + let confirmation_target = ConfirmationTarget::OnchainPayment; + let fee_rate = maybe_map_fee_rate_opt!(fee_rate) + .unwrap_or_else(|| self.wallet.estimate_fee_rate(confirmation_target)); + + // Get a drain script (change address) + let drain_script = self.wallet.get_drain_script()?; + + // Apply coin selection + let selected_outpoints = self.wallet.select_utxos_with_algorithm( + target_amount_sats, + available_utxos.clone(), + fee_rate, + algorithm, + &drain_script, + &self.channel_manager, + )?; + + // Convert selected outpoints back to SpendableUtxo by direct filtering + let selected_utxos: Vec = available_utxos + .into_iter() + .filter(|utxo| selected_outpoints.contains(&utxo.outpoint)) + .map(SpendableUtxo::from) + .collect(); + + Ok(selected_utxos) + } + + /// Calculates the total fee for an on-chain payment without sending it. + /// + /// This method simulates creating a transaction to the given address for the specified amount + /// and returns the total fee that would be paid. This is useful for displaying fee estimates + /// to users before they confirm a transaction. + /// + /// The calculation respects any on-chain reserve requirements and validates that sufficient + /// funds are available, just like [`send_to_address`]. + /// + /// **Note on maximum amounts:** For calculating the fee when sending the entire spendable + /// balance, prefer [`calculate_send_all_fee`] which is purpose-built for that use case. + /// This method includes a best-effort fallback for near-max amounts, but it may not + /// trigger in all cases depending on the underlying wallet error. + /// + /// [`calculate_send_all_fee`]: Self::calculate_send_all_fee + /// + /// # Arguments + /// + /// * `address` - The Bitcoin address to send to + /// * `amount_sats` - The amount to send in satoshis (or total balance for max send) + /// * `fee_rate` - Optional fee rate to use (if None, will estimate based on current network conditions) + /// * `utxos_to_spend` - Optional list of specific UTXOs to use for the transaction + /// + /// # Returns + /// + /// The total fee in satoshis that would be paid for this transaction. + /// + /// # Errors + /// + /// * [`Error::NotRunning`] - If the node is not running + /// * [`Error::InvalidAddress`] - If the address is invalid + /// * [`Error::InsufficientFunds`] - If there are insufficient funds for the payment + /// * [`Error::WalletOperationFailed`] - If fee calculation fails + /// + /// [`send_to_address`]: Self::send_to_address + /// [`BalanceDetails::total_onchain_balance_sats`]: crate::balance::BalanceDetails::total_onchain_balance_sats + pub fn calculate_total_fee( + &self, address: &bitcoin::Address, amount_sats: u64, fee_rate: Option, + utxos_to_spend: Option>, + ) -> Result { + if !*self.is_running.read().unwrap() { + return Err(Error::NotRunning); + } + + let cur_anchor_reserve_sats = + crate::total_anchor_channels_reserve_sats(&self.channel_manager, &self.config); + + // Get current balances + let (_total_balance, spendable_balance) = + self.wallet.get_balances(cur_anchor_reserve_sats).unwrap_or((0, 0)); + + // First try with the exact amount + let outpoints = utxos_to_spend.map(|utxos| utxos.into_iter().map(|u| u.outpoint).collect()); + let fee_rate_opt = maybe_map_fee_rate_opt!(fee_rate); + + // Try calculating with exact amount first + let send_amount = + OnchainSendAmount::ExactRetainingReserve { amount_sats, cur_anchor_reserve_sats }; + let result = self.wallet.calculate_transaction_fee( + address, + send_amount, + fee_rate_opt, + outpoints.clone(), + &self.channel_manager, + ); + + // If we get InsufficientFunds and the amount is within the spendable balance, + // try calculating as if sending all available funds + if matches!(result, Err(Error::InsufficientFunds)) && amount_sats <= spendable_balance { + // Try with AllRetainingReserve to calculate the fee for sending all + let all_retaining = OnchainSendAmount::AllRetainingReserve { cur_anchor_reserve_sats }; + if let Ok(fee) = self.wallet.calculate_transaction_fee( + address, + all_retaining, + fee_rate_opt, + outpoints.clone(), + &self.channel_manager, + ) { + // Return the fee for sending all available funds + return Ok(fee); + } + } + + result + } + + /// Calculates the total fee for sending all available on-chain funds without + /// actually broadcasting. + /// + /// This is the fee-calculation counterpart of [`send_all_to_address`]. Use it to + /// show the user how much a drain / send-all transaction would cost before they + /// confirm. + /// + /// When `retain_reserves` is `true`, the calculation accounts for the on-chain anchor + /// channel reserve (see [`BalanceDetails::total_anchor_channels_reserve_sats`]), sending only + /// the spendable portion. When `false`, the calculation covers draining the entire wallet + /// balance, which may be dangerous if you have open anchor channels whose counterparty you + /// don't trust to spend the anchor output after closure. + /// + /// # Arguments + /// + /// * `address` - The destination Bitcoin address + /// * `retain_reserves` - If `true`, retains the anchor channel reserve; if `false`, drains everything + /// * `fee_rate` - Optional fee rate to use (if `None`, will estimate based on current network conditions) + /// + /// # Returns + /// + /// The total fee in satoshis that would be paid for this transaction. + /// + /// # Errors + /// + /// * [`Error::NotRunning`] - If the node is not running + /// * [`Error::InvalidAddress`] - If the address is invalid + /// * [`Error::InsufficientFunds`] - If there are insufficient funds + /// * [`Error::WalletOperationFailed`] - If fee calculation fails + /// + /// [`send_all_to_address`]: Self::send_all_to_address + /// [`BalanceDetails::total_anchor_channels_reserve_sats`]: crate::BalanceDetails::total_anchor_channels_reserve_sats + pub fn calculate_send_all_fee( + &self, address: &bitcoin::Address, retain_reserves: bool, fee_rate: Option, + ) -> Result { + if !*self.is_running.read().unwrap() { + return Err(Error::NotRunning); + } + + let send_amount = if retain_reserves { + let cur_anchor_reserve_sats = + crate::total_anchor_channels_reserve_sats(&self.channel_manager, &self.config); + OnchainSendAmount::AllRetainingReserve { cur_anchor_reserve_sats } + } else { + OnchainSendAmount::AllDrainingReserve + }; + + let fee_rate_opt = maybe_map_fee_rate_opt!(fee_rate); + self.wallet.calculate_transaction_fee( + address, + send_amount, + fee_rate_opt, + None, + &self.channel_manager, + ) + } + /// Send an on-chain payment to the given address. /// /// This will respect any on-chain reserve we need to keep, i.e., won't allow to cut into @@ -74,6 +541,7 @@ impl OnchainPayment { /// [`BalanceDetails::total_anchor_channels_reserve_sats`]: crate::BalanceDetails::total_anchor_channels_reserve_sats pub fn send_to_address( &self, address: &bitcoin::Address, amount_sats: u64, fee_rate: Option, + utxos_to_spend: Option>, ) -> Result { if !*self.is_running.read().unwrap() { return Err(Error::NotRunning); @@ -83,8 +551,15 @@ impl OnchainPayment { crate::total_anchor_channels_reserve_sats(&self.channel_manager, &self.config); let send_amount = OnchainSendAmount::ExactRetainingReserve { amount_sats, cur_anchor_reserve_sats }; + let outpoints = utxos_to_spend.map(|utxos| utxos.into_iter().map(|u| u.outpoint).collect()); let fee_rate_opt = maybe_map_fee_rate_opt!(fee_rate); - self.wallet.send_to_address(address, send_amount, fee_rate_opt) + self.wallet.send_to_address( + address, + send_amount, + fee_rate_opt, + outpoints, + &self.channel_manager, + ) } /// Send an on-chain payment to the given address, draining the available funds. @@ -92,6 +567,8 @@ impl OnchainPayment { /// This is useful if you have closed all channels and want to migrate funds to another /// on-chain wallet. /// + /// To preview the fee before broadcasting, use [`calculate_send_all_fee`]. + /// /// Please note that if `retain_reserves` is set to `false` this will **not** retain any on-chain reserves, which might be potentially /// dangerous if you have open Anchor channels for which you can't trust the counterparty to /// spend the Anchor output after channel closure. If `retain_reserves` is set to `true`, this @@ -101,6 +578,7 @@ impl OnchainPayment { /// If `fee_rate` is set it will be used on the resulting transaction. Otherwise a reasonable /// we'll retrieve an estimate from the configured chain source. /// + /// [`calculate_send_all_fee`]: Self::calculate_send_all_fee /// [`BalanceDetails::spendable_onchain_balance_sats`]: crate::balance::BalanceDetails::spendable_onchain_balance_sats pub fn send_all_to_address( &self, address: &bitcoin::Address, retain_reserves: bool, fee_rate: Option, @@ -118,6 +596,132 @@ impl OnchainPayment { }; let fee_rate_opt = maybe_map_fee_rate_opt!(fee_rate); - self.wallet.send_to_address(address, send_amount, fee_rate_opt) + self.wallet.send_to_address(address, send_amount, fee_rate_opt, None, &self.channel_manager) + } + + /// Bumps the fee of an existing transaction using Replace-By-Fee (RBF). + /// + /// This allows a previously sent transaction to be replaced with a new version + /// that pays a higher fee. The original transaction must have been created with + /// RBF enabled (which is the default for transactions created by LDK). + /// + /// **Note:** This cannot be used on funding transactions as doing so would invalidate the channel. + /// + /// # Arguments + /// + /// * `txid` - The transaction ID of the transaction to be replaced + /// * `fee_rate` - The new fee rate to use (must be higher than the original fee rate) + /// + /// # Returns + /// + /// The transaction ID of the new transaction if successful. + /// + /// # Errors + /// + /// * [`Error::NotRunning`] - If the node is not running + /// * [`Error::TransactionNotFound`] - If the transaction can't be found in the wallet + /// * [`Error::TransactionAlreadyConfirmed`] - If the transaction is already confirmed + /// * [`Error::CannotRbfFundingTransaction`] - If the transaction is a channel funding transaction + /// * [`Error::InvalidFeeRate`] - If the new fee rate is not higher than the original + /// * [`Error::OnchainTxCreationFailed`] - If the new transaction couldn't be created + pub fn bump_fee_by_rbf(&self, txid: &Txid, fee_rate: FeeRate) -> Result { + if !*self.is_running.read().unwrap() { + return Err(Error::NotRunning); + } + + // Pass through to the wallet implementation + #[cfg(not(feature = "uniffi"))] + let fee_rate_param = fee_rate; + #[cfg(feature = "uniffi")] + let fee_rate_param = *fee_rate; + + self.wallet.bump_fee_by_rbf(txid, fee_rate_param, &self.channel_manager) + } + + /// Accelerates confirmation of a transaction using Child-Pays-For-Parent (CPFP). + /// + /// This creates a new transaction (child) that spends an output from the + /// transaction to be accelerated (parent), with a high enough fee to pay for both. + /// + /// # Arguments + /// + /// * `txid` - The transaction ID of the transaction to be accelerated + /// * `fee_rate` - The fee rate to use for the child transaction (or None to calculate automatically) + /// * `destination_address` - Optional address to send the funds to (if None, funds are sent to an internal address) + /// + /// # Returns + /// + /// The transaction ID of the child transaction if successful. + /// + /// # Errors + /// + /// * [`Error::NotRunning`] - If the node is not running + /// * [`Error::TransactionNotFound`] - If the transaction can't be found + /// * [`Error::TransactionAlreadyConfirmed`] - If the transaction is already confirmed + /// * [`Error::NoSpendableOutputs`] - If the transaction has no spendable outputs + /// * [`Error::OnchainTxCreationFailed`] - If the child transaction couldn't be created + pub fn accelerate_by_cpfp( + &self, txid: &Txid, fee_rate: Option, destination_address: Option

, + ) -> Result { + if !*self.is_running.read().unwrap() { + return Err(Error::NotRunning); + } + + // Calculate fee rate if not provided + #[cfg(not(feature = "uniffi"))] + let fee_rate_param = match fee_rate { + Some(rate) => rate, + None => self.wallet.calculate_cpfp_fee_rate(txid, true)?, + }; + + #[cfg(feature = "uniffi")] + let fee_rate_param = match fee_rate { + Some(rate) => *rate, + None => self.wallet.calculate_cpfp_fee_rate(txid, true)?, + }; + + // Pass through to the wallet implementation + self.wallet.accelerate_by_cpfp(txid, fee_rate_param, destination_address) + } + + /// Calculates an appropriate fee rate for a CPFP transaction to ensure + /// the parent transaction gets confirmed within the target number of blocks. + /// + /// This method analyzes the parent transaction's current fee rate and calculates + /// how much the child transaction needs to pay to bring the combined package + /// fee rate up to the target level. + /// + /// # Arguments + /// + /// * `parent_txid` - The transaction ID of the parent transaction to accelerate + /// * `urgent` - If true, uses a more aggressive fee rate for faster confirmation + /// + /// # Returns + /// + /// The fee rate that should be used for the child transaction. + /// + /// # Errors + /// + /// * [`Error::NotRunning`] - If the node is not running + /// * [`Error::TransactionNotFound`] - If the parent transaction can't be found + /// * [`Error::TransactionAlreadyConfirmed`] - If the parent transaction is already confirmed + /// * [`Error::WalletOperationFailed`] - If fee calculation fails + pub fn calculate_cpfp_fee_rate( + &self, parent_txid: &Txid, urgent: bool, + ) -> Result { + if !*self.is_running.read().unwrap() { + return Err(Error::NotRunning); + } + + let fee_rate = self.wallet.calculate_cpfp_fee_rate(parent_txid, urgent)?; + + #[cfg(not(feature = "uniffi"))] + { + Ok(fee_rate) + } + #[cfg(feature = "uniffi")] + { + Ok(Arc::new(fee_rate)) + } } } diff --git a/src/payment/spontaneous.rs b/src/payment/spontaneous.rs index 6c074f308f..a1a5f7438c 100644 --- a/src/payment/spontaneous.rs +++ b/src/payment/spontaneous.rs @@ -20,6 +20,7 @@ use crate::error::Error; use crate::logger::{log_error, log_info, LdkLogger, Logger}; use crate::payment::store::{PaymentDetails, PaymentDirection, PaymentKind, PaymentStatus}; use crate::types::{ChannelManager, CustomTlvRecord, KeysManager, PaymentStore}; +use crate::ProbeHandle; // The default `final_cltv_expiry_delta` we apply when not set. const LDK_DEFAULT_FINAL_CLTV_EXPIRY_DELTA: u32 = 144; @@ -191,10 +192,13 @@ impl SpontaneousPayment { /// Sends payment probes over all paths of a route that would be used to pay the given /// amount to the given `node_id`. /// - /// See [`Bolt11Payment::send_probes`] for more information. + /// See [`Bolt11Payment::send_probes`] for semantics and how returned [`ProbeHandle`] values + /// correlate with [`crate::Event::ProbeSuccessful`] / [`crate::Event::ProbeFailed`]. /// - /// [`Bolt11Payment::send_probes`]: crate::payment::Bolt11Payment - pub fn send_probes(&self, amount_msat: u64, node_id: PublicKey) -> Result<(), Error> { + /// [`Bolt11Payment::send_probes`]: crate::payment::Bolt11Payment::send_probes + pub fn send_probes( + &self, amount_msat: u64, node_id: PublicKey, + ) -> Result, Error> { if !*self.is_running.read().unwrap() { return Err(Error::NotRunning); } @@ -208,11 +212,15 @@ impl SpontaneousPayment { LDK_DEFAULT_FINAL_CLTV_EXPIRY_DELTA, liquidity_limit_multiplier, ) + .map(|pairs| { + pairs + .into_iter() + .map(|(payment_hash, payment_id)| ProbeHandle { payment_hash, payment_id }) + .collect() + }) .map_err(|e| { log_error!(self.logger, "Failed to send payment probes: {:?}", e); Error::ProbeSendingFailed - })?; - - Ok(()) + }) } } diff --git a/src/payment/store.rs b/src/payment/store.rs index 184de2ea97..99ab21dd0f 100644 --- a/src/payment/store.rs +++ b/src/payment/store.rs @@ -136,9 +136,11 @@ impl Readable for PaymentDetails { secret, counterparty_skimmed_fee_msat, lsp_fee_limits, + description: None, + bolt11: None, } } else { - PaymentKind::Bolt11 { hash, preimage, secret } + PaymentKind::Bolt11 { hash, preimage, secret, description: None, bolt11: None } } } else { PaymentKind::Spontaneous { hash, preimage } @@ -291,6 +293,16 @@ impl StorableObject for PaymentDetails { } } + // Direction can change for onchain payments as wallets sync; never downgrade from + // Outbound since a pure receive always has sent=0 and can never compute as Outbound. + if let Some(direction) = update.direction { + let downgrade = self.direction == PaymentDirection::Outbound + && direction == PaymentDirection::Inbound; + if !downgrade { + update_if_necessary!(self.direction, direction); + } + } + if updated { self.latest_update_timestamp = SystemTime::now() .duration_since(UNIX_EPOCH) @@ -362,6 +374,10 @@ pub enum PaymentKind { preimage: Option, /// The secret used by the payment. secret: Option, + /// The description from the BOLT 11 invoice. + description: Option, + /// The BOLT 11 invoice string. + bolt11: Option, }, /// A [BOLT 11] payment intended to open an [bLIP-52 / LSPS 2] just-in-time channel. /// @@ -389,6 +405,10 @@ pub enum PaymentKind { /// /// [`LdkChannelConfig::accept_underpaying_htlcs`]: lightning::util::config::ChannelConfig::accept_underpaying_htlcs lsp_fee_limits: LSPFeeLimits, + /// The description from the BOLT 11 invoice. + description: Option, + /// The BOLT 11 invoice string. + bolt11: Option, }, /// A [BOLT 12] 'offer' payment, i.e., a payment for an [`Offer`]. /// @@ -454,6 +474,8 @@ impl_writeable_tlv_based_enum!(PaymentKind, (0, hash, required), (2, preimage, option), (4, secret, option), + (6, description, option), + (8, bolt11, option), }, (4, Bolt11Jit) => { (0, hash, required), @@ -461,6 +483,8 @@ impl_writeable_tlv_based_enum!(PaymentKind, (2, preimage, option), (4, secret, option), (6, lsp_fee_limits, required), + (8, description, option), + (10, bolt11, option), }, (6, Bolt12Offer) => { (0, hash, option), @@ -605,6 +629,7 @@ impl StorableObjectUpdate for PaymentDetailsUpdate { #[cfg(test)] mod tests { + use bitcoin::hashes::Hash; use bitcoin::io::Cursor; use lightning::util::ser::Readable; @@ -669,7 +694,13 @@ mod tests { ); match bolt11_decoded.kind { - PaymentKind::Bolt11 { hash: h, preimage: p, secret: s } => { + PaymentKind::Bolt11 { + hash: h, + preimage: p, + secret: s, + description: _, + bolt11: _, + } => { assert_eq!(hash, h); assert_eq!(preimage, p); assert_eq!(secret, s); @@ -718,6 +749,8 @@ mod tests { secret: s, counterparty_skimmed_fee_msat: c, lsp_fee_limits: l, + description: _, + bolt11: _, } => { assert_eq!(hash, h); assert_eq!(preimage, p); @@ -768,4 +801,65 @@ mod tests { } } } + + #[test] + fn onchain_direction_never_downgrades_from_outbound() { + // A change-only wallet syncing before an input-holding wallet can temporarily + // make received > partial-sent, producing a spurious Inbound update. The guard + // must reject it and leave direction as Outbound throughout. + let txid = Txid::from_slice(&[1u8; 32]).unwrap(); + let id = PaymentId(txid.to_byte_array()); + let kind = PaymentKind::Onchain { txid, status: ConfirmationStatus::Unconfirmed }; + + // Primary wallet has inputs, so initial direction is Outbound. + let mut payment = PaymentDetails::new( + id, + kind.clone(), + Some(5_000 * 1000), + Some(100 * 1000), + PaymentDirection::Outbound, + PaymentStatus::Pending, + ); + assert_eq!(payment.direction, PaymentDirection::Outbound); + + // Change-only secondary syncs: partial view would produce Inbound; guard blocks it. + let mut update = PaymentDetailsUpdate::new(id); + update.direction = Some(PaymentDirection::Inbound); + update.amount_msat = Some(Some(8_000 * 1000)); + payment.update(&update); + assert_eq!(payment.direction, PaymentDirection::Outbound); + + // Input secondary syncs: full picture, Outbound is confirmed. + let mut update = PaymentDetailsUpdate::new(id); + update.direction = Some(PaymentDirection::Outbound); + update.amount_msat = Some(Some(1_000 * 1000)); + payment.update(&update); + assert_eq!(payment.direction, PaymentDirection::Outbound); + } + + #[test] + fn onchain_direction_corrects_inbound_to_outbound() { + // Primary wallet sees only the change output initially (Inbound); once a + // secondary wallet syncs and reveals the spent inputs, direction must update. + let txid = Txid::from_slice(&[2u8; 32]).unwrap(); + let id = PaymentId(txid.to_byte_array()); + let kind = PaymentKind::Onchain { txid, status: ConfirmationStatus::Unconfirmed }; + + let mut payment = PaymentDetails::new( + id, + kind.clone(), + Some(9_000 * 1000), + Some(0), + PaymentDirection::Inbound, + PaymentStatus::Pending, + ); + assert_eq!(payment.direction, PaymentDirection::Inbound); + + // Secondary wallet syncs with full view; direction must be corrected. + let mut update = PaymentDetailsUpdate::new(id); + update.direction = Some(PaymentDirection::Outbound); + update.amount_msat = Some(Some(1_000 * 1000)); + payment.update(&update); + assert_eq!(payment.direction, PaymentDirection::Outbound); + } } diff --git a/src/payment/unified_qr.rs b/src/payment/unified_qr.rs index 6ebf25563a..fcfb4388cc 100644 --- a/src/payment/unified_qr.rs +++ b/src/payment/unified_qr.rs @@ -179,6 +179,7 @@ impl UnifiedQrPayment { &uri_network_checked.address, amount.to_sat(), None, + None, )?; Ok(QrPaymentResult::Onchain { txid }) diff --git a/src/peer_store.rs b/src/peer_store.rs index 59cd3d94f0..9d9771681e 100644 --- a/src/peer_store.rs +++ b/src/peer_store.rs @@ -5,21 +5,22 @@ // http://opensource.org/licenses/MIT>, at your option. You may not use this file except in // accordance with one or both of these licenses. -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::ops::Deref; use std::sync::{Arc, RwLock}; use bitcoin::secp256k1::PublicKey; use lightning::impl_writeable_tlv_based; -use lightning::util::persist::KVStoreSync; +use lightning::routing::gossip::NodeId; +use lightning::util::persist::KVStore; use lightning::util::ser::{Readable, ReadableArgs, Writeable, Writer}; use crate::io::{ PEER_INFO_PERSISTENCE_KEY, PEER_INFO_PERSISTENCE_PRIMARY_NAMESPACE, PEER_INFO_PERSISTENCE_SECONDARY_NAMESPACE, }; -use crate::logger::{log_error, LdkLogger}; -use crate::types::DynStore; +use crate::logger::{log_error, log_info, LdkLogger}; +use crate::types::{DynStore, Graph}; use crate::{Error, SocketAddress}; pub struct PeerStore @@ -27,6 +28,7 @@ where L::Target: LdkLogger, { peers: RwLock>, + mutation_lock: tokio::sync::Mutex<()>, kv_store: Arc, logger: L, } @@ -37,44 +39,90 @@ where { pub(crate) fn new(kv_store: Arc, logger: L) -> Self { let peers = RwLock::new(HashMap::new()); - Self { peers, kv_store, logger } + let mutation_lock = tokio::sync::Mutex::new(()); + Self { peers, mutation_lock, kv_store, logger } } - pub(crate) fn add_peer(&self, peer_info: PeerInfo) -> Result<(), Error> { - let mut locked_peers = self.peers.write().unwrap(); + pub(crate) async fn add_peer(&self, peer_info: PeerInfo) -> Result<(), Error> { + let _guard = self.mutation_lock.lock().await; + let node_id = peer_info.node_id; + let (previous_peer, data) = { + let mut locked_peers = self.peers.write().expect("lock"); + if let Some(existing) = locked_peers.get(&node_id) { + if existing.address == peer_info.address { + return Ok(()); + } + log_info!( + self.logger, + "Updating socket address for peer {}: {} -> {}", + node_id, + existing.address, + peer_info.address + ); + } - if locked_peers.contains_key(&peer_info.node_id) { - return Ok(()); - } + let previous_peer = locked_peers.insert(node_id, peer_info); + let data = PeerStoreSerWrapper(&locked_peers).encode(); + (previous_peer, data) + }; - locked_peers.insert(peer_info.node_id, peer_info); - self.persist_peers(&*locked_peers) + if let Err(e) = self.persist_peers(data).await { + let mut locked_peers = self.peers.write().expect("lock"); + if let Some(previous_peer) = previous_peer { + locked_peers.insert(node_id, previous_peer); + } else { + locked_peers.remove(&node_id); + } + return Err(e); + } + Ok(()) } - pub(crate) fn remove_peer(&self, node_id: &PublicKey) -> Result<(), Error> { - let mut locked_peers = self.peers.write().unwrap(); + pub(crate) async fn remove_peer(&self, node_id: &PublicKey) -> Result<(), Error> { + let _guard = self.mutation_lock.lock().await; + let (removed_peer, data) = { + let mut locked_peers = self.peers.write().expect("lock"); + let removed_peer = locked_peers.remove(node_id); + let data = PeerStoreSerWrapper(&locked_peers).encode(); + (removed_peer, data) + }; - locked_peers.remove(node_id); - self.persist_peers(&*locked_peers) + if let Err(e) = self.persist_peers(data).await { + if let Some(peer_info) = removed_peer { + self.peers.write().expect("lock").insert(*node_id, peer_info); + } + return Err(e); + } + Ok(()) } + /// Returns the current in-memory peer set. + /// + /// The async mutation lock serializes `add_peer` and `remove_peer`, but this synchronous + /// reader cannot wait on it. Until peer-store reads are async, callers may observe peer + /// changes that are still being persisted. pub(crate) fn list_peers(&self) -> Vec { - self.peers.read().unwrap().values().cloned().collect() + self.peers.read().expect("lock").values().cloned().collect() } + /// Returns the current in-memory peer info for `node_id`. + /// + /// The async mutation lock serializes `add_peer` and `remove_peer`, but this synchronous + /// reader cannot wait on it. Until peer-store reads are async, callers may observe peer + /// changes that are still being persisted. pub(crate) fn get_peer(&self, node_id: &PublicKey) -> Option { - self.peers.read().unwrap().get(node_id).cloned() + self.peers.read().expect("lock").get(node_id).cloned() } - fn persist_peers(&self, locked_peers: &HashMap) -> Result<(), Error> { - let data = PeerStoreSerWrapper(&*locked_peers).encode(); - KVStoreSync::write( + async fn persist_peers(&self, data: Vec) -> Result<(), Error> { + KVStore::write( &*self.kv_store, PEER_INFO_PERSISTENCE_PRIMARY_NAMESPACE, PEER_INFO_PERSISTENCE_SECONDARY_NAMESPACE, PEER_INFO_PERSISTENCE_KEY, data, ) + .await .map_err(|e| { log_error!( self.logger, @@ -101,7 +149,8 @@ where let (kv_store, logger) = args; let read_peers: PeerStoreDeserWrapper = Readable::read(reader)?; let peers: RwLock> = RwLock::new(read_peers.0); - Ok(Self { peers, kv_store, logger }) + let mutation_lock = tokio::sync::Mutex::new(()); + Ok(Self { peers, mutation_lock, kv_store, logger }) } } @@ -147,18 +196,96 @@ impl_writeable_tlv_based!(PeerInfo, { (2, address, required), }); +pub(crate) async fn persist_missing_channel_peers( + counterparty_node_ids: I, network_graph: &Graph, peer_store: &PeerStore, logger: L, +) where + L: Deref, + L::Target: LdkLogger, + I: IntoIterator, +{ + persist_missing_channel_peers_excluding( + counterparty_node_ids, + network_graph, + peer_store, + &HashSet::new(), + logger, + ) + .await +} + +pub(crate) async fn persist_missing_channel_peers_excluding( + counterparty_node_ids: I, network_graph: &Graph, peer_store: &PeerStore, + excluded_node_ids: &HashSet, logger: L, +) where + L: Deref, + L::Target: LdkLogger, + I: IntoIterator, +{ + let missing_peers = { + let graph = network_graph.read_only(); + let mut seen = HashSet::new(); + counterparty_node_ids + .into_iter() + .filter_map(|counterparty_node_id| { + if !seen.insert(counterparty_node_id) + || excluded_node_ids.contains(&counterparty_node_id) + || peer_store.get_peer(&counterparty_node_id).is_some() + { + return None; + } + + graph + .nodes() + .get(&NodeId::from_pubkey(&counterparty_node_id)) + .and_then(|node_info| node_info.announcement_info.as_ref()) + .and_then(|announcement_info| announcement_info.addresses().first()) + .cloned() + .map(|address| PeerInfo { node_id: counterparty_node_id, address }) + }) + .collect::>() + }; + + for peer_info in missing_peers { + let node_id = peer_info.node_id; + if peer_store.get_peer(&node_id).is_some() { + continue; + } + + match peer_store.add_peer(peer_info).await { + Ok(()) => { + log_info!(logger, "Persisted peer {} from channel counterparty", node_id) + }, + Err(e) => { + log_error!(logger, "Failed to persist peer {}: {}", node_id, e) + }, + } + } +} + #[cfg(test)] mod tests { + use std::collections::HashMap; + use std::future::Future; + use std::pin::Pin; use std::str::FromStr; - use std::sync::Arc; + use std::sync::atomic::{AtomicBool, Ordering}; + use std::sync::{Arc, Mutex}; + use std::time::Duration; + use bitcoin::Network; + use lightning::io; + use lightning::ln::msgs::UnsignedNodeAnnouncement; + use lightning::routing::gossip::{NodeAlias, NodeId}; + use lightning::types::features::{ChannelFeatures, NodeFeatures}; + use lightning::util::persist::{KVStore, KVStoreSync}; use lightning::util::test_utils::TestLogger; use super::*; use crate::io::test_utils::InMemoryStore; + use crate::logger::Logger; - #[test] - fn peer_info_persistence() { + #[tokio::test] + async fn peer_info_persistence() { let store: Arc = Arc::new(InMemoryStore::new()); let logger = Arc::new(TestLogger::new()); let peer_store = PeerStore::new(Arc::clone(&store), Arc::clone(&logger)); @@ -169,22 +296,24 @@ mod tests { .unwrap(); let address = SocketAddress::from_str("127.0.0.1:9738").unwrap(); let expected_peer_info = PeerInfo { node_id, address }; - assert!(KVStoreSync::read( + assert!(KVStore::read( &*store, PEER_INFO_PERSISTENCE_PRIMARY_NAMESPACE, PEER_INFO_PERSISTENCE_SECONDARY_NAMESPACE, PEER_INFO_PERSISTENCE_KEY, ) + .await .is_err()); - peer_store.add_peer(expected_peer_info.clone()).unwrap(); + peer_store.add_peer(expected_peer_info.clone()).await.unwrap(); // Check we can read back what we persisted. - let persisted_bytes = KVStoreSync::read( + let persisted_bytes = KVStore::read( &*store, PEER_INFO_PERSISTENCE_PRIMARY_NAMESPACE, PEER_INFO_PERSISTENCE_SECONDARY_NAMESPACE, PEER_INFO_PERSISTENCE_KEY, ) + .await .unwrap(); let deser_peer_store = PeerStore::read(&mut &persisted_bytes[..], (Arc::clone(&store), logger)).unwrap(); @@ -194,4 +323,583 @@ mod tests { assert_eq!(peers[0], expected_peer_info); assert_eq!(deser_peer_store.get_peer(&node_id), Some(expected_peer_info)); } + + #[tokio::test] + async fn peer_address_updated_on_readd() { + let store: Arc = Arc::new(InMemoryStore::new()); + let logger = Arc::new(TestLogger::new()); + let peer_store = PeerStore::new(Arc::clone(&store), Arc::clone(&logger)); + + let node_id = PublicKey::from_str( + "0276607124ebe6a6c9338517b6f485825b27c2dcc0b9fc2aa6a4c0df91194e5993", + ) + .unwrap(); + let old_address = SocketAddress::from_str("34.65.186.40:9735").unwrap(); + let new_address = SocketAddress::from_str("34.65.153.174:9735").unwrap(); + + peer_store.add_peer(PeerInfo { node_id, address: old_address.clone() }).await.unwrap(); + assert_eq!(peer_store.get_peer(&node_id).unwrap().address, old_address); + + peer_store.add_peer(PeerInfo { node_id, address: new_address.clone() }).await.unwrap(); + assert_eq!(peer_store.get_peer(&node_id).unwrap().address, new_address); + + assert_eq!(peer_store.list_peers().len(), 1); + + let persisted_bytes = KVStore::read( + &*store, + PEER_INFO_PERSISTENCE_PRIMARY_NAMESPACE, + PEER_INFO_PERSISTENCE_SECONDARY_NAMESPACE, + PEER_INFO_PERSISTENCE_KEY, + ) + .await + .unwrap(); + let deser_peer_store = + PeerStore::read(&mut &persisted_bytes[..], (Arc::clone(&store), logger)).unwrap(); + assert_eq!(deser_peer_store.get_peer(&node_id).unwrap().address, new_address); + } + + #[tokio::test] + async fn peer_same_address_skips_persist() { + let store: Arc = Arc::new(InMemoryStore::new()); + let logger = Arc::new(TestLogger::new()); + let peer_store = PeerStore::new(Arc::clone(&store), Arc::clone(&logger)); + + let node_id = PublicKey::from_str( + "0276607124ebe6a6c9338517b6f485825b27c2dcc0b9fc2aa6a4c0df91194e5993", + ) + .unwrap(); + let address = SocketAddress::from_str("127.0.0.1:9738").unwrap(); + + peer_store.add_peer(PeerInfo { node_id, address: address.clone() }).await.unwrap(); + + peer_store.add_peer(PeerInfo { node_id, address }).await.unwrap(); + assert_eq!(peer_store.list_peers().len(), 1); + } + + #[tokio::test] + async fn peer_add_persistence_failure_leaves_peer_retryable() { + let store: Arc = Arc::new(FailableWriteStore::new(true)); + let logger = Arc::new(TestLogger::new()); + let peer_store = PeerStore::new(Arc::clone(&store), Arc::clone(&logger)); + + let node_id = PublicKey::from_str( + "0276607124ebe6a6c9338517b6f485825b27c2dcc0b9fc2aa6a4c0df91194e5993", + ) + .unwrap(); + let address = SocketAddress::from_str("127.0.0.1:9738").unwrap(); + let peer_info = PeerInfo { node_id, address }; + + assert!(matches!( + peer_store.add_peer(peer_info.clone()).await, + Err(Error::PersistenceFailed) + )); + assert!(peer_store.get_peer(&node_id).is_none()); + + peer_store.add_peer(peer_info.clone()).await.unwrap(); + assert_eq!(peer_store.get_peer(&node_id), Some(peer_info)); + } + + #[tokio::test] + async fn peer_address_update_persistence_failure_leaves_update_retryable() { + let store = Arc::new(FailableWriteStore::new(false)); + let dyn_store: Arc = store.clone(); + let logger = Arc::new(TestLogger::new()); + let peer_store = PeerStore::new(dyn_store, Arc::clone(&logger)); + + let node_id = PublicKey::from_str( + "0276607124ebe6a6c9338517b6f485825b27c2dcc0b9fc2aa6a4c0df91194e5993", + ) + .unwrap(); + let old_address = SocketAddress::from_str("34.65.186.40:9735").unwrap(); + let new_address = SocketAddress::from_str("34.65.153.174:9735").unwrap(); + let old_peer_info = PeerInfo { node_id, address: old_address }; + let new_peer_info = PeerInfo { node_id, address: new_address }; + + peer_store.add_peer(old_peer_info.clone()).await.unwrap(); + store.fail_next_write(); + assert!(matches!( + peer_store.add_peer(new_peer_info.clone()).await, + Err(Error::PersistenceFailed) + )); + assert_eq!(peer_store.get_peer(&node_id), Some(old_peer_info)); + + peer_store.add_peer(new_peer_info.clone()).await.unwrap(); + assert_eq!(peer_store.get_peer(&node_id), Some(new_peer_info)); + } + + #[tokio::test] + async fn peer_remove_persistence_failure_leaves_removal_retryable() { + let store = Arc::new(FailableWriteStore::new(false)); + let dyn_store: Arc = store.clone(); + let logger = Arc::new(TestLogger::new()); + let peer_store = PeerStore::new(dyn_store, Arc::clone(&logger)); + + let node_id = PublicKey::from_str( + "0276607124ebe6a6c9338517b6f485825b27c2dcc0b9fc2aa6a4c0df91194e5993", + ) + .unwrap(); + let address = SocketAddress::from_str("127.0.0.1:9738").unwrap(); + let peer_info = PeerInfo { node_id, address }; + + peer_store.add_peer(peer_info.clone()).await.unwrap(); + store.fail_next_write(); + assert!(matches!(peer_store.remove_peer(&node_id).await, Err(Error::PersistenceFailed))); + assert_eq!(peer_store.get_peer(&node_id), Some(peer_info)); + + peer_store.remove_peer(&node_id).await.unwrap(); + assert!(peer_store.get_peer(&node_id).is_none()); + } + + #[tokio::test] + async fn peer_reads_continue_while_async_persistence_is_pending() { + let store = Arc::new(BlockingWriteStore::new()); + let dyn_store: Arc = store.clone(); + let logger = Arc::new(TestLogger::new()); + let peer_store = Arc::new(PeerStore::new(dyn_store, Arc::clone(&logger))); + + let first_node_id = PublicKey::from_str( + "0276607124ebe6a6c9338517b6f485825b27c2dcc0b9fc2aa6a4c0df91194e5993", + ) + .unwrap(); + let second_node_id = PublicKey::from_str( + "02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619", + ) + .unwrap(); + let first_peer_info = PeerInfo { + node_id: first_node_id, + address: SocketAddress::from_str("127.0.0.1:9738").unwrap(), + }; + let second_peer_info = PeerInfo { + node_id: second_node_id, + address: SocketAddress::from_str("127.0.0.1:9739").unwrap(), + }; + + let first_writer_store = Arc::clone(&peer_store); + let first_writer_peer = first_peer_info.clone(); + let first_writer = + tokio::spawn(async move { first_writer_store.add_peer(first_writer_peer).await }); + store.wait_for_write().await; + + let reader_store = Arc::clone(&peer_store); + let observed_peers = tokio::time::timeout( + Duration::from_millis(200), + tokio::task::spawn_blocking(move || reader_store.list_peers()), + ) + .await + .expect("peer reads must not wait for persistence") + .unwrap(); + assert_eq!(observed_peers, vec![first_peer_info]); + + let second_writer_store = Arc::clone(&peer_store); + let mut second_writer = + tokio::spawn(async move { second_writer_store.add_peer(second_peer_info).await }); + assert!( + tokio::time::timeout(Duration::from_millis(200), &mut second_writer).await.is_err(), + "peer mutations must remain serialized while persistence is pending" + ); + + store.release_write(); + first_writer.await.unwrap().unwrap(); + second_writer.await.unwrap().unwrap(); + assert_eq!(peer_store.list_peers().len(), 2); + + let persisted_bytes = KVStore::read( + &*store, + PEER_INFO_PERSISTENCE_PRIMARY_NAMESPACE, + PEER_INFO_PERSISTENCE_SECONDARY_NAMESPACE, + PEER_INFO_PERSISTENCE_KEY, + ) + .await + .unwrap(); + let persisted_peer_store = + PeerStore::read(&mut &persisted_bytes[..], (store, logger)).unwrap(); + assert_eq!(persisted_peer_store.list_peers().len(), 2); + } + + #[tokio::test] + async fn missing_channel_peer_is_persisted_from_graph() { + let store: Arc = Arc::new(InMemoryStore::new()); + let logger = Arc::new(Logger::new_log_facade()); + let peer_store = PeerStore::new(Arc::clone(&store), Arc::clone(&logger)); + let network_graph = Graph::new(Network::Regtest.into(), Arc::clone(&logger)); + + let node_id = PublicKey::from_str( + "0276607124ebe6a6c9338517b6f485825b27c2dcc0b9fc2aa6a4c0df91194e5993", + ) + .unwrap(); + let other_node_id = PublicKey::from_str( + "02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619", + ) + .unwrap(); + let address = SocketAddress::from_str("127.0.0.1:9738").unwrap(); + + network_graph + .add_channel_from_partial_announcement( + 42, + None, + 0, + ChannelFeatures::empty(), + NodeId::from_pubkey(&node_id), + NodeId::from_pubkey(&other_node_id), + ) + .unwrap(); + network_graph + .update_node_from_unsigned_announcement(&UnsignedNodeAnnouncement { + features: NodeFeatures::empty(), + timestamp: 1, + node_id: NodeId::from_pubkey(&node_id), + rgb: [0; 3], + alias: NodeAlias([0; 32]), + addresses: vec![address.clone()], + excess_address_data: Vec::new(), + excess_data: Vec::new(), + }) + .unwrap(); + + persist_missing_channel_peers(vec![node_id], &network_graph, &peer_store, logger).await; + + let peer = peer_store.get_peer(&node_id).unwrap(); + assert_eq!(peer.node_id, node_id); + assert_eq!(peer.address, address); + } + + #[tokio::test] + async fn missing_channel_peer_without_announced_address_is_skipped() { + let store: Arc = Arc::new(InMemoryStore::new()); + let logger = Arc::new(Logger::new_log_facade()); + let peer_store = PeerStore::new(Arc::clone(&store), Arc::clone(&logger)); + let network_graph = Graph::new(Network::Regtest.into(), Arc::clone(&logger)); + + let node_id = PublicKey::from_str( + "0276607124ebe6a6c9338517b6f485825b27c2dcc0b9fc2aa6a4c0df91194e5993", + ) + .unwrap(); + + persist_missing_channel_peers(vec![node_id], &network_graph, &peer_store, logger).await; + + assert!(peer_store.get_peer(&node_id).is_none()); + } + + #[tokio::test] + async fn missing_channel_peer_is_persisted_after_graph_retry() { + let store: Arc = Arc::new(InMemoryStore::new()); + let logger = Arc::new(Logger::new_log_facade()); + let peer_store = PeerStore::new(Arc::clone(&store), Arc::clone(&logger)); + let network_graph = Graph::new(Network::Regtest.into(), Arc::clone(&logger)); + + let node_id = PublicKey::from_str( + "0276607124ebe6a6c9338517b6f485825b27c2dcc0b9fc2aa6a4c0df91194e5993", + ) + .unwrap(); + let other_node_id = PublicKey::from_str( + "02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619", + ) + .unwrap(); + let address = SocketAddress::from_str("127.0.0.1:9738").unwrap(); + + persist_missing_channel_peers( + vec![node_id], + &network_graph, + &peer_store, + Arc::clone(&logger), + ) + .await; + assert!(peer_store.get_peer(&node_id).is_none()); + + network_graph + .add_channel_from_partial_announcement( + 42, + None, + 0, + ChannelFeatures::empty(), + NodeId::from_pubkey(&node_id), + NodeId::from_pubkey(&other_node_id), + ) + .unwrap(); + network_graph + .update_node_from_unsigned_announcement(&UnsignedNodeAnnouncement { + features: NodeFeatures::empty(), + timestamp: 1, + node_id: NodeId::from_pubkey(&node_id), + rgb: [0; 3], + alias: NodeAlias([0; 32]), + addresses: vec![address.clone()], + excess_address_data: Vec::new(), + excess_data: Vec::new(), + }) + .unwrap(); + + persist_missing_channel_peers(vec![node_id], &network_graph, &peer_store, logger).await; + + let peer = peer_store.get_peer(&node_id).unwrap(); + assert_eq!(peer.node_id, node_id); + assert_eq!(peer.address, address); + } + + #[tokio::test] + async fn excluded_missing_channel_peer_is_not_persisted_from_graph() { + let store: Arc = Arc::new(InMemoryStore::new()); + let logger = Arc::new(Logger::new_log_facade()); + let peer_store = PeerStore::new(Arc::clone(&store), Arc::clone(&logger)); + let network_graph = Graph::new(Network::Regtest.into(), Arc::clone(&logger)); + + let node_id = PublicKey::from_str( + "0276607124ebe6a6c9338517b6f485825b27c2dcc0b9fc2aa6a4c0df91194e5993", + ) + .unwrap(); + let other_node_id = PublicKey::from_str( + "02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619", + ) + .unwrap(); + let address = SocketAddress::from_str("127.0.0.1:9738").unwrap(); + let excluded_node_ids = HashSet::from([node_id]); + + network_graph + .add_channel_from_partial_announcement( + 42, + None, + 0, + ChannelFeatures::empty(), + NodeId::from_pubkey(&node_id), + NodeId::from_pubkey(&other_node_id), + ) + .unwrap(); + network_graph + .update_node_from_unsigned_announcement(&UnsignedNodeAnnouncement { + features: NodeFeatures::empty(), + timestamp: 1, + node_id: NodeId::from_pubkey(&node_id), + rgb: [0; 3], + alias: NodeAlias([0; 32]), + addresses: vec![address], + excess_address_data: Vec::new(), + excess_data: Vec::new(), + }) + .unwrap(); + + persist_missing_channel_peers_excluding( + vec![node_id], + &network_graph, + &peer_store, + &excluded_node_ids, + logger, + ) + .await; + + assert!(peer_store.get_peer(&node_id).is_none()); + } + + struct FailableWriteStore { + persisted_bytes: Mutex>>>, + fail_next_write: AtomicBool, + } + + impl FailableWriteStore { + fn new(fail_next_write: bool) -> Self { + Self { + persisted_bytes: Mutex::new(HashMap::new()), + fail_next_write: AtomicBool::new(fail_next_write), + } + } + + fn fail_next_write(&self) { + self.fail_next_write.store(true, Ordering::Relaxed); + } + + fn read_internal( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, + ) -> io::Result> { + let persisted_lock = self.persisted_bytes.lock().unwrap(); + let prefixed = format!("{}/{}", primary_namespace, secondary_namespace); + persisted_lock + .get(&prefixed) + .and_then(|inner| inner.get(key)) + .cloned() + .ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "Key not found")) + } + + fn write_internal( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, buf: Vec, + ) -> io::Result<()> { + if self.fail_next_write.swap(false, Ordering::Relaxed) { + return Err(io::Error::new(io::ErrorKind::Other, "Injected write failure")); + } + + let mut persisted_lock = self.persisted_bytes.lock().unwrap(); + let prefixed = format!("{}/{}", primary_namespace, secondary_namespace); + persisted_lock + .entry(prefixed) + .or_insert_with(HashMap::new) + .insert(key.to_string(), buf); + Ok(()) + } + + fn remove_internal( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, + ) -> io::Result<()> { + let mut persisted_lock = self.persisted_bytes.lock().unwrap(); + let prefixed = format!("{}/{}", primary_namespace, secondary_namespace); + if let Some(inner) = persisted_lock.get_mut(&prefixed) { + inner.remove(key); + } + Ok(()) + } + + fn list_internal( + &self, primary_namespace: &str, secondary_namespace: &str, + ) -> io::Result> { + let persisted_lock = self.persisted_bytes.lock().unwrap(); + let prefixed = format!("{}/{}", primary_namespace, secondary_namespace); + Ok(persisted_lock + .get(&prefixed) + .map(|inner| inner.keys().cloned().collect()) + .unwrap_or_default()) + } + } + + impl KVStore for FailableWriteStore { + fn read( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, + ) -> Pin>> + Send + 'static>> { + let res = self.read_internal(primary_namespace, secondary_namespace, key); + Box::pin(async move { res }) + } + + fn write( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, buf: Vec, + ) -> Pin> + Send + 'static>> { + let res = self.write_internal(primary_namespace, secondary_namespace, key, buf); + Box::pin(async move { res }) + } + + fn remove( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, _lazy: bool, + ) -> Pin> + Send + 'static>> { + let res = self.remove_internal(primary_namespace, secondary_namespace, key); + Box::pin(async move { res }) + } + + fn list( + &self, primary_namespace: &str, secondary_namespace: &str, + ) -> Pin>> + Send + 'static>> { + let res = self.list_internal(primary_namespace, secondary_namespace); + Box::pin(async move { res }) + } + } + + impl KVStoreSync for FailableWriteStore { + fn read( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, + ) -> io::Result> { + self.read_internal(primary_namespace, secondary_namespace, key) + } + + fn write( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, buf: Vec, + ) -> io::Result<()> { + self.write_internal(primary_namespace, secondary_namespace, key, buf) + } + + fn remove( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, _lazy: bool, + ) -> io::Result<()> { + self.remove_internal(primary_namespace, secondary_namespace, key) + } + + fn list( + &self, primary_namespace: &str, secondary_namespace: &str, + ) -> io::Result> { + self.list_internal(primary_namespace, secondary_namespace) + } + } + + struct BlockingWriteStore { + store: InMemoryStore, + block_next_write: AtomicBool, + write_started: Arc, + release_write: Arc, + } + + impl BlockingWriteStore { + fn new() -> Self { + Self { + store: InMemoryStore::new(), + block_next_write: AtomicBool::new(true), + write_started: Arc::new(tokio::sync::Notify::new()), + release_write: Arc::new(tokio::sync::Notify::new()), + } + } + + async fn wait_for_write(&self) { + self.write_started.notified().await; + } + + fn release_write(&self) { + self.release_write.notify_one(); + } + } + + impl KVStore for BlockingWriteStore { + fn read( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, + ) -> Pin>> + Send + 'static>> { + KVStore::read(&self.store, primary_namespace, secondary_namespace, key) + } + + fn write( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, buf: Vec, + ) -> Pin> + Send + 'static>> { + let write = + KVStore::write(&self.store, primary_namespace, secondary_namespace, key, buf); + if self.block_next_write.swap(false, Ordering::AcqRel) { + let write_started = Arc::clone(&self.write_started); + let release_write = Arc::clone(&self.release_write); + Box::pin(async move { + write_started.notify_one(); + release_write.notified().await; + write.await + }) + } else { + write + } + } + + fn remove( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, lazy: bool, + ) -> Pin> + Send + 'static>> { + KVStore::remove(&self.store, primary_namespace, secondary_namespace, key, lazy) + } + + fn list( + &self, primary_namespace: &str, secondary_namespace: &str, + ) -> Pin>> + Send + 'static>> { + KVStore::list(&self.store, primary_namespace, secondary_namespace) + } + } + + impl KVStoreSync for BlockingWriteStore { + fn read( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, + ) -> io::Result> { + KVStoreSync::read(&self.store, primary_namespace, secondary_namespace, key) + } + + fn write( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, buf: Vec, + ) -> io::Result<()> { + KVStoreSync::write(&self.store, primary_namespace, secondary_namespace, key, buf) + } + + fn remove( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, lazy: bool, + ) -> io::Result<()> { + KVStoreSync::remove(&self.store, primary_namespace, secondary_namespace, key, lazy) + } + + fn list( + &self, primary_namespace: &str, secondary_namespace: &str, + ) -> io::Result> { + KVStoreSync::list(&self.store, primary_namespace, secondary_namespace) + } + } } diff --git a/src/probe_handle.rs b/src/probe_handle.rs new file mode 100644 index 0000000000..d5ac5e5823 --- /dev/null +++ b/src/probe_handle.rs @@ -0,0 +1,29 @@ +// This file is Copyright its original authors, visible in version control history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license , at your option. You may not use this file except in +// accordance with one or both of these licenses. + +//! Handle returned when sending pre-flight probes. +//! +//! UniFFI uses `dictionary ProbeHandle` in `bindings/ldk_node.udl`; this module defines the Rust +//! struct with the same fields. With `feature = "uniffi"`, `lib.rs` must `pub use` this type +//! **before** `uniffi::include_scaffolding!` so the generated `FfiConverter` impl applies here (same +//! pattern as [`crate::SpendableUtxo`], [`crate::PeerDetails`], etc.). + +use lightning::ln::channelmanager::PaymentId; +use lightning_types::payment::PaymentHash; + +/// Identifies one outbound probe; match against [`crate::Event::ProbeSuccessful`] / +/// [`crate::Event::ProbeFailed`] using [`Self::payment_id`] and/or [`Self::payment_hash`]. +/// +/// The [`PaymentHash`] is **not** the BOLT11 invoice payment hash; LDK generates a synthetic hash +/// per probe. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct ProbeHandle { + /// Synthetic probe payment hash (not the BOLT11 invoice payment hash). + pub payment_hash: PaymentHash, + /// Local id for this probe; matches probe [`crate::Event`] variants. + pub payment_id: PaymentId, +} diff --git a/src/runtime.rs b/src/runtime.rs index 1e9883ae4b..d00734a31f 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -97,15 +97,6 @@ impl Runtime { *background_processor_task = Some(handle); } - pub fn spawn_blocking(&self, func: F) -> JoinHandle - where - F: FnOnce() -> R + Send + 'static, - R: Send + 'static, - { - let handle = self.handle(); - handle.spawn_blocking(func) - } - pub fn block_on(&self, future: F) -> F::Output { // While we generally decided not to overthink via which call graph users would enter our // runtime context, we'd still try to reuse whatever current context would be present @@ -207,7 +198,7 @@ impl Runtime { ); } - fn handle(&self) -> &tokio::runtime::Handle { + pub(crate) fn handle(&self) -> &tokio::runtime::Handle { match &self.mode { RuntimeMode::Owned(rt) => rt.handle(), RuntimeMode::Handle(handle) => handle, @@ -219,3 +210,22 @@ enum RuntimeMode { Owned(tokio::runtime::Runtime), Handle(tokio::runtime::Handle), } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn runtime_handle_does_not_retain_runtime_owner() { + let runtime = Arc::new(Runtime::new(Arc::new(Logger::new_log_facade())).unwrap()); + let weak_runtime = Arc::downgrade(&runtime); + + let runtime_handle = runtime.handle().clone(); + + assert_eq!(Arc::strong_count(&runtime), 1); + drop(runtime); + assert!(weak_runtime.upgrade().is_none()); + + drop(runtime_handle); + } +} diff --git a/src/scoring.rs b/src/scoring.rs index e85abade3e..ee70f0087c 100644 --- a/src/scoring.rs +++ b/src/scoring.rs @@ -25,7 +25,7 @@ pub fn setup_background_pathfinding_scores_sync( let logger = Arc::clone(&logger); - runtime.spawn_background_processor_task(async move { + runtime.spawn_cancellable_background_task(async move { let mut interval = tokio::time::interval(EXTERNAL_PATHFINDING_SCORES_SYNC_INTERVAL); loop { tokio::select! { diff --git a/src/types.rs b/src/types.rs index 6d6bdcd201..717aa61113 100644 --- a/src/types.rs +++ b/src/types.rs @@ -228,12 +228,15 @@ impl fmt::Display for UserChannelId { /// Details of a channel as returned by [`Node::list_channels`]. /// +/// When a channel is spliced, most fields continue to refer to the original pre-splice channel +/// state until the splice transaction reaches sufficient confirmations to be locked (and we +/// exchange `splice_locked` messages with our peer). See individual fields for details. +/// /// [`Node::list_channels`]: crate::Node::list_channels #[derive(Debug, Clone)] pub struct ChannelDetails { - /// The channel ID (prior to funding transaction generation, this is a random 32-byte - /// identifier, afterwards this is the transaction ID of the funding transaction XOR the - /// funding transaction output). + /// The channel's ID (prior to initial channel setup this is a random 32 bytes, thereafter it + /// is derived from channel funding or key material). /// /// Note that this means this value is *not* persistent - it can change once during the /// lifetime of the channel. @@ -242,6 +245,10 @@ pub struct ChannelDetails { pub counterparty_node_id: PublicKey, /// The channel's funding transaction output, if we've negotiated the funding transaction with /// our counterparty already. + /// + /// When a channel is spliced, this continues to refer to the original pre-splice channel + /// state until the splice transaction reaches sufficient confirmations to be locked (and we + /// exchange `splice_locked` messages with our peer). pub funding_txo: Option, /// The position of the funding transaction in the chain. None if the funding transaction has /// not yet been confirmed and the channel fully opened. @@ -252,6 +259,10 @@ pub struct ChannelDetails { /// For channels with [`confirmations_required`] set to `Some(0)`, [`outbound_scid_alias`] may /// be used in place of this in outbound routes. /// + /// When a channel is spliced, this continues to refer to the original pre-splice channel state + /// until the splice transaction reaches sufficient confirmations to be locked (and we exchange + /// `splice_locked` messages with our peer). + /// /// [`inbound_scid_alias`]: Self::inbound_scid_alias /// [`outbound_scid_alias`]: Self::outbound_scid_alias /// [`confirmations_required`]: Self::confirmations_required @@ -263,6 +274,10 @@ pub struct ChannelDetails { /// /// This will be `None` as long as the channel is not available for routing outbound payments. /// + /// When a channel is spliced, this continues to refer to the original pre-splice channel + /// state until the splice transaction reaches sufficient confirmations to be locked (and we + /// exchange `splice_locked` messages with our peer). + /// /// [`short_channel_id`]: Self::short_channel_id /// [`confirmations_required`]: Self::confirmations_required pub outbound_scid_alias: Option, @@ -277,6 +292,10 @@ pub struct ChannelDetails { /// [`short_channel_id`]: Self::short_channel_id pub inbound_scid_alias: Option, /// The value, in satoshis, of this channel as it appears in the funding output. + /// + /// When a channel is spliced, this continues to refer to the original pre-splice channel + /// state until the splice transaction reaches sufficient confirmations to be locked (and we + /// exchange `splice_locked` messages with our peer). pub channel_value_sats: u64, /// The value, in satoshis, that must always be held as a reserve in the channel for us. This /// value ensures that if we broadcast a revoked state, our counterparty can punish us by @@ -379,6 +398,11 @@ pub struct ChannelDetails { pub inbound_htlc_maximum_msat: Option, /// Set of configurable parameters that affect channel operation. pub config: ChannelConfig, + /// The amount, in satoshis, claimable if the channel is closed now. + /// + /// This is computed from the channel monitor and represents the confirmed balance + /// excluding pending HTLCs. Returns `None` if no monitor exists yet (pre-funding). + pub claimable_on_close_sats: Option, } impl From for ChannelDetails { @@ -433,10 +457,21 @@ impl From for ChannelDetails { inbound_htlc_maximum_msat: value.inbound_htlc_maximum_msat, // unwrap safety: `config` is only `None` for LDK objects serialized prior to 0.0.109. config: value.config.map(|c| c.into()).unwrap(), + claimable_on_close_sats: None, } } } +impl ChannelDetails { + pub(crate) fn from_ldk_with_balance( + value: LdkChannelDetails, claimable_on_close_sats: Option, + ) -> Self { + let mut details: ChannelDetails = value.into(); + details.claimable_on_close_sats = claimable_on_close_sats; + details + } +} + /// Details of a known Lightning peer as returned by [`Node::list_peers`]. /// /// [`Node::list_peers`]: crate::Node::list_peers @@ -471,3 +506,18 @@ impl From<&(u64, Vec)> for CustomTlvRecord { CustomTlvRecord { type_num: tlv.0, value: tlv.1.clone() } } } + +/// A spendable on-chain UTXO. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SpendableUtxo { + /// The outpoint of the UTXO. + pub outpoint: OutPoint, + /// The value of the UTXO in satoshis. + pub value_sats: u64, +} + +impl From for SpendableUtxo { + fn from(output: bdk_wallet::LocalOutput) -> Self { + SpendableUtxo { outpoint: output.outpoint, value_sats: output.txout.value.to_sat() } + } +} diff --git a/src/wallet/mod.rs b/src/wallet/mod.rs index 2f8daa5001..26fde71f80 100644 --- a/src/wallet/mod.rs +++ b/src/wallet/mod.rs @@ -5,18 +5,23 @@ // http://opensource.org/licenses/MIT>, at your option. You may not use this file except in // accordance with one or both of these licenses. +use std::collections::{HashMap, HashSet}; use std::future::Future; use std::ops::Deref; use std::pin::Pin; use std::str::FromStr; -use std::sync::{Arc, Mutex}; +use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; +use std::sync::{Arc, Mutex, MutexGuard, RwLock}; use bdk_chain::spk_client::{FullScanRequest, SyncRequest}; -use bdk_wallet::descriptor::ExtendedDescriptor; -#[allow(deprecated)] -use bdk_wallet::SignOptions; -use bdk_wallet::{Balance, KeychainKind, PersistedWallet, Update}; +use bdk_chain::ConfirmationBlockTime; +use bdk_wallet::event::WalletEvent; +use bdk_wallet::{ + AddressInfo, Balance, KeychainKind as BdkKeychainKind, LocalOutput, PersistedWallet, Update, +}; +use bdk_wallet_aggregate::{AggregateWallet, UtxoPsbtInfo}; use bitcoin::address::NetworkUnchecked; +use bitcoin::bip32::Xpriv; use bitcoin::blockdata::constants::WITNESS_SCALE_FACTOR; use bitcoin::blockdata::locktime::absolute::LockTime; use bitcoin::hashes::Hash; @@ -26,8 +31,8 @@ use bitcoin::secp256k1::ecdh::SharedSecret; use bitcoin::secp256k1::ecdsa::{RecoverableSignature, Signature}; use bitcoin::secp256k1::{All, PublicKey, Scalar, Secp256k1, SecretKey}; use bitcoin::{ - Address, Amount, FeeRate, ScriptBuf, Transaction, TxOut, Txid, WPubkeyHash, Weight, - WitnessProgram, WitnessVersion, + Address, Amount, FeeRate, Network, OutPoint, PubkeyHash, Script, ScriptBuf, Transaction, TxIn, + TxOut, Txid, WPubkeyHash, Weight, WitnessProgram, WitnessVersion, }; use lightning::chain::chaininterface::BroadcasterInterface; use lightning::chain::channelmonitor::ANTI_REORG_DELAY; @@ -45,320 +50,1818 @@ use lightning::sign::{ use lightning::util::message_signing; use lightning_invoice::RawBolt11Invoice; use persist::KVStoreWalletPersister; +use zeroize::Zeroizing; -use crate::config::Config; +use crate::config::{ + AddressType, AddressTypeRuntimeConfig, Config, OnchainWalletAccount, WALLET_KEYS_SEED_LEN, +}; +use crate::event::{TxInput, TxOutput}; use crate::fee_estimator::{ConfirmationTarget, FeeEstimator, OnchainFeeEstimator}; use crate::logger::{log_debug, log_error, log_info, log_trace, LdkLogger, Logger}; use crate::payment::store::ConfirmationStatus; -use crate::payment::{PaymentDetails, PaymentDirection, PaymentStatus}; -use crate::types::{Broadcaster, PaymentStore}; -use crate::Error; +use crate::payment::{KeychainKind, PaymentDetails, PaymentDirection, PaymentStatus}; +use crate::types::{Broadcaster, ChannelManager, DynStore, PaymentStore}; +use crate::{Error, NodeMetrics}; + +// Minimum economical output value (dust limit) +const DUST_LIMIT_SATS: u64 = 546; +const BIP32_MAX_NORMAL_INDEX: u32 = (1 << 31) - 1; +const MAX_ADDRESS_INFO_BATCH_COUNT: u32 = bdk_wallet_aggregate::MAX_ADDRESS_INFO_BATCH_COUNT; + +fn validate_derivation_index(index: u32) -> Result<(), Error> { + if index > BIP32_MAX_NORMAL_INDEX { + return Err(Error::InvalidQuantity); + } + Ok(()) +} + +fn validate_derivation_range(start_index: u32, count: u32) -> Result<(), Error> { + validate_derivation_index(start_index)?; + if count > MAX_ADDRESS_INFO_BATCH_COUNT { + return Err(Error::InvalidQuantity); + } + if count == 0 { + return Ok(()); + } + + let last_index = start_index.checked_add(count - 1).ok_or(Error::InvalidQuantity)?; + validate_derivation_index(last_index) +} + +fn map_wallet_account_error( + wallet_account: OnchainWalletAccount, error: bdk_wallet_aggregate::Error, +) -> Error { + match error { + bdk_wallet_aggregate::Error::WalletNotFound if wallet_account.is_derived() => { + Error::OnchainWalletAccountNotRegistered + }, + _ => Error::WalletOperationFailed, + } +} +fn additional_input_weight(utxos: &[UtxoPsbtInfo]) -> Result { + let base_weight = TxIn::default().segwit_weight().to_wu(); + let total = utxos.iter().try_fold(0u64, |total, utxo| { + total + .checked_add(base_weight) + .and_then(|weight| weight.checked_add(utxo.weight.to_wu())) + .ok_or(Error::InvalidFeeRate) + })?; + Ok(Weight::from_wu(total)) +} + +#[derive(Clone, Copy)] pub(crate) enum OnchainSendAmount { ExactRetainingReserve { amount_sats: u64, cur_anchor_reserve_sats: u64 }, AllRetainingReserve { cur_anchor_reserve_sats: u64 }, AllDrainingReserve, } +/// Available coin selection algorithms +#[derive(Debug, Clone, Copy)] +pub enum CoinSelectionAlgorithm { + /// Branch and bound algorithm (tries to find exact match) + BranchAndBound, + /// Select largest UTXOs first + LargestFirst, + /// Select oldest UTXOs first + OldestFirst, + /// Select UTXOs randomly + SingleRandomDraw, +} + pub(crate) mod persist; pub(crate) mod ser; pub(crate) struct Wallet { - // A BDK on-chain wallet. - inner: Mutex>, - persister: Mutex, + inner: Mutex>, + // Serializes account membership, primary selection, and account reloads. + operation_lock: Mutex<()>, + account_generation: AtomicU64, + synced_derived_accounts: Mutex>, broadcaster: Arc, fee_estimator: Arc, payment_store: Arc, + payment_store_update_pending: AtomicBool, config: Arc, + kv_store: Arc, + seed_bytes: Zeroizing<[u8; WALLET_KEYS_SEED_LEN]>, + address_type_runtime_config: Arc>, + node_metrics: Arc>, logger: Arc, + derived_account_lookahead: u32, } impl Wallet { pub(crate) fn new( wallet: bdk_wallet::PersistedWallet, - wallet_persister: KVStoreWalletPersister, broadcaster: Arc, + wallet_persister: KVStoreWalletPersister, + additional_wallets: Vec<( + OnchainWalletAccount, + PersistedWallet, + KVStoreWalletPersister, + )>, + seed_bytes: [u8; WALLET_KEYS_SEED_LEN], broadcaster: Arc, fee_estimator: Arc, payment_store: Arc, - config: Arc, logger: Arc, + config: Arc, kv_store: Arc, + address_type_runtime_config: Arc>, + node_metrics: Arc>, logger: Arc, + derived_account_lookahead: u32, ) -> Self { - let inner = Mutex::new(wallet); - let persister = Mutex::new(wallet_persister); - Self { inner, persister, broadcaster, fee_estimator, payment_store, config, logger } + let primary_account = OnchainWalletAccount::account_zero(config.address_type); + let aggregate = + AggregateWallet::new(wallet, wallet_persister, primary_account, additional_wallets); + let inner = Mutex::new(aggregate); + let operation_lock = Mutex::new(()); + Self { + inner, + operation_lock, + account_generation: AtomicU64::new(0), + synced_derived_accounts: Mutex::new(HashSet::new()), + broadcaster, + fee_estimator, + payment_store, + payment_store_update_pending: AtomicBool::new(false), + config, + kv_store, + seed_bytes: Zeroizing::new(seed_bytes), + address_type_runtime_config, + node_metrics, + logger, + derived_account_lookahead, + } + } + + pub(crate) fn is_funding_transaction( + &self, txid: &Txid, channel_manager: &ChannelManager, + ) -> bool { + // Check all channels (pending and confirmed) for matching funding txid + for channel in channel_manager.list_channels() { + if let Some(funding_txo) = channel.funding_txo { + if funding_txo.txid == *txid { + log_debug!( + self.logger, + "Transaction {} is a funding transaction for channel {}", + txid, + channel.channel_id + ); + return true; + } + } + } + false } - pub(crate) fn get_full_scan_request(&self) -> FullScanRequest { + pub(crate) fn estimate_fee_rate(&self, target: ConfirmationTarget) -> FeeRate { + self.fee_estimator.estimate_fee_rate(target) + } + + pub(crate) fn get_full_scan_request(&self) -> FullScanRequest { self.inner.lock().unwrap().start_full_scan().build() } - pub(crate) fn get_incremental_sync_request(&self) -> SyncRequest<(KeychainKind, u32)> { + pub(crate) fn get_incremental_sync_request(&self) -> SyncRequest<(BdkKeychainKind, u32)> { self.inner.lock().unwrap().start_sync_with_revealed_spks().build() } + pub(crate) fn get_wallet_full_scan_request( + &self, wallet_account: OnchainWalletAccount, + ) -> Result, bdk_wallet_aggregate::Error> { + self.inner.lock().unwrap().wallet_full_scan_request(&wallet_account) + } + + pub(crate) fn get_wallet_incremental_sync_request( + &self, wallet_account: OnchainWalletAccount, + ) -> Result, bdk_wallet_aggregate::Error> { + let aggregate = self.inner.lock().unwrap(); + if wallet_account.account_index == 0 { + aggregate.wallet_incremental_sync_request(&wallet_account) + } else { + aggregate.wallet_incremental_sync_request_with_lookahead(&wallet_account) + } + } + pub(crate) fn get_cached_txs(&self) -> Vec> { - self.inner.lock().unwrap().tx_graph().full_txs().map(|tx_node| tx_node.tx).collect() + self.inner.lock().unwrap().cached_txs() } pub(crate) fn get_unconfirmed_txids(&self) -> Vec { - self.inner + self.inner.lock().unwrap().unconfirmed_txids() + } + + pub(crate) fn get_unconfirmed_txids_with_last_seen(&self) -> Vec<(Txid, u64)> { + self.inner.lock().unwrap().unconfirmed_txids_with_last_seen() + } + + pub(crate) fn transaction_confirmations(&self) -> HashMap { + self.inner.lock().unwrap().transaction_confirmations() + } + + pub(crate) fn current_best_block(&self) -> BestBlock { + let (block_hash, height) = self.inner.lock().unwrap().current_best_block(); + BestBlock { block_hash, height } + } + + /// Returns an account generation and matching chain-tip snapshot for Bitcoind sync. + pub(crate) fn account_sync_snapshot(&self) -> (u64, Vec<(OnchainWalletAccount, BestBlock)>) { + let _operation = self.operation_lock.lock().unwrap(); + let generation = self.account_generation.load(Ordering::Acquire); + let tips = self + .inner .lock() .unwrap() - .transactions() - .filter(|t| t.chain_position.is_unconfirmed()) - .map(|t| t.tx_node.txid) - .collect() + .chain_tips_by_key() + .into_iter() + .map(|(account, block_hash, height)| (account, BestBlock { block_hash, height })) + .collect(); + (generation, tips) } - pub(crate) fn current_best_block(&self) -> BestBlock { - let checkpoint = self.inner.lock().unwrap().latest_checkpoint(); - BestBlock { block_hash: checkpoint.hash(), height: checkpoint.height() } + pub(crate) fn lock_account_operations(&self) -> MutexGuard<'_, ()> { + self.operation_lock.lock().unwrap() } - pub(crate) fn apply_update(&self, update: impl Into) -> Result<(), Error> { - let mut locked_wallet = self.inner.lock().unwrap(); - match locked_wallet.apply_update(update) { - Ok(()) => { - let mut locked_persister = self.persister.lock().unwrap(); - locked_wallet.persist(&mut locked_persister).map_err(|e| { - log_error!(self.logger, "Failed to persist wallet: {}", e); - Error::PersistenceFailed - })?; + pub(crate) fn account_generation(&self) -> u64 { + self.account_generation.load(Ordering::Acquire) + } - self.update_payment_store(&mut *locked_wallet).map_err(|e| { - log_error!(self.logger, "Failed to update payment store: {}", e); - Error::PersistenceFailed - })?; + pub(crate) fn rewind_wallet_account( + &self, account: OnchainWalletAccount, checkpoint: BestBlock, + ) -> Result<(), Error> { + let _operation = self.operation_lock.lock().unwrap(); + let xprv = + Xpriv::new_master(self.config.network, self.seed_bytes.as_slice()).map_err(|e| { + log_error!( + self.logger, + "Failed to derive master secret while rewinding wallet: {}", + e + ); + Error::WalletOperationFailed + })?; + let mut aggregate = self.inner.lock().unwrap(); + if aggregate.wallet(&account).is_none() { + return Err(Error::WalletOperationFailed); + } + aggregate.persist_all().map_err(|e| { + log_error!(self.logger, "Failed to persist {:?} before wallet rewind: {}", account, e); + Error::PersistenceFailed + })?; + let mut persister = KVStoreWalletPersister::new( + Arc::clone(&self.kv_store), + Arc::clone(&self.logger), + account, + ); + let checkpoint_id = + bdk_chain::BlockId { height: checkpoint.height, hash: checkpoint.block_hash }; + persister.rewind_to_checkpoint(checkpoint_id).map_err(|e| { + log_error!(self.logger, "Failed to persist wallet rewind for {:?}: {}", account, e); + Error::PersistenceFailed + })?; - Ok(()) - }, - Err(e) => { - log_error!(self.logger, "Sync failed due to chain connection error: {}", e); - Err(Error::WalletOperationFailed) - }, + let (wallet, loaded_from_store) = crate::builder::get_or_create_wallet_for_account( + account, + xprv, + self.config.network, + &mut persister, + (account.account_index != 0).then_some(self.derived_account_lookahead), + ) + .map_err(|e| { + log_error!(self.logger, "Failed to reload wallet {:?} after rewind: {}", account, e); + Error::WalletOperationFailed + })?; + if !loaded_from_store || wallet.latest_checkpoint().block_id() != checkpoint_id { + log_error!( + self.logger, + "Wallet {:?} did not reload at the requested checkpoint", + account + ); + return Err(Error::WalletOperationFailed); } + + aggregate.wallets_mut().insert(account, wallet); + aggregate.persisters_mut().insert(account, persister); + self.payment_store_update_pending.store(true, Ordering::Release); + Ok(()) } - pub(crate) fn apply_mempool_txs( - &self, unconfirmed_txs: Vec<(Transaction, u64)>, evicted_txids: Vec<(Txid, u64)>, + pub(crate) fn apply_block_to_account( + &self, account: OnchainWalletAccount, block: &bitcoin::Block, height: u32, ) -> Result<(), Error> { - let mut locked_wallet = self.inner.lock().unwrap(); - locked_wallet.apply_unconfirmed_txs(unconfirmed_txs); - locked_wallet.apply_evicted_txs(evicted_txids); + let mut locked = self.inner.lock().unwrap(); + self.payment_store_update_pending.store(true, Ordering::Release); + locked.apply_block_to(&account, block, height).map_err(|e| { + log_error!( + self.logger, + "Failed to apply block {} at height {} to {:?}: {}", + block.block_hash(), + height, + account, + e + ); + match e { + bdk_wallet_aggregate::Error::PersistenceFailed => Error::PersistenceFailed, + _ => Error::WalletOperationFailed, + } + })?; + Ok(()) + } - let mut locked_persister = self.persister.lock().unwrap(); - locked_wallet.persist(&mut locked_persister).map_err(|e| { - log_error!(self.logger, "Failed to persist wallet: {}", e); + pub(crate) fn finish_pending_sync(&self, refresh_payment_store: bool) -> Result<(), Error> { + let mut locked = self.inner.lock().unwrap(); + locked.persist_all().map_err(|e| { + log_error!(self.logger, "Failed to persist pending wallet changes: {}", e); Error::PersistenceFailed })?; + if refresh_payment_store || self.payment_store_update_pending.load(Ordering::Acquire) { + self.update_payment_store(&locked).map_err(|e| { + log_error!( + self.logger, + "Failed to update payment store after wallet persistence: {}", + e + ); + e + })?; + } + Ok(()) + } + + // Get a drain script for change outputs. + pub(crate) fn get_drain_script(&self) -> Result { + let locked_wallet = self.inner.lock().unwrap(); + let change_address = locked_wallet.peek_address(BdkKeychainKind::Internal, 0); + Ok(change_address.address.script_pubkey()) + } + + /// Returns the list of all loaded account-0 address types (primary + monitored). + pub(crate) fn get_loaded_address_types(&self) -> Vec { + self.inner + .lock() + .unwrap() + .loaded_keys() + .into_iter() + .filter(|account| account.account_index == 0) + .map(|account| account.address_type) + .collect() + } + + /// Returns all loaded on-chain wallet accounts, including derived accounts. + pub(crate) fn get_loaded_onchain_wallet_accounts(&self) -> Vec { + self.inner.lock().unwrap().loaded_keys() + } + + pub(crate) fn has_onchain_wallet_account(&self, account: OnchainWalletAccount) -> bool { + self.inner.lock().unwrap().wallet(&account).is_some() + } + + pub(crate) fn has_synced_derived_account(&self, account: OnchainWalletAccount) -> bool { + debug_assert_ne!(account.account_index, 0); + self.synced_derived_accounts.lock().unwrap().contains(&account) + } + + pub(crate) fn mark_derived_account_synced(&self, account: OnchainWalletAccount) { + debug_assert_ne!(account.account_index, 0); + self.synced_derived_accounts.lock().unwrap().insert(account); + } + /// Adds an address type to the monitored set, creating its wallet if not already loaded. + /// + /// Only account `0` address types can be managed through this API. Derived accounts must + /// use [`Self::add_onchain_wallet_account`]. + pub(crate) fn add_monitored_address_type( + &self, address_type: AddressType, seed_bytes: &[u8; WALLET_KEYS_SEED_LEN], + ) -> Result<(), Error> { + let _op = self.operation_lock.lock().unwrap(); + let wallet_account = OnchainWalletAccount::account_zero(address_type); + + { + let runtime_config = self.address_type_runtime_config.read().unwrap(); + if runtime_config.primary == address_type { + return Err(Error::AddressTypeIsPrimary); + } + if runtime_config.monitored.contains(&address_type) { + return Err(Error::AddressTypeAlreadyMonitored); + } + } + + let (wallet, persister) = create_wallet_for_account( + seed_bytes, + self.config.network, + wallet_account, + self.current_best_block(), + Arc::clone(&self.kv_store), + Arc::clone(&self.logger), + None, + )?; + + { + let mut aggregate = self.inner.lock().unwrap(); + aggregate.add_wallet(wallet_account, wallet, persister).map_err(|e| { + log_error!(self.logger, "Failed to add wallet for {:?}: {}", wallet_account, e); + Error::WalletOperationFailed + })?; + self.account_generation.fetch_add(1, Ordering::AcqRel); + self.address_type_runtime_config.write().unwrap().monitored.push(address_type); + } + + log_info!(self.logger, "Added address type {:?} to monitor", address_type); Ok(()) } - fn update_payment_store<'a>( - &self, locked_wallet: &'a mut PersistedWallet, + /// Removes an address type from monitoring and unloads its wallet. + /// Persisted state is retained so re-adding recovers funds on the next sync. + pub(crate) fn remove_monitored_address_type( + &self, address_type: AddressType, ) -> Result<(), Error> { - for wtx in locked_wallet.transactions() { - let id = PaymentId(wtx.tx_node.txid.to_byte_array()); - let txid = wtx.tx_node.txid; - let (payment_status, confirmation_status) = match wtx.chain_position { - bdk_chain::ChainPosition::Confirmed { anchor, .. } => { - let confirmation_height = anchor.block_id.height; - let cur_height = locked_wallet.latest_checkpoint().height(); - let payment_status = if cur_height >= confirmation_height + ANTI_REORG_DELAY - 1 - { - PaymentStatus::Succeeded - } else { - PaymentStatus::Pending - }; - let confirmation_status = ConfirmationStatus::Confirmed { - block_hash: anchor.block_id.hash, - height: confirmation_height, - timestamp: anchor.confirmation_time, - }; - (payment_status, confirmation_status) + let _op = self.operation_lock.lock().unwrap(); + let wallet_account = OnchainWalletAccount::account_zero(address_type); + + { + let runtime_config = self.address_type_runtime_config.read().unwrap(); + if runtime_config.primary == address_type { + return Err(Error::AddressTypeIsPrimary); + } + if !runtime_config.monitored.contains(&address_type) { + return Err(Error::AddressTypeNotMonitored); + } + } + + let mut removed = false; + { + let mut aggregate = self.inner.lock().unwrap(); + match aggregate.remove_wallet(wallet_account) { + Ok(()) => removed = true, + Err(bdk_wallet_aggregate::Error::CannotRemovePrimary) => { + return Err(Error::AddressTypeIsPrimary); + }, + Err(bdk_wallet_aggregate::Error::WalletNotFound) => { + log_debug!( + self.logger, + "Wallet for {:?} was not in aggregate (already unloaded)", + wallet_account + ); }, - bdk_chain::ChainPosition::Unconfirmed { .. } => { - (PaymentStatus::Pending, ConfirmationStatus::Unconfirmed) + Err(e) => { + log_error!(self.logger, "Failed to remove wallet {:?}: {}", wallet_account, e); + return Err(Error::WalletOperationFailed); }, - }; - // TODO: It would be great to introduce additional variants for - // `ChannelFunding` and `ChannelClosing`. For the former, we could just - // take a reference to `ChannelManager` here and check against - // `list_channels`. But for the latter the best approach is much less - // clear: for force-closes/HTLC spends we should be good querying - // `OutputSweeper::tracked_spendable_outputs`, but regular channel closes - // (i.e., `SpendableOutputDescriptor::StaticOutput` variants) are directly - // spent to a wallet address. The only solution I can come up with is to - // create and persist a list of 'static pending outputs' that we could use - // here to determine the `PaymentKind`, but that's not really satisfactory, so - // we're punting on it until we can come up with a better solution. - let kind = crate::payment::PaymentKind::Onchain { txid, status: confirmation_status }; - let fee = locked_wallet.calculate_fee(&wtx.tx_node.tx).unwrap_or(Amount::ZERO); - let (sent, received) = locked_wallet.sent_and_received(&wtx.tx_node.tx); - let (direction, amount_msat) = if sent > received { - let direction = PaymentDirection::Outbound; - let amount_msat = Some( - sent.to_sat().saturating_sub(fee.to_sat()).saturating_sub(received.to_sat()) - * 1000, - ); - (direction, amount_msat) - } else { - let direction = PaymentDirection::Inbound; - let amount_msat = Some( - received.to_sat().saturating_sub(sent.to_sat().saturating_sub(fee.to_sat())) - * 1000, + } + self.address_type_runtime_config + .write() + .unwrap() + .monitored + .retain(|&at| at != address_type); + if removed { + self.account_generation.fetch_add(1, Ordering::AcqRel); + } + } + + log_info!(self.logger, "Removed address type {:?} from monitor", address_type); + Ok(()) + } + + /// Sets the primary address type for account `0`, creating its wallet if not already loaded. + /// The previous primary is demoted to the monitored set. + pub(crate) fn set_primary_address_type( + &self, address_type: AddressType, seed_bytes: &[u8; WALLET_KEYS_SEED_LEN], + ) -> Result<(), Error> { + let _op = self.operation_lock.lock().unwrap(); + let wallet_account = OnchainWalletAccount::account_zero(address_type); + + let old_primary = self.address_type_runtime_config.read().unwrap().primary; + if address_type == old_primary { + return Ok(()); + } + + let already_loaded = self.inner.lock().unwrap().loaded_keys().contains(&wallet_account); + + let new_wallet = if !already_loaded { + Some(create_wallet_for_account( + seed_bytes, + self.config.network, + wallet_account, + self.current_best_block(), + Arc::clone(&self.kv_store), + Arc::clone(&self.logger), + None, + )?) + } else { + None + }; + + { + let mut aggregate = self.inner.lock().unwrap(); + if let Some((wallet, persister)) = new_wallet { + aggregate.add_wallet(wallet_account, wallet, persister).map_err(|e| { + log_error!(self.logger, "Failed to add wallet for {:?}: {}", wallet_account, e); + Error::WalletOperationFailed + })?; + self.account_generation.fetch_add(1, Ordering::AcqRel); + } + + aggregate.set_primary(wallet_account).map_err(|e| { + log_error!( + self.logger, + "Failed to set primary address type to {:?}: {}", + address_type, + e ); - (direction, amount_msat) - }; + Error::WalletOperationFailed + })?; + + let mut runtime_config = self.address_type_runtime_config.write().unwrap(); + runtime_config.primary = address_type; + runtime_config.monitored.retain(|&at| at != address_type); + if !runtime_config.monitored.contains(&old_primary) { + runtime_config.monitored.push(old_primary); + } + } + + // Clear primary sync timestamp for never-synced types so the next cycle does a full + // scan. Additional wallets have independent per-account timestamps in node_metrics. + let needs_full_scan = + self.node_metrics.read().unwrap().get_wallet_sync_timestamp(wallet_account).is_none(); + if needs_full_scan { + self.node_metrics.write().unwrap().latest_onchain_wallet_sync_timestamp = None; + } + + log_info!(self.logger, "Set primary address type to {:?}", address_type); + Ok(()) + } + + /// Exports the account-level xpub for `(address_type, account_index)`. + pub(crate) fn export_onchain_wallet_account_xpub( + &self, address_type: AddressType, account_index: u32, + ) -> Result { + if account_index > crate::config::MAX_ONCHAIN_WALLET_ACCOUNT_INDEX { + log_error!( + self.logger, + "Account index {} exceeds the maximum hardened BIP32 account index", + account_index + ); + return Err(Error::InvalidQuantity); + } + + let xprv = + Xpriv::new_master(self.config.network, self.seed_bytes.as_slice()).map_err(|e| { + log_error!(self.logger, "Failed to derive master secret: {}", e); + Error::InvalidSeedBytes + })?; + crate::builder::derive_account_xpub_string( + xprv, + self.config.network, + address_type, + account_index, + ) + .map_err(|e| { + log_error!( + self.logger, + "Failed to export xpub for {:?}/{}: {}", + address_type, + account_index, + e + ); + Error::InvalidSeedBytes + }) + } + + /// Registers a derived on-chain wallet account (`account_index >= 1`). + /// + /// Runtime registration is not persisted. Idempotent for the same xpub. + pub(crate) fn add_onchain_wallet_account( + &self, address_type: AddressType, account_index: u32, xpub: &str, + ) -> Result<(), Error> { + if account_index == 0 || account_index > crate::config::MAX_ONCHAIN_WALLET_ACCOUNT_INDEX { + log_error!( + self.logger, + "Derived account index must be in 1..={}", + crate::config::MAX_ONCHAIN_WALLET_ACCOUNT_INDEX + ); + return Err(Error::InvalidQuantity); + } - let fee_paid_msat = Some(fee.to_sat() * 1000); + let wallet_account = OnchainWalletAccount { address_type, account_index }; - let payment = PaymentDetails::new( - id, - kind, - amount_msat, - fee_paid_msat, - direction, - payment_status, + let expected_xpub = self.export_onchain_wallet_account_xpub(address_type, account_index)?; + let provided = xpub.trim(); + if provided != expected_xpub { + log_error!( + self.logger, + "Provided xpub does not match the node's master seed for {:?}/{}", + address_type, + account_index ); + return Err(Error::InvalidSeedBytes); + } + + let _op = self.operation_lock.lock().unwrap(); - self.payment_store.insert_or_update(payment)?; + { + let mut aggregate = self.inner.lock().unwrap(); + if aggregate.loaded_keys().contains(&wallet_account) { + aggregate.persist_all().map_err(|e| { + log_error!( + self.logger, + "Failed to persist derived account {:?}: {}", + wallet_account, + e + ); + Error::PersistenceFailed + })?; + drop(aggregate); + let mut runtime_config = self.address_type_runtime_config.write().unwrap(); + if !runtime_config.derived_accounts.contains(&wallet_account) { + runtime_config.derived_accounts.push(wallet_account); + } + log_info!(self.logger, "Derived account {:?} already loaded", wallet_account); + return Ok(()); + } + } + + let (wallet, persister) = create_wallet_for_account( + &*self.seed_bytes, + self.config.network, + wallet_account, + self.current_best_block(), + Arc::clone(&self.kv_store), + Arc::clone(&self.logger), + Some(self.derived_account_lookahead), + )?; + + { + let mut aggregate = self.inner.lock().unwrap(); + aggregate.add_wallet_and_persist(wallet_account, wallet, persister).map_err(|e| { + log_error!( + self.logger, + "Failed to add derived account {:?}: {}", + wallet_account, + e + ); + match e { + bdk_wallet_aggregate::Error::PersistenceFailed => Error::PersistenceFailed, + _ => Error::WalletOperationFailed, + } + })?; + self.account_generation.fetch_add(1, Ordering::AcqRel); + let mut runtime_config = self.address_type_runtime_config.write().unwrap(); + if !runtime_config.derived_accounts.contains(&wallet_account) { + runtime_config.derived_accounts.push(wallet_account); + } + } + + log_info!(self.logger, "Registered derived on-chain wallet account {:?}", wallet_account); + Ok(()) + } + + /// Unloads a derived on-chain wallet account while retaining its persisted state. + pub(crate) fn remove_onchain_wallet_account( + &self, address_type: AddressType, account_index: u32, + ) -> Result<(), Error> { + if account_index == 0 || account_index > crate::config::MAX_ONCHAIN_WALLET_ACCOUNT_INDEX { + return Err(Error::InvalidQuantity); + } + + let wallet_account = OnchainWalletAccount { address_type, account_index }; + let _op = self.operation_lock.lock().unwrap(); + if !self + .address_type_runtime_config + .read() + .unwrap() + .derived_accounts + .contains(&wallet_account) + { + return Err(Error::OnchainWalletAccountNotRegistered); + } + + let removed = { + let mut aggregate = self.inner.lock().unwrap(); + match aggregate.remove_wallet(wallet_account) { + Ok(()) => true, + Err(bdk_wallet_aggregate::Error::WalletNotFound) => false, + Err(e) => { + log_error!( + self.logger, + "Failed to remove derived account {:?}: {}", + wallet_account, + e + ); + return Err(Error::WalletOperationFailed); + }, + } + }; + + self.address_type_runtime_config + .write() + .unwrap() + .derived_accounts + .retain(|account| *account != wallet_account); + self.synced_derived_accounts.lock().unwrap().remove(&wallet_account); + if removed { + self.account_generation.fetch_add(1, Ordering::AcqRel); + } + + log_info!(self.logger, "Removed derived on-chain wallet account {:?}", wallet_account); + Ok(()) + } + + /// Callers are responsible for calling `update_payment_store_for_all_transactions` + /// after all updates have been applied. + pub(crate) fn apply_update( + &self, update: impl Into, + ) -> Result, Error> { + let mut locked_wallet = self.inner.lock().unwrap(); + match locked_wallet.apply_update(update) { + Ok((events, _txids)) => Ok(events), + Err(e) => { + log_error!(self.logger, "Sync failed due to chain connection error: {}", e); + Err(match e { + bdk_wallet_aggregate::Error::PersistenceFailed + | bdk_wallet_aggregate::Error::PersisterNotFound => Error::PersistenceFailed, + _ => Error::WalletOperationFailed, + }) + }, + } + } + + /// Callers are responsible for calling `update_payment_store_for_all_transactions` + /// after all updates have been applied. + pub(crate) fn apply_update_for_wallet_account( + &self, wallet_account: OnchainWalletAccount, update: impl Into, + ) -> Result>, Error> { + let _op = self.operation_lock.lock().unwrap(); + let mut locked_wallet = self.inner.lock().unwrap(); + if locked_wallet.wallet(&wallet_account).is_none() { + return Ok(None); + } + match locked_wallet.apply_update_to_wallet(wallet_account, update) { + Ok((events, _txids)) => Ok(Some(events)), + Err(e) => { + log_error!( + self.logger, + "Failed to apply update for wallet account {:?}: {}", + wallet_account, + e + ); + Err(match e { + bdk_wallet_aggregate::Error::PersistenceFailed + | bdk_wallet_aggregate::Error::PersisterNotFound => Error::PersistenceFailed, + _ => Error::WalletOperationFailed, + }) + }, } + } + + pub(crate) fn apply_mempool_txs( + &self, unconfirmed_txs: Vec<(Transaction, u64)>, evicted_txids: Vec<(Txid, u64)>, + ) -> Result<(), Error> { + let mut locked_wallet = self.inner.lock().unwrap(); + self.payment_store_update_pending.store(true, Ordering::Release); + locked_wallet.apply_mempool_txs(unconfirmed_txs, evicted_txids).map_err(|e| { + log_error!(self.logger, "Failed to apply mempool txs: {}", e); + Error::PersistenceFailed + })?; + self.update_payment_store(&locked_wallet) + } + + // Bumps the fee of an existing transaction using Replace-By-Fee (RBF). + // Returns the txid of the new transaction if successful. + pub(crate) fn bump_fee_by_rbf( + &self, txid: &Txid, fee_rate: FeeRate, channel_manager: &ChannelManager, + ) -> Result { + // Check if this is a funding transaction + if self.is_funding_transaction(txid, channel_manager) { + log_error!( + self.logger, + "Cannot RBF transaction {}: it is a channel funding transaction", + txid + ); + return Err(Error::CannotRbfFundingTransaction); + } + + let mut locked_wallet = self.inner.lock().unwrap(); + + let (tx, original_fee) = locked_wallet.build_rbf(*txid, fee_rate).map_err(|e| match e { + bdk_wallet_aggregate::Error::TransactionNotFound => { + log_error!(self.logger, "Transaction not found in any wallet: {}", txid); + Error::TransactionNotFound + }, + bdk_wallet_aggregate::Error::TransactionAlreadyConfirmed => { + log_error!(self.logger, "Cannot replace confirmed transaction: {}", txid); + Error::TransactionAlreadyConfirmed + }, + bdk_wallet_aggregate::Error::InvalidFeeRate => { + log_error!(self.logger, "RBF rejected: new fee rate is not higher"); + Error::InvalidFeeRate + }, + bdk_wallet_aggregate::Error::InsufficientFunds => { + log_error!(self.logger, "Insufficient funds for RBF fee bump of {}", txid); + Error::InsufficientFunds + }, + bdk_wallet_aggregate::Error::UtxoNotFoundLocally(outpoint) => { + log_error!( + self.logger, + "Cannot calculate fee for RBF of {}: input UTXO {} not found locally. \ + Try syncing the wallet first.", + txid, + outpoint, + ); + Error::OnchainTxCreationFailed + }, + other => { + log_error!(self.logger, "Failed to build RBF for {}: {}", txid, other); + Error::OnchainTxCreationFailed + }, + })?; + + // Persist wallet changes + locked_wallet.persist_all().map_err(|e| { + log_error!(self.logger, "Failed to persist wallet: {}", e); + Error::PersistenceFailed + })?; + + // Extract and broadcast the transaction + self.broadcaster.broadcast_transactions(&[&tx]); + + let new_txid = tx.compute_txid(); + + // Calculate and log the actual fee increase achieved + let new_fee = locked_wallet.calculate_tx_fee(&tx).unwrap_or(Amount::ZERO); + let actual_fee_rate = new_fee / tx.weight(); + + log_info!(self.logger, "RBF transaction created successfully!"); + log_info!(self.logger, " Original: {} ({} sats fee)", txid, original_fee.to_sat()); + log_info!( + self.logger, + " Replacement: {} ({} sat/vB, {} sats fee)", + new_txid, + actual_fee_rate.to_sat_per_vb_ceil(), + new_fee.to_sat() + ); + log_info!( + self.logger, + " Additional fee paid: {} sats", + new_fee.to_sat().saturating_sub(original_fee.to_sat()) + ); + + Ok(new_txid) + } + + // Accelerates confirmation of a transaction using Child-Pays-For-Parent (CPFP). + // Returns the txid of the child transaction if successful. + pub(crate) fn accelerate_by_cpfp( + &self, txid: &Txid, fee_rate: FeeRate, destination_address: Option
, + ) -> Result { + let destination_script = match destination_address { + Some(ref addr) => { + self.parse_and_validate_address(addr)?; + Some(addr.script_pubkey()) + }, + None => None, + }; + + let mut locked_wallet = self.inner.lock().unwrap(); + + let (tx, parent_fee, parent_fee_rate) = + locked_wallet.build_cpfp(*txid, fee_rate, destination_script).map_err(|e| { + log_error!(self.logger, "Failed to build CPFP for {}: {}", txid, e); + match e { + bdk_wallet_aggregate::Error::TransactionNotFound => Error::TransactionNotFound, + bdk_wallet_aggregate::Error::TransactionAlreadyConfirmed => { + Error::TransactionAlreadyConfirmed + }, + bdk_wallet_aggregate::Error::NoSpendableOutputs => Error::NoSpendableOutputs, + _ => Error::OnchainTxCreationFailed, + } + })?; + + // Persist wallet changes + locked_wallet.persist_all().map_err(|e| { + log_error!(self.logger, "Failed to persist wallet: {}", e); + Error::PersistenceFailed + })?; + + // Extract and broadcast the transaction + self.broadcaster.broadcast_transactions(&[&tx]); + + let child_txid = tx.compute_txid(); + + // Calculate and log the actual results + let child_fee = locked_wallet.calculate_tx_fee(&tx).unwrap_or(Amount::ZERO); + let actual_child_fee_rate = child_fee / tx.weight(); + + log_info!(self.logger, "CPFP transaction created successfully!"); + log_info!( + self.logger, + " Parent: {} ({} sat/vB, {} sats fee)", + txid, + parent_fee_rate.to_sat_per_vb_ceil(), + parent_fee.to_sat() + ); + log_info!( + self.logger, + " Child: {} ({} sat/vB, {} sats fee)", + child_txid, + actual_child_fee_rate.to_sat_per_vb_ceil(), + child_fee.to_sat() + ); + + Ok(child_txid) + } + + // Calculates an appropriate fee rate for a CPFP transaction. + pub(crate) fn calculate_cpfp_fee_rate( + &self, parent_txid: &Txid, urgent: bool, + ) -> Result { + let target = if urgent { + ConfirmationTarget::Lightning( + lightning::chain::chaininterface::ConfirmationTarget::MaximumFeeEstimate, + ) + } else { + ConfirmationTarget::OnchainPayment + }; + let target_fee_rate = self.fee_estimator.estimate_fee_rate(target); + + let locked_wallet = self.inner.lock().unwrap(); + locked_wallet.calculate_cpfp_fee_rate(*parent_txid, target_fee_rate).map_err(|e| { + log_error!(self.logger, "Failed to calculate CPFP fee rate for {}: {}", parent_txid, e); + match e { + bdk_wallet_aggregate::Error::TransactionNotFound => Error::TransactionNotFound, + bdk_wallet_aggregate::Error::TransactionAlreadyConfirmed => { + Error::TransactionAlreadyConfirmed + }, + _ => Error::WalletOperationFailed, + } + }) + } + + pub(crate) fn update_payment_store_for_all_transactions(&self) -> Result<(), Error> { + let locked_wallet = self.inner.lock().unwrap(); + self.update_payment_store(&locked_wallet) + } + + fn update_payment_store( + &self, locked_wallet: &AggregateWallet, + ) -> Result<(), Error> { + self.payment_store_update_pending.store(true, Ordering::Release); + let result = self.update_payment_store_inner(locked_wallet); + if result.is_ok() { + self.payment_store_update_pending.store(false, Ordering::Release); + } + result + } + + fn update_payment_store_inner( + &self, locked_wallet: &AggregateWallet, + ) -> Result<(), Error> { + let mut seen_txids = std::collections::HashSet::new(); + let cur_height = locked_wallet.current_best_block().1; + let transaction_confirmations = locked_wallet.transaction_confirmations(); + + for wallet in locked_wallet.wallets().values() { + for wtx in wallet.transactions() { + let txid = wtx.tx_node.txid; + if !seen_txids.insert(txid) { + continue; + } + + let id = PaymentId(txid.to_byte_array()); + let (payment_status, confirmation_status) = + if let Some(anchor) = transaction_confirmations.get(&txid).copied() { + let confirmation_height = anchor.block_id.height; + let payment_status = + if cur_height >= confirmation_height + ANTI_REORG_DELAY - 1 { + PaymentStatus::Succeeded + } else { + PaymentStatus::Pending + }; + let confirmation_status = ConfirmationStatus::Confirmed { + block_hash: anchor.block_id.hash, + height: confirmation_height, + timestamp: anchor.confirmation_time, + }; + (payment_status, confirmation_status) + } else { + (PaymentStatus::Pending, ConfirmationStatus::Unconfirmed) + }; + // TODO: It would be great to introduce additional variants for + // `ChannelFunding` and `ChannelClosing`. For the former, we could just + // take a reference to `ChannelManager` here and check against + // `list_channels`. But for the latter the best approach is much less + // clear: for force-closes/HTLC spends we should be good querying + // `OutputSweeper::tracked_spendable_outputs`, but regular channel closes + // (i.e., `SpendableOutputDescriptor::StaticOutput` variants) are directly + // spent to a wallet address. The only solution I can come up with is to + // create and persist a list of 'static pending outputs' that we could use + // here to determine the `PaymentKind`, but that's not really satisfactory, so + // we're punting on it until we can come up with a better solution. + let kind = + crate::payment::PaymentKind::Onchain { txid, status: confirmation_status }; + + let fee = locked_wallet.calculate_tx_fee(&wtx.tx_node.tx).unwrap_or(Amount::ZERO); + let (sent_sat, received_sat) = + locked_wallet.sent_and_received(txid).unwrap_or((0, 0)); + let fee_sat = fee.to_sat(); + + let (direction, amount_msat) = if sent_sat > received_sat { + let direction = PaymentDirection::Outbound; + let amount_msat = + Some(sent_sat.saturating_sub(fee_sat).saturating_sub(received_sat) * 1000); + (direction, amount_msat) + } else { + let direction = PaymentDirection::Inbound; + let amount_msat = + Some(received_sat.saturating_sub(sent_sat.saturating_sub(fee_sat)) * 1000); + (direction, amount_msat) + }; + + let fee_paid_msat = Some(fee_sat * 1000); + + let payment = PaymentDetails::new( + id, + kind, + amount_msat, + fee_paid_msat, + direction, + payment_status, + ); + + self.payment_store.insert_or_update(payment)?; + } + } + + Ok(()) + } + + #[allow(deprecated)] + pub(crate) fn create_funding_transaction( + &self, output_script: ScriptBuf, amount: Amount, confirmation_target: ConfirmationTarget, + locktime: LockTime, + ) -> Result { + let fee_rate = self.fee_estimator.estimate_fee_rate(confirmation_target); + let mut locked_wallet = self.inner.lock().unwrap(); + let primary_account = locked_wallet.primary_key(); + + let tx = if primary_account.address_type == AddressType::Legacy { + log_info!( + self.logger, + "Primary is Legacy, using best account-0 SegWit wallet for channel funding" + ); + locked_wallet.build_and_sign_tx_with_best_wallet( + output_script, + amount, + fee_rate, + locktime, + |k| k.account_index == 0 && k.address_type != AddressType::Legacy, + ) + } else { + locked_wallet.build_and_sign_funding_tx(output_script, amount, fee_rate, locktime) + }; + + tx.map_err(|e| { + log_error!(self.logger, "Failed to create funding transaction: {}", e); + match e { + bdk_wallet_aggregate::Error::InsufficientFunds => Error::InsufficientFunds, + bdk_wallet_aggregate::Error::OnchainTxSigningFailed => { + Error::OnchainTxSigningFailed + }, + bdk_wallet_aggregate::Error::PersistenceFailed => Error::PersistenceFailed, + _ => Error::OnchainTxCreationFailed, + } + }) + } + + pub(crate) fn get_new_address(&self) -> Result { + self.get_new_address_info().map(|address_info| address_info.address) + } + + pub(crate) fn get_new_address_info(&self) -> Result { + let mut locked_wallet = self.inner.lock().unwrap(); + locked_wallet.new_address_info().map_err(|e| { + log_error!(self.logger, "Failed to get new address: {}", e); + Error::WalletOperationFailed + }) + } + + pub(crate) fn get_new_address_for_type( + &self, address_type: AddressType, + ) -> Result { + self.get_new_address_info_for_type(address_type).map(|address_info| address_info.address) + } + + pub(crate) fn get_new_address_info_for_type( + &self, address_type: AddressType, + ) -> Result { + self.get_new_address_info_for_account(OnchainWalletAccount::account_zero(address_type)) + } + + pub(crate) fn get_new_address_info_for_account( + &self, wallet_account: OnchainWalletAccount, + ) -> Result { + let mut locked_wallet = self.inner.lock().unwrap(); + locked_wallet.new_address_info_for(&wallet_account).map_err(|e| { + log_error!( + self.logger, + "Failed to get new address for account {:?}: {}", + wallet_account, + e + ); + map_wallet_account_error(wallet_account, e) + }) + } + + pub(crate) fn get_new_address_for_account( + &self, wallet_account: OnchainWalletAccount, + ) -> Result { + self.get_new_address_info_for_account(wallet_account) + .map(|address_info| address_info.address) + } + + pub(crate) fn get_address_info_for_type_at_index( + &self, address_type: AddressType, keychain: KeychainKind, index: u32, + ) -> Result { + self.get_address_info_for_account_at_index( + OnchainWalletAccount::account_zero(address_type), + keychain, + index, + ) + } + + pub(crate) fn get_address_info_for_account_at_index( + &self, wallet_account: OnchainWalletAccount, keychain: KeychainKind, index: u32, + ) -> Result { + validate_derivation_index(index)?; + + let locked_wallet = self.inner.lock().unwrap(); + locked_wallet.address_info_for(&wallet_account, keychain.into(), index).map_err(|e| { + log_error!( + self.logger, + "Failed to get address info for account {:?} keychain {:?} at index {}: {}", + wallet_account, + keychain, + index, + e + ); + map_wallet_account_error(wallet_account, e) + }) + } + + pub(crate) fn get_address_infos_for_type( + &self, address_type: AddressType, keychain: KeychainKind, start_index: u32, count: u32, + ) -> Result, Error> { + self.get_address_infos_for_account( + OnchainWalletAccount::account_zero(address_type), + keychain, + start_index, + count, + ) + } + + pub(crate) fn get_address_infos_for_account( + &self, wallet_account: OnchainWalletAccount, keychain: KeychainKind, start_index: u32, + count: u32, + ) -> Result, Error> { + validate_derivation_range(start_index, count)?; + + let locked_wallet = self.inner.lock().unwrap(); + locked_wallet + .address_infos_for(&wallet_account, keychain.into(), start_index, count) + .map_err(|e| { + log_error!( + self.logger, + "Failed to get address infos for account {:?} keychain {:?} at indexes {}..{}: {}", + wallet_account, + keychain, + start_index, + start_index.saturating_add(count), + e + ); + map_wallet_account_error(wallet_account, e) + }) + } + + pub(crate) fn reveal_receive_addresses_to( + &self, address_type: AddressType, index: u32, + ) -> Result<(), Error> { + self.reveal_receive_addresses_to_account( + OnchainWalletAccount::account_zero(address_type), + index, + ) + } + + pub(crate) fn reveal_receive_addresses_to_account( + &self, wallet_account: OnchainWalletAccount, index: u32, + ) -> Result<(), Error> { + validate_derivation_index(index)?; + let mut locked_wallet = self.inner.lock().unwrap(); + locked_wallet.reveal_addresses_to(&wallet_account, index).map_err(|e| { + log_error!( + self.logger, + "Failed to reveal receive addresses through {} for account {:?}: {}", + index, + wallet_account, + e + ); + map_wallet_account_error(wallet_account, e) + }) + } + + // Returns a native witness address for Lightning channel scripts. + // Falls back to a loaded NativeSegwit/Taproot wallet if the primary is not one. + pub(crate) fn get_new_witness_address(&self) -> Result { + let locked_wallet = self.inner.lock().unwrap(); + let primary = locked_wallet.primary_key(); + + if primary.account_index == 0 && primary.address_type.is_native_witness() { + drop(locked_wallet); + return self.get_new_address(); + } + + let witness_key = locked_wallet + .loaded_keys() + .into_iter() + .find(|k| k.account_index == 0 && k.address_type.is_native_witness()); + drop(locked_wallet); + + match witness_key { + Some(key) => self.get_new_address_for_type(key.address_type), + None => { + log_error!(self.logger, "No native witness wallet loaded for Lightning operations"); + Err(Error::WalletOperationFailed) + }, + } + } + + pub(crate) fn get_new_internal_address(&self) -> Result { + let mut locked_wallet = self.inner.lock().unwrap(); + locked_wallet.new_internal_address().map_err(|e| { + log_error!(self.logger, "Failed to get new internal address: {}", e); + Error::WalletOperationFailed + }) + } + + pub(crate) fn cancel_tx(&self, tx: &Transaction) -> Result<(), Error> { + let mut locked_wallet = self.inner.lock().unwrap(); + locked_wallet.cancel_tx(tx).map_err(|e| { + log_error!(self.logger, "Failed to cancel transaction: {}", e); + Error::PersistenceFailed + }) + } + + pub(crate) fn get_balances( + &self, total_anchor_channels_reserve_sats: u64, + ) -> Result<(u64, u64), Error> { + let balance = self.inner.lock().unwrap().balance(); + + // Make sure `list_confirmed_utxos` returns at least one `Utxo` we could use to spend/bump + // Anchors if we have any confirmed amounts. + #[cfg(debug_assertions)] + if balance.confirmed != Amount::ZERO { + debug_assert!( + self.list_confirmed_utxos_inner().map_or(false, |v| !v.is_empty()), + "Confirmed amounts should always be available for Anchor spending" + ); + } + + self.get_balances_inner(&balance, total_anchor_channels_reserve_sats) + } + + pub(crate) fn get_balance_for_address_type( + &self, address_type: AddressType, + ) -> Result<(u64, u64), Error> { + self.get_balance_for_onchain_wallet_account(OnchainWalletAccount::account_zero( + address_type, + )) + } + + pub(crate) fn get_balance_for_onchain_wallet_account( + &self, wallet_account: OnchainWalletAccount, + ) -> Result<(u64, u64), Error> { + let locked_wallet = self.inner.lock().unwrap(); + let balance = locked_wallet.balance_for(&wallet_account).map_err(|e| { + log_error!(self.logger, "Failed to get balance for {:?}: {}", wallet_account, e); + map_wallet_account_error(wallet_account, e) + })?; + + self.get_balances_inner(&balance, 0) + } + + fn get_balances_inner( + &self, balance: &Balance, total_anchor_channels_reserve_sats: u64, + ) -> Result<(u64, u64), Error> { + let spendable_base = if self.config.include_untrusted_pending_in_spendable { + balance.trusted_spendable().to_sat() + balance.untrusted_pending.to_sat() + } else { + balance.trusted_spendable().to_sat() + }; + + let (total, spendable) = ( + balance.total().to_sat(), + spendable_base.saturating_sub(total_anchor_channels_reserve_sats), + ); + + Ok((total, spendable)) + } + + pub(crate) fn get_spendable_amount_sats( + &self, total_anchor_channels_reserve_sats: u64, + ) -> Result { + self.get_balances(total_anchor_channels_reserve_sats).map(|(_, s)| s) + } + + pub(crate) fn get_witness_spendable_amount_sats( + &self, total_anchor_channels_reserve_sats: u64, + ) -> Result { + let locked_wallet = self.inner.lock().unwrap(); + // Legacy-primary funding needs an account-0 non-Legacy wallet as the builder/change + // wallet. Derived SegWit UTXOs can still be selected as foreign inputs once that builder + // exists, so count all non-Legacy funds only when such a builder is loaded. + let has_account_zero_segwit_builder = locked_wallet + .loaded_keys() + .iter() + .any(|k| k.account_index == 0 && k.address_type != AddressType::Legacy); + if !has_account_zero_segwit_builder { + return Ok(0); + } + let balance = locked_wallet.balance_filtered(|k| k.address_type != AddressType::Legacy); + self.get_balances_inner(&balance, total_anchor_channels_reserve_sats).map(|(_, s)| s) + } + + // Get transaction details including inputs, outputs, and net amount. + // Returns None if the transaction is not found in any wallet. + pub(crate) fn get_tx_details(&self, txid: &Txid) -> Option<(i64, Vec, Vec)> { + let locked_wallet = self.inner.lock().unwrap(); + let (sent_sat, received_sat) = locked_wallet.sent_and_received(*txid)?; + let tx = locked_wallet.find_tx(*txid)?; + let net_amount = received_sat as i64 - sent_sat as i64; + + let inputs: Vec = tx.input.iter().map(TxInput::from_tx_input).collect(); + + let outputs: Vec = tx + .output + .iter() + .enumerate() + .map(|(index, tx_output)| { + TxOutput::from_tx_output(tx_output, index as u32, self.config.network) + }) + .collect(); + + Some((net_amount, inputs, outputs)) + } + + pub(crate) fn parse_and_validate_address(&self, address: &Address) -> Result { + Address::::from_str(address.to_string().as_str()) + .map_err(|_| Error::InvalidAddress)? + .require_network(self.config.network) + .map_err(|_| Error::InvalidAddress) + } + + // Returns all UTXOs that are safe to spend (excluding channel funding transactions). + pub fn get_spendable_utxos( + &self, channel_manager: &ChannelManager, + ) -> Result, Error> { + let locked_wallet = self.inner.lock().unwrap(); + + let all_utxos: Vec = locked_wallet.list_unspent(); + let total_count = all_utxos.len(); + + // Filter out channel funding transactions + let spendable_utxos: Vec = all_utxos + .into_iter() + .filter(|utxo| { + // Check if this UTXO's transaction is a channel funding transaction + if self.is_funding_transaction(&utxo.outpoint.txid, channel_manager) { + log_debug!( + self.logger, + "Filtering out UTXO {:?} as it's part of a channel funding transaction", + utxo.outpoint + ); + false + } else { + true + } + }) + .collect(); + + log_debug!( + self.logger, + "Found {} spendable UTXOs out of {} total UTXOs", + spendable_utxos.len(), + total_count + ); + + Ok(spendable_utxos) + } + + // Select UTXOs using a specific coin selection algorithm. + // Returns selected UTXOs that meet the target amount plus fees, excluding channel funding txs. + pub fn select_utxos_with_algorithm( + &self, target_amount: u64, available_utxos: Vec, fee_rate: FeeRate, + algorithm: CoinSelectionAlgorithm, drain_script: &Script, channel_manager: &ChannelManager, + ) -> Result, Error> { + let excluded_outpoints: Vec = available_utxos + .iter() + .filter(|utxo| self.is_funding_transaction(&utxo.outpoint.txid, channel_manager)) + .map(|utxo| utxo.outpoint) + .collect(); + + let locked_wallet = self.inner.lock().unwrap(); + let algo = match algorithm { + CoinSelectionAlgorithm::BranchAndBound => { + bdk_wallet_aggregate::CoinSelectionAlgorithm::BranchAndBound + }, + CoinSelectionAlgorithm::LargestFirst => { + bdk_wallet_aggregate::CoinSelectionAlgorithm::LargestFirst + }, + CoinSelectionAlgorithm::OldestFirst => { + bdk_wallet_aggregate::CoinSelectionAlgorithm::OldestFirst + }, + CoinSelectionAlgorithm::SingleRandomDraw => { + bdk_wallet_aggregate::CoinSelectionAlgorithm::SingleRandomDraw + }, + }; + + locked_wallet + .select_utxos( + target_amount, + available_utxos, + fee_rate, + algo, + drain_script, + &excluded_outpoints, + ) + .map_err(|e| { + log_error!(self.logger, "Coin selection failed: {}", e); + Error::CoinSelectionFailed + }) + } + + // Helper that builds a transaction PSBT with shared logic for send_to_address + // and calculate_transaction_fee. + // Supports cross-wallet spending: unified coin selection pools UTXOs from all + // loaded wallets and selects optimally across the full set. + fn build_transaction_psbt( + &self, address: &Address, send_amount: OnchainSendAmount, fee_rate: FeeRate, + utxos_to_spend: Option>, channel_manager: &ChannelManager, + ) -> Result< + (Psbt, MutexGuard<'_, AggregateWallet>), + Error, + > { + let mut locked_wallet = self.inner.lock().unwrap(); + + let all_utxos = locked_wallet.list_unspent(); + + // Validate and check UTXOs if provided + if let Some(ref outpoints) = utxos_to_spend { + let all_utxo_set: std::collections::HashSet<_> = + all_utxos.iter().map(|u| u.outpoint).collect(); + + for outpoint in outpoints { + if !all_utxo_set.contains(outpoint) { + log_error!(self.logger, "UTXO {:?} not found in any wallet", outpoint); + return Err(Error::WalletOperationFailed); + } + if self.is_funding_transaction(&outpoint.txid, channel_manager) { + log_error!( + self.logger, + "UTXO {:?} is part of a channel funding transaction and cannot be spent", + outpoint + ); + return Err(Error::WalletOperationFailed); + } + } + + // Calculate total value of selected UTXOs + let selected_value: u64 = all_utxos + .iter() + .filter(|u| outpoints.contains(&u.outpoint)) + .map(|u| u.txout.value.to_sat()) + .sum(); + + // For exact amounts, ensure we have enough value + if let OnchainSendAmount::ExactRetainingReserve { amount_sats, .. } = send_amount { + // Calculate a fee buffer based on fee rate + // Assume a typical tx with 1 input and 2 outputs (~200 vbytes) + let typical_tx_weight = Weight::from_vb(200).expect("Valid weight"); + let fee_buffer = + fee_rate.fee_wu(typical_tx_weight).expect("Valid fee calculation").to_sat(); + // Use at least 1000 sats as minimum buffer + let min_fee_buffer = fee_buffer.max(1000); + let min_required = amount_sats.saturating_add(min_fee_buffer); + if selected_value < min_required { + log_error!( + self.logger, + "Selected UTXOs have insufficient value. Have: {}sats, Need at least: {}sats", + selected_value, + min_required + ); + return Err(Error::InsufficientFunds); + } + } + + log_debug!( + self.logger, + "Using {} manually selected UTXOs with total value: {}sats", + outpoints.len(), + selected_value + ); + } + + let funding_txids: std::collections::HashSet = all_utxos + .iter() + .filter(|u| self.is_funding_transaction(&u.outpoint.txid, channel_manager)) + .map(|u| u.outpoint.txid) + .collect(); + + let non_primary_utxo_infos: Option> = + match (&utxos_to_spend, send_amount) { + (Some(_), _) => None, + (None, OnchainSendAmount::AllDrainingReserve) + | (None, OnchainSendAmount::AllRetainingReserve { .. }) => { + let infos = + locked_wallet.non_primary_foreign_utxos(&funding_txids).map_err(|e| { + log_error!(self.logger, "Failed to prepare non-primary UTXOs: {}", e); + Error::WalletOperationFailed + })?; + (!infos.is_empty()).then_some(infos) + }, + (None, OnchainSendAmount::ExactRetainingReserve { .. }) => None, + }; + + let manual_utxo_infos: Option> = + if let Some(ref outpoints) = utxos_to_spend { + Some(locked_wallet.prepare_outpoints_for_psbt(outpoints).map_err(|e| { + log_error!(self.logger, "Failed to prepare manually selected UTXOs: {}", e); + Error::WalletOperationFailed + })?) + } else { + None + }; + + let aggregate_balance = locked_wallet.balance(); + + // Prepare the tx_builder. We properly check the reserve requirements (again) further down. + let mut tx_builder = match send_amount { + OnchainSendAmount::ExactRetainingReserve { amount_sats, .. } => { + let primary = locked_wallet.primary_wallet_mut(); + let mut tx_builder = primary.build_tx(); + let amount = Amount::from_sat(amount_sats); + tx_builder.add_recipient(address.script_pubkey(), amount).fee_rate(fee_rate); + tx_builder + }, + OnchainSendAmount::AllRetainingReserve { cur_anchor_reserve_sats } + if cur_anchor_reserve_sats > DUST_LIMIT_SATS => + { + let change_address_info = + locked_wallet.primary_wallet().peek_address(BdkKeychainKind::Internal, 0); + let spendable_amount_sats = self + .get_balances_inner(&aggregate_balance, cur_anchor_reserve_sats) + .map(|(_, s)| s) + .unwrap_or(0); + let tmp_psbt = { + let primary = locked_wallet.primary_wallet_mut(); + let mut tmp_tx_builder = primary.build_tx(); + tmp_tx_builder + .drain_wallet() + .drain_to(address.script_pubkey()) + .add_recipient( + change_address_info.address.script_pubkey(), + Amount::from_sat(cur_anchor_reserve_sats), + ) + .fee_rate(fee_rate); + + if let Some(ref infos) = manual_utxo_infos { + bdk_wallet_aggregate::utxo::add_utxos_to_tx_builder( + &mut tmp_tx_builder, + infos, + ) + .map_err(|e| { + log_error!(self.logger, "Failed to add UTXOs to temp tx: {}", e); + Error::OnchainTxCreationFailed + })?; + tmp_tx_builder.manually_selected_only(); + } + + match tmp_tx_builder.finish() { + Ok(psbt) => psbt, + Err(err) => { + log_error!( + self.logger, + "Failed to create temporary transaction: {}", + err + ); + return Err(err.into()); + }, + } + }; + + // Cancel the temp tx to free up the change address. + locked_wallet.cancel_dry_run_tx(&tmp_psbt.unsigned_tx); + + let base_fee = locked_wallet.calculate_fee_from_psbt(&tmp_psbt).map_err(|e| { + log_error!( + self.logger, + "Failed to calculate fee of temporary transaction: {}", + e + ); + Error::WalletOperationFailed + })?; + let base_fee = Amount::from_sat(base_fee); + + // Adjust the fee estimate for non-primary inputs that will be + // added to the actual tx (the temp tx only used primary UTXOs). + let extra_input_weight = non_primary_utxo_infos + .as_deref() + .map(additional_input_weight) + .transpose()? + .unwrap_or(Weight::ZERO); + let extra_input_fee = + fee_rate.fee_wu(extra_input_weight).ok_or(Error::InvalidFeeRate)?; + let estimated_tx_fee = + base_fee.checked_add(extra_input_fee).ok_or(Error::InvalidFeeRate)?; + + let estimated_spendable_amount = Amount::from_sat( + spendable_amount_sats.saturating_sub(estimated_tx_fee.to_sat()), + ); - Ok(()) - } + if estimated_spendable_amount < Amount::from_sat(DUST_LIMIT_SATS) { + log_error!(self.logger, + "Unable to send payment without infringing on Anchor reserves. Available: {}sats, estimated fee required: {}sats.", + spendable_amount_sats, + estimated_tx_fee, + ); + return Err(Error::InsufficientFunds); + } - #[allow(deprecated)] - pub(crate) fn create_funding_transaction( - &self, output_script: ScriptBuf, amount: Amount, confirmation_target: ConfirmationTarget, - locktime: LockTime, - ) -> Result { - let fee_rate = self.fee_estimator.estimate_fee_rate(confirmation_target); + let primary = locked_wallet.primary_wallet_mut(); + let mut tx_builder = primary.build_tx(); + tx_builder + .add_recipient(address.script_pubkey(), estimated_spendable_amount) + .fee_absolute(estimated_tx_fee); + tx_builder + }, + OnchainSendAmount::AllDrainingReserve + | OnchainSendAmount::AllRetainingReserve { cur_anchor_reserve_sats: _ } => { + let primary = locked_wallet.primary_wallet_mut(); + let mut tx_builder = primary.build_tx(); + tx_builder.drain_wallet().drain_to(address.script_pubkey()).fee_rate(fee_rate); + tx_builder + }, + }; - let mut locked_wallet = self.inner.lock().unwrap(); - let mut tx_builder = locked_wallet.build_tx(); + if let Some(ref utxo_infos) = manual_utxo_infos { + bdk_wallet_aggregate::utxo::add_utxos_to_tx_builder(&mut tx_builder, utxo_infos) + .map_err(|e| { + log_error!(self.logger, "Failed to add manually selected UTXOs: {}", e); + Error::OnchainTxCreationFailed + })?; + tx_builder.manually_selected_only(); + } - tx_builder.add_recipient(output_script, amount).fee_rate(fee_rate).nlocktime(locktime); + if let Some(ref infos) = non_primary_utxo_infos { + bdk_wallet_aggregate::utxo::add_utxos_to_tx_builder(&mut tx_builder, infos).map_err( + |e| { + log_error!(self.logger, "Failed to add cross-wallet UTXOs: {}", e); + Error::OnchainTxCreationFailed + }, + )?; + } - let mut psbt = match tx_builder.finish() { + let psbt = match tx_builder.finish() { Ok(psbt) => { - log_trace!(self.logger, "Created funding PSBT: {:?}", psbt); + log_trace!(self.logger, "Created PSBT: {:?}", psbt); psbt }, Err(err) => { - log_error!(self.logger, "Failed to create funding transaction: {}", err); - return Err(err.into()); + let can_retry = + matches!(send_amount, OnchainSendAmount::ExactRetainingReserve { .. }) + && manual_utxo_infos.is_none() + && non_primary_utxo_infos.is_none(); + + if can_retry { + let amount_sats = match send_amount { + OnchainSendAmount::ExactRetainingReserve { amount_sats, .. } => amount_sats, + _ => unreachable!(), + }; + locked_wallet + .build_psbt_with_cross_wallet_fallback( + address.script_pubkey(), + Amount::from_sat(amount_sats), + fee_rate, + &funding_txids, + bdk_wallet_aggregate::CoinSelectionAlgorithm::BranchAndBound, + ) + .map_err(|e| { + log_error!(self.logger, "Failed to create transaction: {}", e); + match e { + bdk_wallet_aggregate::Error::InsufficientFunds => { + Error::InsufficientFunds + }, + _ => Error::OnchainTxCreationFailed, + } + })? + } else { + log_error!(self.logger, "Failed to create transaction: {}", err); + return Err(err.into()); + } }, }; - match locked_wallet.sign(&mut psbt, SignOptions::default()) { - Ok(finalized) => { - if !finalized { - return Err(Error::OnchainTxCreationFailed); + // Check the reserve requirements (again) and return an error if they aren't met. + // Cancel the PSBT before each early return to free up the change address. + match send_amount { + OnchainSendAmount::ExactRetainingReserve { amount_sats, cur_anchor_reserve_sats } => { + let spendable_amount_sats = self + .get_balances_inner(&aggregate_balance, cur_anchor_reserve_sats) + .map(|(_, s)| s) + .unwrap_or(0); + let fee_result = locked_wallet.calculate_fee_with_fallback(&psbt); + let tx_fee_sats = match fee_result { + Ok(fee) => fee, + Err(e) => { + log_error!( + self.logger, + "Failed to calculate fee of candidate transaction: {}", + e + ); + locked_wallet.cancel_dry_run_tx(&psbt.unsigned_tx); + return Err(Error::WalletOperationFailed); + }, + }; + if spendable_amount_sats < amount_sats.saturating_add(tx_fee_sats) { + log_error!(self.logger, + "Unable to send payment due to insufficient funds. Available: {}sats, Required: {}sats + {}sats fee", + spendable_amount_sats, + amount_sats, + tx_fee_sats, + ); + locked_wallet.cancel_dry_run_tx(&psbt.unsigned_tx); + return Err(Error::InsufficientFunds); } }, - Err(err) => { - log_error!(self.logger, "Failed to create funding transaction: {}", err); - return Err(err.into()); + OnchainSendAmount::AllRetainingReserve { cur_anchor_reserve_sats } => { + let spendable_amount_sats = self + .get_balances_inner(&aggregate_balance, cur_anchor_reserve_sats) + .map(|(_, s)| s) + .unwrap_or(0); + let drain_amount = locked_wallet.drain_amount_from_psbt(&psbt); + if spendable_amount_sats < drain_amount { + log_error!(self.logger, + "Unable to send payment due to insufficient funds. Available: {}sats, Required: {}sats", + spendable_amount_sats, + drain_amount, + ); + locked_wallet.cancel_dry_run_tx(&psbt.unsigned_tx); + return Err(Error::InsufficientFunds); + } }, + _ => {}, } - let mut locked_persister = self.persister.lock().unwrap(); - locked_wallet.persist(&mut locked_persister).map_err(|e| { - log_error!(self.logger, "Failed to persist wallet: {}", e); - Error::PersistenceFailed - })?; - - let tx = psbt.extract_tx().map_err(|e| { - log_error!(self.logger, "Failed to extract transaction: {}", e); - e - })?; - - Ok(tx) + Ok((psbt, locked_wallet)) } - pub(crate) fn get_new_address(&self) -> Result { - let mut locked_wallet = self.inner.lock().unwrap(); - let mut locked_persister = self.persister.lock().unwrap(); + pub(crate) fn calculate_transaction_fee( + &self, address: &Address, send_amount: OnchainSendAmount, fee_rate: Option, + utxos_to_spend: Option>, channel_manager: &ChannelManager, + ) -> Result { + self.parse_and_validate_address(&address)?; - let address_info = locked_wallet.reveal_next_address(KeychainKind::External); - locked_wallet.persist(&mut locked_persister).map_err(|e| { - log_error!(self.logger, "Failed to persist wallet: {}", e); - Error::PersistenceFailed - })?; - Ok(address_info.address) - } + // Use the set fee_rate or default to fee estimation. + let confirmation_target = ConfirmationTarget::OnchainPayment; + let fee_rate = + fee_rate.unwrap_or_else(|| self.fee_estimator.estimate_fee_rate(confirmation_target)); - pub(crate) fn get_new_internal_address(&self) -> Result { - let mut locked_wallet = self.inner.lock().unwrap(); - let mut locked_persister = self.persister.lock().unwrap(); + let (psbt, mut locked_wallet) = self.build_transaction_psbt( + address, + send_amount, + fee_rate, + utxos_to_spend, + channel_manager, + )?; - let address_info = locked_wallet.next_unused_address(KeychainKind::Internal); - locked_wallet.persist(&mut locked_persister).map_err(|e| { - log_error!(self.logger, "Failed to persist wallet: {}", e); - Error::PersistenceFailed - })?; - Ok(address_info.address) - } + let fee_result = locked_wallet.calculate_fee_with_fallback(&psbt); - pub(crate) fn cancel_tx(&self, tx: &Transaction) -> Result<(), Error> { - let mut locked_wallet = self.inner.lock().unwrap(); - let mut locked_persister = self.persister.lock().unwrap(); + // Cancel the dry-run PSBT to free up the change address. + locked_wallet.cancel_dry_run_tx(&psbt.unsigned_tx); - locked_wallet.cancel_tx(tx); - locked_wallet.persist(&mut locked_persister).map_err(|e| { - log_error!(self.logger, "Failed to persist wallet: {}", e); - Error::PersistenceFailed + let calculated_fee = fee_result.map_err(|e| { + log_error!(self.logger, "Failed to calculate transaction fee: {}", e); + Error::WalletOperationFailed })?; - Ok(()) - } - - pub(crate) fn get_balances( - &self, total_anchor_channels_reserve_sats: u64, - ) -> Result<(u64, u64), Error> { - let balance = self.inner.lock().unwrap().balance(); - - // Make sure `list_confirmed_utxos` returns at least one `Utxo` we could use to spend/bump - // Anchors if we have any confirmed amounts. - #[cfg(debug_assertions)] - if balance.confirmed != Amount::ZERO { - debug_assert!( - self.list_confirmed_utxos_inner().map_or(false, |v| !v.is_empty()), - "Confirmed amounts should always be available for Anchor spending" - ); - } - - self.get_balances_inner(balance, total_anchor_channels_reserve_sats) - } - - fn get_balances_inner( - &self, balance: Balance, total_anchor_channels_reserve_sats: u64, - ) -> Result<(u64, u64), Error> { - let (total, spendable) = ( - balance.total().to_sat(), - balance.trusted_spendable().to_sat().saturating_sub(total_anchor_channels_reserve_sats), + log_info!( + self.logger, + "Calculated transaction fee: {}sats for sending to address {}", + calculated_fee, + address ); - Ok((total, spendable)) - } - - pub(crate) fn get_spendable_amount_sats( - &self, total_anchor_channels_reserve_sats: u64, - ) -> Result { - self.get_balances(total_anchor_channels_reserve_sats).map(|(_, s)| s) - } - - pub(crate) fn parse_and_validate_address(&self, address: &Address) -> Result { - Address::::from_str(address.to_string().as_str()) - .map_err(|_| Error::InvalidAddress)? - .require_network(self.config.network) - .map_err(|_| Error::InvalidAddress) + Ok(calculated_fee) } #[allow(deprecated)] pub(crate) fn send_to_address( - &self, address: &bitcoin::Address, send_amount: OnchainSendAmount, - fee_rate: Option, + &self, address: &Address, send_amount: OnchainSendAmount, fee_rate: Option, + utxos_to_spend: Option>, channel_manager: &ChannelManager, ) -> Result { self.parse_and_validate_address(&address)?; @@ -367,174 +1870,46 @@ impl Wallet { let fee_rate = fee_rate.unwrap_or_else(|| self.fee_estimator.estimate_fee_rate(confirmation_target)); - let tx = { - let mut locked_wallet = self.inner.lock().unwrap(); - - // Prepare the tx_builder. We properly check the reserve requirements (again) further down. - const DUST_LIMIT_SATS: u64 = 546; - let tx_builder = match send_amount { - OnchainSendAmount::ExactRetainingReserve { amount_sats, .. } => { - let mut tx_builder = locked_wallet.build_tx(); - let amount = Amount::from_sat(amount_sats); - tx_builder.add_recipient(address.script_pubkey(), amount).fee_rate(fee_rate); - tx_builder - }, - OnchainSendAmount::AllRetainingReserve { cur_anchor_reserve_sats } - if cur_anchor_reserve_sats > DUST_LIMIT_SATS => - { - let change_address_info = locked_wallet.peek_address(KeychainKind::Internal, 0); - let balance = locked_wallet.balance(); - let spendable_amount_sats = self - .get_balances_inner(balance, cur_anchor_reserve_sats) - .map(|(_, s)| s) - .unwrap_or(0); - let tmp_tx = { - let mut tmp_tx_builder = locked_wallet.build_tx(); - tmp_tx_builder - .drain_wallet() - .drain_to(address.script_pubkey()) - .add_recipient( - change_address_info.address.script_pubkey(), - Amount::from_sat(cur_anchor_reserve_sats), - ) - .fee_rate(fee_rate); - match tmp_tx_builder.finish() { - Ok(psbt) => psbt.unsigned_tx, - Err(err) => { - log_error!( - self.logger, - "Failed to create temporary transaction: {}", - err - ); - return Err(err.into()); - }, - } - }; - - let estimated_tx_fee = locked_wallet.calculate_fee(&tmp_tx).map_err(|e| { - log_error!( - self.logger, - "Failed to calculate fee of temporary transaction: {}", - e - ); - e - })?; - - // 'cancel' the transaction to free up any used change addresses - locked_wallet.cancel_tx(&tmp_tx); - - let estimated_spendable_amount = Amount::from_sat( - spendable_amount_sats.saturating_sub(estimated_tx_fee.to_sat()), - ); - - if estimated_spendable_amount == Amount::ZERO { - log_error!(self.logger, - "Unable to send payment without infringing on Anchor reserves. Available: {}sats, estimated fee required: {}sats.", - spendable_amount_sats, - estimated_tx_fee, - ); - return Err(Error::InsufficientFunds); - } - - let mut tx_builder = locked_wallet.build_tx(); - tx_builder - .add_recipient(address.script_pubkey(), estimated_spendable_amount) - .fee_absolute(estimated_tx_fee); - tx_builder - }, - OnchainSendAmount::AllDrainingReserve - | OnchainSendAmount::AllRetainingReserve { cur_anchor_reserve_sats: _ } => { - let mut tx_builder = locked_wallet.build_tx(); - tx_builder.drain_wallet().drain_to(address.script_pubkey()).fee_rate(fee_rate); - tx_builder - }, - }; - - let mut psbt = match tx_builder.finish() { - Ok(psbt) => { - log_trace!(self.logger, "Created PSBT: {:?}", psbt); - psbt - }, - Err(err) => { - log_error!(self.logger, "Failed to create transaction: {}", err); - return Err(err.into()); - }, - }; - - // Check the reserve requirements (again) and return an error if they aren't met. - match send_amount { - OnchainSendAmount::ExactRetainingReserve { - amount_sats, - cur_anchor_reserve_sats, - } => { - let balance = locked_wallet.balance(); - let spendable_amount_sats = self - .get_balances_inner(balance, cur_anchor_reserve_sats) - .map(|(_, s)| s) - .unwrap_or(0); - let tx_fee_sats = locked_wallet - .calculate_fee(&psbt.unsigned_tx) - .map_err(|e| { - log_error!( - self.logger, - "Failed to calculate fee of candidate transaction: {}", - e - ); - e - })? - .to_sat(); - if spendable_amount_sats < amount_sats.saturating_add(tx_fee_sats) { - log_error!(self.logger, - "Unable to send payment due to insufficient funds. Available: {}sats, Required: {}sats + {}sats fee", - spendable_amount_sats, - amount_sats, - tx_fee_sats, - ); - return Err(Error::InsufficientFunds); - } - }, - OnchainSendAmount::AllRetainingReserve { cur_anchor_reserve_sats } => { - let balance = locked_wallet.balance(); - let spendable_amount_sats = self - .get_balances_inner(balance, cur_anchor_reserve_sats) - .map(|(_, s)| s) - .unwrap_or(0); - let (sent, received) = locked_wallet.sent_and_received(&psbt.unsigned_tx); - let drain_amount = sent - received; - if spendable_amount_sats < drain_amount.to_sat() { - log_error!(self.logger, - "Unable to send payment due to insufficient funds. Available: {}sats, Required: {}", - spendable_amount_sats, - drain_amount, - ); - return Err(Error::InsufficientFunds); - } - }, - _ => {}, - } - - match locked_wallet.sign(&mut psbt, SignOptions::default()) { - Ok(finalized) => { - if !finalized { - return Err(Error::OnchainTxCreationFailed); - } - }, - Err(err) => { - log_error!(self.logger, "Failed to create transaction: {}", err); - return Err(err.into()); - }, - } + let is_drain_all = match send_amount { + OnchainSendAmount::AllDrainingReserve => true, + OnchainSendAmount::AllRetainingReserve { cur_anchor_reserve_sats } => { + cur_anchor_reserve_sats <= DUST_LIMIT_SATS + }, + _ => false, + }; - let mut locked_persister = self.persister.lock().unwrap(); - locked_wallet.persist(&mut locked_persister).map_err(|e| { + let tx = if is_drain_all && utxos_to_spend.is_none() { + let mut locked_wallet = self.inner.lock().unwrap(); + let tx = locked_wallet + .build_and_sign_drain(address.script_pubkey(), fee_rate) + .map_err(|e| { + log_error!(self.logger, "Failed to drain wallets: {}", e); + Error::OnchainTxCreationFailed + })?; + locked_wallet.persist_all().map_err(|e| { log_error!(self.logger, "Failed to persist wallet: {}", e); Error::PersistenceFailed })?; + tx + } else { + let (psbt, mut locked_wallet) = self.build_transaction_psbt( + address, + send_amount, + fee_rate, + utxos_to_spend, + channel_manager, + )?; + + let tx = locked_wallet.sign_psbt_all(psbt).map_err(|e| { + log_error!(self.logger, "Failed to sign transaction: {}", e); + Error::OnchainTxSigningFailed + })?; - psbt.extract_tx().map_err(|e| { - log_error!(self.logger, "Failed to extract transaction: {}", e); - e - })? + locked_wallet.persist_all().map_err(|e| { + log_error!(self.logger, "Failed to persist wallet: {}", e); + Error::PersistenceFailed + })?; + tx }; self.broadcaster.broadcast_transactions(&[&tx]); @@ -553,12 +1928,12 @@ impl Wallet { }, OnchainSendAmount::AllRetainingReserve { cur_anchor_reserve_sats } => { log_info!( - self.logger, - "Created new transaction {} sending available on-chain funds retaining a reserve of {}sats to address {}", - txid, - cur_anchor_reserve_sats, - address, - ); + self.logger, + "Created new transaction {} sending available on-chain funds retaining a reserve of {}sats to address {}", + txid, + cur_anchor_reserve_sats, + address, + ); }, OnchainSendAmount::AllDrainingReserve => { log_info!( @@ -577,14 +1952,16 @@ impl Wallet { &self, must_spend: Vec, must_pay_to: &[TxOut], fee_rate: FeeRate, ) -> Result, ()> { let mut locked_wallet = self.inner.lock().unwrap(); - debug_assert!(matches!( - locked_wallet.public_descriptor(KeychainKind::External), - ExtendedDescriptor::Wpkh(_) - )); - debug_assert!(matches!( - locked_wallet.public_descriptor(KeychainKind::Internal), - ExtendedDescriptor::Wpkh(_) - )); + + // Splicing requires native witness (P2WPKH/P2TR) primary because + // FundingTxInput only supports native witness script types. + if !locked_wallet.primary_key().address_type.is_native_witness() { + log_error!( + self.logger, + "Splicing requires a native witness primary wallet (NativeSegwit or Taproot)" + ); + return Err(()); + } let mut tx_builder = locked_wallet.build_tx(); tx_builder.only_witness_utxo(); @@ -605,11 +1982,11 @@ impl Wallet { tx_builder.fee_rate(fee_rate); tx_builder.exclude_unconfirmed(); - tx_builder - .finish() - .map_err(|e| { - log_error!(self.logger, "Failed to select confirmed UTXOs: {}", e); - })? + let psbt = tx_builder.finish().map_err(|e| { + log_error!(self.logger, "Failed to select confirmed UTXOs: {}", e); + })?; + + let result = psbt .unsigned_tx .input .iter() @@ -620,22 +1997,20 @@ impl Wallet { .map(|tx_details| tx_details.tx.deref().clone()) .map(|prevtx| FundingTxInput::new_p2wpkh(prevtx, txin.previous_output.vout)) }) - .collect::, ()>>() + .collect::, ()>>(); + + // Cancel the dry-run PSBT to free up the change address. + locked_wallet.cancel_dry_run_tx(&psbt.unsigned_tx); + + result } fn list_confirmed_utxos_inner(&self) -> Result, ()> { let locked_wallet = self.inner.lock().unwrap(); let mut utxos = Vec::new(); - let confirmed_txs: Vec = locked_wallet - .transactions() - .filter(|t| t.chain_position.is_confirmed()) - .map(|t| t.tx_node.txid) - .collect(); - let unspent_confirmed_utxos = - locked_wallet.list_unspent().filter(|u| confirmed_txs.contains(&u.outpoint.txid)); - for u in unspent_confirmed_utxos { - let script_pubkey = u.txout.script_pubkey; + for u in locked_wallet.list_confirmed_unspent() { + let script_pubkey = u.txout.script_pubkey.clone(); match script_pubkey.witness_version() { Some(version @ WitnessVersion::V0) => { // According to the SegWit rules of [BIP 141] a witness program is defined as: @@ -703,11 +2078,29 @@ impl Wallet { log_error!(self.logger, "Unexpected witness version: {}", version,); }, None => { - log_error!( - self.logger, - "Tried to use a non-witness script. This must never happen." - ); - panic!("Tried to use a non-witness script. This must never happen."); + let script_bytes = script_pubkey.as_bytes(); + if script_pubkey.is_p2pkh() { + let pkh = PubkeyHash::from_slice(&script_bytes[3..23]).map_err(|e| { + log_error!(self.logger, "Failed to extract PubkeyHash: {}", e); + })?; + utxos.push(Utxo::new_p2pkh(u.outpoint, u.txout.value, &pkh)); + } else if script_pubkey.is_p2sh() { + if let Some(wpkh) = locked_wallet.derive_wpkh_for_p2sh(&u) { + utxos.push(Utxo::new_nested_p2wpkh(u.outpoint, u.txout.value, &wpkh)); + } else { + log_debug!( + self.logger, + "Skipping P2SH UTXO {:?}: could not derive inner WPubkeyHash", + u.outpoint + ); + } + } else { + log_debug!( + self.logger, + "Skipping non-standard non-witness UTXO {:?}", + u.outpoint + ); + } }, } } @@ -718,81 +2111,23 @@ impl Wallet { #[allow(deprecated)] fn get_change_script_inner(&self) -> Result { let mut locked_wallet = self.inner.lock().unwrap(); - let mut locked_persister = self.persister.lock().unwrap(); - - let address_info = locked_wallet.next_unused_address(KeychainKind::Internal); - locked_wallet.persist(&mut locked_persister).map_err(|e| { - log_error!(self.logger, "Failed to persist wallet: {}", e); - () - })?; - Ok(address_info.address.script_pubkey()) + locked_wallet.new_internal_address().map(|addr| addr.script_pubkey()).map_err(|e| { + log_error!(self.logger, "Failed to get change script: {}", e); + }) } - #[allow(deprecated)] pub(crate) fn sign_owned_inputs(&self, unsigned_tx: Transaction) -> Result { - let locked_wallet = self.inner.lock().unwrap(); - - let mut psbt = Psbt::from_unsigned_tx(unsigned_tx).map_err(|e| { - log_error!(self.logger, "Failed to construct PSBT: {}", e); - })?; - for (i, txin) in psbt.unsigned_tx.input.iter().enumerate() { - if let Some(utxo) = locked_wallet.get_utxo(txin.previous_output) { - debug_assert!(!utxo.is_spent); - psbt.inputs[i] = locked_wallet.get_psbt_input(utxo, None, true).map_err(|e| { - log_error!(self.logger, "Failed to construct PSBT input: {}", e); - })?; - } - } - - let mut sign_options = SignOptions::default(); - sign_options.trust_witness_utxo = true; - - match locked_wallet.sign(&mut psbt, sign_options) { - Ok(finalized) => debug_assert!(!finalized), - Err(e) => { - log_error!(self.logger, "Failed to sign owned inputs: {}", e); - return Err(()); - }, - } - - match psbt.extract_tx() { - Ok(tx) => Ok(tx), - Err(bitcoin::psbt::ExtractTxError::MissingInputValue { tx }) => Ok(tx), - Err(e) => { - log_error!(self.logger, "Failed to extract transaction: {}", e); - Err(()) - }, - } + let mut locked_wallet = self.inner.lock().unwrap(); + locked_wallet.sign_owned_inputs(unsigned_tx).map_err(|e| { + log_error!(self.logger, "Failed to sign transaction: {}", e); + }) } - #[allow(deprecated)] - fn sign_psbt_inner(&self, mut psbt: Psbt) -> Result { - let locked_wallet = self.inner.lock().unwrap(); - - // While BDK populates both `witness_utxo` and `non_witness_utxo` fields, LDK does not. As - // BDK by default doesn't trust the witness UTXO to account for the Segwit bug, we must - // disable it here as otherwise we fail to sign. - let mut sign_options = SignOptions::default(); - sign_options.trust_witness_utxo = true; - - match locked_wallet.sign(&mut psbt, sign_options) { - Ok(_finalized) => { - // BDK will fail to finalize for all LDK-provided inputs of the PSBT. Unfortunately - // we can't check more fine grained if it succeeded for all the other inputs here, - // so we just ignore the returned `finalized` bool. - }, - Err(err) => { - log_error!(self.logger, "Failed to sign transaction: {}", err); - return Err(()); - }, - } - - let tx = psbt.extract_tx().map_err(|e| { - log_error!(self.logger, "Failed to extract transaction: {}", e); - () - })?; - - Ok(tx) + fn sign_psbt_inner(&self, psbt: Psbt) -> Result { + let mut locked_wallet = self.inner.lock().unwrap(); + locked_wallet.sign_psbt_all(psbt).map_err(|e| { + log_error!(self.logger, "Failed to sign PSBT: {}", e); + }) } } @@ -811,8 +2146,9 @@ impl Listen for Wallet { let mut locked_wallet = self.inner.lock().unwrap(); let pre_checkpoint = locked_wallet.latest_checkpoint(); - if pre_checkpoint.height() != height - 1 - || pre_checkpoint.hash() != block.header.prev_blockhash + if height > 0 + && (pre_checkpoint.height() != height - 1 + || pre_checkpoint.hash() != block.header.prev_blockhash) { log_debug!( self.logger, @@ -823,8 +2159,8 @@ impl Listen for Wallet { } match locked_wallet.apply_block(block, height) { - Ok(()) => { - if let Err(e) = self.update_payment_store(&mut *locked_wallet) { + Ok(_all_txids) => { + if let Err(e) = self.update_payment_store(&locked_wallet) { log_error!(self.logger, "Failed to update payment store: {}", e); return; } @@ -838,15 +2174,6 @@ impl Listen for Wallet { return; }, }; - - let mut locked_persister = self.persister.lock().unwrap(); - match locked_wallet.persist(&mut locked_persister) { - Ok(_) => (), - Err(e) => { - log_error!(self.logger, "Failed to persist on-chain wallet: {}", e); - return; - }, - }; } fn blocks_disconnected(&self, _fork_point_block: BestBlock) { @@ -856,6 +2183,51 @@ impl Listen for Wallet { } } +fn create_wallet_for_account( + seed_bytes: &[u8; WALLET_KEYS_SEED_LEN], network: Network, + wallet_account: OnchainWalletAccount, chain_tip: BestBlock, kv_store: Arc, + logger: Arc, lookahead: Option, +) -> Result<(PersistedWallet, KVStoreWalletPersister), Error> { + let xprv = Xpriv::new_master(network, seed_bytes).map_err(|e| { + log_error!(logger, "Failed to derive master secret: {}", e); + Error::WalletOperationFailed + })?; + + let mut persister = + KVStoreWalletPersister::new(Arc::clone(&kv_store), Arc::clone(&logger), wallet_account); + + let (mut wallet, loaded_from_store) = crate::builder::get_or_create_wallet_for_account( + wallet_account, + xprv, + network, + &mut persister, + lookahead, + ) + .map_err(|e| { + log_error!(logger, "Failed to setup wallet for {:?}: {}", wallet_account, e); + Error::WalletOperationFailed + })?; + + // Only advance brand-new wallets to the current tip. Re-loaded wallets keep their persisted + // checkpoint so per-account Bitcoind sync can replay every block after the older tip. + // + // New derived wallets still start at the current tip: Bitcoind has no account full-scan, so + // confirmed pre-registration history remains undiscoverable there. Esplora and Electrum recover + // it with a full scan regardless of the local checkpoint. + if !loaded_from_store { + let block_id = bdk_chain::BlockId { height: chain_tip.height, hash: chain_tip.block_hash }; + let mut cp = wallet.latest_checkpoint(); + cp = cp.insert(block_id); + let update = bdk_wallet::Update { chain: Some(cp), ..Default::default() }; + wallet.apply_update(update).map_err(|e| { + log_error!(logger, "Failed to apply checkpoint for {:?}: {}", wallet_account, e); + Error::WalletOperationFailed + })?; + } + + Ok((wallet, persister)) +} + impl WalletSource for Wallet { fn list_confirmed_utxos<'a>( &'a self, @@ -989,15 +2361,15 @@ impl SignerProvider for WalletKeysManager { } fn get_destination_script(&self, _channel_keys_id: [u8; 32]) -> Result { - let address = self.wallet.get_new_address().map_err(|e| { - log_error!(self.logger, "Failed to retrieve new address from wallet: {}", e); + let address = self.wallet.get_new_witness_address().map_err(|e| { + log_error!(self.logger, "Failed to retrieve new witness address from wallet: {}", e); })?; Ok(address.script_pubkey()) } fn get_shutdown_scriptpubkey(&self) -> Result { - let address = self.wallet.get_new_address().map_err(|e| { - log_error!(self.logger, "Failed to retrieve new address from wallet: {}", e); + let address = self.wallet.get_new_witness_address().map_err(|e| { + log_error!(self.logger, "Failed to retrieve new witness address from wallet: {}", e); })?; match address.witness_program() { @@ -1007,9 +2379,10 @@ impl SignerProvider for WalletKeysManager { _ => { log_error!( self.logger, - "Tried to use a non-witness address. This must never happen." + "get_shutdown_scriptpubkey received a non-native-witness address. \ + This is a bug in get_new_witness_address." ); - panic!("Tried to use a non-witness address. This must never happen."); + Err(()) }, } } @@ -1032,3 +2405,84 @@ impl ChangeDestinationSource for WalletKeysManager { }) } } + +#[cfg(test)] +mod tests { + use super::{ + additional_input_weight, map_wallet_account_error, validate_derivation_index, + validate_derivation_range, BIP32_MAX_NORMAL_INDEX, MAX_ADDRESS_INFO_BATCH_COUNT, + }; + use crate::config::{AddressType, OnchainWalletAccount}; + use crate::Error; + use bdk_wallet_aggregate::UtxoPsbtInfo; + use bitcoin::{psbt, OutPoint, TxIn, Weight}; + + #[test] + fn derivation_index_validation_rejects_hardened_range() { + assert_eq!(validate_derivation_index(BIP32_MAX_NORMAL_INDEX), Ok(())); + assert_eq!( + validate_derivation_index(BIP32_MAX_NORMAL_INDEX + 1), + Err(Error::InvalidQuantity) + ); + } + + #[test] + fn derivation_range_validation_rejects_overflow_into_hardened_range() { + assert_eq!(validate_derivation_range(BIP32_MAX_NORMAL_INDEX - 1, 2), Ok(())); + assert_eq!( + validate_derivation_range(BIP32_MAX_NORMAL_INDEX - 1, 3), + Err(Error::InvalidQuantity) + ); + assert_eq!(validate_derivation_range(u32::MAX, 1), Err(Error::InvalidQuantity)); + } + + #[test] + fn derivation_range_validation_rejects_oversized_batches() { + assert_eq!(validate_derivation_range(0, MAX_ADDRESS_INFO_BATCH_COUNT), Ok(())); + assert_eq!( + validate_derivation_range(0, MAX_ADDRESS_INFO_BATCH_COUNT + 1), + Err(Error::InvalidQuantity) + ); + } + + #[test] + fn derivation_range_validation_allows_empty_ranges_at_valid_start() { + assert_eq!(validate_derivation_range(BIP32_MAX_NORMAL_INDEX, 0), Ok(())); + } + + #[test] + fn missing_derived_wallet_maps_to_not_registered() { + let derived = + OnchainWalletAccount { address_type: AddressType::NativeSegwit, account_index: 1 }; + let account_zero = OnchainWalletAccount::account_zero(AddressType::NativeSegwit); + + assert_eq!( + map_wallet_account_error(derived, bdk_wallet_aggregate::Error::WalletNotFound), + Error::OnchainWalletAccountNotRegistered + ); + assert_eq!( + map_wallet_account_error(account_zero, bdk_wallet_aggregate::Error::WalletNotFound), + Error::WalletOperationFailed + ); + assert_eq!( + map_wallet_account_error(derived, bdk_wallet_aggregate::Error::PersistenceFailed), + Error::WalletOperationFailed + ); + } + + #[test] + fn additional_input_weight_includes_the_base_input_weight() { + let satisfaction_weight = Weight::from_wu(107); + let utxo = UtxoPsbtInfo { + outpoint: OutPoint::null(), + psbt_input: psbt::Input::default(), + weight: satisfaction_weight, + is_primary: false, + }; + + assert_eq!( + additional_input_weight(&[utxo]).unwrap(), + TxIn::default().segwit_weight() + satisfaction_weight + ); + } +} diff --git a/src/wallet/persist.rs b/src/wallet/persist.rs index 5c8668937e..762ef96cd8 100644 --- a/src/wallet/persist.rs +++ b/src/wallet/persist.rs @@ -7,9 +7,11 @@ use std::sync::Arc; +use bdk_chain::BlockId; use bdk_chain::Merge; use bdk_wallet::{ChangeSet, WalletPersister}; +use crate::config::OnchainWalletAccount; use crate::io::utils::{ read_bdk_wallet_change_set, write_bdk_wallet_change_descriptor, write_bdk_wallet_descriptor, write_bdk_wallet_indexer, write_bdk_wallet_local_chain, write_bdk_wallet_network, @@ -21,11 +23,42 @@ pub(crate) struct KVStoreWalletPersister { latest_change_set: Option, kv_store: Arc, logger: Arc, + wallet_account: OnchainWalletAccount, } impl KVStoreWalletPersister { - pub(crate) fn new(kv_store: Arc, logger: Arc) -> Self { - Self { latest_change_set: None, kv_store, logger } + pub(crate) fn new( + kv_store: Arc, logger: Arc, wallet_account: OnchainWalletAccount, + ) -> Self { + Self { latest_change_set: None, kv_store, logger, wallet_account } + } + + /// Replaces the stored local-chain tip while retaining descriptors, transactions, and indexes. + pub(crate) fn rewind_to_checkpoint( + &mut self, checkpoint: BlockId, + ) -> Result<(), std::io::Error> { + let persisted = ::initialize(self)?; + if checkpoint.height == 0 + && persisted.local_chain.blocks.get(&0).copied().flatten() != Some(checkpoint.hash) + { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Wallet genesis does not match the requested checkpoint", + )); + } + + let mut rewind = ChangeSet::default(); + for height in persisted + .local_chain + .blocks + .keys() + .copied() + .filter(|height| *height > checkpoint.height) + { + rewind.local_chain.blocks.insert(height, None); + } + rewind.local_chain.blocks.insert(checkpoint.height, Some(checkpoint.hash)); + ::persist(self, &rewind) } } @@ -41,6 +74,7 @@ impl WalletPersister for KVStoreWalletPersister { let change_set_opt = read_bdk_wallet_change_set( Arc::clone(&persister.kv_store), Arc::clone(&persister.logger), + persister.wallet_account, )?; let change_set = match change_set_opt { @@ -91,6 +125,7 @@ impl WalletPersister for KVStoreWalletPersister { &descriptor, Arc::clone(&persister.kv_store), Arc::clone(&persister.logger), + persister.wallet_account, )?; } } @@ -114,6 +149,7 @@ impl WalletPersister for KVStoreWalletPersister { &change_descriptor, Arc::clone(&persister.kv_store), Arc::clone(&persister.logger), + persister.wallet_account, )?; } } @@ -135,6 +171,7 @@ impl WalletPersister for KVStoreWalletPersister { &network, Arc::clone(&persister.kv_store), Arc::clone(&persister.logger), + persister.wallet_account, )?; } } @@ -149,16 +186,14 @@ impl WalletPersister for KVStoreWalletPersister { // Merge and persist the sub-changesets individually if necessary. // // According to the BDK team the individual sub-changesets can be persisted - // individually/non-atomically, "(h)owever, the localchain tip is used by block-by-block - // chain sources as a reference as to where to sync from, so I would persist that last", "I - // would write in this order: indexer, tx_graph, local_chain", which is why we follow this - // particular order. + // independently as long as we ensure the above fields are persisted first. if !change_set.indexer.is_empty() { latest_change_set.indexer.merge(change_set.indexer.clone()); write_bdk_wallet_indexer( &latest_change_set.indexer, Arc::clone(&persister.kv_store), Arc::clone(&persister.logger), + persister.wallet_account, )?; } @@ -168,6 +203,7 @@ impl WalletPersister for KVStoreWalletPersister { &latest_change_set.tx_graph, Arc::clone(&persister.kv_store), Arc::clone(&persister.logger), + persister.wallet_account, )?; } @@ -177,6 +213,7 @@ impl WalletPersister for KVStoreWalletPersister { &latest_change_set.local_chain, Arc::clone(&persister.kv_store), Arc::clone(&persister.logger), + persister.wallet_account, )?; } diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 699f8f1d0e..0dd32e4d90 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -23,7 +23,7 @@ use bitcoin::hashes::hex::FromHex; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::Hash; use bitcoin::{ - Address, Amount, Network, OutPoint, ScriptBuf, Sequence, Transaction, Txid, Witness, + Address, Amount, FeeRate, Network, OutPoint, ScriptBuf, Sequence, Transaction, Txid, Witness, }; use electrsd::corepc_node::{Client as BitcoindClient, Node as BitcoinD}; use electrsd::{corepc_node, ElectrsD}; @@ -47,16 +47,65 @@ use rand::distr::Alphanumeric; use rand::{rng, Rng}; use serde_json::{json, Value}; +#[cfg(not(feature = "uniffi"))] +pub(crate) fn api_fee_rate(fee_rate: FeeRate) -> FeeRate { + fee_rate +} + +#[cfg(feature = "uniffi")] +pub(crate) fn api_fee_rate(fee_rate: FeeRate) -> Arc { + Arc::new(fee_rate) +} + +#[cfg(not(feature = "uniffi"))] +pub(crate) fn api_seed_bytes(seed: [u8; 64]) -> [u8; 64] { + seed +} + +#[cfg(feature = "uniffi")] +pub(crate) fn api_seed_bytes(seed: [u8; 64]) -> Vec { + seed.to_vec() +} + +pub(crate) fn drain_all_events(node: &TestNode) { + while let Some(event) = node.next_event() { + println!("{} draining event {:?}", node.node_id(), event); + node.event_handled().unwrap(); + } +} + +pub(crate) fn is_informational_event(event: &Event) -> bool { + matches!( + event, + Event::OnchainTransactionConfirmed { .. } + | Event::OnchainTransactionReceived { .. } + | Event::OnchainTransactionReplaced { .. } + | Event::OnchainTransactionReorged { .. } + | Event::OnchainTransactionEvicted { .. } + | Event::SyncCompleted { .. } + | Event::SyncProgress { .. } + | Event::BalanceChanged { .. } + ) +} + macro_rules! expect_event { ($node:expr, $event_type:ident) => {{ - match $node.next_event_async().await { - ref e @ Event::$event_type { .. } => { - println!("{} got event {:?}", $node.node_id(), e); - $node.event_handled().unwrap(); - }, - ref e => { - panic!("{} got unexpected event!: {:?}", std::stringify!($node), e); - }, + loop { + match $node.next_event_async().await { + ref e @ Event::$event_type { .. } => { + println!("{} got event {:?}", $node.node_id(), e); + $node.event_handled().unwrap(); + break; + }, + ref e if $crate::common::is_informational_event(e) => { + println!("{} skipping event {:?}", $node.node_id(), e); + $node.event_handled().unwrap(); + continue; + }, + ref e => { + panic!("{} got unexpected event!: {:?}", std::stringify!($node), e); + }, + } } }}; } @@ -65,16 +114,23 @@ pub(crate) use expect_event; macro_rules! expect_channel_pending_event { ($node:expr, $counterparty_node_id:expr) => {{ - match $node.next_event_async().await { - ref e @ Event::ChannelPending { funding_txo, counterparty_node_id, .. } => { - println!("{} got event {:?}", $node.node_id(), e); - assert_eq!(counterparty_node_id, $counterparty_node_id); - $node.event_handled().unwrap(); - funding_txo - }, - ref e => { - panic!("{} got unexpected event!: {:?}", std::stringify!($node), e); - }, + loop { + match $node.next_event_async().await { + ref e @ Event::ChannelPending { funding_txo, counterparty_node_id, .. } => { + println!("{} got event {:?}", $node.node_id(), e); + assert_eq!(counterparty_node_id, $counterparty_node_id); + $node.event_handled().unwrap(); + break funding_txo; + }, + ref e if $crate::common::is_informational_event(e) => { + println!("{} skipping event {:?}", $node.node_id(), e); + $node.event_handled().unwrap(); + continue; + }, + ref e => { + panic!("{} got unexpected event!: {:?}", std::stringify!($node), e); + }, + } } }}; } @@ -83,16 +139,23 @@ pub(crate) use expect_channel_pending_event; macro_rules! expect_channel_ready_event { ($node:expr, $counterparty_node_id:expr) => {{ - match $node.next_event_async().await { - ref e @ Event::ChannelReady { user_channel_id, counterparty_node_id, .. } => { - println!("{} got event {:?}", $node.node_id(), e); - assert_eq!(counterparty_node_id, Some($counterparty_node_id)); - $node.event_handled().unwrap(); - user_channel_id - }, - ref e => { - panic!("{} got unexpected event!: {:?}", std::stringify!($node), e); - }, + loop { + match $node.next_event_async().await { + ref e @ Event::ChannelReady { user_channel_id, counterparty_node_id, .. } => { + println!("{} got event {:?}", $node.node_id(), e); + assert_eq!(counterparty_node_id, Some($counterparty_node_id)); + $node.event_handled().unwrap(); + break user_channel_id; + }, + ref e if $crate::common::is_informational_event(e) => { + println!("{} skipping event {:?}", $node.node_id(), e); + $node.event_handled().unwrap(); + continue; + }, + ref e => { + panic!("{} got unexpected event!: {:?}", std::stringify!($node), e); + }, + } } }}; } @@ -100,17 +163,24 @@ macro_rules! expect_channel_ready_event { pub(crate) use expect_channel_ready_event; macro_rules! expect_splice_pending_event { - ($node: expr, $counterparty_node_id: expr) => {{ - match $node.next_event_async().await { - ref e @ Event::SplicePending { new_funding_txo, counterparty_node_id, .. } => { - println!("{} got event {:?}", $node.node_id(), e); - assert_eq!(counterparty_node_id, $counterparty_node_id); - $node.event_handled().unwrap(); - new_funding_txo - }, - ref e => { - panic!("{} got unexpected event!: {:?}", std::stringify!($node), e); - }, + ($node:expr, $counterparty_node_id:expr) => {{ + loop { + match $node.next_event_async().await { + ref e @ Event::SplicePending { new_funding_txo, counterparty_node_id, .. } => { + println!("{} got event {:?}", $node.node_id(), e); + assert_eq!(counterparty_node_id, $counterparty_node_id); + $node.event_handled().unwrap(); + break new_funding_txo; + }, + ref e if $crate::common::is_informational_event(e) => { + println!("{} skipping event {:?}", $node.node_id(), e); + $node.event_handled().unwrap(); + continue; + }, + ref e => { + panic!("{} got unexpected event!: {:?}", std::stringify!($node), e); + }, + } } }}; } @@ -119,20 +189,27 @@ pub(crate) use expect_splice_pending_event; macro_rules! expect_payment_received_event { ($node:expr, $amount_msat:expr) => {{ - match $node.next_event_async().await { - ref e @ Event::PaymentReceived { payment_id, amount_msat, .. } => { - println!("{} got event {:?}", $node.node_id(), e); - assert_eq!(amount_msat, $amount_msat); - let payment = $node.payment(&payment_id.unwrap()).unwrap(); - if !matches!(payment.kind, PaymentKind::Onchain { .. }) { - assert_eq!(payment.fee_paid_msat, None); - } - $node.event_handled().unwrap(); - payment_id - }, - ref e => { - panic!("{} got unexpected event!: {:?}", std::stringify!(node_b), e); - }, + loop { + match $node.next_event_async().await { + ref e @ Event::PaymentReceived { payment_id, amount_msat, .. } => { + println!("{} got event {:?}", $node.node_id(), e); + assert_eq!(amount_msat, $amount_msat); + let payment = $node.payment(&payment_id.unwrap()).unwrap(); + if !matches!(payment.kind, PaymentKind::Onchain { .. }) { + assert_eq!(payment.fee_paid_msat, None); + } + $node.event_handled().unwrap(); + break payment_id; + }, + ref e if $crate::common::is_informational_event(e) => { + println!("{} skipping event {:?}", $node.node_id(), e); + $node.event_handled().unwrap(); + continue; + }, + ref e => { + panic!("{} got unexpected event!: {:?}", std::stringify!(node_b), e); + }, + } } }}; } @@ -141,23 +218,30 @@ pub(crate) use expect_payment_received_event; macro_rules! expect_payment_claimable_event { ($node:expr, $payment_id:expr, $payment_hash:expr, $claimable_amount_msat:expr) => {{ - match $node.next_event_async().await { - ref e @ Event::PaymentClaimable { - payment_id, - payment_hash, - claimable_amount_msat, - .. - } => { - println!("{} got event {:?}", std::stringify!($node), e); - assert_eq!(payment_hash, $payment_hash); - assert_eq!(payment_id, $payment_id); - assert_eq!(claimable_amount_msat, $claimable_amount_msat); - $node.event_handled().unwrap(); - claimable_amount_msat - }, - ref e => { - panic!("{} got unexpected event!: {:?}", std::stringify!($node), e); - }, + loop { + match $node.next_event_async().await { + ref e @ Event::PaymentClaimable { + payment_id, + payment_hash, + claimable_amount_msat, + .. + } => { + println!("{} got event {:?}", std::stringify!($node), e); + assert_eq!(payment_hash, $payment_hash); + assert_eq!(payment_id, $payment_id); + assert_eq!(claimable_amount_msat, $claimable_amount_msat); + $node.event_handled().unwrap(); + break claimable_amount_msat; + }, + ref e if $crate::common::is_informational_event(e) => { + println!("{} skipping event {:?}", $node.node_id(), e); + $node.event_handled().unwrap(); + continue; + }, + ref e => { + panic!("{} got unexpected event!: {:?}", std::stringify!($node), e); + }, + } } }}; } @@ -166,20 +250,28 @@ pub(crate) use expect_payment_claimable_event; macro_rules! expect_payment_successful_event { ($node:expr, $payment_id:expr, $fee_paid_msat:expr) => {{ - match $node.next_event_async().await { - ref e @ Event::PaymentSuccessful { payment_id, fee_paid_msat, .. } => { - println!("{} got event {:?}", $node.node_id(), e); - if let Some(fee_msat) = $fee_paid_msat { - assert_eq!(fee_paid_msat, fee_msat); - } - let payment = $node.payment(&$payment_id.unwrap()).unwrap(); - assert_eq!(payment.fee_paid_msat, fee_paid_msat); - assert_eq!(payment_id, $payment_id); - $node.event_handled().unwrap(); - }, - ref e => { - panic!("{} got unexpected event!: {:?}", std::stringify!(node_b), e); - }, + loop { + match $node.next_event_async().await { + ref e @ Event::PaymentSuccessful { payment_id, fee_paid_msat, .. } => { + println!("{} got event {:?}", $node.node_id(), e); + if let Some(fee_msat) = $fee_paid_msat { + assert_eq!(fee_paid_msat, fee_msat); + } + let payment = $node.payment(&$payment_id.unwrap()).unwrap(); + assert_eq!(payment.fee_paid_msat, fee_paid_msat); + assert_eq!(payment_id, $payment_id); + $node.event_handled().unwrap(); + break; + }, + ref e if $crate::common::is_informational_event(e) => { + println!("{} skipping event {:?}", $node.node_id(), e); + $node.event_handled().unwrap(); + continue; + }, + ref e => { + panic!("{} got unexpected event!: {:?}", std::stringify!(node_b), e); + }, + } } }}; } @@ -223,9 +315,17 @@ pub(crate) fn random_port() -> u16 { pub(crate) fn random_listening_addresses() -> Vec { let num_addresses = 2; let mut listening_addresses = Vec::with_capacity(num_addresses); + let mut used_ports = std::collections::HashSet::new(); for _ in 0..num_addresses { - let rand_port = random_port(); + let mut rand_port = random_port(); + let mut attempts = 0u32; + while used_ports.contains(&rand_port) { + rand_port = random_port(); + attempts += 1; + assert!(attempts < 1000, "Failed to find a unique random port after 1000 attempts"); + } + used_ports.insert(rand_port); let address: SocketAddress = format!("127.0.0.1:{}", rand_port).parse().unwrap(); listening_addresses.push(address); } @@ -370,7 +470,8 @@ pub(crate) fn setup_node_for_async_payments( }, TestChainSource::Electrum(electrsd) => { let electrum_url = format!("tcp://{}", electrsd.electrum_url); - let sync_config = ElectrumSyncConfig { background_sync_config: None }; + let sync_config = + ElectrumSyncConfig { background_sync_config: None, ..Default::default() }; builder.set_chain_source_electrum(electrum_url.clone(), Some(sync_config)); }, TestChainSource::BitcoindRpcSync(bitcoind) => { @@ -739,9 +840,9 @@ pub(crate) async fn do_channel_full_cycle( 0 ); - // Check we haven't got any events yet - assert_eq!(node_a.next_event(), None); - assert_eq!(node_b.next_event(), None); + // Drain events from initial sync (OnchainTransactionConfirmed, SyncCompleted, etc.) + drain_all_events(&node_a); + drain_all_events(&node_b); println!("\nA -- open_channel -> B"); let funding_amount_sat = 2_080_000; @@ -1286,9 +1387,9 @@ pub(crate) async fn do_channel_full_cycle( 2 ); - // Check we handled all events - assert_eq!(node_a.next_event(), None); - assert_eq!(node_b.next_event(), None); + // Drain any remaining events + drain_all_events(&node_a); + drain_all_events(&node_b); node_a.stop().unwrap(); println!("\nA stopped"); diff --git a/tests/integration_tests_rust.rs b/tests/integration_tests_rust.rs index d6c7c9447f..7cb56ed19a 100644 --- a/tests/integration_tests_rust.rs +++ b/tests/integration_tests_rust.rs @@ -14,18 +14,18 @@ use std::sync::Arc; use bitcoin::address::NetworkUnchecked; use bitcoin::hashes::sha256::Hash as Sha256Hash; use bitcoin::hashes::Hash; -use bitcoin::{Address, Amount, ScriptBuf}; +use bitcoin::{Address, Amount, ScriptBuf, Txid}; use common::logging::{init_log_logger, validate_log_entry, MultiNodeLogger, TestLogWriter}; use common::{ - bump_fee_and_broadcast, distribute_funds_unconfirmed, do_channel_full_cycle, - expect_channel_pending_event, expect_channel_ready_event, expect_event, + api_fee_rate, bump_fee_and_broadcast, distribute_funds_unconfirmed, do_channel_full_cycle, + drain_all_events, expect_channel_pending_event, expect_channel_ready_event, expect_event, expect_payment_claimable_event, expect_payment_received_event, expect_payment_successful_event, expect_splice_pending_event, generate_blocks_and_wait, open_channel, open_channel_push_amt, premine_and_distribute_funds, premine_blocks, prepare_rbf, random_config, random_listening_addresses, setup_bitcoind_and_electrsd, setup_builder, setup_node, setup_node_for_async_payments, setup_two_nodes, wait_for_tx, TestChainSource, TestSyncStore, }; -use ldk_node::config::{AsyncPaymentsRole, EsploraSyncConfig}; +use ldk_node::config::{AsyncPaymentsRole, ElectrumSyncConfig, EsploraSyncConfig}; use ldk_node::liquidity::LSPS2ServiceConfig; use ldk_node::payment::{ ConfirmationStatus, PaymentDetails, PaymentDirection, PaymentKind, PaymentStatus, @@ -177,7 +177,7 @@ async fn multi_hop_sending() { for n in &nodes { n.sync_wallets().unwrap(); assert_eq!(n.list_balances().spendable_onchain_balance_sats, premine_amount_sat); - assert_eq!(n.next_event(), None); + drain_all_events(n); } // Setup channel topology: @@ -236,8 +236,21 @@ async fn multi_hop_sending() { expect_event!(nodes[1], PaymentForwarded); // We expect that the payment goes through N2 or N3, so we check both for the PaymentForwarded event. - let node_2_fwd_event = matches!(nodes[2].next_event(), Some(Event::PaymentForwarded { .. })); - let node_3_fwd_event = matches!(nodes[3].next_event(), Some(Event::PaymentForwarded { .. })); + // Check all events from each node to find PaymentForwarded + let mut node_2_fwd_event = false; + while let Some(event) = nodes[2].next_event() { + if matches!(event, Event::PaymentForwarded { .. }) { + node_2_fwd_event = true; + } + nodes[2].event_handled().unwrap(); + } + let mut node_3_fwd_event = false; + while let Some(event) = nodes[3].next_event() { + if matches!(event, Event::PaymentForwarded { .. }) { + node_3_fwd_event = true; + } + nodes[3].event_handled().unwrap(); + } assert!(node_2_fwd_event || node_3_fwd_event); let payment_id = expect_payment_received_event!(&nodes[4], 2_500_000); @@ -389,12 +402,12 @@ async fn onchain_send_receive() { assert_eq!( Err(NodeError::InsufficientFunds), - node_a.onchain_payment().send_to_address(&addr_b, expected_node_a_balance + 1, None) + node_a.onchain_payment().send_to_address(&addr_b, expected_node_a_balance + 1, None, None) ); assert_eq!( Err(NodeError::InvalidAddress), - node_a.onchain_payment().send_to_address(&addr_c, expected_node_a_balance + 1, None) + node_a.onchain_payment().send_to_address(&addr_c, expected_node_a_balance + 1, None, None) ); assert_eq!( @@ -404,7 +417,7 @@ async fn onchain_send_receive() { let amount_to_send_sats = 54321; let txid = - node_b.onchain_payment().send_to_address(&addr_a, amount_to_send_sats, None).unwrap(); + node_b.onchain_payment().send_to_address(&addr_a, amount_to_send_sats, None, None).unwrap(); wait_for_tx(&electrsd.client, txid).await; node_a.sync_wallets().unwrap(); node_b.sync_wallets().unwrap(); @@ -583,6 +596,24 @@ async fn onchain_send_all_retains_reserve() { ..=premine_amount_sat) .contains(&node_b.list_balances().spendable_onchain_balance_sats)); + // With an open anchor channel, retain_reserves=true vs false should produce different fees + // because retain=true excludes the reserve from the send amount (smaller tx output, same + // inputs) while retain=false drains everything. + let fee_retain = node_b + .onchain_payment() + .calculate_send_all_fee(&addr_a, true, None) + .expect("fee with retain should succeed"); + let fee_drain = node_b + .onchain_payment() + .calculate_send_all_fee(&addr_a, false, None) + .expect("fee with drain should succeed"); + assert!(fee_retain > 0); + assert!(fee_drain > 0); + // Drain sends a larger output (includes reserve), so its fee may differ. + // Both must be less than the total balance. + assert!(fee_retain < node_b.list_balances().total_onchain_balance_sats); + assert!(fee_drain < node_b.list_balances().total_onchain_balance_sats); + // Send all over again, this time ensuring the reserve is accounted for let txid = node_b.onchain_payment().send_all_to_address(&addr_a, true, None).unwrap(); @@ -600,6 +631,126 @@ async fn onchain_send_all_retains_reserve() { .contains(&node_a.list_balances().spendable_onchain_balance_sats)); } +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn calculate_send_all_fee_matches_actual() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false); + + let addr_a = node_a.onchain_payment().new_address().unwrap(); + let addr_b = node_b.onchain_payment().new_address().unwrap(); + + let premine_amount_sat = 1_000_000; + premine_and_distribute_funds( + &bitcoind.client, + &electrsd.client, + vec![addr_a.clone()], + Amount::from_sat(premine_amount_sat), + ) + .await; + node_a.sync_wallets().unwrap(); + + // No channels open: retain_reserves=true should still work (reserve is 0). + let estimated_fee = node_a + .onchain_payment() + .calculate_send_all_fee(&addr_b, true, None) + .expect("fee estimation should succeed"); + assert!(estimated_fee > 0, "fee must be positive"); + assert!(estimated_fee < premine_amount_sat, "fee must be less than balance"); + + // Drain with retain_reserves=false should give the same result when no channels exist. + let estimated_fee_drain = node_a + .onchain_payment() + .calculate_send_all_fee(&addr_b, false, None) + .expect("drain fee estimation should succeed"); + assert_eq!(estimated_fee, estimated_fee_drain); + + // Custom fee rate should produce a different (but still valid) estimate. + let custom_fee_rate = bitcoin::FeeRate::from_sat_per_kwu(500); + let estimated_fee_custom = node_a + .onchain_payment() + .calculate_send_all_fee(&addr_b, true, Some(api_fee_rate(custom_fee_rate))) + .expect("custom fee rate estimation should succeed"); + assert!(estimated_fee_custom > 0); + + // Actually send and compare the real fee with the estimate (using default fee rate). + let txid = node_a.onchain_payment().send_all_to_address(&addr_b, true, None).unwrap(); + wait_for_tx(&electrsd.client, txid).await; + generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 6).await; + node_a.sync_wallets().unwrap(); + node_b.sync_wallets().unwrap(); + + let received = node_b.list_balances().spendable_onchain_balance_sats; + let actual_fee = premine_amount_sat - received; + assert_eq!(estimated_fee, actual_fee, "estimated fee should match the actual fee paid"); + + // After draining, node_a has zero balance — fee estimation should fail. + assert!(node_a.onchain_payment().calculate_send_all_fee(&addr_b, true, None).is_err()); + + // Verify wrong-network address returns an error (testnet address on regtest). + let wrong_net_addr: Address = + "tb1q0d40e5rta4fty63z64gztf8c3v20cvet6v2jdh".parse().expect("parse unchecked"); + let wrong_net_addr = wrong_net_addr.assume_checked(); + assert_eq!( + Err(NodeError::InvalidAddress), + node_b.onchain_payment().calculate_send_all_fee(&wrong_net_addr, true, None) + ); +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn calculate_total_fee_estimation() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false); + + let addr_a = node_a.onchain_payment().new_address().unwrap(); + let addr_b = node_b.onchain_payment().new_address().unwrap(); + + let premine_amount_sat = 1_000_000; + premine_and_distribute_funds( + &bitcoind.client, + &electrsd.client, + vec![addr_a.clone()], + Amount::from_sat(premine_amount_sat), + ) + .await; + node_a.sync_wallets().unwrap(); + + let send_amount = 100_000; + let fee = node_a + .onchain_payment() + .calculate_total_fee(&addr_b, send_amount, None, None) + .expect("fee calculation should succeed"); + assert!(fee > 0, "fee must be positive"); + assert!(fee < send_amount, "fee should be less than the send amount"); + + // Send and verify the actual fee matches. + let txid = node_a.onchain_payment().send_to_address(&addr_b, send_amount, None, None).unwrap(); + wait_for_tx(&electrsd.client, txid).await; + generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 6).await; + node_a.sync_wallets().unwrap(); + node_b.sync_wallets().unwrap(); + + let node_a_balance = node_a.list_balances().spendable_onchain_balance_sats; + let actual_fee = premine_amount_sat - send_amount - node_a_balance; + assert_eq!(fee, actual_fee, "estimated fee should match the actual fee paid"); + + // When the amount exceeds spendable balance, we should get an error. + let spendable = node_a.list_balances().spendable_onchain_balance_sats; + assert!(node_a + .onchain_payment() + .calculate_total_fee(&addr_b, spendable + 1, None, None) + .is_err()); + + // For max-amount sends, use calculate_send_all_fee instead of calculate_total_fee. + let send_all_fee = node_a + .onchain_payment() + .calculate_send_all_fee(&addr_b, true, None) + .expect("send_all fee should work for max-amount"); + assert!(send_all_fee > 0); + assert!(send_all_fee < spendable); +} + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn onchain_wallet_recovery() { let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); @@ -898,6 +1049,66 @@ async fn do_connection_restart_behavior(persist: bool) { } } +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn peer_address_persisted_on_connect_failure() { + let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + let (node_a, node_b) = setup_two_nodes(&chain_source, false, false, false); + + let node_id_b = node_b.node_id(); + let real_addr_b = node_b.listening_addresses().unwrap().first().unwrap().clone(); + + // Stop node_b so all connection attempts to it will fail. + node_b.stop().unwrap(); + + let fake_addr: lightning::ln::msgs::SocketAddress = "127.0.0.1:19999".parse().unwrap(); + + // Attempt to connect with persist=true to an unreachable address. The connection + // will fail, but the peer address must still be persisted. This is a regression test + // for a bug where add_peer was called AFTER the connection attempt, meaning a failed + // connect would skip persistence entirely. + let res = node_a.connect(node_id_b, fake_addr.clone(), true); + assert!(res.is_err()); + + let peers_a = node_a.list_peers(); + let peer = peers_a + .iter() + .find(|p| p.node_id == node_id_b) + .expect("Peer must be in store even after failed connection when persist=true"); + assert!(peer.is_persisted); + assert!(!peer.is_connected); + assert_eq!(peer.address, fake_addr); + + // Now "update" to the real address (still unreachable since node_b is stopped). + // This verifies the upsert: even though connect fails again, the stored address + // should be updated to the new one. + let res = node_a.connect(node_id_b, real_addr_b.clone(), true); + assert!(res.is_err()); + + let peers_a = node_a.list_peers(); + let peer = peers_a + .iter() + .find(|p| p.node_id == node_id_b) + .expect("Peer must still be in store after second failed connection"); + assert_eq!(peer.address, real_addr_b, "Stored address must be updated to the new one"); + + // Restart node_b and node_a to verify the persisted address survives restart + // and the reconnection loop uses the correct (updated) address. + node_b.start().unwrap(); + node_a.stop().unwrap(); + node_a.start().unwrap(); + + tokio::time::sleep(std::time::Duration::from_secs(5)).await; + + let peers_a = node_a.list_peers(); + let peer = peers_a + .iter() + .find(|p| p.node_id == node_id_b) + .expect("Peer must reconnect after restart using persisted address"); + assert!(peer.is_connected); + assert!(peer.is_persisted); +} + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn concurrent_connections_succeed() { let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); @@ -2002,6 +2213,22 @@ async fn drop_in_async_context() { node.stop().unwrap(); } +#[test] +fn owned_runtime_electrum_lifecycle() { + let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Electrum(&electrsd); + let config = random_config(true); + let node = setup_node(&chain_source, config, Some(vec![42u8; 64])); + + node.sync_wallets().unwrap(); + node.stop().unwrap(); + node.start().unwrap(); + node.sync_wallets().unwrap(); + node.stop().unwrap(); + + drop(node); +} + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn lsps2_client_trusts_lsp() { let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); @@ -2301,3 +2528,848 @@ async fn lsps2_lsp_trusts_client_but_client_does_not_claim() { Some(6) ); } + +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn onchain_transaction_events() { + use std::time::Duration; + + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + let config = random_config(false); + let node = setup_node(&chain_source, config, None); + + let addr = node.onchain_payment().new_address().unwrap(); + let premine_amount_sat = 100_000; + premine_and_distribute_funds( + &bitcoind.client, + &electrsd.client, + vec![addr.clone()], + Amount::from_sat(premine_amount_sat), + ) + .await; + + while node.next_event().is_some() { + node.event_handled().unwrap(); + } + + node.sync_wallets().unwrap(); + + let mut received_confirmed_event = false; + let mut txid_from_event = None; + + for _ in 0..5 { + if let Some(event) = node.next_event() { + match event { + Event::OnchainTransactionConfirmed { txid, block_height, details, .. } => { + println!( + "OnchainTransactionConfirmed: txid={}, height={}, amount={}", + txid, block_height, details.amount_sats + ); + assert!(!details.inputs.is_empty()); + assert!(!details.outputs.is_empty()); + received_confirmed_event = true; + txid_from_event = Some(txid); + node.event_handled().unwrap(); + break; + }, + other_event => { + println!("Got other event: {:?}", other_event); + node.event_handled().unwrap(); + }, + } + } + std::thread::sleep(Duration::from_millis(100)); + } + + assert!(received_confirmed_event, "Should have received OnchainTransactionConfirmed event"); + assert!(txid_from_event.is_some(), "Should have captured txid from event"); + + // Test unconfirmation after reorg (simulate by generating new blocks on a different chain) + // Note: This is complex to test in a real scenario, so we'll just verify the event exists + // and can be pattern matched + match node.next_event() { + None => {}, // No more events is fine + Some(Event::OnchainTransactionReceived { .. }) => { + node.event_handled().unwrap(); + }, + Some(_) => {}, // Other events are fine + } + + node.stop().unwrap(); +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn onchain_transaction_events_electrum() { + // Test onchain events work with Electrum backend too + use std::time::Duration; + + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Electrum(&electrsd); + let config = random_config(false); + let node = setup_node(&chain_source, config, None); + + let addr = node.onchain_payment().new_address().unwrap(); + let premine_amount_sat = 50_000; + + premine_and_distribute_funds( + &bitcoind.client, + &electrsd.client, + vec![addr.clone()], + Amount::from_sat(premine_amount_sat), + ) + .await; + + while node.next_event().is_some() { + node.event_handled().unwrap(); + } + + node.sync_wallets().unwrap(); + + // Check we received the onchain transaction confirmed event + let mut found_event = false; + for _ in 0..5 { + if let Some(event) = node.next_event() { + if let Event::OnchainTransactionConfirmed { details, .. } = event { + // Verify TransactionDetails structure is populated + assert!(!details.inputs.is_empty(), "Transaction should have inputs"); + assert!(!details.outputs.is_empty(), "Transaction should have outputs"); + found_event = true; + node.event_handled().unwrap(); + break; + } + node.event_handled().unwrap(); + } + std::thread::sleep(Duration::from_millis(100)); + } + + assert!(found_event, "Should receive OnchainTransactionConfirmed event with Electrum backend"); + + node.stop().unwrap(); +} + +#[test] +fn sync_completed_event() { + // Test that SyncCompleted event is emitted after wallet sync + use std::time::Duration; + + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + let config = random_config(false); + let node = setup_node(&chain_source, config, None); + + while node.next_event().is_some() { + node.event_handled().unwrap(); + } + + node.sync_wallets().unwrap(); + + let mut found_sync_completed = false; + for _ in 0..10 { + if let Some(event) = node.next_event() { + match event { + Event::SyncCompleted { sync_type, synced_block_height } => { + println!( + "Received SyncCompleted event: type={:?}, height={}", + sync_type, synced_block_height + ); + found_sync_completed = true; + node.event_handled().unwrap(); + break; + }, + other_event => { + println!("Got other event: {:?}", other_event); + node.event_handled().unwrap(); + }, + } + } + std::thread::sleep(Duration::from_millis(100)); + } + + assert!(found_sync_completed, "Should have received SyncCompleted event"); + + node.stop().unwrap(); +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn balance_changed_event() { + use std::time::Duration; + + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + let config = random_config(false); + let node = setup_node(&chain_source, config, None); + + node.sync_wallets().unwrap(); + + while node.next_event().is_some() { + node.event_handled().unwrap(); + } + + let initial_total_balance = node.list_balances().total_onchain_balance_sats; + println!("Initial balance: {} sats", initial_total_balance); + + let addr = node.onchain_payment().new_address().unwrap(); + let fund_amount = 100_000; + premine_and_distribute_funds( + &bitcoind.client, + &electrsd.client, + vec![addr.clone()], + Amount::from_sat(fund_amount), + ) + .await; + + node.sync_wallets().unwrap(); + + let mut found_balance_changed = false; + for _ in 0..20 { + if let Some(event) = node.next_event() { + match event { + Event::BalanceChanged { + old_spendable_onchain_balance_sats, + new_spendable_onchain_balance_sats, + old_total_onchain_balance_sats, + new_total_onchain_balance_sats, + old_total_lightning_balance_sats, + new_total_lightning_balance_sats, + } => { + println!( + "BalanceChanged: spendable {} -> {}, total {} -> {}, lightning {} -> {}", + old_spendable_onchain_balance_sats, + new_spendable_onchain_balance_sats, + old_total_onchain_balance_sats, + new_total_onchain_balance_sats, + old_total_lightning_balance_sats, + new_total_lightning_balance_sats + ); + assert!(new_total_onchain_balance_sats > old_total_onchain_balance_sats); + assert_eq!( + new_total_onchain_balance_sats - old_total_onchain_balance_sats, + fund_amount + ); + + found_balance_changed = true; + node.event_handled().unwrap(); + break; + }, + other_event => { + println!("Got other event: {:?}", other_event); + node.event_handled().unwrap(); + }, + } + } + std::thread::sleep(Duration::from_millis(100)); + } + + assert!(found_balance_changed); + + let final_balance = node.list_balances().total_onchain_balance_sats; + assert_eq!(final_balance, initial_total_balance + fund_amount); + + node.stop().unwrap(); +} + +#[test] +fn test_event_serialization_roundtrip() { + use bitcoin::{BlockHash, Txid}; + use ldk_node::{Event, SyncType, TransactionDetails, TxInput, TxOutput}; + use lightning::util::ser::{Readable, Writeable}; + + // Helper function to test serialization roundtrip + fn test_roundtrip(event: Event) { + let mut buffer = Vec::new(); + event.write(&mut buffer).unwrap(); + let mut cursor = std::io::Cursor::new(&buffer); + let deserialized = Event::read(&mut cursor).unwrap(); + assert_eq!(event, deserialized, "Event serialization roundtrip failed"); + } + + // Test OnchainTransactionConfirmed + let event = Event::OnchainTransactionConfirmed { + txid: Txid::from_slice(&[1; 32]).unwrap(), + block_hash: BlockHash::from_slice(&[2; 32]).unwrap(), + block_height: 100000, + confirmation_time: 1234567890, + details: TransactionDetails { + amount_sats: 100000, + inputs: vec![TxInput { + txid: Txid::from_slice(&[10; 32]).unwrap(), + vout: 0, + scriptsig: "".to_string(), + witness: vec![], + sequence: 0xffffffff, + }], + outputs: vec![TxOutput { + scriptpubkey: "0014".to_string(), + scriptpubkey_type: Some("p2wpkh".to_string()), + scriptpubkey_address: None, + value: 100000, + n: 0, + }], + }, + }; + test_roundtrip(event); + + // Test OnchainTransactionReceived + let event = Event::OnchainTransactionReceived { + txid: Txid::from_slice(&[3; 32]).unwrap(), + details: TransactionDetails { + amount_sats: -50000, // Test negative amount for outgoing + inputs: vec![TxInput { + txid: Txid::from_slice(&[11; 32]).unwrap(), + vout: 1, + scriptsig: "".to_string(), + witness: vec![], + sequence: 0xffffffff, + }], + outputs: vec![], + }, + }; + test_roundtrip(event); + + // Test OnchainTransactionReplaced + let event = Event::OnchainTransactionReplaced { + txid: Txid::from_slice(&[6; 32]).unwrap(), + conflicts: vec![Txid::from_slice(&[7; 32]).unwrap()], + }; + test_roundtrip(event); + + // Test OnchainTransactionReorged + let event = Event::OnchainTransactionReorged { txid: Txid::from_slice(&[7; 32]).unwrap() }; + test_roundtrip(event); + + // Test SyncProgress + let event = Event::SyncProgress { + sync_type: SyncType::OnchainWallet, + progress_percent: 75, + current_block_height: 750000, + target_block_height: 800000, + }; + test_roundtrip(event); + + // Test SyncCompleted + let event = + Event::SyncCompleted { sync_type: SyncType::LightningWallet, synced_block_height: 800000 }; + test_roundtrip(event); + + // Test BalanceChanged + let event = Event::BalanceChanged { + old_spendable_onchain_balance_sats: 1000000, + new_spendable_onchain_balance_sats: 1500000, + old_total_onchain_balance_sats: 2000000, + new_total_onchain_balance_sats: 2500000, + old_total_lightning_balance_sats: 500000, + new_total_lightning_balance_sats: 600000, + }; + test_roundtrip(event); + + // Test TransactionDetails with multiple inputs and outputs + let details = TransactionDetails { + amount_sats: 1000000, + inputs: vec![TxInput { + txid: Txid::from_slice(&[12; 32]).unwrap(), + vout: 0, + scriptsig: "160014".to_string(), + witness: vec!["30440220".to_string()], + sequence: 0xffffffff, + }], + outputs: vec![TxOutput { + scriptpubkey: "0014".to_string(), + scriptpubkey_type: Some("p2wpkh".to_string()), + scriptpubkey_address: None, + value: 1000000, + n: 0, + }], + }; + let event = Event::OnchainTransactionConfirmed { + txid: Txid::from_slice(&[6; 32]).unwrap(), + block_hash: BlockHash::from_slice(&[7; 32]).unwrap(), + block_height: 100001, + confirmation_time: 1234567891, + details, + }; + test_roundtrip(event); + + // Test TransactionDetails with coinbase input + let details = TransactionDetails { + amount_sats: 62500000000, // Block reward + inputs: vec![TxInput { + txid: Txid::from_slice(&[0u8; 32]).unwrap(), + vout: 0xffffffff, + scriptsig: "03".to_string(), + witness: vec![], + sequence: 0xffffffff, + }], + outputs: vec![TxOutput { + scriptpubkey: "0014".to_string(), + scriptpubkey_type: Some("p2wpkh".to_string()), + scriptpubkey_address: None, + value: 62500000000, + n: 0, + }], + }; + let event = Event::OnchainTransactionConfirmed { + txid: Txid::from_slice(&[9; 32]).unwrap(), + block_hash: BlockHash::from_slice(&[10; 32]).unwrap(), + block_height: 100002, + confirmation_time: 1234567892, + details, + }; + test_roundtrip(event); +} + +#[test] +fn test_concurrent_event_emission() { + use std::sync::Arc; + use std::thread; + use std::time::Duration; + + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + let config = random_config(false); + let node = Arc::new(setup_node(&chain_source, config, None)); + + while node.next_event().is_some() { + node.event_handled().unwrap(); + } + + // Spawn multiple threads that sync concurrently + let mut handles = vec![]; + for i in 0..5 { + let node_clone = Arc::clone(&node); + let handle = thread::spawn(move || { + // Sleep briefly to stagger the syncs + thread::sleep(Duration::from_millis(i * 10)); + node_clone.sync_wallets().unwrap(); + }); + handles.push(handle); + } + + // Wait for all threads to complete + for handle in handles { + handle.join().unwrap(); + } + + // Count the events - we should have multiple SyncCompleted events + let mut sync_completed_count = 0; + + for _ in 0..50 { + if let Some(event) = node.next_event() { + if matches!(event, Event::SyncCompleted { .. }) { + sync_completed_count += 1; + } + node.event_handled().unwrap(); + } + thread::sleep(Duration::from_millis(10)); + } + + // We should have received at least one SyncCompleted event per thread + assert!( + sync_completed_count >= 1, + "Should have received at least one SyncCompleted event from concurrent syncs" + ); + + node.stop().unwrap(); +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn test_reorg_event_emission() { + // Note: This is a simplified test as true reorg testing requires complex setup + use std::thread; + use std::time::Duration; + + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + let config = random_config(false); + let node = setup_node(&chain_source, config, None); + + // Get a new address and fund it + let addr = node.onchain_payment().new_address().unwrap(); + let premine_amount_sat = 100_000; + premine_and_distribute_funds( + &bitcoind.client, + &electrsd.client, + vec![addr.clone()], + Amount::from_sat(premine_amount_sat), + ) + .await; + + while node.next_event().is_some() { + node.event_handled().unwrap(); + } + + // Sync to detect the confirmed transaction + node.sync_wallets().unwrap(); + + let mut confirmed_txid = None; + for _ in 0..10 { + if let Some(event) = node.next_event() { + if let Event::OnchainTransactionConfirmed { txid, .. } = event { + confirmed_txid = Some(txid); + node.event_handled().unwrap(); + break; + } + node.event_handled().unwrap(); + } + thread::sleep(Duration::from_millis(100)); + } + + assert!(confirmed_txid.is_some(), "Should have received a confirmation event"); + + // In a real scenario, we would trigger a reorg here by mining competing blocks + // For this test, we just verify the event structure is correct + + node.stop().unwrap(); +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn onchain_transaction_evicted_event() { + use std::thread; + use std::time::Duration; + + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + let config = random_config(false); + let node = setup_node(&chain_source, config, None); + + // Fund the node first + let addr = node.onchain_payment().new_address().unwrap(); + let fund_amount = 200_000; + premine_and_distribute_funds( + &bitcoind.client, + &electrsd.client, + vec![addr.clone()], + Amount::from_sat(fund_amount), + ) + .await; + + // Sync to get the funds + node.sync_wallets().unwrap(); + + while node.next_event().is_some() { + node.event_handled().unwrap(); + } + + // Create a transaction - this will be unconfirmed initially + let recipient_addr = node.onchain_payment().new_address().unwrap(); + let send_amount = 50_000; + let txid = + node.onchain_payment().send_to_address(&recipient_addr, send_amount, None, None).unwrap(); + + println!("Created transaction {} (unconfirmed)", txid); + + // Wait for transaction to be broadcast + thread::sleep(Duration::from_millis(500)); + + // Sync to detect the unconfirmed transaction + node.sync_wallets().unwrap(); + + let mut found_received_event = false; + for _ in 0..10 { + if let Some(event) = node.next_event() { + match event { + Event::OnchainTransactionReceived { txid: event_txid, .. } => { + if event_txid == txid { + found_received_event = true; + println!("Received OnchainTransactionReceived event for {}", txid); + node.event_handled().unwrap(); + break; + } + node.event_handled().unwrap(); + }, + _ => { + node.event_handled().unwrap(); + }, + } + } + thread::sleep(Duration::from_millis(100)); + } + + assert!( + found_received_event, + "Should have received OnchainTransactionReceived event for transaction {}", + txid + ); + + // Remove the transaction from bitcoind's mempool to simulate eviction + let txid_hex = format!("{:x}", txid); + + let removed = + match bitcoind.client.call::("removetx", &[serde_json::json!(txid_hex)]) + { + Ok(_) => { + println!("Removed transaction {} from mempool using removetx", txid); + true + }, + Err(e) => { + println!( + "removetx RPC not available ({}). Skipping test (requires Bitcoin Core 25.0+).", + e + ); + node.stop().unwrap(); + return; + }, + }; + + assert!(removed, "Failed to remove transaction from mempool"); + + // Wait for the removal to propagate + thread::sleep(Duration::from_millis(1000)); + + // Sync again - this should detect the eviction + node.sync_wallets().unwrap(); + + let mut found_evicted_event = false; + let mut evicted_txid = None; + + for _ in 0..20 { + if let Some(event) = node.next_event() { + match event { + Event::OnchainTransactionEvicted { txid: event_txid } => { + if event_txid == txid { + found_evicted_event = true; + evicted_txid = Some(event_txid); + println!("Received OnchainTransactionEvicted event for {}", event_txid); + node.event_handled().unwrap(); + break; + } + node.event_handled().unwrap(); + }, + _ => { + node.event_handled().unwrap(); + }, + } + } + thread::sleep(Duration::from_millis(100)); + } + + assert!( + found_evicted_event, + "Should have received OnchainTransactionEvicted event for transaction {}", + txid + ); + assert_eq!(evicted_txid, Some(txid), "Evicted txid should match the transaction we created"); + + node.stop().unwrap(); +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn get_transaction_details() { + use std::time::Duration; + + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + let config = random_config(false); + let node = setup_node(&chain_source, config, None); + + // Fund the node + let addr = node.onchain_payment().new_address().unwrap(); + let fund_amount = 100_000; + premine_and_distribute_funds( + &bitcoind.client, + &electrsd.client, + vec![addr.clone()], + Amount::from_sat(fund_amount), + ) + .await; + + // Sync to get the funds - this emits OnchainTransactionConfirmed + node.sync_wallets().unwrap(); + + // Find the OnchainTransactionConfirmed event (skip other informational events) + let txid = loop { + match node.next_event().expect("Should have events after sync") { + Event::OnchainTransactionConfirmed { txid, details, .. } => { + assert!(!details.inputs.is_empty()); + assert!(!details.outputs.is_empty()); + node.event_handled().unwrap(); + break txid; + }, + _ => { + node.event_handled().unwrap(); + }, + } + }; + + let details = node.get_transaction_details(&txid).unwrap(); + assert!(!details.inputs.is_empty()); + assert!(!details.outputs.is_empty()); + assert_eq!(details.amount_sats, fund_amount as i64); + + for input in &details.inputs { + assert!(!input.txid.to_string().is_empty()); + assert!(!input.scriptsig.is_empty() || !input.witness.is_empty()); + } + + for output in &details.outputs { + assert!(output.value > 0); + assert!(!output.scriptpubkey.is_empty()); + } + let fake_txid = + Txid::from_str("0000000000000000000000000000000000000000000000000000000000000000").unwrap(); + let result = node.get_transaction_details(&fake_txid); + assert!(result.is_none(), "Non-existent transaction should return None"); + + // Create a new transaction and verify we can get its details + let recipient_addr = node.onchain_payment().new_address().unwrap(); + let send_amount = 20_000; + let send_txid = + node.onchain_payment().send_to_address(&recipient_addr, send_amount, None, None).unwrap(); + + // Sync to include the new transaction + node.sync_wallets().unwrap(); + + // Wait a bit + std::thread::sleep(Duration::from_millis(500)); + + // Get details for the send transaction + let send_details = + node.get_transaction_details(&send_txid).expect("Send transaction should be found"); + + // Verify the send transaction details + assert!(!send_details.inputs.is_empty()); + assert!(!send_details.outputs.is_empty()); + // The amount should be negative (outgoing) or positive depending on change + // But the absolute value should be at least the send amount + assert!(send_details.amount_sats.abs() >= send_amount as i64 || send_details.amount_sats < 0); + + node.stop().unwrap(); +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn get_address_balance_esplora() { + use std::time::Duration; + + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + let config = random_config(false); + let node = setup_node(&chain_source, config, None); + + // Fund an address + let addr = node.onchain_payment().new_address().unwrap(); + let fund_amount = 100_000; + premine_and_distribute_funds( + &bitcoind.client, + &electrsd.client, + vec![addr.clone()], + Amount::from_sat(fund_amount), + ) + .await; + + // Sync to get the funds + node.sync_wallets().unwrap(); + + // Wait a bit for the chain source to index the transaction + std::thread::sleep(Duration::from_millis(500)); + + // Test get_address_balance with the funded address + let balance = node.get_address_balance(&addr.to_string()).unwrap(); + assert_eq!(balance, fund_amount, "Balance should match funded amount"); + + // Test with an unfunded address + let unfunded_addr = node.onchain_payment().new_address().unwrap(); + let unfunded_balance = node.get_address_balance(&unfunded_addr.to_string()).unwrap(); + assert_eq!(unfunded_balance, 0, "Unfunded address should have zero balance"); + + // Test with an invalid address + let invalid_result = node.get_address_balance("invalid_address"); + assert!(invalid_result.is_err(), "Invalid address should return error"); +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn get_address_balance_electrum() { + use std::time::Duration; + + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Electrum(&electrsd); + let config = random_config(false); + let node = setup_node(&chain_source, config, None); + + // Fund an address + let addr = node.onchain_payment().new_address().unwrap(); + let fund_amount = 100_000; + premine_and_distribute_funds( + &bitcoind.client, + &electrsd.client, + vec![addr.clone()], + Amount::from_sat(fund_amount), + ) + .await; + + // Sync to get the funds + node.sync_wallets().unwrap(); + + // Wait a bit for the chain source to index the transaction + std::thread::sleep(Duration::from_millis(500)); + + // Test get_address_balance with the funded address + let balance = node.get_address_balance(&addr.to_string()).unwrap(); + assert_eq!(balance, fund_amount, "Balance should match funded amount"); + + // Test with an unfunded address + let unfunded_addr = node.onchain_payment().new_address().unwrap(); + let unfunded_balance = node.get_address_balance(&unfunded_addr.to_string()).unwrap(); + assert_eq!(unfunded_balance, 0, "Unfunded address should have zero balance"); + + // Test with an invalid address + let invalid_result = node.get_address_balance("invalid_address"); + assert!(invalid_result.is_err(), "Invalid address should return error"); +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn electrum_connection_timeout_config() { + let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let electrum_url = format!("tcp://{}", electrsd.electrum_url); + let config = random_config(false); + setup_builder!(builder, config.node_config); + let sync_config = ElectrumSyncConfig { + background_sync_config: None, + connection_timeout_secs: 20, + ..Default::default() + }; + builder.set_chain_source_electrum(electrum_url, Some(sync_config)); + let node = builder.build().unwrap(); + node.start().unwrap(); + node.sync_wallets().unwrap(); + node.stop().unwrap(); +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn electrum_connection_timeout_zero_disables() { + // connection_timeout_secs: 0 must map to no socket timeout rather than passing + // Duration::ZERO to set_read_timeout, which errors on most platforms and would + // cause start() to fail. + let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let electrum_url = format!("tcp://{}", electrsd.electrum_url); + let config = random_config(false); + setup_builder!(builder, config.node_config); + let sync_config = ElectrumSyncConfig { + background_sync_config: None, + connection_timeout_secs: 0, + ..Default::default() + }; + builder.set_chain_source_electrum(electrum_url, Some(sync_config)); + let node = builder.build().unwrap(); + node.start().unwrap(); + node.sync_wallets().unwrap(); + node.stop().unwrap(); +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn electrum_connection_timeout_above_max_is_capped() { + // Values above 255 must be capped to 255 (electrum_client uses u8) and must not + // prevent startup or sync — the node should start and sync successfully. + let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let electrum_url = format!("tcp://{}", electrsd.electrum_url); + let config = random_config(false); + setup_builder!(builder, config.node_config); + let sync_config = ElectrumSyncConfig { + background_sync_config: None, + connection_timeout_secs: 300, + ..Default::default() + }; + builder.set_chain_source_electrum(electrum_url, Some(sync_config)); + let node = builder.build().unwrap(); + node.start().unwrap(); + node.sync_wallets().unwrap(); + node.stop().unwrap(); +} diff --git a/tests/multi_address_types_tests.rs b/tests/multi_address_types_tests.rs new file mode 100644 index 0000000000..060716e419 --- /dev/null +++ b/tests/multi_address_types_tests.rs @@ -0,0 +1,5072 @@ +// This file is Copyright its original authors, visible in version control history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license , at your option. You may not use this file except in +// accordance with one or both of these licenses. + +mod common; + +// --------------------------------------------------------------------------- +// Shared helpers +// --------------------------------------------------------------------------- +mod helpers { + use std::str::FromStr; + + use bitcoin::{Address, Txid}; + use electrsd::corepc_node::Node as BitcoinD; + use electrsd::ElectrsD; + use ldk_node::bitcoin::Amount; + use ldk_node::config::AddressType; + use ldk_node::Node; + + use crate::common::{generate_blocks_and_wait, premine_and_distribute_funds}; + + /// Default amount to fund a peer node for channel tests. + pub const CHANNEL_PEER_FUNDING_SATS: u64 = 500_000; + + /// Fake txid used in error-case tests (RBF/CPFP reject unknown tx). + pub fn fake_txid_for_error_tests() -> Txid { + "0000000000000000000000000000000000000000000000000000000000000001".parse().unwrap() + } + + /// Standard regtest recipient address used across all tests. + pub fn test_recipient() -> Address { + Address::from_str("bcrt1qw508d6qejxtdg4y5r3zarvary0c5xw7kygt080") + .unwrap() + .require_network(bitcoin::Network::Regtest) + .unwrap() + } + + /// Fund a single address, mine 6 blocks, sync the node, and sleep. + pub async fn fund_and_sync( + bitcoind: &BitcoinD, electrsd: &ElectrsD, node: &Node, addr: Address, amount: u64, + ) { + premine_and_distribute_funds( + &bitcoind.client, + &electrsd.client, + vec![addr], + Amount::from_sat(amount), + ) + .await; + generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 6).await; + node.sync_wallets().unwrap(); + std::thread::sleep(std::time::Duration::from_secs(2)); + } + + /// Fund multiple addresses (each with its own amount), mine 6 blocks, + /// sync, and sleep once at the end. + pub async fn fund_multiple_and_sync( + bitcoind: &BitcoinD, electrsd: &ElectrsD, node: &Node, + addrs_and_amounts: Vec<(Address, u64)>, + ) { + for (addr, amount) in addrs_and_amounts { + premine_and_distribute_funds( + &bitcoind.client, + &electrsd.client, + vec![addr], + Amount::from_sat(amount), + ) + .await; + } + generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 6).await; + node.sync_wallets().unwrap(); + std::thread::sleep(std::time::Duration::from_secs(2)); + } + + /// Fund a peer node for channel tests: premine, mine 6 blocks, sync node, sleep. + pub async fn fund_peer_node_and_sync( + bitcoind: &BitcoinD, electrsd: &ElectrsD, node: &Node, addr: Address, amount: u64, + ) { + premine_and_distribute_funds( + &bitcoind.client, + &electrsd.client, + vec![addr], + Amount::from_sat(amount), + ) + .await; + generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 6).await; + node.sync_wallets().unwrap(); + std::thread::sleep(std::time::Duration::from_secs(2)); + } + + /// Mine blocks, sync node(s), and sleep. Used after confirming txs. + pub async fn confirm_and_sync( + bitcoind: &BitcoinD, electrsd: &ElectrsD, blocks: usize, nodes: &[&Node], + ) { + generate_blocks_and_wait(&bitcoind.client, &electrsd.client, blocks).await; + for node in nodes { + node.sync_wallets().unwrap(); + } + std::thread::sleep(std::time::Duration::from_secs(1)); + } + + /// Convenience: create a node config with a given primary + monitored types. + pub fn node_config( + primary: AddressType, monitored: Vec, + ) -> crate::common::TestConfig { + let mut config = crate::common::random_config(true); + config.node_config.address_type = primary; + config.node_config.address_types_to_monitor = monitored; + config + } + + /// Read the seed bytes from the node's storage directory (created by the default entropy + /// source during build). Used to pass seed bytes to the dynamic address type APIs in tests. + pub fn read_node_seed(node: &Node) -> [u8; 64] { + let config = node.config(); + let seed_path = format!("{}/keys_seed", config.storage_dir_path); + let seed = std::fs::read(&seed_path) + .unwrap_or_else(|e| panic!("Failed to read seed file at {}: {}", seed_path, e)); + assert_eq!( + seed.len(), + 64, + "keys_seed at {} must be 64 bytes (got {})", + seed_path, + seed.len() + ); + let mut bytes = [0u8; 64]; + bytes.copy_from_slice(&seed); + bytes + } +} + +// --------------------------------------------------------------------------- +// Setup & Configuration +// --------------------------------------------------------------------------- +mod setup { + use ldk_node::config::AddressType; + + use crate::common::{setup_bitcoind_and_electrsd, setup_node, TestChainSource}; + use crate::helpers::{fund_multiple_and_sync, node_config}; + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_multi_wallet_setup() { + let (_bitcoind, _electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&_electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node = setup_node(&chain_source, config, None); + + assert!(node.status().is_running); + let addr = node.onchain_payment().new_address().unwrap(); + assert!(!addr.to_string().is_empty()); + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_all_address_types_as_primary() { + let address_types = vec![ + AddressType::Legacy, + AddressType::NestedSegwit, + AddressType::NativeSegwit, + AddressType::Taproot, + ]; + + for primary_type in address_types { + let (_bitcoind, _electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&_electrsd); + + let config = node_config(primary_type, vec![]); + let node = setup_node(&chain_source, config, None); + assert!(node.status().is_running); + + let addr = node.onchain_payment().new_address().unwrap(); + assert!(!addr.to_string().is_empty()); + node.stop().unwrap(); + } + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_multi_wallet_all_combinations() { + let address_types = vec![ + AddressType::Legacy, + AddressType::NestedSegwit, + AddressType::NativeSegwit, + AddressType::Taproot, + ]; + + for primary_type in &address_types { + for monitored_type in &address_types { + if primary_type == monitored_type { + continue; + } + + let (_bitcoind, _electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&_electrsd); + + let config = node_config(*primary_type, vec![*monitored_type]); + let node = setup_node(&chain_source, config, None); + assert!(node.status().is_running); + + let addr = node.onchain_payment().new_address().unwrap(); + assert!(!addr.to_string().is_empty()); + node.stop().unwrap(); + + // Brief delay to allow OS to release ports (TIME_WAIT) before next bind + std::thread::sleep(std::time::Duration::from_millis(100)); + } + } + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_multi_wallet_electrum_setup() { + let (_bitcoind, _electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Electrum(&_electrsd); + + let config = node_config( + AddressType::NestedSegwit, + vec![AddressType::NativeSegwit, AddressType::Taproot], + ); + let node = setup_node(&chain_source, config, None); + assert!(node.status().is_running); + + let addr = node.onchain_payment().new_address().unwrap(); + assert!(!addr.to_string().is_empty()); + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_multi_wallet_empty_monitoring() { + let (_bitcoind, _electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&_electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![]); + let node = setup_node(&chain_source, config, None); + assert!(node.status().is_running); + + let addr = node.onchain_payment().new_address().unwrap(); + assert!(!addr.to_string().is_empty()); + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_new_address_for_type() { + let (_bitcoind, _electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&_electrsd); + + let config = node_config( + AddressType::NativeSegwit, + vec![AddressType::Legacy, AddressType::NestedSegwit, AddressType::Taproot], + ); + let node = setup_node(&chain_source, config, None); + + for address_type in [ + AddressType::Legacy, + AddressType::NestedSegwit, + AddressType::NativeSegwit, + AddressType::Taproot, + ] { + let addr = node.onchain_payment().new_address_for_type(address_type).unwrap(); + assert!(!addr.to_string().is_empty()); + } + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_new_address_for_unmonitored_type() { + let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![]); + let node = setup_node(&chain_source, config, None); + + assert!(node.onchain_payment().new_address_for_type(AddressType::NativeSegwit).is_ok()); + assert!(node.onchain_payment().new_address_for_type(AddressType::Legacy).is_err()); + assert!(node.onchain_payment().new_address_for_type(AddressType::Taproot).is_err()); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_duplicate_monitor_types_deduplicated() { + let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config( + AddressType::NativeSegwit, + vec![AddressType::Legacy, AddressType::Legacy, AddressType::Taproot], + ); + let node = setup_node(&chain_source, config, None); + + let monitored = node.list_monitored_address_types(); + assert_eq!( + monitored.len(), + 3, + "Duplicate Legacy should be deduplicated, got {:?}", + monitored + ); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_multi_wallet_persistence_across_restart() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = + node_config(AddressType::NativeSegwit, vec![AddressType::Legacy, AddressType::Taproot]); + let node = setup_node(&chain_source, config, None); + + let native_addr = node.onchain_payment().new_address().unwrap(); + let legacy_addr = node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + let taproot_addr = + node.onchain_payment().new_address_for_type(AddressType::Taproot).unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![(native_addr, 100_000), (legacy_addr, 100_000), (taproot_addr, 100_000)], + ) + .await; + + let native_before = + node.get_balance_for_address_type(AddressType::NativeSegwit).unwrap().total_sats; + let legacy_before = + node.get_balance_for_address_type(AddressType::Legacy).unwrap().total_sats; + let taproot_before = + node.get_balance_for_address_type(AddressType::Taproot).unwrap().total_sats; + let total_before = node.list_balances().total_onchain_balance_sats; + + assert!(native_before >= 99_000); + assert!(legacy_before >= 99_000); + assert!(taproot_before >= 99_000); + + node.stop().unwrap(); + node.start().unwrap(); + + node.sync_wallets().unwrap(); + std::thread::sleep(std::time::Duration::from_secs(1)); + + assert_eq!( + node.get_balance_for_address_type(AddressType::NativeSegwit).unwrap().total_sats, + native_before + ); + assert_eq!( + node.get_balance_for_address_type(AddressType::Legacy).unwrap().total_sats, + legacy_before + ); + assert_eq!( + node.get_balance_for_address_type(AddressType::Taproot).unwrap().total_sats, + taproot_before + ); + assert_eq!(node.list_balances().total_onchain_balance_sats, total_before); + + let monitored = node.list_monitored_address_types(); + assert!(monitored.contains(&AddressType::NativeSegwit)); + assert!(monitored.contains(&AddressType::Legacy)); + assert!(monitored.contains(&AddressType::Taproot)); + + node.stop().unwrap(); + } +} + +// --------------------------------------------------------------------------- +// Electrum chain source +// --------------------------------------------------------------------------- +mod electrum_chain { + use ldk_node::config::AddressType; + + use crate::common::{setup_bitcoind_and_electrsd, setup_node, wait_for_tx, TestChainSource}; + use crate::helpers::{confirm_and_sync, fund_multiple_and_sync, node_config, test_recipient}; + + /// Electrum chain source: balance sync and send work with multi-address-types. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_electrum_sync_and_send() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Electrum(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node = setup_node(&chain_source, config, None); + + let native_addr = node.onchain_payment().new_address().unwrap(); + let legacy_addr = node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![(native_addr, 100_000), (legacy_addr, 100_000)], + ) + .await; + + let native_balance = node.get_balance_for_address_type(AddressType::NativeSegwit).unwrap(); + let legacy_balance = node.get_balance_for_address_type(AddressType::Legacy).unwrap(); + assert!(native_balance.total_sats >= 99_000); + assert!(legacy_balance.total_sats >= 99_000); + + let txid = node + .onchain_payment() + .send_to_address(&test_recipient(), 50_000, None, None) + .expect("Send with Electrum should succeed"); + + wait_for_tx(&electrsd.client, txid).await; + confirm_and_sync(&bitcoind, &electrsd, 1, &[&node]).await; + + let total_after = node.list_balances().total_onchain_balance_sats; + assert!(total_after < 200_000 - 50_000 + 5_000); + + node.stop().unwrap(); + } +} + +// --------------------------------------------------------------------------- +// Balance +// --------------------------------------------------------------------------- +mod balance { + use ldk_node::config::AddressType; + + use crate::common::{setup_bitcoind_and_electrsd, setup_node, wait_for_tx, TestChainSource}; + use crate::helpers::{ + confirm_and_sync, fund_and_sync, fund_multiple_and_sync, node_config, test_recipient, + }; + + // --- Balance sync & queries --- + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_sync_updates_all_wallet_balances() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config( + AddressType::NativeSegwit, + vec![AddressType::Legacy, AddressType::NestedSegwit, AddressType::Taproot], + ); + let node = setup_node(&chain_source, config, None); + + let native_addr = node.onchain_payment().new_address().unwrap(); + let legacy_addr = node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + let nested_addr = + node.onchain_payment().new_address_for_type(AddressType::NestedSegwit).unwrap(); + let taproot_addr = + node.onchain_payment().new_address_for_type(AddressType::Taproot).unwrap(); + + // Verify all balances are 0 before funding. + assert_eq!( + node.get_balance_for_address_type(AddressType::NativeSegwit).unwrap().total_sats, + 0 + ); + assert_eq!(node.get_balance_for_address_type(AddressType::Legacy).unwrap().total_sats, 0); + assert_eq!( + node.get_balance_for_address_type(AddressType::NestedSegwit).unwrap().total_sats, + 0 + ); + assert_eq!(node.get_balance_for_address_type(AddressType::Taproot).unwrap().total_sats, 0); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![ + (native_addr, 100_000), + (legacy_addr, 200_000), + (nested_addr, 300_000), + (taproot_addr, 400_000), + ], + ) + .await; + + let native_balance = node.get_balance_for_address_type(AddressType::NativeSegwit).unwrap(); + let legacy_balance = node.get_balance_for_address_type(AddressType::Legacy).unwrap(); + let nested_balance = node.get_balance_for_address_type(AddressType::NestedSegwit).unwrap(); + let taproot_balance = node.get_balance_for_address_type(AddressType::Taproot).unwrap(); + + assert!(native_balance.total_sats >= 99_000, "NativeSegwit: {}", native_balance.total_sats); + assert!(legacy_balance.total_sats >= 199_000, "Legacy: {}", legacy_balance.total_sats); + assert!( + nested_balance.total_sats >= 299_000, + "NestedSegwit: {}", + nested_balance.total_sats + ); + assert!(taproot_balance.total_sats >= 399_000, "Taproot: {}", taproot_balance.total_sats); + + let total = node.list_balances().total_onchain_balance_sats; + let expected_total = native_balance.total_sats + + legacy_balance.total_sats + + nested_balance.total_sats + + taproot_balance.total_sats; + assert_eq!(total, expected_total); + + node.stop().unwrap(); + } + + // --- Error cases --- + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_get_balance_for_unmonitored_type() { + let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![]); + let node = setup_node(&chain_source, config, None); + + assert!(node.get_balance_for_address_type(AddressType::NativeSegwit).is_ok()); + assert!(node.get_balance_for_address_type(AddressType::Legacy).is_err()); + assert!(node.get_balance_for_address_type(AddressType::Taproot).is_err()); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_spend_with_empty_monitored_wallet() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node = setup_node(&chain_source, config, None); + + let native_addr = node.onchain_payment().new_address().unwrap(); + fund_and_sync(&bitcoind, &electrsd, &node, native_addr, 200_000).await; + + let native_balance = node.get_balance_for_address_type(AddressType::NativeSegwit).unwrap(); + let legacy_balance = node.get_balance_for_address_type(AddressType::Legacy).unwrap(); + assert!(native_balance.total_sats >= 199_000); + assert_eq!(legacy_balance.total_sats, 0); + + let result = node.onchain_payment().send_to_address(&test_recipient(), 50_000, None, None); + assert!(result.is_ok(), "Send should succeed using only NativeSegwit funds"); + + node.stop().unwrap(); + } + + /// Send fails with InsufficientFunds when total across all wallets is insufficient. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_insufficient_funds_returns_error() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = + node_config(AddressType::NativeSegwit, vec![AddressType::Legacy, AddressType::Taproot]); + let node = setup_node(&chain_source, config, None); + + let native_addr = node.onchain_payment().new_address().unwrap(); + let legacy_addr = node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + let taproot_addr = + node.onchain_payment().new_address_for_type(AddressType::Taproot).unwrap(); + + // Total ~150k across all wallets. + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![(native_addr, 50_000), (legacy_addr, 50_000), (taproot_addr, 50_000)], + ) + .await; + + let total = node.list_balances().total_onchain_balance_sats; + assert!(total < 200_000); + + let result = node.onchain_payment().send_to_address(&test_recipient(), 200_000, None, None); + assert!(result.is_err(), "Send should fail when total balance is insufficient"); + let err = result.unwrap_err(); + assert!( + matches!( + err, + ldk_node::NodeError::InsufficientFunds + | ldk_node::NodeError::OnchainTxCreationFailed + ), + "Expected InsufficientFunds or OnchainTxCreationFailed, got {:?}", + err + ); + + node.stop().unwrap(); + } + + // --- Balance consistency --- + + /// Asserts listBalances().spendableOnchainBalanceSats equals sum of listSpendableOutputs() values. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_list_balances_matches_utxo_sum() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Taproot]); + let node = setup_node(&chain_source, config, None); + + let native_addr = node.onchain_payment().new_address().unwrap(); + let taproot_addr = + node.onchain_payment().new_address_for_type(AddressType::Taproot).unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![(native_addr, 100_000), (taproot_addr, 200_000)], + ) + .await; + + let balances = node.list_balances(); + let utxos = node.onchain_payment().list_spendable_outputs().unwrap(); + let utxo_sum: u64 = utxos.iter().map(|u| u.value_sats).sum(); + + assert_eq!( + balances.spendable_onchain_balance_sats, utxo_sum, + "listBalances spendable should equal UTXO sum (spendable={} utxo_sum={})", + balances.spendable_onchain_balance_sats, utxo_sum + ); + + node.stop().unwrap(); + } + + /// Asserts sum of per-type spendable equals listBalances().spendableOnchainBalanceSats. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_per_type_sum_equals_aggregate_spendable() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = + node_config(AddressType::NativeSegwit, vec![AddressType::Legacy, AddressType::Taproot]); + let node = setup_node(&chain_source, config, None); + + let native_addr = node.onchain_payment().new_address().unwrap(); + let legacy_addr = node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + let taproot_addr = + node.onchain_payment().new_address_for_type(AddressType::Taproot).unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![(native_addr, 80_000), (legacy_addr, 70_000), (taproot_addr, 90_000)], + ) + .await; + + let aggregate_spendable = node.list_balances().spendable_onchain_balance_sats; + let per_type_sum: u64 = node + .list_monitored_address_types() + .iter() + .filter_map(|t| node.get_balance_for_address_type(*t).ok()) + .map(|b| b.spendable_sats) + .sum(); + + assert_eq!( + per_type_sum, aggregate_spendable, + "Sum of per-type spendable should equal aggregate (per_type_sum={} aggregate={})", + per_type_sum, aggregate_spendable + ); + + node.stop().unwrap(); + } + + /// Asserts no phantom balance after spend-all: listSpendableOutputs empty, total==0. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_no_phantom_balance_after_spend_all() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Taproot]); + let node = setup_node(&chain_source, config, None); + + let native_addr = node.onchain_payment().new_address().unwrap(); + let taproot_addr = + node.onchain_payment().new_address_for_type(AddressType::Taproot).unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![(native_addr, 50_000), (taproot_addr, 50_000)], + ) + .await; + + let txid = node + .onchain_payment() + .send_all_to_address(&test_recipient(), false, None) + .expect("spend-all should succeed"); + + wait_for_tx(&electrsd.client, txid).await; + confirm_and_sync(&bitcoind, &electrsd, 1, &[&node]).await; + + // Poll a few times to catch sync timing issues + for _ in 0..5 { + let utxos = node.onchain_payment().list_spendable_outputs().unwrap(); + let balances = node.list_balances(); + + assert!(utxos.is_empty(), "listSpendableOutputs should be empty after spend-all"); + assert_eq!( + balances.total_onchain_balance_sats, 0, + "total_onchain_balance_sats should be 0" + ); + assert_eq!( + balances.spendable_onchain_balance_sats, 0, + "spendable_onchain_balance_sats should be 0" + ); + + std::thread::sleep(std::time::Duration::from_secs(1)); + } + + node.stop().unwrap(); + } + + /// Asserts spendable equals UTXO sum for a single-address-type wallet. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_balance_consistency_single_address_type() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![]); + let node = setup_node(&chain_source, config, None); + + let addr = node.onchain_payment().new_address().unwrap(); + fund_and_sync(&bitcoind, &electrsd, &node, addr, 150_000).await; + + let balances = node.list_balances(); + let utxos = node.onchain_payment().list_spendable_outputs().unwrap(); + let utxo_sum: u64 = utxos.iter().map(|u| u.value_sats).sum(); + + assert_eq!( + balances.spendable_onchain_balance_sats, utxo_sum, + "Single-type: spendable should equal UTXO sum" + ); + + node.stop().unwrap(); + } +} + +// --------------------------------------------------------------------------- +// Send +// --------------------------------------------------------------------------- +mod send { + use bitcoin::FeeRate; + use electrum_client::ElectrumApi; + use ldk_node::config::AddressType; + + use crate::common::{ + api_fee_rate, setup_bitcoind_and_electrsd, setup_node, wait_for_tx, TestChainSource, + }; + use crate::helpers::{ + confirm_and_sync, fund_and_sync, fund_multiple_and_sync, node_config, test_recipient, + }; + + // --- Basic & cross-wallet sends --- + + /// Basic send works for all primary address types. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_send_basic() { + let test_cases = vec![ + (AddressType::NativeSegwit, vec![AddressType::Legacy]), + (AddressType::Legacy, vec![AddressType::NativeSegwit, AddressType::Taproot]), + (AddressType::Taproot, vec![AddressType::NestedSegwit]), + ]; + + for (primary_type, monitored_types) in test_cases { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(primary_type, monitored_types); + let node = setup_node(&chain_source, config, None); + + let addr = node.onchain_payment().new_address().unwrap(); + fund_and_sync(&bitcoind, &electrsd, &node, addr, 200_000).await; + + let balances = node.list_balances(); + assert!(balances.spendable_onchain_balance_sats >= 190_000); + + let txid = node + .onchain_payment() + .send_to_address(&test_recipient(), 50_000, None, None) + .expect("Send should succeed for all address type combinations"); + + wait_for_tx(&electrsd.client, txid).await; + confirm_and_sync(&bitcoind, &electrsd, 1, &[&node]).await; + + let new_balances = node.list_balances(); + assert!( + new_balances.spendable_onchain_balance_sats + < balances.spendable_onchain_balance_sats + ); + + node.stop().unwrap(); + } + } + + /// Send with custom fee rate across address types. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_send_with_custom_fee_rate() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node = setup_node(&chain_source, config, None); + + let native_addr = node.onchain_payment().new_address().unwrap(); + let legacy_addr = node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![(native_addr, 100_000), (legacy_addr, 100_000)], + ) + .await; + + let custom_fee_rate = bitcoin::FeeRate::from_sat_per_kwu(800); + let txid = node + .onchain_payment() + .send_to_address(&test_recipient(), 50_000, Some(api_fee_rate(custom_fee_rate)), None) + .expect("Send with custom fee rate should succeed"); + + wait_for_tx(&electrsd.client, txid).await; + confirm_and_sync(&bitcoind, &electrsd, 1, &[&node]).await; + + let new_balance = node.list_balances().total_onchain_balance_sats; + assert!(new_balance < 200_000 - 50_000); + + node.stop().unwrap(); + } + + /// Send requiring UTXOs from two different wallet types. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_cross_wallet_spending() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node = setup_node(&chain_source, config, None); + + let native_addr = node.onchain_payment().new_address().unwrap(); + let legacy_addr = node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![(native_addr, 100_000), (legacy_addr, 100_000)], + ) + .await; + + let native_balance = node.get_balance_for_address_type(AddressType::NativeSegwit).unwrap(); + let legacy_balance = node.get_balance_for_address_type(AddressType::Legacy).unwrap(); + assert!(native_balance.total_sats >= 99_000); + assert!(legacy_balance.total_sats >= 99_000); + + // 150k > either wallet alone, requires both. + let txid = node + .onchain_payment() + .send_to_address(&test_recipient(), 150_000, None, None) + .expect("Cross-wallet spending should succeed"); + + wait_for_tx(&electrsd.client, txid).await; + confirm_and_sync(&bitcoind, &electrsd, 1, &[&node]).await; + + let monitored_types = node.list_monitored_address_types(); + assert!(monitored_types.contains(&AddressType::NativeSegwit)); + assert!(monitored_types.contains(&AddressType::Legacy)); + + node.stop().unwrap(); + } + + /// Send requiring UTXOs from all four wallet types. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_cross_wallet_spending_all_four_types() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config( + AddressType::NativeSegwit, + vec![AddressType::Legacy, AddressType::NestedSegwit, AddressType::Taproot], + ); + let node = setup_node(&chain_source, config, None); + + let native_addr = node.onchain_payment().new_address().unwrap(); + let legacy_addr = node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + let nested_addr = + node.onchain_payment().new_address_for_type(AddressType::NestedSegwit).unwrap(); + let taproot_addr = + node.onchain_payment().new_address_for_type(AddressType::Taproot).unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![ + (native_addr, 60_000), + (legacy_addr, 60_000), + (nested_addr, 60_000), + (taproot_addr, 60_000), + ], + ) + .await; + + let total_before = node.list_balances().total_onchain_balance_sats; + + // 200k > any three wallets (180k), requires all four. + let txid = node + .onchain_payment() + .send_to_address(&test_recipient(), 200_000, None, None) + .expect("Cross-wallet spending with all 4 types should succeed"); + + wait_for_tx(&electrsd.client, txid).await; + + let tx = electrsd.client.transaction_get(&txid).unwrap(); + assert!(tx.input.len() >= 4, "Should use at least 4 inputs, got {}", tx.input.len()); + + confirm_and_sync(&bitcoind, &electrsd, 1, &[&node]).await; + + let total_after = node.list_balances().total_onchain_balance_sats; + assert!(total_after < total_before - 200_000 + 10_000); + + node.stop().unwrap(); + } + + // --- send_all --- + + /// send_all drains both wallets (retain_reserves=true). + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_send_all_drains_all_wallets() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::Taproot, vec![AddressType::NativeSegwit]); + let node = setup_node(&chain_source, config, None); + + let taproot_addr = node.onchain_payment().new_address().unwrap(); + let native_addr = + node.onchain_payment().new_address_for_type(AddressType::NativeSegwit).unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![(taproot_addr, 100_000), (native_addr, 100_000)], + ) + .await; + + assert!( + node.get_balance_for_address_type(AddressType::Taproot).unwrap().total_sats >= 99_000 + ); + assert!( + node.get_balance_for_address_type(AddressType::NativeSegwit).unwrap().total_sats + >= 99_000 + ); + + let txid = node + .onchain_payment() + .send_all_to_address(&test_recipient(), true, None) + .expect("send_all should succeed"); + + wait_for_tx(&electrsd.client, txid).await; + confirm_and_sync(&bitcoind, &electrsd, 1, &[&node]).await; + + assert!( + node.get_balance_for_address_type(AddressType::Taproot).unwrap().spendable_sats + < 10_000 + ); + assert!( + node.get_balance_for_address_type(AddressType::NativeSegwit).unwrap().spendable_sats + < 10_000 + ); + assert!(node.list_balances().total_onchain_balance_sats < 10_000); + + node.stop().unwrap(); + } + + /// send_all with retain_reserves=false drains every wallet to zero. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_send_all_drain_reserve_multi_wallet() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = + node_config(AddressType::NativeSegwit, vec![AddressType::Legacy, AddressType::Taproot]); + let node = setup_node(&chain_source, config, None); + + let native_addr = node.onchain_payment().new_address().unwrap(); + let legacy_addr = node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + let taproot_addr = + node.onchain_payment().new_address_for_type(AddressType::Taproot).unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![(native_addr, 50_000), (legacy_addr, 50_000), (taproot_addr, 50_000)], + ) + .await; + + let total_before = node.list_balances().total_onchain_balance_sats; + assert!(total_before >= 140_000); + + let txid = node + .onchain_payment() + .send_all_to_address(&test_recipient(), false, None) + .expect("drain all should succeed"); + + wait_for_tx(&electrsd.client, txid).await; + confirm_and_sync(&bitcoind, &electrsd, 1, &[&node]).await; + + assert_eq!(node.list_balances().total_onchain_balance_sats, 0); + + let drain_tx = electrsd.client.transaction_get(&txid).unwrap(); + assert!( + drain_tx.input.len() >= 3, + "Should drain all 3 wallets, got {} inputs", + drain_tx.input.len() + ); + + node.stop().unwrap(); + } + + /// send_all with custom fee rate drains all wallets. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_send_all_with_custom_fee_rate() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node = setup_node(&chain_source, config, None); + + let native_addr = node.onchain_payment().new_address().unwrap(); + let legacy_addr = node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![(native_addr, 100_000), (legacy_addr, 100_000)], + ) + .await; + + let custom_fee_rate = bitcoin::FeeRate::from_sat_per_kwu(1000); + let txid = node + .onchain_payment() + .send_all_to_address(&test_recipient(), true, Some(api_fee_rate(custom_fee_rate))) + .expect("send_all with custom fee rate should succeed"); + + wait_for_tx(&electrsd.client, txid).await; + confirm_and_sync(&bitcoind, &electrsd, 1, &[&node]).await; + + assert!(node.list_balances().total_onchain_balance_sats < 10_000); + + node.stop().unwrap(); + } + + /// send_all works correctly when primary is Legacy. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_send_all_legacy_primary() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::Legacy, vec![AddressType::NativeSegwit]); + let node = setup_node(&chain_source, config, None); + + let legacy_addr = node.onchain_payment().new_address().unwrap(); + let segwit_addr = + node.onchain_payment().new_address_for_type(AddressType::NativeSegwit).unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![(legacy_addr, 100_000), (segwit_addr, 100_000)], + ) + .await; + + assert!( + node.get_balance_for_address_type(AddressType::Legacy).unwrap().total_sats >= 99_000 + ); + assert!( + node.get_balance_for_address_type(AddressType::NativeSegwit).unwrap().total_sats + >= 99_000 + ); + + let txid = node + .onchain_payment() + .send_all_to_address(&test_recipient(), true, None) + .expect("send_all with legacy primary should succeed"); + + wait_for_tx(&electrsd.client, txid).await; + confirm_and_sync(&bitcoind, &electrsd, 1, &[&node]).await; + + assert!( + node.get_balance_for_address_type(AddressType::Legacy).unwrap().spendable_sats < 10_000 + ); + assert!( + node.get_balance_for_address_type(AddressType::NativeSegwit).unwrap().spendable_sats + < 10_000 + ); + assert!(node.list_balances().total_onchain_balance_sats < 10_000); + + node.stop().unwrap(); + } + + // --- Manual UTXO selection --- + + /// Send using manually-selected UTXOs from different address types. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_send_with_specific_utxos_from_different_types() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = + node_config(AddressType::NativeSegwit, vec![AddressType::Legacy, AddressType::Taproot]); + let node = setup_node(&chain_source, config, None); + + let native_addr = node.onchain_payment().new_address().unwrap(); + let legacy_addr = node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + let taproot_addr = + node.onchain_payment().new_address_for_type(AddressType::Taproot).unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![(native_addr, 50_000), (legacy_addr, 50_000), (taproot_addr, 50_000)], + ) + .await; + + let selected_utxos = node + .onchain_payment() + .select_utxos_with_algorithm( + 140_000, + Some(api_fee_rate(FeeRate::from_sat_per_kwu(500))), + ldk_node::CoinSelectionAlgorithm::LargestFirst, + None, + ) + .expect("Should select UTXOs from multiple wallet types"); + + assert!( + selected_utxos.len() >= 3, + "Should have at least 3 UTXOs, got {}", + selected_utxos.len() + ); + + let txid = node + .onchain_payment() + .send_to_address(&test_recipient(), 100_000, None, Some(selected_utxos)) + .expect("Send with specific UTXOs should succeed"); + + wait_for_tx(&electrsd.client, txid).await; + + let tx = electrsd.client.transaction_get(&txid).unwrap(); + assert!(tx.input.len() >= 3, "Tx should have at least 3 inputs, got {}", tx.input.len()); + + node.stop().unwrap(); + } +} + +// --------------------------------------------------------------------------- +// Channel Funding +// --------------------------------------------------------------------------- +mod channel_funding { + use electrum_client::ElectrumApi; + use ldk_node::config::AddressType; + use ldk_node::Event; + + use crate::common::{ + expect_channel_ready_event, expect_event, open_channel, setup_bitcoind_and_electrsd, + setup_node, wait_for_outpoint_spend, TestChainSource, + }; + use crate::helpers::{ + confirm_and_sync, fund_multiple_and_sync, fund_peer_node_and_sync, node_config, + CHANNEL_PEER_FUNDING_SATS, + }; + + // --- Cross-wallet & witness requirements --- + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_open_channel_with_cross_wallet_witness_inputs() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config_a = node_config( + AddressType::NativeSegwit, + vec![AddressType::Legacy, AddressType::NestedSegwit, AddressType::Taproot], + ); + let node_a = setup_node(&chain_source, config_a, None); + + let config_b = crate::common::random_config(true); + let node_b = setup_node(&chain_source, config_b, None); + + let native_addr = node_a.onchain_payment().new_address().unwrap(); + let legacy_addr = + node_a.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + let nested_addr = + node_a.onchain_payment().new_address_for_type(AddressType::NestedSegwit).unwrap(); + let taproot_addr = + node_a.onchain_payment().new_address_for_type(AddressType::Taproot).unwrap(); + + let addr_b = node_b.onchain_payment().new_address().unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node_a, + vec![ + (native_addr, 55_000), + (legacy_addr, 55_000), + (nested_addr, 55_000), + (taproot_addr, 55_000), + ], + ) + .await; + + fund_peer_node_and_sync(&bitcoind, &electrsd, &node_b, addr_b, CHANNEL_PEER_FUNDING_SATS) + .await; + + // 120k > any two witness wallets (110k), needs all three. + let funding_txo = open_channel(&node_a, &node_b, 120_000, false, &electrsd).await; + + let funding_tx = electrsd.client.transaction_get(&funding_txo.txid).unwrap(); + assert!( + funding_tx.input.len() >= 3, + "Should have at least 3 witness inputs, got {}", + funding_tx.input.len() + ); + + confirm_and_sync(&bitcoind, &electrsd, 6, &[&node_a, &node_b]).await; + + assert!(!node_a.list_channels().is_empty()); + + // Legacy funds untouched. + let legacy_after = node_a.get_balance_for_address_type(AddressType::Legacy).unwrap(); + assert!(legacy_after.total_sats >= 54_000); + + node_a.stop().unwrap(); + node_b.stop().unwrap(); + } + + /// Opening a channel with only non-witness outputs (Legacy or NestedSegwit) fails. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_open_channel_non_witness_only_returns_error() { + for primary_type in [AddressType::Legacy, AddressType::NestedSegwit] { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config_a = node_config(primary_type, vec![]); + let node_a = setup_node(&chain_source, config_a, None); + + let config_b = crate::common::random_config(true); + let node_b = setup_node(&chain_source, config_b, None); + + let addr_a = node_a.onchain_payment().new_address().unwrap(); + let addr_b = node_b.onchain_payment().new_address().unwrap(); + + fund_multiple_and_sync(&bitcoind, &electrsd, &node_a, vec![(addr_a, 500_000)]).await; + fund_peer_node_and_sync( + &bitcoind, + &electrsd, + &node_b, + addr_b, + CHANNEL_PEER_FUNDING_SATS, + ) + .await; + + let result = node_a.open_channel( + node_b.node_id(), + node_b.listening_addresses().unwrap().first().unwrap().clone(), + 100_000, + None, + None, + ); + + assert!(result.is_err(), "Opening with only {:?} should fail", primary_type); + // Legacy returns InsufficientFunds; NestedSegwit may return ChannelCreationFailed + let err = result.unwrap_err(); + assert!( + matches!( + err, + ldk_node::NodeError::InsufficientFunds + | ldk_node::NodeError::ChannelCreationFailed + ), + "Expected InsufficientFunds or ChannelCreationFailed, got {:?}", + err + ); + + node_a.stop().unwrap(); + node_b.stop().unwrap(); + } + } + + // --- Legacy primary + Segwit --- + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_open_channel_legacy_primary_uses_segwit_wallet() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config_a = node_config(AddressType::Legacy, vec![AddressType::NativeSegwit]); + let node_a = setup_node(&chain_source, config_a, None); + + let config_b = crate::common::random_config(true); + let node_b = setup_node(&chain_source, config_b, None); + + let legacy_addr = node_a.onchain_payment().new_address().unwrap(); + let segwit_addr = + node_a.onchain_payment().new_address_for_type(AddressType::NativeSegwit).unwrap(); + let addr_b = node_b.onchain_payment().new_address().unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node_a, + vec![(legacy_addr, 200_000), (segwit_addr, 200_000)], + ) + .await; + fund_peer_node_and_sync(&bitcoind, &electrsd, &node_b, addr_b, CHANNEL_PEER_FUNDING_SATS) + .await; + + let funding_txo = open_channel(&node_a, &node_b, 100_000, false, &electrsd).await; + + confirm_and_sync(&bitcoind, &electrsd, 6, &[&node_a, &node_b]).await; + + assert!(!node_a.list_channels().is_empty()); + + // Legacy untouched. + let legacy_balance = node_a.get_balance_for_address_type(AddressType::Legacy).unwrap(); + assert!(legacy_balance.total_sats >= 190_000); + + // NativeSegwit was used. + let segwit_balance = + node_a.get_balance_for_address_type(AddressType::NativeSegwit).unwrap(); + assert!(segwit_balance.total_sats < 190_000); + + // All funding inputs have witness data. + let funding_tx = electrsd.client.transaction_get(&funding_txo.txid).unwrap(); + for input in &funding_tx.input { + assert!( + !input.witness.is_empty(), + "Input {:?} has empty witness", + input.previous_output + ); + } + + node_a.stop().unwrap(); + node_b.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_legacy_primary_channel_funding_excludes_legacy_inputs() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config_a = + node_config(AddressType::Legacy, vec![AddressType::NativeSegwit, AddressType::Taproot]); + let node_a = setup_node(&chain_source, config_a, None); + + let config_b = crate::common::random_config(true); + let node_b = setup_node(&chain_source, config_b, None); + + let legacy_addr = node_a.onchain_payment().new_address().unwrap(); + let native_addr = + node_a.onchain_payment().new_address_for_type(AddressType::NativeSegwit).unwrap(); + let taproot_addr = + node_a.onchain_payment().new_address_for_type(AddressType::Taproot).unwrap(); + let addr_b = node_b.onchain_payment().new_address().unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node_a, + vec![(legacy_addr, 200_000), (native_addr, 100_000), (taproot_addr, 100_000)], + ) + .await; + fund_peer_node_and_sync(&bitcoind, &electrsd, &node_b, addr_b, CHANNEL_PEER_FUNDING_SATS) + .await; + + // Legacy has 200k (enough alone) but must be excluded. + let funding_txo = open_channel(&node_a, &node_b, 120_000, false, &electrsd).await; + + let funding_tx = electrsd.client.transaction_get(&funding_txo.txid).unwrap(); + for input in &funding_tx.input { + assert!(!input.witness.is_empty(), "All funding inputs must have witness data"); + } + + // Legacy balance untouched. + node_a.sync_wallets().unwrap(); + let legacy_balance = node_a.get_balance_for_address_type(AddressType::Legacy).unwrap(); + assert!(legacy_balance.total_sats >= 190_000); + + node_a.stop().unwrap(); + node_b.stop().unwrap(); + } + + // --- NestedSegwit primary --- + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_inbound_channel_with_non_native_witness_primary() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config_a = node_config(AddressType::Legacy, vec![AddressType::Taproot]); + let node_a = setup_node(&chain_source, config_a, None); + + let config_b = crate::common::random_config(true); + let node_b = setup_node(&chain_source, config_b, None); + + let addr_b = node_b.onchain_payment().new_address().unwrap(); + fund_peer_node_and_sync(&bitcoind, &electrsd, &node_b, addr_b, CHANNEL_PEER_FUNDING_SATS) + .await; + node_a.sync_wallets().unwrap(); + + // Node B opens toward node A (inbound). get_shutdown_scriptpubkey must + // produce a native witness address from Taproot, not Legacy. + let _funding_txo = open_channel(&node_b, &node_a, 100_000, false, &electrsd).await; + + confirm_and_sync(&bitcoind, &electrsd, 6, &[&node_a, &node_b]).await; + + assert!(!node_a.list_channels().is_empty(), "Node A should have an inbound channel"); + + node_a.stop().unwrap(); + node_b.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_open_channel_nested_primary_with_native_monitor() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config_a = node_config(AddressType::NestedSegwit, vec![AddressType::NativeSegwit]); + let node_a = setup_node(&chain_source, config_a, None); + + let config_b = crate::common::random_config(true); + let node_b = setup_node(&chain_source, config_b, None); + + let nested_addr = node_a.onchain_payment().new_address().unwrap(); + let addr_b = node_b.onchain_payment().new_address().unwrap(); + + fund_multiple_and_sync(&bitcoind, &electrsd, &node_a, vec![(nested_addr, 300_000)]).await; + fund_peer_node_and_sync(&bitcoind, &electrsd, &node_b, addr_b, CHANNEL_PEER_FUNDING_SATS) + .await; + + let funding_txo = open_channel(&node_a, &node_b, 100_000, false, &electrsd).await; + + confirm_and_sync(&bitcoind, &electrsd, 6, &[&node_a, &node_b]).await; + + assert!(!node_a.list_channels().is_empty()); + + let funding_tx = electrsd.client.transaction_get(&funding_txo.txid).unwrap(); + for input in &funding_tx.input { + assert!(!input.witness.is_empty(), "All inputs must have witness data"); + } + + node_a.stop().unwrap(); + node_b.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_open_channel_nested_primary_mixed_inputs() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config_a = node_config(AddressType::NestedSegwit, vec![AddressType::NativeSegwit]); + let node_a = setup_node(&chain_source, config_a, None); + + let config_b = crate::common::random_config(true); + let node_b = setup_node(&chain_source, config_b, None); + + // Fund NestedSegwit with 80k — not enough for 120k channel. + let nested_addr = node_a.onchain_payment().new_address().unwrap(); + let native_addr = + node_a.onchain_payment().new_address_for_type(AddressType::NativeSegwit).unwrap(); + let addr_b = node_b.onchain_payment().new_address().unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node_a, + vec![(nested_addr, 80_000), (native_addr, 80_000)], + ) + .await; + fund_peer_node_and_sync(&bitcoind, &electrsd, &node_b, addr_b, CHANNEL_PEER_FUNDING_SATS) + .await; + + let funding_txo = open_channel(&node_a, &node_b, 120_000, false, &electrsd).await; + + confirm_and_sync(&bitcoind, &electrsd, 6, &[&node_a, &node_b]).await; + + assert!(!node_a.list_channels().is_empty()); + + let funding_tx = electrsd.client.transaction_get(&funding_txo.txid).unwrap(); + assert!(funding_tx.input.len() >= 2, "Should use inputs from both wallets"); + for input in &funding_tx.input { + assert!(!input.witness.is_empty()); + } + + node_a.stop().unwrap(); + node_b.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_open_channel_native_primary_with_nested_inputs() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config_a = node_config(AddressType::NativeSegwit, vec![AddressType::NestedSegwit]); + let node_a = setup_node(&chain_source, config_a, None); + + let config_b = crate::common::random_config(true); + let node_b = setup_node(&chain_source, config_b, None); + + let native_addr = node_a.onchain_payment().new_address().unwrap(); + let nested_addr = + node_a.onchain_payment().new_address_for_type(AddressType::NestedSegwit).unwrap(); + let addr_b = node_b.onchain_payment().new_address().unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node_a, + vec![(native_addr, 80_000), (nested_addr, 80_000)], + ) + .await; + fund_peer_node_and_sync(&bitcoind, &electrsd, &node_b, addr_b, CHANNEL_PEER_FUNDING_SATS) + .await; + + let funding_txo = open_channel(&node_a, &node_b, 120_000, false, &electrsd).await; + + confirm_and_sync(&bitcoind, &electrsd, 6, &[&node_a, &node_b]).await; + + assert!(!node_a.list_channels().is_empty()); + + let funding_tx = electrsd.client.transaction_get(&funding_txo.txid).unwrap(); + assert!(funding_tx.input.len() >= 2, "Should use inputs from both wallets"); + for input in &funding_tx.input { + assert!(!input.witness.is_empty()); + } + + node_a.stop().unwrap(); + node_b.stop().unwrap(); + } + + // --- Channel close --- + + /// Cooperative channel close: verify funds return to the correct address type. + /// With Legacy primary + NativeSegwit monitored, channel scripts come from + /// NativeSegwit. On close, the output should land in NativeSegwit and show + /// in that wallet's balance. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_channel_close_funds_return_to_correct_address_type() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + // Legacy primary, NativeSegwit monitored — channel scripts from NativeSegwit. + let config_a = node_config(AddressType::Legacy, vec![AddressType::NativeSegwit]); + let node_a = setup_node(&chain_source, config_a, None); + + let config_b = crate::common::random_config(true); + let node_b = setup_node(&chain_source, config_b, None); + + let legacy_addr = node_a.onchain_payment().new_address().unwrap(); + let segwit_addr = + node_a.onchain_payment().new_address_for_type(AddressType::NativeSegwit).unwrap(); + let addr_b = node_b.onchain_payment().new_address().unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node_a, + vec![(legacy_addr, 200_000), (segwit_addr, 200_000)], + ) + .await; + fund_peer_node_and_sync(&bitcoind, &electrsd, &node_b, addr_b, CHANNEL_PEER_FUNDING_SATS) + .await; + + let funding_txo = open_channel(&node_a, &node_b, 100_000, false, &electrsd).await; + + confirm_and_sync(&bitcoind, &electrsd, 6, &[&node_a, &node_b]).await; + + // NativeSegwit balance after open (channel holds 100k; we spent it from NativeSegwit). + let segwit_after_open = + node_a.get_balance_for_address_type(AddressType::NativeSegwit).unwrap().total_sats; + + let user_channel_id = expect_channel_ready_event!(node_a, node_b.node_id()); + expect_channel_ready_event!(node_b, node_a.node_id()); + + // Cooperative close. + node_a.close_channel(&user_channel_id, node_b.node_id()).unwrap(); + expect_event!(node_a, ChannelClosed); + expect_event!(node_b, ChannelClosed); + + wait_for_outpoint_spend(&electrsd.client, funding_txo).await; + confirm_and_sync(&bitcoind, &electrsd, 1, &[&node_a, &node_b]).await; + + // Close output should land in NativeSegwit (shutdown script). + let segwit_after = + node_a.get_balance_for_address_type(AddressType::NativeSegwit).unwrap().total_sats; + + // NativeSegwit should increase after close (channel value returned minus closing fee). + assert!( + segwit_after > segwit_after_open, + "NativeSegwit balance should increase after close (after_open: {}, after_close: {})", + segwit_after_open, + segwit_after + ); + // Legacy should be untouched. + let legacy_after = node_a.get_balance_for_address_type(AddressType::Legacy).unwrap(); + assert!(legacy_after.total_sats >= 199_000, "Legacy balance should be untouched"); + + node_a.stop().unwrap(); + node_b.stop().unwrap(); + } + + /// Cooperative channel close: verify funds return to Taproot when primary is Taproot. + /// With Taproot primary, get_shutdown_scriptpubkey returns a Taproot address. + /// On close, the output should land in Taproot and show in that wallet's balance. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_channel_close_funds_return_to_taproot() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + // Taproot primary — channel scripts and shutdown from Taproot. + let config_a = node_config(AddressType::Taproot, vec![AddressType::NativeSegwit]); + let node_a = setup_node(&chain_source, config_a, None); + + let config_b = crate::common::random_config(true); + let node_b = setup_node(&chain_source, config_b, None); + + let taproot_addr = node_a.onchain_payment().new_address().unwrap(); + let segwit_addr = + node_a.onchain_payment().new_address_for_type(AddressType::NativeSegwit).unwrap(); + let addr_b = node_b.onchain_payment().new_address().unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node_a, + vec![(taproot_addr, 200_000), (segwit_addr, 200_000)], + ) + .await; + fund_peer_node_and_sync(&bitcoind, &electrsd, &node_b, addr_b, CHANNEL_PEER_FUNDING_SATS) + .await; + + let funding_txo = open_channel(&node_a, &node_b, 100_000, false, &electrsd).await; + + confirm_and_sync(&bitcoind, &electrsd, 6, &[&node_a, &node_b]).await; + + // Taproot balance after open (channel holds 100k; we spent it from Taproot). + let taproot_after_open = + node_a.get_balance_for_address_type(AddressType::Taproot).unwrap().total_sats; + + let user_channel_id = expect_channel_ready_event!(node_a, node_b.node_id()); + expect_channel_ready_event!(node_b, node_a.node_id()); + + node_a.close_channel(&user_channel_id, node_b.node_id()).unwrap(); + expect_event!(node_a, ChannelClosed); + expect_event!(node_b, ChannelClosed); + + wait_for_outpoint_spend(&electrsd.client, funding_txo).await; + confirm_and_sync(&bitcoind, &electrsd, 1, &[&node_a, &node_b]).await; + + // Close output should land in Taproot (shutdown script). + let taproot_after = + node_a.get_balance_for_address_type(AddressType::Taproot).unwrap().total_sats; + + assert!( + taproot_after > taproot_after_open, + "Taproot balance should increase after close (after_open: {}, after_close: {})", + taproot_after_open, + taproot_after + ); + // Close output went to Taproot; NativeSegwit should not have gained it. + let segwit_after_open = + node_a.get_balance_for_address_type(AddressType::NativeSegwit).unwrap().total_sats; + let segwit_after = + node_a.get_balance_for_address_type(AddressType::NativeSegwit).unwrap().total_sats; + assert!( + segwit_after <= segwit_after_open + 1000, + "Close output should not land in NativeSegwit (after_open: {}, after_close: {})", + segwit_after_open, + segwit_after + ); + + node_a.stop().unwrap(); + node_b.stop().unwrap(); + } + + /// Cooperative channel close: verify funds return to NativeSegwit when primary is NativeSegwit. + /// With NativeSegwit primary, get_shutdown_scriptpubkey returns a NativeSegwit address. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_channel_close_funds_return_to_native_segwit() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config_a = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node_a = setup_node(&chain_source, config_a, None); + + let config_b = crate::common::random_config(true); + let node_b = setup_node(&chain_source, config_b, None); + + let segwit_addr = node_a.onchain_payment().new_address().unwrap(); + let legacy_addr = + node_a.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + let addr_b = node_b.onchain_payment().new_address().unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node_a, + vec![(segwit_addr, 200_000), (legacy_addr, 200_000)], + ) + .await; + fund_peer_node_and_sync(&bitcoind, &electrsd, &node_b, addr_b, CHANNEL_PEER_FUNDING_SATS) + .await; + + let funding_txo = open_channel(&node_a, &node_b, 100_000, false, &electrsd).await; + + confirm_and_sync(&bitcoind, &electrsd, 6, &[&node_a, &node_b]).await; + + let segwit_after_open = + node_a.get_balance_for_address_type(AddressType::NativeSegwit).unwrap().total_sats; + + let user_channel_id = expect_channel_ready_event!(node_a, node_b.node_id()); + expect_channel_ready_event!(node_b, node_a.node_id()); + + node_a.close_channel(&user_channel_id, node_b.node_id()).unwrap(); + expect_event!(node_a, ChannelClosed); + expect_event!(node_b, ChannelClosed); + + wait_for_outpoint_spend(&electrsd.client, funding_txo).await; + confirm_and_sync(&bitcoind, &electrsd, 1, &[&node_a, &node_b]).await; + + let segwit_after = + node_a.get_balance_for_address_type(AddressType::NativeSegwit).unwrap().total_sats; + + assert!( + segwit_after > segwit_after_open, + "NativeSegwit balance should increase after close (after_open: {}, after_close: {})", + segwit_after_open, + segwit_after + ); + let legacy_after = node_a.get_balance_for_address_type(AddressType::Legacy).unwrap(); + assert!(legacy_after.total_sats >= 199_000, "Legacy balance should be untouched"); + + node_a.stop().unwrap(); + node_b.stop().unwrap(); + } + + /// Cooperative channel close: NestedSegwit primary uses monitored NativeSegwit for shutdown. + /// Verify funds return to NativeSegwit (monitored native witness) on close. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_channel_close_nested_primary_funds_return_to_native_segwit() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + // NestedSegwit primary cannot use its own script for shutdown; uses monitored NativeSegwit. + let config_a = node_config(AddressType::NestedSegwit, vec![AddressType::NativeSegwit]); + let node_a = setup_node(&chain_source, config_a, None); + + let config_b = crate::common::random_config(true); + let node_b = setup_node(&chain_source, config_b, None); + + let nested_addr = node_a.onchain_payment().new_address().unwrap(); + let segwit_addr = + node_a.onchain_payment().new_address_for_type(AddressType::NativeSegwit).unwrap(); + let addr_b = node_b.onchain_payment().new_address().unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node_a, + vec![(nested_addr, 200_000), (segwit_addr, 200_000)], + ) + .await; + fund_peer_node_and_sync(&bitcoind, &electrsd, &node_b, addr_b, CHANNEL_PEER_FUNDING_SATS) + .await; + + let funding_txo = open_channel(&node_a, &node_b, 100_000, false, &electrsd).await; + + confirm_and_sync(&bitcoind, &electrsd, 6, &[&node_a, &node_b]).await; + + let segwit_after_open = + node_a.get_balance_for_address_type(AddressType::NativeSegwit).unwrap().total_sats; + + let user_channel_id = expect_channel_ready_event!(node_a, node_b.node_id()); + expect_channel_ready_event!(node_b, node_a.node_id()); + + node_a.close_channel(&user_channel_id, node_b.node_id()).unwrap(); + expect_event!(node_a, ChannelClosed); + expect_event!(node_b, ChannelClosed); + + wait_for_outpoint_spend(&electrsd.client, funding_txo).await; + confirm_and_sync(&bitcoind, &electrsd, 1, &[&node_a, &node_b]).await; + + let segwit_after = + node_a.get_balance_for_address_type(AddressType::NativeSegwit).unwrap().total_sats; + + assert!( + segwit_after > segwit_after_open, + "NativeSegwit (shutdown script) should increase after close (after_open: {}, after_close: {})", + segwit_after_open, + segwit_after + ); + + node_a.stop().unwrap(); + node_b.stop().unwrap(); + } +} + +// --------------------------------------------------------------------------- +// RBF +// --------------------------------------------------------------------------- +mod rbf { + use bitcoin::FeeRate; + use electrum_client::ElectrumApi; + use ldk_node::config::AddressType; + + use crate::common::{ + api_fee_rate, setup_bitcoind_and_electrsd, setup_node, wait_for_tx, TestChainSource, + }; + use crate::helpers::{ + confirm_and_sync, fake_txid_for_error_tests, fund_and_sync, fund_multiple_and_sync, + node_config, test_recipient, + }; + + // --- Success cases --- + + /// RBF on a transaction using inputs from only the primary wallet. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_rbf_single_wallet() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node = setup_node(&chain_source, config, None); + + let native_addr = node.onchain_payment().new_address().unwrap(); + let legacy_addr = node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![(native_addr, 300_000), (legacy_addr, 100_000)], + ) + .await; + + // Send a smaller amount that can be satisfied by primary alone. + let initial_txid = node + .onchain_payment() + .send_to_address(&test_recipient(), 50_000, None, None) + .expect("Initial send should succeed"); + + wait_for_tx(&electrsd.client, initial_txid).await; + node.sync_wallets().unwrap(); + std::thread::sleep(std::time::Duration::from_millis(500)); + + let higher_fee_rate = FeeRate::from_sat_per_kwu(1000); + let rbf_txid = node + .onchain_payment() + .bump_fee_by_rbf(&initial_txid, api_fee_rate(higher_fee_rate)) + .expect("RBF should succeed"); + + assert_ne!(initial_txid, rbf_txid); + wait_for_tx(&electrsd.client, rbf_txid).await; + + node.stop().unwrap(); + } + + /// RBF on a cross-wallet transaction (change output reduction). + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_rbf_cross_wallet_transaction() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node = setup_node(&chain_source, config, None); + + let native_addr = node.onchain_payment().new_address().unwrap(); + let legacy_addr = node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![(native_addr, 100_000), (legacy_addr, 100_000)], + ) + .await; + + // 120k requires both wallets. + let initial_txid = node + .onchain_payment() + .send_to_address(&test_recipient(), 120_000, None, None) + .expect("Initial cross-wallet send should succeed"); + + wait_for_tx(&electrsd.client, initial_txid).await; + node.sync_wallets().unwrap(); + std::thread::sleep(std::time::Duration::from_secs(1)); + + let total_before_rbf = node.list_balances().total_onchain_balance_sats; + + let higher_fee_rate = FeeRate::from_sat_per_kwu(2000); + let rbf_txid = node + .onchain_payment() + .bump_fee_by_rbf(&initial_txid, api_fee_rate(higher_fee_rate)) + .expect("Cross-wallet RBF should succeed"); + + assert_ne!(initial_txid, rbf_txid); + wait_for_tx(&electrsd.client, rbf_txid).await; + node.sync_wallets().unwrap(); + std::thread::sleep(std::time::Duration::from_secs(1)); + + // Confirm replacement; balance check after confirm avoids sync timing flakiness. + confirm_and_sync(&bitcoind, &electrsd, 1, &[&node]).await; + + let total_after_rbf = node.list_balances().total_onchain_balance_sats; + assert!( + total_after_rbf < total_before_rbf, + "Balance should decrease after RBF (higher fee): before={} after={}", + total_before_rbf, + total_after_rbf + ); + + node.stop().unwrap(); + } + + /// RBF on a transaction with inputs from all four address types. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_rbf_cross_wallet_all_four_types() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config( + AddressType::NativeSegwit, + vec![AddressType::Legacy, AddressType::NestedSegwit, AddressType::Taproot], + ); + let node = setup_node(&chain_source, config, None); + + let native_addr = node.onchain_payment().new_address().unwrap(); + let legacy_addr = node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + let nested_addr = + node.onchain_payment().new_address_for_type(AddressType::NestedSegwit).unwrap(); + let taproot_addr = + node.onchain_payment().new_address_for_type(AddressType::Taproot).unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![ + (native_addr, 80_000), + (legacy_addr, 80_000), + (nested_addr, 80_000), + (taproot_addr, 80_000), + ], + ) + .await; + + // 280k requires all four. + let initial_txid = node + .onchain_payment() + .send_to_address(&test_recipient(), 280_000, None, None) + .expect("Initial cross-wallet send should succeed"); + + wait_for_tx(&electrsd.client, initial_txid).await; + + let initial_tx = electrsd.client.transaction_get(&initial_txid).unwrap(); + assert!(initial_tx.input.len() >= 4); + + node.sync_wallets().unwrap(); + std::thread::sleep(std::time::Duration::from_secs(1)); + + let total_before_rbf = node.list_balances().total_onchain_balance_sats; + + let rbf_txid = node + .onchain_payment() + .bump_fee_by_rbf(&initial_txid, api_fee_rate(FeeRate::from_sat_per_kwu(2000))) + .expect("RBF with all 4 types should succeed"); + + assert_ne!(initial_txid, rbf_txid); + wait_for_tx(&electrsd.client, rbf_txid).await; + + let rbf_tx = electrsd.client.transaction_get(&rbf_txid).unwrap(); + assert!(rbf_tx.input.len() >= 4); + + confirm_and_sync(&bitcoind, &electrsd, 1, &[&node]).await; + + assert!(node.list_balances().total_onchain_balance_sats < total_before_rbf); + + node.stop().unwrap(); + } + + /// RBF that needs additional inputs verifies fee accounting. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_rbf_additional_inputs_fee_rate_correctness() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![]); + let node = setup_node(&chain_source, config, None); + + let addr1 = node.onchain_payment().new_address().unwrap(); + let addr2 = node.onchain_payment().new_address().unwrap(); + let addr3 = node.onchain_payment().new_address().unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![(addr1, 50_000), (addr2, 50_000), (addr3, 50_000)], + ) + .await; + + let initial_balance = node.list_balances().total_onchain_balance_sats; + assert!(initial_balance >= 147_000); + + // Send 30k — uses 1 UTXO, ~20k change. + let initial_txid = node + .onchain_payment() + .send_to_address(&test_recipient(), 30_000, None, None) + .expect("Initial send should succeed"); + + wait_for_tx(&electrsd.client, initial_txid).await; + node.sync_wallets().unwrap(); + std::thread::sleep(std::time::Duration::from_secs(1)); + + // Very high fee forces adding inputs. + let high_fee_rate = FeeRate::from_sat_per_kwu(5000); + let rbf_txid = node + .onchain_payment() + .bump_fee_by_rbf(&initial_txid, api_fee_rate(high_fee_rate)) + .expect("RBF with added inputs should succeed"); + + assert_ne!(initial_txid, rbf_txid); + wait_for_tx(&electrsd.client, rbf_txid).await; + + confirm_and_sync(&bitcoind, &electrsd, 1, &[&node]).await; + + let final_balance = node.list_balances().total_onchain_balance_sats; + let fee_paid = initial_balance - final_balance - 30_000; + assert!(fee_paid < 15_000, "Fee {} too high", fee_paid); + assert!(fee_paid > 1_000, "Fee {} too low", fee_paid); + + node.stop().unwrap(); + } + + /// RBF adds inputs from a different address-type wallet when change is insufficient. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_rbf_adds_inputs_from_different_address_type() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node = setup_node(&chain_source, config, None); + + let native_addr = node.onchain_payment().new_address().unwrap(); + let legacy_addr = node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + + // NativeSegwit: just enough for 50k send with small change. + // Legacy: available for RBF fee bumping. + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![(native_addr, 55_000), (legacy_addr, 60_000)], + ) + .await; + + let initial_txid = node + .onchain_payment() + .send_to_address(&test_recipient(), 50_000, None, None) + .expect("Initial send should succeed"); + + wait_for_tx(&electrsd.client, initial_txid).await; + + let initial_tx = electrsd.client.transaction_get(&initial_txid).unwrap(); + assert_eq!(initial_tx.input.len(), 1); + + node.sync_wallets().unwrap(); + std::thread::sleep(std::time::Duration::from_secs(1)); + + // Extremely high fee rate to exhaust the small change. + let high_fee_rate = FeeRate::from_sat_per_kwu(50_000); + let rbf_txid = node + .onchain_payment() + .bump_fee_by_rbf(&initial_txid, api_fee_rate(high_fee_rate)) + .expect("RBF should add Legacy input"); + + assert_ne!(initial_txid, rbf_txid); + wait_for_tx(&electrsd.client, rbf_txid).await; + + let rbf_tx = electrsd.client.transaction_get(&rbf_txid).unwrap(); + assert!(rbf_tx.input.len() > initial_tx.input.len()); + + confirm_and_sync(&bitcoind, &electrsd, 1, &[&node]).await; + + node.stop().unwrap(); + } + + /// Cross-wallet RBF adds extra inputs when change cannot absorb fee increase. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_cross_wallet_rbf_adds_extra_inputs_when_needed() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node = setup_node(&chain_source, config, None); + + let native_addr = node.onchain_payment().new_address().unwrap(); + let legacy_addr1 = + node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + let legacy_addr2 = + node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![(native_addr, 60_000), (legacy_addr1, 60_000), (legacy_addr2, 60_000)], + ) + .await; + + // 115k requires primary (60k) + 1 Legacy (60k) = 120k. + let txid = + node.onchain_payment().send_to_address(&test_recipient(), 115_000, None, None).unwrap(); + wait_for_tx(&electrsd.client, txid).await; + node.sync_wallets().unwrap(); + std::thread::sleep(std::time::Duration::from_secs(1)); + + let initial_tx = electrsd.client.transaction_get(&txid).unwrap(); + assert_eq!(initial_tx.input.len(), 2); + + // High fee forces adding the remaining Legacy UTXO. + let rbf_txid = node + .onchain_payment() + .bump_fee_by_rbf(&txid, api_fee_rate(FeeRate::from_sat_per_kwu(25_000))) + .expect("Cross-wallet RBF with extra input should succeed"); + + wait_for_tx(&electrsd.client, rbf_txid).await; + + let rbf_tx = electrsd.client.transaction_get(&rbf_txid).unwrap(); + assert!(rbf_tx.input.len() > initial_tx.input.len()); + + node.stop().unwrap(); + } + + /// RBF with a Legacy primary wallet. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_rbf_legacy_primary() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::Legacy, vec![AddressType::NativeSegwit]); + let node = setup_node(&chain_source, config, None); + + let legacy_addr = node.onchain_payment().new_address().unwrap(); + fund_and_sync(&bitcoind, &electrsd, &node, legacy_addr, 300_000).await; + + let initial_txid = node + .onchain_payment() + .send_to_address(&test_recipient(), 50_000, None, None) + .expect("Send from Legacy should succeed"); + + wait_for_tx(&electrsd.client, initial_txid).await; + node.sync_wallets().unwrap(); + std::thread::sleep(std::time::Duration::from_millis(500)); + + let rbf_txid = node + .onchain_payment() + .bump_fee_by_rbf(&initial_txid, api_fee_rate(FeeRate::from_sat_per_kwu(1000))) + .expect("RBF should succeed for Legacy primary"); + + assert_ne!(initial_txid, rbf_txid); + wait_for_tx(&electrsd.client, rbf_txid).await; + + node.stop().unwrap(); + } + + // --- Error cases --- + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_rbf_rejects_lower_fee_rate() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![]); + let node = setup_node(&chain_source, config, None); + + let addr = node.onchain_payment().new_address().unwrap(); + fund_and_sync(&bitcoind, &electrsd, &node, addr, 200_000).await; + + let initial_fee_rate = FeeRate::from_sat_per_kwu(2000); + let txid = node + .onchain_payment() + .send_to_address(&test_recipient(), 50_000, Some(api_fee_rate(initial_fee_rate)), None) + .unwrap(); + + wait_for_tx(&electrsd.client, txid).await; + node.sync_wallets().unwrap(); + + let result = node + .onchain_payment() + .bump_fee_by_rbf(&txid, api_fee_rate(FeeRate::from_sat_per_kwu(1000))); + assert!(result.is_err()); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_rbf_rejects_confirmed_transaction() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![]); + let node = setup_node(&chain_source, config, None); + + let addr = node.onchain_payment().new_address().unwrap(); + fund_and_sync(&bitcoind, &electrsd, &node, addr, 200_000).await; + + let txid = + node.onchain_payment().send_to_address(&test_recipient(), 50_000, None, None).unwrap(); + + wait_for_tx(&electrsd.client, txid).await; + confirm_and_sync(&bitcoind, &electrsd, 1, &[&node]).await; + + let result = node + .onchain_payment() + .bump_fee_by_rbf(&txid, api_fee_rate(FeeRate::from_sat_per_kwu(5000))); + assert!(result.is_err()); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_rbf_rejects_unknown_transaction() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![]); + let node = setup_node(&chain_source, config, None); + + let addr = node.onchain_payment().new_address().unwrap(); + fund_and_sync(&bitcoind, &electrsd, &node, addr, 100_000).await; + + let result = node.onchain_payment().bump_fee_by_rbf( + &fake_txid_for_error_tests(), + api_fee_rate(FeeRate::from_sat_per_kwu(2000)), + ); + assert!(result.is_err()); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_rbf_insufficient_funds_for_fee_bump() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![]); + let node = setup_node(&chain_source, config, None); + + let addr = node.onchain_payment().new_address().unwrap(); + fund_and_sync(&bitcoind, &electrsd, &node, addr, 51_000).await; + + let txid = + node.onchain_payment().send_to_address(&test_recipient(), 50_000, None, None).unwrap(); + wait_for_tx(&electrsd.client, txid).await; + node.sync_wallets().unwrap(); + + let result = node + .onchain_payment() + .bump_fee_by_rbf(&txid, api_fee_rate(FeeRate::from_sat_per_kwu(100_000))); + assert!(result.is_err()); + + node.stop().unwrap(); + } + + /// RBF on send_all (no change) must not reduce the recipient amount. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_rbf_send_all_no_change_does_not_reduce_recipient() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node = setup_node(&chain_source, config, None); + + let addr = node.onchain_payment().new_address().unwrap(); + fund_and_sync(&bitcoind, &electrsd, &node, addr, 100_000).await; + + let txid = + node.onchain_payment().send_all_to_address(&test_recipient(), true, None).unwrap(); + wait_for_tx(&electrsd.client, txid).await; + node.sync_wallets().unwrap(); + std::thread::sleep(std::time::Duration::from_millis(500)); + + let result = node + .onchain_payment() + .bump_fee_by_rbf(&txid, api_fee_rate(FeeRate::from_sat_per_kwu(5000))); + assert!(result.is_err(), "RBF on send-all (no change) should fail"); + + node.stop().unwrap(); + } +} + +// --------------------------------------------------------------------------- +// CPFP +// --------------------------------------------------------------------------- +mod cpfp { + use bitcoin::FeeRate; + use electrum_client::ElectrumApi; + use ldk_node::config::AddressType; + + use crate::common::{ + api_fee_rate, setup_bitcoind_and_electrsd, setup_node, wait_for_tx, TestChainSource, + }; + use crate::helpers::{ + confirm_and_sync, fake_txid_for_error_tests, fund_and_sync, fund_multiple_and_sync, + node_config, test_recipient, + }; + + // --- Success cases --- + + /// Single-wallet CPFP with fee rate calculation. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_cpfp_single_wallet() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config( + AddressType::NestedSegwit, + vec![AddressType::Legacy, AddressType::NativeSegwit, AddressType::Taproot], + ); + let node = setup_node(&chain_source, config, None); + + let addr = node.onchain_payment().new_address().unwrap(); + fund_and_sync(&bitcoind, &electrsd, &node, addr, 400_000).await; + + let parent_txid = + node.onchain_payment().send_to_address(&test_recipient(), 60_000, None, None).unwrap(); + + wait_for_tx(&electrsd.client, parent_txid).await; + node.sync_wallets().unwrap(); + std::thread::sleep(std::time::Duration::from_millis(500)); + + let cpfp_fee_rate = FeeRate::from_sat_per_kwu(1500); + let cpfp_txid = node + .onchain_payment() + .accelerate_by_cpfp(&parent_txid, Some(api_fee_rate(cpfp_fee_rate)), None) + .unwrap(); + + assert_ne!(parent_txid, cpfp_txid); + + let calculated_fee_rate = + node.onchain_payment().calculate_cpfp_fee_rate(&parent_txid, false).unwrap(); + assert!(calculated_fee_rate.to_sat_per_kwu() > 0); + } + + /// CPFP on a cross-wallet transaction (change goes to primary). + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_cpfp_for_cross_wallet_transaction() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node = setup_node(&chain_source, config, None); + + let native_addr = node.onchain_payment().new_address().unwrap(); + let legacy_addr = node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![(native_addr, 100_000), (legacy_addr, 100_000)], + ) + .await; + + // 140k requires both wallets. + let parent_txid = node + .onchain_payment() + .send_to_address(&test_recipient(), 140_000, None, None) + .expect("Cross-wallet send should succeed"); + + wait_for_tx(&electrsd.client, parent_txid).await; + node.sync_wallets().unwrap(); + std::thread::sleep(std::time::Duration::from_secs(1)); + + let cpfp_txid = node + .onchain_payment() + .accelerate_by_cpfp( + &parent_txid, + Some(api_fee_rate(FeeRate::from_sat_per_kwu(1500))), + None, + ) + .expect("CPFP should work for cross-wallet transactions"); + + assert_ne!(parent_txid, cpfp_txid); + wait_for_tx(&electrsd.client, cpfp_txid).await; + + node.stop().unwrap(); + } + + /// CPFP on a transaction with inputs from all four address types. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_cpfp_cross_wallet_all_four_types() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config( + AddressType::NativeSegwit, + vec![AddressType::Legacy, AddressType::NestedSegwit, AddressType::Taproot], + ); + let node = setup_node(&chain_source, config, None); + + let native_addr = node.onchain_payment().new_address().unwrap(); + let legacy_addr = node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + let nested_addr = + node.onchain_payment().new_address_for_type(AddressType::NestedSegwit).unwrap(); + let taproot_addr = + node.onchain_payment().new_address_for_type(AddressType::Taproot).unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![ + (native_addr, 100_000), + (legacy_addr, 100_000), + (nested_addr, 100_000), + (taproot_addr, 100_000), + ], + ) + .await; + + // 320k requires all four. + let parent_txid = node + .onchain_payment() + .send_to_address(&test_recipient(), 320_000, None, None) + .expect("Cross-wallet send should succeed"); + + wait_for_tx(&electrsd.client, parent_txid).await; + + let parent_tx = electrsd.client.transaction_get(&parent_txid).unwrap(); + assert!(parent_tx.input.len() >= 4); + + node.sync_wallets().unwrap(); + std::thread::sleep(std::time::Duration::from_secs(1)); + + let cpfp_txid = node + .onchain_payment() + .accelerate_by_cpfp( + &parent_txid, + Some(api_fee_rate(FeeRate::from_sat_per_kwu(1500))), + None, + ) + .expect("CPFP with all 4 types should succeed"); + + assert_ne!(parent_txid, cpfp_txid); + wait_for_tx(&electrsd.client, cpfp_txid).await; + + let cpfp_tx = electrsd.client.transaction_get(&cpfp_txid).unwrap(); + assert!(cpfp_tx.input.iter().any(|i| i.previous_output.txid == parent_txid)); + + node.stop().unwrap(); + } + + /// CPFP with a Legacy primary wallet. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_cpfp_legacy_primary() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::Legacy, vec![AddressType::NativeSegwit]); + let node = setup_node(&chain_source, config, None); + + let legacy_addr = node.onchain_payment().new_address().unwrap(); + let segwit_addr = + node.onchain_payment().new_address_for_type(AddressType::NativeSegwit).unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![(legacy_addr, 200_000), (segwit_addr, 100_000)], + ) + .await; + + let parent_txid = node + .onchain_payment() + .send_to_address(&test_recipient(), 60_000, None, None) + .expect("Send from legacy should succeed"); + + wait_for_tx(&electrsd.client, parent_txid).await; + node.sync_wallets().unwrap(); + std::thread::sleep(std::time::Duration::from_millis(500)); + + let cpfp_txid = node + .onchain_payment() + .accelerate_by_cpfp( + &parent_txid, + Some(api_fee_rate(FeeRate::from_sat_per_kwu(1500))), + None, + ) + .expect("CPFP should succeed for Legacy primary"); + + assert_ne!(parent_txid, cpfp_txid); + wait_for_tx(&electrsd.client, cpfp_txid).await; + + node.stop().unwrap(); + } + + // --- Error cases --- + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_cpfp_rejects_unknown_transaction() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![]); + let node = setup_node(&chain_source, config, None); + + let addr = node.onchain_payment().new_address().unwrap(); + fund_and_sync(&bitcoind, &electrsd, &node, addr, 100_000).await; + + let result = + node.onchain_payment().accelerate_by_cpfp(&fake_txid_for_error_tests(), None, None); + assert!(result.is_err()); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_cpfp_rejects_confirmed_transaction() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![]); + let node = setup_node(&chain_source, config, None); + + let addr = node.onchain_payment().new_address().unwrap(); + fund_and_sync(&bitcoind, &electrsd, &node, addr, 200_000).await; + + let txid = + node.onchain_payment().send_to_address(&test_recipient(), 50_000, None, None).unwrap(); + + wait_for_tx(&electrsd.client, txid).await; + confirm_and_sync(&bitcoind, &electrsd, 1, &[&node]).await; + + let result = node.onchain_payment().accelerate_by_cpfp(&txid, None, None); + assert!(result.is_err()); + + node.stop().unwrap(); + } +} + +// --------------------------------------------------------------------------- +// Coin Selection +// --------------------------------------------------------------------------- +mod coin_selection { + use bitcoin::FeeRate; + use electrum_client::ElectrumApi; + use ldk_node::config::AddressType; + + use crate::common::{ + api_fee_rate, open_channel, setup_bitcoind_and_electrsd, setup_node, wait_for_tx, + TestChainSource, + }; + use crate::helpers::{ + fund_and_sync, fund_multiple_and_sync, fund_peer_node_and_sync, node_config, + test_recipient, CHANNEL_PEER_FUNDING_SATS, + }; + + // --- API & fee calculation --- + + /// Basic UTXO selection API works with multi-wallet. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_utxo_selection() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config( + AddressType::NativeSegwit, + vec![AddressType::Legacy, AddressType::NestedSegwit], + ); + let node = setup_node(&chain_source, config, None); + + let addr = node.onchain_payment().new_address().unwrap(); + fund_and_sync(&bitcoind, &electrsd, &node, addr, 500_000).await; + + let spendable = node.onchain_payment().list_spendable_outputs().unwrap(); + assert!(!spendable.is_empty()); + + let selected = node + .onchain_payment() + .select_utxos_with_algorithm( + 100_000, + Some(api_fee_rate(FeeRate::from_sat_per_kwu(500))), + ldk_node::CoinSelectionAlgorithm::LargestFirst, + None, + ) + .unwrap(); + + assert!(!selected.is_empty()); + } + + /// list_spendable_outputs returns UTXOs from multiple address types when funded. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_list_spendable_outputs_includes_multiple_address_types() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = + node_config(AddressType::NativeSegwit, vec![AddressType::Legacy, AddressType::Taproot]); + let node = setup_node(&chain_source, config, None); + + let native_addr = node.onchain_payment().new_address().unwrap(); + let legacy_addr = node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + let taproot_addr = + node.onchain_payment().new_address_for_type(AddressType::Taproot).unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![(native_addr, 60_000), (legacy_addr, 50_000), (taproot_addr, 55_000)], + ) + .await; + + let spendable = node.onchain_payment().list_spendable_outputs().unwrap(); + assert!( + spendable.len() >= 3, + "Should have at least 3 UTXOs from 3 address types, got {}", + spendable.len() + ); + + let total_value: u64 = spendable.iter().map(|u| u.value_sats).sum(); + let expected_min = 60_000 + 50_000 + 55_000 - 5_000; + assert!( + total_value >= expected_min, + "Total spendable value should be >= {} (got {})", + expected_min, + total_value + ); + + node.stop().unwrap(); + } + + /// Fee calculation considers all wallets. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_calculate_total_fee() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::Taproot, vec![AddressType::NativeSegwit]); + let node = setup_node(&chain_source, config, None); + + let addr = node.onchain_payment().new_address().unwrap(); + fund_and_sync(&bitcoind, &electrsd, &node, addr, 300_000).await; + + let total_fee = node + .onchain_payment() + .calculate_total_fee( + &test_recipient(), + 100_000, + Some(api_fee_rate(FeeRate::from_sat_per_kwu(500))), + None, + ) + .unwrap(); + + assert!(total_fee > 0); + } + + // --- Minimum inputs --- + + /// Unified selection pools all UTXOs; should pick an efficient subset, + /// not dump all foreign UTXOs. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_cross_wallet_send_uses_minimum_inputs() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node = setup_node(&chain_source, config, None); + + let primary_addr = node.onchain_payment().new_address().unwrap(); + let legacy_addr1 = + node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + let legacy_addr2 = + node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + let legacy_addr3 = + node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![ + (primary_addr, 10_000), + (legacy_addr1, 20_000), + (legacy_addr2, 30_000), + (legacy_addr3, 50_000), + ], + ) + .await; + + // BranchAndBound should pick an efficient combination — not all 4. + let txid = + node.onchain_payment().send_to_address(&test_recipient(), 15_000, None, None).unwrap(); + wait_for_tx(&electrsd.client, txid).await; + + let tx = electrsd.client.transaction_get(&txid).unwrap(); + assert!(tx.input.len() <= 2, "Should use minimum inputs, got {}", tx.input.len()); + + node.stop().unwrap(); + } + + // --- Channel funding --- + + /// Channel funding picks minimum witness inputs. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_channel_funding_uses_minimum_witness_inputs() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config_a = node_config(AddressType::NativeSegwit, vec![AddressType::Taproot]); + let node_a = setup_node(&chain_source, config_a, None); + + let config_b = crate::common::random_config(true); + let node_b = setup_node(&chain_source, config_b, None); + + let native_addr = node_a.onchain_payment().new_address().unwrap(); + let taproot_addr1 = + node_a.onchain_payment().new_address_for_type(AddressType::Taproot).unwrap(); + let taproot_addr2 = + node_a.onchain_payment().new_address_for_type(AddressType::Taproot).unwrap(); + let taproot_addr3 = + node_a.onchain_payment().new_address_for_type(AddressType::Taproot).unwrap(); + let addr_b = node_b.onchain_payment().new_address().unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node_a, + vec![ + (native_addr, 20_000), + (taproot_addr1, 40_000), + (taproot_addr2, 40_000), + (taproot_addr3, 40_000), + ], + ) + .await; + fund_peer_node_and_sync(&bitcoind, &electrsd, &node_b, addr_b, CHANNEL_PEER_FUNDING_SATS) + .await; + + let funding_txo = open_channel(&node_a, &node_b, 50_000, false, &electrsd).await; + + let funding_tx = electrsd.client.transaction_get(&funding_txo.txid).unwrap(); + assert!( + funding_tx.input.len() <= 3, + "Should not use all UTXOs, got {}", + funding_tx.input.len() + ); + + node_a.stop().unwrap(); + node_b.stop().unwrap(); + } + + // --- RBF fallback --- + + /// RBF fallback selects minimum foreign inputs. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_rbf_fallback_uses_minimum_foreign_inputs() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node = setup_node(&chain_source, config, None); + + let native_addr = node.onchain_payment().new_address().unwrap(); + let legacy_addr1 = + node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + let legacy_addr2 = + node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + let legacy_addr3 = + node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![ + (native_addr, 55_000), + (legacy_addr1, 60_000), + (legacy_addr2, 60_000), + (legacy_addr3, 60_000), + ], + ) + .await; + + // Send 50k — uses primary (55k). Leaves ~5k change. + let txid = + node.onchain_payment().send_to_address(&test_recipient(), 50_000, None, None).unwrap(); + wait_for_tx(&electrsd.client, txid).await; + node.sync_wallets().unwrap(); + std::thread::sleep(std::time::Duration::from_secs(1)); + + let initial_tx = electrsd.client.transaction_get(&txid).unwrap(); + assert_eq!(initial_tx.input.len(), 1); + + // High fee rate forces adding 1 Legacy UTXO. + let rbf_txid = node + .onchain_payment() + .bump_fee_by_rbf(&txid, api_fee_rate(FeeRate::from_sat_per_kwu(50_000))) + .expect("RBF should succeed by adding Legacy input"); + + wait_for_tx(&electrsd.client, rbf_txid).await; + + let rbf_tx = electrsd.client.transaction_get(&rbf_txid).unwrap(); + assert!( + rbf_tx.input.len() <= 2, + "Should use minimum foreign inputs, got {}", + rbf_tx.input.len() + ); + + node.stop().unwrap(); + } + + // --- Optimal UTXO preference --- + + /// Unified selection prefers a single optimal UTXO over many small ones. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_unified_selection_prefers_optimal_utxo() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Taproot]); + let node = setup_node(&chain_source, config, None); + + // 3 small primary UTXOs (10k each) + 1 large Taproot (25k). + let addr1 = node.onchain_payment().new_address().unwrap(); + let addr2 = node.onchain_payment().new_address().unwrap(); + let addr3 = node.onchain_payment().new_address().unwrap(); + let taproot_addr = + node.onchain_payment().new_address_for_type(AddressType::Taproot).unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![(addr1, 10_000), (addr2, 10_000), (addr3, 10_000), (taproot_addr, 25_000)], + ) + .await; + + // Send 20k. Unified selection should not use all 4 UTXOs. + let txid = + node.onchain_payment().send_to_address(&test_recipient(), 20_000, None, None).unwrap(); + wait_for_tx(&electrsd.client, txid).await; + + let tx = electrsd.client.transaction_get(&txid).unwrap(); + assert!(tx.input.len() <= 3, "Should pick optimal UTXOs, got {}", tx.input.len()); + + node.stop().unwrap(); + } +} + +// --------------------------------------------------------------------------- +// Dynamic Address Types Changes +// --------------------------------------------------------------------------- +mod dynamic_address_type_changes { + use ldk_node::config::AddressType; + + use crate::common::{ + api_seed_bytes, setup_bitcoind_and_electrsd, setup_node, wait_for_tx, TestChainSource, + }; + use crate::helpers::{ + confirm_and_sync, fund_and_sync, node_config, read_node_seed, test_recipient, + }; + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_add_address_type_to_monitor() { + let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![]); + let node = setup_node(&chain_source, config, None); + + let monitored = node.list_monitored_address_types(); + assert_eq!(monitored.len(), 1); + assert!(monitored.contains(&AddressType::NativeSegwit)); + + node.add_address_type_to_monitor( + AddressType::Legacy, + api_seed_bytes(read_node_seed(&node)), + ) + .unwrap(); + + let monitored = node.list_monitored_address_types(); + assert!(monitored.contains(&AddressType::Legacy)); + assert!(monitored.contains(&AddressType::NativeSegwit)); + + let legacy_addr = node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + assert!(legacy_addr.script_pubkey().is_p2pkh()); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_add_address_type_taproot() { + let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![]); + let node = setup_node(&chain_source, config, None); + + node.add_address_type_to_monitor( + AddressType::Taproot, + api_seed_bytes(read_node_seed(&node)), + ) + .unwrap(); + let taproot_addr = + node.onchain_payment().new_address_for_type(AddressType::Taproot).unwrap(); + assert!(taproot_addr.script_pubkey().is_p2tr()); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_add_address_type_then_fund_and_sync() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![]); + let node = setup_node(&chain_source, config, None); + + node.add_address_type_to_monitor( + AddressType::Legacy, + api_seed_bytes(read_node_seed(&node)), + ) + .unwrap(); + let legacy_addr = node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + + fund_and_sync(&bitcoind, &electrsd, &node, legacy_addr, 100_000).await; + + let legacy_balance = node.get_balance_for_address_type(AddressType::Legacy).unwrap(); + assert!(legacy_balance.total_sats >= 99_000); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_add_address_type_already_primary_returns_error() { + let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![]); + let node = setup_node(&chain_source, config, None); + + let result = node.add_address_type_to_monitor( + AddressType::NativeSegwit, + api_seed_bytes(read_node_seed(&node)), + ); + assert_eq!(result, Err(ldk_node::NodeError::AddressTypeIsPrimary)); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_add_address_type_nested_segwit() { + let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![]); + let node = setup_node(&chain_source, config, None); + + node.add_address_type_to_monitor( + AddressType::NestedSegwit, + api_seed_bytes(read_node_seed(&node)), + ) + .unwrap(); + let nested_addr = + node.onchain_payment().new_address_for_type(AddressType::NestedSegwit).unwrap(); + assert!(nested_addr.script_pubkey().is_p2sh()); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_add_address_type_already_monitored_returns_error() { + let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node = setup_node(&chain_source, config, None); + + let result = node.add_address_type_to_monitor( + AddressType::Legacy, + api_seed_bytes(read_node_seed(&node)), + ); + assert_eq!(result, Err(ldk_node::NodeError::AddressTypeAlreadyMonitored)); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_remove_address_type_from_monitor() { + let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node = setup_node(&chain_source, config, None); + + assert!(node.list_monitored_address_types().contains(&AddressType::Legacy)); + + node.remove_address_type_from_monitor(AddressType::Legacy).unwrap(); + + assert!(!node.list_monitored_address_types().contains(&AddressType::Legacy)); + assert!(node.onchain_payment().new_address_for_type(AddressType::Legacy).is_err()); + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_remove_then_add_preserves_funds() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node = setup_node(&chain_source, config, None); + + let legacy_addr = node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + fund_and_sync(&bitcoind, &electrsd, &node, legacy_addr, 50_000).await; + + let balance_before = node.get_balance_for_address_type(AddressType::Legacy).unwrap(); + assert!(balance_before.total_sats >= 49_000); + + node.remove_address_type_from_monitor(AddressType::Legacy).unwrap(); + assert!(node.get_balance_for_address_type(AddressType::Legacy).is_err()); + + node.add_address_type_to_monitor( + AddressType::Legacy, + api_seed_bytes(read_node_seed(&node)), + ) + .unwrap(); + node.sync_wallets().unwrap(); + let balance_after = node.get_balance_for_address_type(AddressType::Legacy).unwrap(); + assert!(balance_after.total_sats >= 49_000); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_remove_primary_returns_error() { + let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node = setup_node(&chain_source, config, None); + + let result = node.remove_address_type_from_monitor(AddressType::NativeSegwit); + assert_eq!(result, Err(ldk_node::NodeError::AddressTypeIsPrimary)); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_remove_unmonitored_type_returns_error() { + let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node = setup_node(&chain_source, config, None); + + let result = node.remove_address_type_from_monitor(AddressType::Taproot); + assert_eq!(result, Err(ldk_node::NodeError::AddressTypeNotMonitored)); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_set_primary_address_type() { + let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node = setup_node(&chain_source, config, None); + + let addr_before = node.onchain_payment().new_address().unwrap(); + assert!(addr_before.script_pubkey().is_p2wpkh()); + + node.set_primary_address_type(AddressType::Legacy, api_seed_bytes(read_node_seed(&node))) + .unwrap(); + + let addr_after = node.onchain_payment().new_address().unwrap(); + assert!(addr_after.script_pubkey().is_p2pkh()); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_set_primary_auto_loads_unloaded_type() { + let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![]); + let node = setup_node(&chain_source, config, None); + + // Taproot not loaded; set_primary should auto-load it + node.set_primary_address_type(AddressType::Taproot, api_seed_bytes(read_node_seed(&node))) + .unwrap(); + + let addr = node.onchain_payment().new_address().unwrap(); + assert!(addr.script_pubkey().is_p2tr()); + + // Old primary should be demoted to the monitored set + let monitored = node.list_monitored_address_types(); + assert!(monitored.contains(&AddressType::NativeSegwit)); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_set_primary_same_primary_no_op() { + let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node = setup_node(&chain_source, config, None); + + // Setting to current primary should succeed (no-op) + node.set_primary_address_type( + AddressType::NativeSegwit, + api_seed_bytes(read_node_seed(&node)), + ) + .unwrap(); + + let addr = node.onchain_payment().new_address().unwrap(); + assert!(addr.script_pubkey().is_p2wpkh()); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_set_primary_round_trip_preserves_monitored() { + let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node = setup_node(&chain_source, config, None); + + // NativeSegwit primary, Legacy monitored + assert!(node.list_monitored_address_types().contains(&AddressType::Legacy)); + assert!(node.list_monitored_address_types().contains(&AddressType::NativeSegwit)); + + // Swap to Legacy + node.set_primary_address_type(AddressType::Legacy, api_seed_bytes(read_node_seed(&node))) + .unwrap(); + assert!(node.onchain_payment().new_address().unwrap().script_pubkey().is_p2pkh()); + + // Swap back to NativeSegwit + node.set_primary_address_type( + AddressType::NativeSegwit, + api_seed_bytes(read_node_seed(&node)), + ) + .unwrap(); + assert!(node.onchain_payment().new_address().unwrap().script_pubkey().is_p2wpkh()); + + // Both types should still be loaded; Legacy should be in monitored again + let monitored = node.list_monitored_address_types(); + assert!(monitored.contains(&AddressType::Legacy)); + assert!(monitored.contains(&AddressType::NativeSegwit)); + assert!(node.onchain_payment().new_address_for_type(AddressType::Legacy).is_ok()); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_add_then_set_primary_then_send() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![]); + let node = setup_node(&chain_source, config, None); + + // set_primary auto-loads Taproot + node.set_primary_address_type(AddressType::Taproot, api_seed_bytes(read_node_seed(&node))) + .unwrap(); + let taproot_addr = node.onchain_payment().new_address().unwrap(); + fund_and_sync(&bitcoind, &electrsd, &node, taproot_addr, 100_000).await; + + let txid = + node.onchain_payment().send_to_address(&test_recipient(), 10_000, None, None).unwrap(); + wait_for_tx(&electrsd.client, txid).await; + confirm_and_sync(&bitcoind, &electrsd, 1, &[&node]).await; + + let balance = node.list_balances().total_onchain_balance_sats; + assert!(balance < 100_000); + + node.stop().unwrap(); + } + + /// set_primary on a never-synced type triggers a full scan, discovering pre-existing UTXOs. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_set_primary_triggers_full_scan_for_never_synced_type() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![]); + let node = setup_node(&chain_source, config, None); + + // Fund NativeSegwit so the node has a non-null primary sync timestamp. + let native_addr = node.onchain_payment().new_address().unwrap(); + fund_and_sync(&bitcoind, &electrsd, &node, native_addr, 50_000).await; + + // Briefly load Taproot to obtain an address, then remove it so no sync timestamp is + // recorded for it. + node.add_address_type_to_monitor( + AddressType::Taproot, + api_seed_bytes(read_node_seed(&node)), + ) + .unwrap(); + let taproot_addr = + node.onchain_payment().new_address_for_type(AddressType::Taproot).unwrap(); + node.remove_address_type_from_monitor(AddressType::Taproot).unwrap(); + + // Fund Taproot while unmonitored; balance is not visible yet. + fund_and_sync(&bitcoind, &electrsd, &node, taproot_addr, 80_000).await; + assert!(node.get_balance_for_address_type(AddressType::Taproot).is_err()); + + // Switching primary to an unsynced type clears the primary sync timestamp, forcing a + // full scan on the next cycle. + node.set_primary_address_type(AddressType::Taproot, api_seed_bytes(read_node_seed(&node))) + .unwrap(); + node.sync_wallets().unwrap(); + + let taproot_balance = node.get_balance_for_address_type(AddressType::Taproot).unwrap(); + assert!(taproot_balance.total_sats >= 79_000, "got {} sats", taproot_balance.total_sats); + + node.stop().unwrap(); + } +} + +// --------------------------------------------------------------------------- +// Event deduplication and payment direction +// --------------------------------------------------------------------------- +mod events { + use std::time::Duration; + + use bitcoin::Txid; + use electrum_client::ElectrumApi; + use ldk_node::config::AddressType; + use ldk_node::payment::{PaymentDirection, PaymentKind}; + use ldk_node::{Event, Node}; + + use crate::common::{ + drain_all_events, generate_blocks_and_wait, invalidate_blocks, setup_bitcoind_and_electrsd, + setup_node, wait_for_tx, TestChainSource, + }; + use crate::helpers::{confirm_and_sync, fund_multiple_and_sync, node_config, test_recipient}; + + /// Drain all pending events from `node` and return a count of those matching `filter`. + fn count_events bool>(node: &Node, filter: F) -> usize { + let mut count = 0; + while let Some(event) = node.next_event() { + if filter(&event) { + count += 1; + } + node.event_handled().unwrap(); + } + count + } + + /// Returns the count of `OnchainTransactionReceived` events matching `expected`. + fn count_received(node: &Node, expected: Txid) -> usize { + count_events( + node, + |e| matches!(e, Event::OnchainTransactionReceived { txid, .. } if *txid == expected), + ) + } + + /// Returns the count of `OnchainTransactionConfirmed` events matching `expected`. + fn count_confirmed(node: &Node, expected: Txid) -> usize { + count_events( + node, + |e| matches!(e, Event::OnchainTransactionConfirmed { txid, .. } if *txid == expected), + ) + } + + fn count_reorg_and_confirmation_events(node: &Node, expected: Txid) -> (usize, usize) { + let mut reorged = 0; + let mut confirmed = 0; + while let Some(event) = node.next_event() { + match event { + Event::OnchainTransactionReorged { txid } if txid == expected => reorged += 1, + Event::OnchainTransactionConfirmed { txid, .. } if txid == expected => { + confirmed += 1 + }, + _ => {}, + } + node.event_handled().unwrap(); + } + (reorged, confirmed) + } + + async fn wait_for_unconfirmed_transaction(electrs: &impl ElectrumApi, expected: Txid) { + let script = test_recipient().script_pubkey(); + for _ in 0..300 { + if let Ok(history) = electrs.script_get_history(&script) { + if history.iter().any(|entry| entry.tx_hash == expected && entry.height <= 0) { + return; + } + } + tokio::time::sleep(Duration::from_millis(100)).await; + } + panic!("transaction {expected} did not become unconfirmed"); + } + + /// Cross-wallet send must emit exactly one `OnchainTransactionReceived`, not one per wallet. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_cross_wallet_send_emits_single_received_event() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + // NativeSegwit primary sees only the change output; Legacy secondary has the inputs. + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node = setup_node(&chain_source, config, None); + + let native_addr = node.onchain_payment().new_address().unwrap(); + let legacy_addr = node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![(native_addr, 100_000), (legacy_addr, 100_000)], + ) + .await; + + drain_all_events(&node); + + // 150 000 sats exceeds either wallet alone, so coin selection must span both. + let txid = node + .onchain_payment() + .send_to_address(&test_recipient(), 150_000, None, None) + .expect("cross-wallet send should succeed"); + + wait_for_tx(&electrsd.client, txid).await; + node.sync_wallets().unwrap(); + + let n = count_received(&node, txid); + assert_eq!(n, 1, "expected exactly 1 OnchainTransactionReceived for txid {txid}, got {n}"); + + node.stop().unwrap(); + } + + /// Cross-wallet send must emit exactly one `OnchainTransactionConfirmed` when mined. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_cross_wallet_send_emits_single_confirmed_event() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node = setup_node(&chain_source, config, None); + + let native_addr = node.onchain_payment().new_address().unwrap(); + let legacy_addr = node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![(native_addr, 100_000), (legacy_addr, 100_000)], + ) + .await; + drain_all_events(&node); + + let txid = node + .onchain_payment() + .send_to_address(&test_recipient(), 150_000, None, None) + .expect("cross-wallet send should succeed"); + + wait_for_tx(&electrsd.client, txid).await; + node.sync_wallets().unwrap(); + drain_all_events(&node); + + confirm_and_sync(&bitcoind, &electrsd, 1, &[&node]).await; + + let n = count_confirmed(&node, txid); + assert_eq!(n, 1, "expected exactly 1 OnchainTransactionConfirmed for txid {txid}, got {n}"); + + node.stop().unwrap(); + } + + /// After a cross-wallet send, `list_payments` must show the tx as Outbound. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_cross_wallet_send_payment_direction_is_outbound() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + // Fund only the Legacy secondary wallet so the primary sees only the change output + // on first sync; the secondary must correct the direction to Outbound. + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node = setup_node(&chain_source, config, None); + + let legacy_addr = node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + fund_multiple_and_sync(&bitcoind, &electrsd, &node, vec![(legacy_addr, 200_000)]).await; + + let txid = node + .onchain_payment() + .send_to_address(&test_recipient(), 50_000, None, None) + .expect("send from secondary wallet should succeed"); + + wait_for_tx(&electrsd.client, txid).await; + node.sync_wallets().unwrap(); + + let outbound_onchain = node.list_payments_with_filter(|p| { + p.direction == PaymentDirection::Outbound + && matches!(p.kind, PaymentKind::Onchain { .. }) + }); + assert!( + outbound_onchain.iter().any(|p| { + if let PaymentKind::Onchain { txid: t, .. } = p.kind { + t == txid + } else { + false + } + }), + "sent payment {txid} should be Outbound in list_payments, \ + but outbound onchain payments are: {outbound_onchain:?}" + ); + + node.stop().unwrap(); + } + + /// Re-confirmation after a reorg must not be duplicated across wallets. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_cross_wallet_reorg_reconfirmation_is_deduplicated() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node = setup_node(&chain_source, config, None); + + let native_addr = node.onchain_payment().new_address().unwrap(); + let legacy_addr = node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![(native_addr, 100_000), (legacy_addr, 100_000)], + ) + .await; + drain_all_events(&node); + + let txid = node + .onchain_payment() + .send_to_address(&test_recipient(), 150_000, None, None) + .expect("cross-wallet send should succeed"); + + wait_for_tx(&electrsd.client, txid).await; + node.sync_wallets().unwrap(); + drain_all_events(&node); + + confirm_and_sync(&bitcoind, &electrsd, 1, &[&node]).await; + let n_confirmed_first = count_confirmed(&node, txid); + assert_eq!(n_confirmed_first, 1, "expected 1 confirmed event before reorg"); + + // Mine an empty replacement block so the transaction remains unconfirmed. + invalidate_blocks(&bitcoind.client, 1); + let block_address = bitcoind.client.new_address().unwrap(); + bitcoind.client.generate_block(&block_address.to_string(), &[], true).unwrap(); + wait_for_unconfirmed_transaction(&electrsd.client, txid).await; + node.sync_wallets().unwrap(); + + let (n_reorged, n_confirmed_during_reorg) = + count_reorg_and_confirmation_events(&node, txid); + assert_eq!(n_reorged, 1, "expected one OnchainTransactionReorged event"); + assert_eq!(n_confirmed_during_reorg, 0, "transaction must be unconfirmed after reorg"); + + // Mine the transaction again and verify the confirmation is also deduplicated. + generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 1).await; + node.sync_wallets().unwrap(); + + let (n_reorged_after_confirmation, n_confirmed_2) = + count_reorg_and_confirmation_events(&node, txid); + assert_eq!(n_reorged_after_confirmation, 0); + assert_eq!( + n_confirmed_2, 1, + "expected one OnchainTransactionConfirmed after reorg, got {n_confirmed_2}" + ); + + node.stop().unwrap(); + } + + /// `send_all_to_address` from a secondary-only wallet must show the tx as Outbound. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_send_all_payment_direction_is_outbound() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + // Fund only the Legacy secondary wallet; primary has no balance. + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node = setup_node(&chain_source, config, None); + + let legacy_addr = node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + fund_multiple_and_sync(&bitcoind, &electrsd, &node, vec![(legacy_addr, 200_000)]).await; + + let txid = node + .onchain_payment() + .send_all_to_address(&test_recipient(), true, None) + .expect("send_all from secondary wallet should succeed"); + + wait_for_tx(&electrsd.client, txid).await; + node.sync_wallets().unwrap(); + + let outbound_onchain = node.list_payments_with_filter(|p| { + p.direction == PaymentDirection::Outbound + && matches!(p.kind, PaymentKind::Onchain { .. }) + }); + assert!( + outbound_onchain.iter().any(|p| { + if let PaymentKind::Onchain { txid: t, .. } = p.kind { + t == txid + } else { + false + } + }), + "send_all payment {txid} should be Outbound, got: {outbound_onchain:?}" + ); + + node.stop().unwrap(); + } + + /// A receive to a secondary wallet must remain Inbound; the never-downgrade guard + /// must not affect payments that are legitimately Inbound. + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_receive_to_secondary_wallet_direction_is_inbound() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node = setup_node(&chain_source, config, None); + + // Receive to the Legacy secondary wallet only (primary has no UTXOs). + let legacy_addr = node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + fund_multiple_and_sync(&bitcoind, &electrsd, &node, vec![(legacy_addr, 100_000)]).await; + + let inbound_onchain = node.list_payments_with_filter(|p| { + p.direction == PaymentDirection::Inbound + && matches!(p.kind, PaymentKind::Onchain { .. }) + }); + assert!( + !inbound_onchain.is_empty(), + "funding tx to secondary wallet should appear as Inbound, got: {inbound_onchain:?}" + ); + + node.stop().unwrap(); + } +} + +// --------------------------------------------------------------------------- +// Derived on-chain wallet accounts +// --------------------------------------------------------------------------- +mod derived_accounts { + #[cfg(feature = "uniffi")] + use std::sync::Arc; + use std::time::{Duration, SystemTime, UNIX_EPOCH}; + use std::{env, str::FromStr}; + + use bitcoin::bip32::{ChildNumber, Xpub}; + use bitcoin::secp256k1::Secp256k1; + use bitcoin::{Address, Amount, CompressedPublicKey, FeeRate, Network}; + use electrsd::corepc_node::{Conf as BitcoindConf, Node as BitcoinD}; + use electrum_client::ElectrumApi; + use ldk_node::config::{AddressType, ElectrumSyncConfig, OnchainWalletAccountConfig}; + use ldk_node::payment::KeychainKind; + use ldk_node::{Builder, NodeError}; + + use crate::common::{ + distribute_funds_unconfirmed, generate_blocks_and_wait, invalidate_blocks, open_channel, + premine_and_distribute_funds, premine_blocks, setup_bitcoind_and_electrsd, setup_node, + wait_for_tx, TestChainSource, + }; + use crate::helpers::{ + confirm_and_sync, fund_and_sync, fund_multiple_and_sync, fund_peer_node_and_sync, + node_config, read_node_seed, test_recipient, CHANNEL_PEER_FUNDING_SATS, + }; + + #[cfg(not(feature = "uniffi"))] + fn api_seed_bytes(seed: [u8; 64]) -> [u8; 64] { + seed + } + + #[cfg(feature = "uniffi")] + fn api_seed_bytes(seed: [u8; 64]) -> Vec { + seed.to_vec() + } + + #[cfg(not(feature = "uniffi"))] + fn api_fee_rate(fee_rate: FeeRate) -> FeeRate { + fee_rate + } + + #[cfg(feature = "uniffi")] + fn api_fee_rate(fee_rate: FeeRate) -> Arc { + Arc::new(fee_rate) + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_derived_account_receive_spend_and_combined_balance() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![]); + let node = setup_node(&chain_source, config, None); + + let xpub = node + .export_onchain_wallet_account_xpub(AddressType::NativeSegwit, 1) + .expect("export account-1 xpub"); + node.add_onchain_wallet_account(AddressType::NativeSegwit, 1, xpub.clone()) + .expect("register account 1"); + node.add_onchain_wallet_account(AddressType::NativeSegwit, 1, xpub) + .expect("idempotent re-registration"); + + let accounts = node.list_onchain_wallet_accounts(); + assert!(accounts + .iter() + .any(|a| { a.address_type == AddressType::NativeSegwit && a.account_index == 1 })); + + let derived_addr = node + .onchain_payment() + .new_address_for_account(AddressType::NativeSegwit, 1) + .expect("derived receive address"); + + fund_and_sync(&bitcoind, &electrsd, &node, derived_addr, 150_000).await; + + let derived_balance = + node.get_balance_for_onchain_wallet_account(AddressType::NativeSegwit, 1).unwrap(); + assert!(derived_balance.total_sats >= 149_000); + + let combined = node.list_balances(); + assert!(combined.total_onchain_balance_sats >= 149_000); + assert_eq!(combined.total_onchain_balance_sats, derived_balance.total_sats); + + let txid = + node.onchain_payment().send_to_address(&test_recipient(), 50_000, None, None).unwrap(); + wait_for_tx(&electrsd.client, txid).await; + confirm_and_sync(&bitcoind, &electrsd, 1, &[&node]).await; + + let after = node.list_balances(); + assert!(after.total_onchain_balance_sats < combined.total_onchain_balance_sats); + + let primary_after = + node.get_balance_for_onchain_wallet_account(AddressType::NativeSegwit, 0).unwrap(); + assert!(primary_after.total_sats > 0); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_rbf_preserves_derived_recipient_and_uses_existing_funds() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![]); + let node = setup_node(&chain_source, config, None); + let xpub = node.export_onchain_wallet_account_xpub(AddressType::NativeSegwit, 1).unwrap(); + node.add_onchain_wallet_account(AddressType::NativeSegwit, 1, xpub).unwrap(); + + let primary_address = node.onchain_payment().new_address().unwrap(); + let derived_funding_address = + node.onchain_payment().new_address_for_account(AddressType::NativeSegwit, 1).unwrap(); + let derived_recipient = + node.onchain_payment().new_address_for_account(AddressType::NativeSegwit, 1).unwrap(); + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![(primary_address, 55_000), (derived_funding_address, 60_000)], + ) + .await; + + let spendable = node.onchain_payment().list_spendable_outputs().unwrap(); + let primary_utxo = spendable.iter().find(|utxo| utxo.value_sats == 55_000).unwrap().clone(); + let derived_utxo = spendable.iter().find(|utxo| utxo.value_sats == 60_000).unwrap().clone(); + let original_txid = node + .onchain_payment() + .send_to_address( + &derived_recipient, + 50_000, + Some(api_fee_rate(FeeRate::from_sat_per_kwu(250))), + Some(vec![primary_utxo]), + ) + .unwrap(); + wait_for_tx(&electrsd.client, original_txid).await; + node.sync_wallets().unwrap(); + + let replacement_txid = node + .onchain_payment() + .bump_fee_by_rbf(&original_txid, api_fee_rate(FeeRate::from_sat_per_kwu(25_000))) + .unwrap(); + wait_for_tx(&electrsd.client, replacement_txid).await; + let replacement = electrsd.client.transaction_get(&replacement_txid).unwrap(); + + assert!(replacement + .input + .iter() + .any(|input| input.previous_output == derived_utxo.outpoint)); + assert!(replacement.input.iter().all(|input| input.previous_output.txid != original_txid)); + assert!(replacement.output.iter().any(|output| { + output.script_pubkey == derived_recipient.script_pubkey() + && output.value == Amount::from_sat(50_000) + })); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_derived_account_re_registration_recovers_persisted_funds() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + // Sqlite so BDK account data survives a full node rebuild. + let mut config = node_config(AddressType::NativeSegwit, vec![]); + config.store_type = crate::common::TestStoreType::Sqlite; + let storage_path = config.node_config.storage_dir_path.clone(); + let node = setup_node(&chain_source, config, None); + let seed = read_node_seed(&node); + + let xpub = node.export_onchain_wallet_account_xpub(AddressType::NativeSegwit, 1).unwrap(); + node.add_onchain_wallet_account(AddressType::NativeSegwit, 1, xpub.clone()).unwrap(); + + let derived_addr = + node.onchain_payment().new_address_for_account(AddressType::NativeSegwit, 1).unwrap(); + fund_and_sync(&bitcoind, &electrsd, &node, derived_addr, 120_000).await; + + let balance_before = node + .get_balance_for_onchain_wallet_account(AddressType::NativeSegwit, 1) + .unwrap() + .total_sats; + assert!(balance_before >= 119_000); + + node.stop().unwrap(); + drop(node); + + let mut config2 = node_config(AddressType::NativeSegwit, vec![]); + config2.store_type = crate::common::TestStoreType::Sqlite; + config2.node_config.storage_dir_path = storage_path; + let node2 = setup_node(&chain_source, config2, Some(seed.to_vec())); + + assert!(!node2.list_onchain_wallet_accounts().iter().any(|a| a.account_index == 1)); + + node2.add_onchain_wallet_account(AddressType::NativeSegwit, 1, xpub).unwrap(); + node2.sync_wallets().unwrap(); + std::thread::sleep(std::time::Duration::from_secs(2)); + + let balance_after = node2 + .get_balance_for_onchain_wallet_account(AddressType::NativeSegwit, 1) + .unwrap() + .total_sats; + assert_eq!(balance_after, balance_before); + + node2.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_config_load_and_runtime_remove_preserve_derived_account_state() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let mut config = node_config(AddressType::NativeSegwit, vec![]); + config.store_type = crate::common::TestStoreType::Sqlite; + let storage_path = config.node_config.storage_dir_path.clone(); + let node = setup_node(&chain_source, config, None); + let seed = read_node_seed(&node); + let xpub = node.export_onchain_wallet_account_xpub(AddressType::Taproot, 1).unwrap(); + node.add_onchain_wallet_account(AddressType::Taproot, 1, xpub.clone()).unwrap(); + let address = + node.onchain_payment().new_address_for_account(AddressType::Taproot, 1).unwrap(); + fund_and_sync(&bitcoind, &electrsd, &node, address, 120_000).await; + let balance_before = node + .get_balance_for_onchain_wallet_account(AddressType::Taproot, 1) + .unwrap() + .total_sats; + node.stop().unwrap(); + drop(node); + + let mut config = node_config(AddressType::NativeSegwit, vec![]); + config.store_type = crate::common::TestStoreType::Sqlite; + config.node_config.storage_dir_path = storage_path; + config.node_config.onchain_wallet_accounts = vec![OnchainWalletAccountConfig { + address_type: AddressType::Taproot, + account_index: 1, + xpub: xpub.clone(), + }]; + let node = setup_node(&chain_source, config, Some(seed.to_vec())); + + assert!(node.list_onchain_wallet_accounts().iter().any(|account| { + account.address_type == AddressType::Taproot && account.account_index == 1 + })); + node.sync_wallets().unwrap(); + let loaded_balance = node + .get_balance_for_onchain_wallet_account(AddressType::Taproot, 1) + .unwrap() + .total_sats; + assert_eq!(loaded_balance, balance_before); + + node.remove_onchain_wallet_account(AddressType::Taproot, 1).unwrap(); + assert!(!node.list_onchain_wallet_accounts().iter().any(|account| { + account.address_type == AddressType::Taproot && account.account_index == 1 + })); + assert_eq!(node.list_balances().total_onchain_balance_sats, 0); + assert_eq!( + node.remove_onchain_wallet_account(AddressType::Taproot, 1), + Err(NodeError::OnchainWalletAccountNotRegistered) + ); + assert_eq!( + node.remove_onchain_wallet_account(AddressType::Taproot, 0), + Err(NodeError::InvalidQuantity) + ); + + node.add_onchain_wallet_account(AddressType::Taproot, 1, xpub).unwrap(); + assert_eq!( + node.get_balance_for_onchain_wallet_account(AddressType::Taproot, 1) + .unwrap() + .total_sats, + balance_before + ); + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_derived_account_address_lookup_by_index_and_range() { + let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + let node = setup_node(&chain_source, node_config(AddressType::NativeSegwit, vec![]), None); + let xpub = node.export_onchain_wallet_account_xpub(AddressType::NativeSegwit, 2).unwrap(); + node.add_onchain_wallet_account(AddressType::NativeSegwit, 2, xpub.clone()).unwrap(); + + let indexed = node + .onchain_payment() + .address_info_for_account_at_index( + AddressType::NativeSegwit, + 2, + KeychainKind::External, + 7, + ) + .unwrap(); + let range = node + .onchain_payment() + .address_infos_for_account(AddressType::NativeSegwit, 2, KeychainKind::External, 6, 3) + .unwrap(); + assert_eq!(range.iter().map(|info| info.index).collect::>(), vec![6, 7, 8]); + assert_eq!(range[1], indexed); + + let account_xpub = Xpub::from_str(&xpub).unwrap(); + let child = account_xpub + .derive_pub( + &Secp256k1::new(), + &[ + ChildNumber::from_normal_idx(0).unwrap(), + ChildNumber::from_normal_idx(7).unwrap(), + ], + ) + .unwrap(); + let expected = Address::p2wpkh(&CompressedPublicKey(child.public_key), Network::Regtest); + assert_eq!(indexed.address, expected); + assert_eq!(indexed.keychain, KeychainKind::External); + let internal = node + .onchain_payment() + .address_info_for_account_at_index( + AddressType::NativeSegwit, + 2, + KeychainKind::Internal, + 7, + ) + .unwrap(); + assert_ne!(internal.address, indexed.address); + assert_eq!(internal.keychain, KeychainKind::Internal); + + let next = node + .onchain_payment() + .new_address_info_for_account(AddressType::NativeSegwit, 2) + .unwrap(); + assert_eq!(next.index, 0); + assert_eq!(next.keychain, KeychainKind::External); + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_electrum_configured_account_full_scan_uses_custom_gap_and_batch_size() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Electrum(&electrsd); + let mut initial_config = node_config(AddressType::NativeSegwit, vec![]); + initial_config.store_type = crate::common::TestStoreType::Sqlite; + let node = setup_node(&chain_source, initial_config, None); + + let xpub = node.export_onchain_wallet_account_xpub(AddressType::NativeSegwit, 1).unwrap(); + let address = native_segwit_receive_address_from_xpub(&xpub, 30); + let mut restart_config = node.config(); + node.stop().unwrap(); + drop(node); + + premine_and_distribute_funds( + &bitcoind.client, + &electrsd.client, + vec![address], + Amount::from_sat(100_000), + ) + .await; + + restart_config.onchain_wallet_accounts = vec![OnchainWalletAccountConfig { + address_type: AddressType::NativeSegwit, + account_index: 1, + xpub, + }]; + crate::common::setup_builder!(builder, restart_config); + let electrum_url = format!("tcp://{}", electrsd.electrum_url); + let sync_config = ElectrumSyncConfig { + background_sync_config: None, + additional_wallet_full_scan_batch_size: 100, + additional_wallet_full_scan_stop_gap: 1_000, + ..Default::default() + }; + builder.set_chain_source_electrum(electrum_url, Some(sync_config)); + builder.set_log_facade_logger(); + let node = builder.build().unwrap(); + node.start().unwrap(); + node.sync_wallets().unwrap(); + assert!(node.list_onchain_wallet_accounts().iter().any(|account| { + account.address_type == AddressType::NativeSegwit && account.account_index == 1 + })); + assert_eq!( + node.get_balance_for_onchain_wallet_account(AddressType::NativeSegwit, 1) + .unwrap() + .total_sats, + 100_000 + ); + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_electrum_derived_account_incremental_sync_rolls_lookahead() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + premine_blocks(&bitcoind.client, &electrsd.client).await; + + let config = node_config(AddressType::NativeSegwit, vec![]); + crate::common::setup_builder!(builder, config.node_config); + let electrum_url = format!("tcp://{}", electrsd.electrum_url); + let sync_config = ElectrumSyncConfig { + background_sync_config: None, + additional_wallet_full_scan_batch_size: 100, + additional_wallet_full_scan_stop_gap: 1_000, + ..Default::default() + }; + builder.set_chain_source_electrum(electrum_url, Some(sync_config)); + builder.set_log_facade_logger(); + let node = builder.build().unwrap(); + node.start().unwrap(); + + let xpub = node.export_onchain_wallet_account_xpub(AddressType::NativeSegwit, 1).unwrap(); + node.add_onchain_wallet_account(AddressType::NativeSegwit, 1, xpub.clone()).unwrap(); + node.onchain_payment() + .reveal_receive_addresses_to_account(AddressType::NativeSegwit, 1, 999) + .unwrap(); + node.sync_wallets().unwrap(); + + let index_990 = native_segwit_receive_address_from_xpub(&xpub, 990); + distribute_funds_unconfirmed( + &bitcoind.client, + &electrsd.client, + vec![index_990], + Amount::from_sat(100_000), + ) + .await; + generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 1).await; + node.sync_wallets().unwrap(); + assert_eq!( + node.get_balance_for_onchain_wallet_account(AddressType::NativeSegwit, 1) + .unwrap() + .total_sats, + 100_000 + ); + + let index_1200 = native_segwit_receive_address_from_xpub(&xpub, 1_200); + distribute_funds_unconfirmed( + &bitcoind.client, + &electrsd.client, + vec![index_1200], + Amount::from_sat(70_000), + ) + .await; + generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 1).await; + node.sync_wallets().unwrap(); + assert_eq!( + node.get_balance_for_onchain_wallet_account(AddressType::NativeSegwit, 1) + .unwrap() + .total_sats, + 170_000 + ); + assert_eq!( + node.onchain_payment() + .new_address_info_for_account(AddressType::NativeSegwit, 1) + .unwrap() + .index, + 1_201 + ); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_derived_account_rejects_wrong_seed_xpub_and_account_zero() { + let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config_a = node_config(AddressType::NativeSegwit, vec![]); + let node_a = setup_node(&chain_source, config_a, None); + + let config_b = node_config(AddressType::NativeSegwit, vec![]); + let node_b = setup_node(&chain_source, config_b, None); + + let foreign_xpub = + node_b.export_onchain_wallet_account_xpub(AddressType::NativeSegwit, 1).unwrap(); + let err = node_a + .add_onchain_wallet_account(AddressType::NativeSegwit, 1, foreign_xpub) + .expect_err("foreign xpub must be rejected"); + assert_eq!(err, NodeError::InvalidSeedBytes); + + let own_xpub0 = + node_a.export_onchain_wallet_account_xpub(AddressType::NativeSegwit, 0).unwrap(); + let err0 = node_a + .add_onchain_wallet_account(AddressType::NativeSegwit, 0, own_xpub0) + .expect_err("account 0 registration must be rejected"); + assert_eq!(err0, NodeError::InvalidQuantity); + + node_a.stop().unwrap(); + node_b.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_legacy_primary_funding_change_never_uses_derived_account() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config_a = node_config(AddressType::Legacy, vec![AddressType::NativeSegwit]); + let node_a = setup_node(&chain_source, config_a, None); + let config_b = crate::common::random_config(true); + let node_b = setup_node(&chain_source, config_b, None); + + let xpub = node_a.export_onchain_wallet_account_xpub(AddressType::NativeSegwit, 1).unwrap(); + node_a.add_onchain_wallet_account(AddressType::NativeSegwit, 1, xpub.clone()).unwrap(); + + let legacy_addr = node_a.onchain_payment().new_address().unwrap(); + let native0_addr = + node_a.onchain_payment().new_address_for_type(AddressType::NativeSegwit).unwrap(); + let derived_addr = + node_a.onchain_payment().new_address_for_account(AddressType::NativeSegwit, 1).unwrap(); + let addr_b = node_b.onchain_payment().new_address().unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node_a, + vec![(legacy_addr, 50_000), (native0_addr, 80_000), (derived_addr, 200_000)], + ) + .await; + fund_peer_node_and_sync(&bitcoind, &electrsd, &node_b, addr_b, CHANNEL_PEER_FUNDING_SATS) + .await; + + let legacy_before = + node_a.get_balance_for_address_type(AddressType::Legacy).unwrap().total_sats; + let native0_before = + node_a.get_balance_for_address_type(AddressType::NativeSegwit).unwrap().total_sats; + let derived_before = node_a + .get_balance_for_onchain_wallet_account(AddressType::NativeSegwit, 1) + .unwrap() + .total_sats; + + let funding_txo = open_channel(&node_a, &node_b, 150_000, false, &electrsd).await; + let funding_tx = electrsd.client.transaction_get(&funding_txo.txid).unwrap(); + for input in &funding_tx.input { + assert!(!input.witness.is_empty(), "funding inputs must be SegWit"); + } + + let channel_output = &funding_tx.output[funding_txo.vout as usize]; + assert_eq!( + channel_output.value, + Amount::from_sat(150_000), + "funding_txo.vout must point at the channel output" + ); + let non_channel_outputs: Vec<_> = funding_tx + .output + .iter() + .enumerate() + .filter(|(idx, _)| *idx as u32 != funding_txo.vout) + .map(|(_, output)| output) + .collect(); + assert!( + !non_channel_outputs.is_empty(), + "funding transaction must include at least one non-channel output" + ); + assert!( + non_channel_outputs.iter().all(|output| output.script_pubkey.is_p2wpkh()), + "Legacy-primary funding must change to account-0 native segwit" + ); + assert!( + non_channel_outputs + .iter() + .all(|output| output.script_pubkey != channel_output.script_pubkey), + "change must be distinct from the channel output" + ); + + let script_on_account_zero_internal = |script: &bitcoin::Script| -> bool { + for index in 0..20 { + let info = node_a + .onchain_payment() + .address_info_for_type_at_index( + AddressType::NativeSegwit, + KeychainKind::Internal, + index, + ) + .unwrap(); + if info.address.script_pubkey() == *script { + return true; + } + } + false + }; + let script_on_account_zero_external = |script: &bitcoin::Script| -> bool { + for index in 0..20 { + let info = node_a + .onchain_payment() + .address_info_for_type_at_index( + AddressType::NativeSegwit, + KeychainKind::External, + index, + ) + .unwrap(); + if info.address.script_pubkey() == *script { + return true; + } + } + false + }; + let script_on_legacy = |script: &bitcoin::Script| -> bool { + for keychain in [KeychainKind::External, KeychainKind::Internal] { + for index in 0..20 { + let info = node_a + .onchain_payment() + .address_info_for_type_at_index(AddressType::Legacy, keychain, index) + .unwrap(); + if info.address.script_pubkey() == *script { + return true; + } + } + } + false + }; + let script_on_derived = |script: &bitcoin::Script| -> bool { + let account_xpub = Xpub::from_str(&xpub).unwrap(); + for chain in [0u32, 1u32] { + for index in 0..20 { + let child = account_xpub + .derive_pub( + &Secp256k1::new(), + &[ + ChildNumber::from_normal_idx(chain).unwrap(), + ChildNumber::from_normal_idx(index).unwrap(), + ], + ) + .unwrap(); + let derived = + Address::p2wpkh(&CompressedPublicKey(child.public_key), Network::Regtest); + if derived.script_pubkey() == *script { + return true; + } + } + } + false + }; + + let mut account_zero_internal_owned = 0usize; + for output in &non_channel_outputs { + assert!( + !script_on_derived(output.script_pubkey.as_script()), + "wallet-owned non-channel output must not belong to derived account 1" + ); + assert!( + !script_on_legacy(output.script_pubkey.as_script()), + "wallet-owned non-channel output must not belong to Legacy account 0" + ); + assert!( + !script_on_account_zero_external(output.script_pubkey.as_script()), + "change must not land on account-0 external chain" + ); + if script_on_account_zero_internal(output.script_pubkey.as_script()) { + account_zero_internal_owned += 1; + } + } + assert_eq!( + account_zero_internal_owned, + non_channel_outputs.len(), + "every wallet-owned non-channel output must belong to account-0 native segwit internal chain" + ); + + confirm_and_sync(&bitcoind, &electrsd, 6, &[&node_a, &node_b]).await; + + let legacy_after = + node_a.get_balance_for_address_type(AddressType::Legacy).unwrap().total_sats; + let native0_after = + node_a.get_balance_for_address_type(AddressType::NativeSegwit).unwrap().total_sats; + let derived_after = node_a + .get_balance_for_onchain_wallet_account(AddressType::NativeSegwit, 1) + .unwrap() + .total_sats; + + assert_eq!(legacy_after, legacy_before, "Legacy wallet must not fund or receive change"); + assert!(derived_after < derived_before, "derived inputs should be spent"); + assert!( + native0_after + derived_after < native0_before + derived_before, + "channel value must leave the combined SegWit wallets" + ); + assert!(native0_after > 0, "account-0 native segwit must retain the change output"); + assert!(!node_a.list_channels().is_empty()); + + node_a.stop().unwrap(); + node_b.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_multi_address_type_behavior_with_derived_account_loaded() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Legacy]); + let node = setup_node(&chain_source, config, None); + + let xpub = node.export_onchain_wallet_account_xpub(AddressType::Taproot, 1).unwrap(); + node.add_onchain_wallet_account(AddressType::Taproot, 1, xpub).unwrap(); + + let native_addr = node.onchain_payment().new_address().unwrap(); + let legacy_addr = node.onchain_payment().new_address_for_type(AddressType::Legacy).unwrap(); + let derived_addr = + node.onchain_payment().new_address_for_account(AddressType::Taproot, 1).unwrap(); + + fund_multiple_and_sync( + &bitcoind, + &electrsd, + &node, + vec![(native_addr, 100_000), (legacy_addr, 100_000), (derived_addr, 100_000)], + ) + .await; + + assert!( + node.get_balance_for_address_type(AddressType::NativeSegwit).unwrap().total_sats + >= 99_000 + ); + assert!( + node.get_balance_for_address_type(AddressType::Legacy).unwrap().total_sats >= 99_000 + ); + assert!( + node.get_balance_for_onchain_wallet_account(AddressType::Taproot, 1) + .unwrap() + .total_sats >= 99_000 + ); + + let total = node.list_balances().total_onchain_balance_sats; + assert!(total >= 297_000); + + let txid = node + .onchain_payment() + .send_to_address(&test_recipient(), 50_000, None, None) + .expect("multi-wallet send with derived account loaded"); + wait_for_tx(&electrsd.client, txid).await; + node.sync_wallets().unwrap(); + + assert!(node.list_balances().total_onchain_balance_sats < total); + + let monitored = node.list_monitored_address_types(); + assert!(monitored.contains(&AddressType::NativeSegwit)); + assert!(monitored.contains(&AddressType::Legacy)); + assert!(!monitored.contains(&AddressType::Taproot)); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_set_primary_with_derived_loaded_keeps_account_zero() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![AddressType::Taproot]); + let node = setup_node(&chain_source, config, None); + let seed = read_node_seed(&node); + + let xpub = node.export_onchain_wallet_account_xpub(AddressType::NativeSegwit, 1).unwrap(); + node.add_onchain_wallet_account(AddressType::NativeSegwit, 1, xpub).unwrap(); + + let derived_addr = + node.onchain_payment().new_address_for_account(AddressType::NativeSegwit, 1).unwrap(); + fund_and_sync(&bitcoind, &electrsd, &node, derived_addr, 100_000).await; + + node.set_primary_address_type(AddressType::Taproot, api_seed_bytes(seed)).unwrap(); + assert!(node.onchain_payment().new_address().unwrap().script_pubkey().is_p2tr()); + assert!(node + .list_onchain_wallet_accounts() + .iter() + .any(|a| a.address_type == AddressType::NativeSegwit && a.account_index == 1)); + assert!( + node.get_balance_for_onchain_wallet_account(AddressType::NativeSegwit, 1) + .unwrap() + .total_sats >= 99_000 + ); + + let before_primary = node + .get_balance_for_onchain_wallet_account(AddressType::Taproot, 0) + .unwrap() + .total_sats; + let txid = + node.onchain_payment().send_to_address(&test_recipient(), 20_000, None, None).unwrap(); + wait_for_tx(&electrsd.client, txid).await; + confirm_and_sync(&bitcoind, &electrsd, 1, &[&node]).await; + + let after_primary = node + .get_balance_for_onchain_wallet_account(AddressType::Taproot, 0) + .unwrap() + .total_sats; + assert!(after_primary > before_primary); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_unregistered_and_account_two_and_mismatched_xpub_when_loaded() { + let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + + let config = node_config(AddressType::NativeSegwit, vec![]); + let node = setup_node(&chain_source, config, None); + + assert_eq!( + node.get_balance_for_onchain_wallet_account(AddressType::NativeSegwit, 1).unwrap_err(), + NodeError::OnchainWalletAccountNotRegistered + ); + assert_eq!( + node.onchain_payment() + .new_address_for_account(AddressType::NativeSegwit, 1) + .unwrap_err(), + NodeError::OnchainWalletAccountNotRegistered + ); + assert_eq!( + node.onchain_payment() + .address_info_for_account_at_index( + AddressType::NativeSegwit, + 1, + KeychainKind::External, + 0, + ) + .unwrap_err(), + NodeError::OnchainWalletAccountNotRegistered + ); + assert_eq!( + node.onchain_payment() + .address_infos_for_account( + AddressType::NativeSegwit, + 1, + KeychainKind::External, + 0, + 1, + ) + .unwrap_err(), + NodeError::OnchainWalletAccountNotRegistered + ); + assert_eq!( + node.onchain_payment() + .reveal_receive_addresses_to_account(AddressType::NativeSegwit, 1, 0) + .unwrap_err(), + NodeError::OnchainWalletAccountNotRegistered + ); + + let xpub2 = node.export_onchain_wallet_account_xpub(AddressType::NativeSegwit, 2).unwrap(); + node.add_onchain_wallet_account(AddressType::NativeSegwit, 2, xpub2.clone()).unwrap(); + assert!(node + .list_onchain_wallet_accounts() + .iter() + .any(|a| a.address_type == AddressType::NativeSegwit && a.account_index == 2)); + let _addr2 = + node.onchain_payment().new_address_for_account(AddressType::NativeSegwit, 2).unwrap(); + + let xpub1 = node.export_onchain_wallet_account_xpub(AddressType::NativeSegwit, 1).unwrap(); + assert_ne!(xpub1, xpub2); + assert_eq!( + node.add_onchain_wallet_account(AddressType::NativeSegwit, 2, xpub1).unwrap_err(), + NodeError::InvalidSeedBytes + ); + node.add_onchain_wallet_account(AddressType::NativeSegwit, 2, xpub2).unwrap(); + + node.stop().unwrap(); + } + + fn native_segwit_receive_address_from_xpub(account_xpub: &str, address_index: u32) -> Address { + let xpub = Xpub::from_str(account_xpub).unwrap(); + let child = xpub + .derive_pub( + &Secp256k1::new(), + &[ + ChildNumber::from_normal_idx(0).unwrap(), + ChildNumber::from_normal_idx(address_index).unwrap(), + ], + ) + .unwrap(); + Address::p2wpkh(&CompressedPublicKey(child.public_key), Network::Regtest) + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_bitcoind_new_account_replays_existing_mempool_transactions() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::BitcoindRpcSync(&bitcoind); + let node = setup_node(&chain_source, node_config(AddressType::NativeSegwit, vec![]), None); + + let xpub = node.export_onchain_wallet_account_xpub(AddressType::NativeSegwit, 1).unwrap(); + let derived_address = native_segwit_receive_address_from_xpub(&xpub, 0); + premine_blocks(&bitcoind.client, &electrsd.client).await; + distribute_funds_unconfirmed( + &bitcoind.client, + &electrsd.client, + vec![derived_address], + Amount::from_sat(70_000), + ) + .await; + + // Advance the global mempool cursor before the receiving account is loaded. + node.sync_wallets().unwrap(); + node.add_onchain_wallet_account(AddressType::NativeSegwit, 1, xpub).unwrap(); + node.sync_wallets().unwrap(); + + let balance = + node.get_balance_for_onchain_wallet_account(AddressType::NativeSegwit, 1).unwrap(); + assert_eq!(balance.total_sats, 70_000); + assert_eq!(balance.spendable_sats, 0); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_bitcoind_restart_evicts_persisted_unconfirmed_derived_funds() { + let bitcoind_exe = env::var("BITCOIND_EXE") + .ok() + .or_else(|| electrsd::corepc_node::downloaded_exe_path().ok()) + .expect("bitcoind executable"); + let data_dir = electrsd::corepc_node::tempfile::tempdir().unwrap(); + let mut bitcoind_conf = BitcoindConf::default(); + bitcoind_conf.args.extend(["-rest", "-persistmempool=0"]); + bitcoind_conf.staticdir = Some(data_dir.path().join("bitcoin")); + let mut bitcoind = BitcoinD::with_conf(&bitcoind_exe, &bitcoind_conf).unwrap(); + + let electrs_exe = env::var("ELECTRS_EXE") + .ok() + .or_else(electrsd::downloaded_exe_path) + .expect("electrs executable"); + let mut electrsd_conf = electrsd::Conf::default(); + electrsd_conf.http_enabled = true; + electrsd_conf.network = "regtest"; + let electrsd = + electrsd::ElectrsD::with_conf(electrs_exe, &bitcoind, &electrsd_conf).unwrap(); + + let chain_source = TestChainSource::BitcoindRpcSync(&bitcoind); + let mut config = node_config(AddressType::NativeSegwit, vec![]); + config.store_type = crate::common::TestStoreType::Sqlite; + let storage_path = config.node_config.storage_dir_path.clone(); + let node = setup_node(&chain_source, config, None); + let seed = read_node_seed(&node); + let xpub = node.export_onchain_wallet_account_xpub(AddressType::NativeSegwit, 1).unwrap(); + node.add_onchain_wallet_account(AddressType::NativeSegwit, 1, xpub.clone()).unwrap(); + let derived_address = + node.onchain_payment().new_address_for_account(AddressType::NativeSegwit, 1).unwrap(); + + premine_blocks(&bitcoind.client, &electrsd.client).await; + distribute_funds_unconfirmed( + &bitcoind.client, + &electrsd.client, + vec![derived_address], + Amount::from_sat(70_000), + ) + .await; + node.sync_wallets().unwrap(); + assert_eq!( + node.get_balance_for_onchain_wallet_account(AddressType::NativeSegwit, 1) + .unwrap() + .total_sats, + 70_000 + ); + node.stop().unwrap(); + drop(node); + drop(electrsd); + bitcoind.stop().unwrap(); + drop(bitcoind); + + let mut restart_conf = bitcoind_conf.clone(); + restart_conf.args.push("-walletbroadcast=0"); + let bitcoind = BitcoinD::with_conf(&bitcoind_exe, &restart_conf).unwrap(); + assert!(bitcoind.client.get_raw_mempool().unwrap().0.is_empty()); + let chain_source = TestChainSource::BitcoindRpcSync(&bitcoind); + let mut config = node_config(AddressType::NativeSegwit, vec![]); + config.store_type = crate::common::TestStoreType::Sqlite; + config.node_config.storage_dir_path = storage_path; + let node = setup_node(&chain_source, config, Some(seed.to_vec())); + node.sync_wallets().unwrap(); + node.stop().unwrap(); + // Load account 1 while stopped so the next initial sync owns the eviction. + node.add_onchain_wallet_account(AddressType::NativeSegwit, 1, xpub).unwrap(); + assert_eq!( + node.get_balance_for_onchain_wallet_account(AddressType::NativeSegwit, 1) + .unwrap() + .total_sats, + 70_000, + "persisted unconfirmed funds must still be present before initial sync" + ); + + let sync_timestamp_before = node + .status() + .latest_onchain_wallet_sync_timestamp + .expect("first lifecycle must publish an on-chain sync timestamp"); + // Sync timestamps use seconds, so start the next lifecycle in a later second. + while SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("system time after Unix epoch") + .as_secs() + <= sync_timestamp_before + { + tokio::time::sleep(Duration::from_millis(10)).await; + } + + node.start().unwrap(); + assert!(node.status().is_running); + + let mut saw_initial_sync = false; + for _ in 0..200 { + let sync_timestamp_after = node.status().latest_onchain_wallet_sync_timestamp; + if matches!(sync_timestamp_after, Some(timestamp) if timestamp > sync_timestamp_before) + { + saw_initial_sync = true; + break; + } + tokio::time::sleep(Duration::from_millis(50)).await; + } + assert!( + saw_initial_sync, + "initial Bitcoind sync must publish a fresh on-chain sync timestamp" + ); + + let balance = + node.get_balance_for_onchain_wallet_account(AddressType::NativeSegwit, 1).unwrap(); + assert_eq!( + balance.total_sats, 0, + "initial sync alone must evict persisted unconfirmed funds when mempool is empty" + ); + assert_eq!(balance.spendable_sats, 0); + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_bitcoind_readd_derived_catches_up_gap_while_primary_ahead() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::BitcoindRpcSync(&bitcoind); + + let mut config = node_config(AddressType::NativeSegwit, vec![]); + config.store_type = crate::common::TestStoreType::Sqlite; + let storage_path = config.node_config.storage_dir_path.clone(); + let node = setup_node(&chain_source, config, None); + let seed = read_node_seed(&node); + + let xpub = node.export_onchain_wallet_account_xpub(AddressType::NativeSegwit, 1).unwrap(); + node.add_onchain_wallet_account(AddressType::NativeSegwit, 1, xpub.clone()).unwrap(); + + // Reveal two receive scripts so Bitcoind Listen can match gap payments after re-add. + let first_addr = + node.onchain_payment().new_address_for_account(AddressType::NativeSegwit, 1).unwrap(); + let second_addr = + node.onchain_payment().new_address_for_account(AddressType::NativeSegwit, 1).unwrap(); + fund_and_sync(&bitcoind, &electrsd, &node, first_addr, 100_000).await; + let balance_before = node + .get_balance_for_onchain_wallet_account(AddressType::NativeSegwit, 1) + .unwrap() + .total_sats; + assert!(balance_before >= 99_000); + + node.stop().unwrap(); + drop(node); + + // Restart without the derived account so only account 0 advances with new blocks. + let mut config2 = node_config(AddressType::NativeSegwit, vec![]); + config2.store_type = crate::common::TestStoreType::Sqlite; + config2.node_config.storage_dir_path = storage_path.clone(); + let node2 = setup_node(&chain_source, config2, Some(seed.to_vec())); + node2.sync_wallets().unwrap(); + + premine_and_distribute_funds( + &bitcoind.client, + &electrsd.client, + vec![second_addr], + Amount::from_sat(70_000), + ) + .await; + generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 6).await; + node2.sync_wallets().unwrap(); + node2.stop().unwrap(); + drop(node2); + + // Fresh start with primary already ahead of the persisted derived tip. Re-add, then sync. + let mut config3 = node_config(AddressType::NativeSegwit, vec![]); + config3.store_type = crate::common::TestStoreType::Sqlite; + config3.node_config.storage_dir_path = storage_path; + let node3 = setup_node(&chain_source, config3, Some(seed.to_vec())); + node3.sync_wallets().unwrap(); + assert!(!node3.list_onchain_wallet_accounts().iter().any(|a| a.account_index == 1)); + + node3.add_onchain_wallet_account(AddressType::NativeSegwit, 1, xpub).unwrap(); + let tip_before_catch_up = node3.status().current_best_block.height; + node3.sync_wallets().expect("bitcoind catch-up must not fail when primary is ahead"); + std::thread::sleep(std::time::Duration::from_secs(2)); + + let bitcoind_height = + bitcoind.client.get_blockchain_info().expect("bitcoind info").blocks as u32; + assert!( + node3.status().current_best_block.height >= tip_before_catch_up, + "account catch-up must not rewind the Lightning tip" + ); + assert_eq!( + node3.status().current_best_block.height, + bitcoind_height, + "account and Lightning listeners must reach the Bitcoind tip together" + ); + + let balance_after = node3 + .get_balance_for_onchain_wallet_account(AddressType::NativeSegwit, 1) + .unwrap() + .total_sats; + assert!( + balance_after >= balance_before + 69_000, + "derived account must recover persisted funds and gap payments, before={}, after={}", + balance_before, + balance_after + ); + + node3.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_bitcoind_readd_sparse_account_recovers_replacement_parent_funds() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + premine_blocks(&bitcoind.client, &electrsd.client).await; + generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 2).await; + let chain_source = TestChainSource::BitcoindRpcSync(&bitcoind); + + let mut config = node_config(AddressType::NativeSegwit, vec![]); + config.store_type = crate::common::TestStoreType::Sqlite; + let storage_path = config.node_config.storage_dir_path.clone(); + let node = setup_node(&chain_source, config, None); + let seed = read_node_seed(&node); + let xpub = node.export_onchain_wallet_account_xpub(AddressType::NativeSegwit, 1).unwrap(); + node.add_onchain_wallet_account(AddressType::NativeSegwit, 1, xpub.clone()).unwrap(); + let derived_address = + node.onchain_payment().new_address_for_account(AddressType::NativeSegwit, 1).unwrap(); + + let height_before = + bitcoind.client.get_blockchain_info().expect("bitcoind info").blocks as u32; + let tip_before = bitcoind + .client + .get_block_hash(height_before as u64) + .expect("tip hash") + .block_hash() + .expect("tip hash present"); + node.stop().unwrap(); + drop(node); + + invalidate_blocks(&bitcoind.client, 2); + let mut amounts = std::collections::HashMap::::new(); + amounts.insert(derived_address.to_string(), Amount::from_sat(70_000).to_btc()); + let funding_txid = bitcoind + .client + .call::( + "sendmany", + &[serde_json::json!(""), serde_json::json!(amounts)], + ) + .expect("send replacement payment") + .as_str() + .expect("txid string") + .to_string(); + generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 2).await; + + let height_after = + bitcoind.client.get_blockchain_info().expect("bitcoind info").blocks as u32; + let tip_after = bitcoind + .client + .get_block_hash(height_after as u64) + .expect("tip hash") + .block_hash() + .expect("tip hash present"); + assert_eq!(height_after, height_before); + assert_ne!(tip_after, tip_before); + + let parent_hash = bitcoind + .client + .get_block_hash((height_after - 1) as u64) + .expect("replacement parent hash") + .block_hash() + .expect("replacement parent hash present"); + let parent_block = bitcoind + .client + .call::( + "getblock", + &[serde_json::json!(parent_hash.to_string()), serde_json::json!(2)], + ) + .expect("replacement parent block"); + assert!(parent_block["tx"] + .as_array() + .unwrap() + .iter() + .any(|transaction| { transaction["txid"].as_str() == Some(funding_txid.as_str()) })); + + let mut config2 = node_config(AddressType::NativeSegwit, vec![]); + config2.store_type = crate::common::TestStoreType::Sqlite; + config2.node_config.storage_dir_path = storage_path; + let node2 = setup_node(&chain_source, config2, Some(seed.to_vec())); + node2.add_onchain_wallet_account(AddressType::NativeSegwit, 1, xpub).unwrap(); + node2.sync_wallets().expect("sparse account must reconcile the full replacement branch"); + + let balance = + node2.get_balance_for_onchain_wallet_account(AddressType::NativeSegwit, 1).unwrap(); + assert!(balance.total_sats >= 69_000); + assert!(node2.list_balances().total_onchain_balance_sats >= balance.total_sats); + + node2.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_bitcoind_wallets_follow_shorter_active_chain() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + premine_blocks(&bitcoind.client, &electrsd.client).await; + generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 2).await; + let chain_source = TestChainSource::BitcoindRpcSync(&bitcoind); + + let config = node_config(AddressType::NativeSegwit, vec![]); + let node = setup_node(&chain_source, config, None); + let xpub = node.export_onchain_wallet_account_xpub(AddressType::NativeSegwit, 1).unwrap(); + node.add_onchain_wallet_account(AddressType::NativeSegwit, 1, xpub).unwrap(); + let derived_address = + node.onchain_payment().new_address_for_account(AddressType::NativeSegwit, 1).unwrap(); + distribute_funds_unconfirmed( + &bitcoind.client, + &electrsd.client, + vec![derived_address.clone()], + Amount::from_sat(70_000), + ) + .await; + generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 2).await; + node.sync_wallets().unwrap(); + let confirmed_balance = + node.get_balance_for_onchain_wallet_account(AddressType::NativeSegwit, 1).unwrap(); + assert!(confirmed_balance.spendable_sats >= 69_000); + + let original_height = + bitcoind.client.get_blockchain_info().expect("bitcoind info").blocks as u32; + invalidate_blocks(&bitcoind.client, 2); + node.sync_wallets().expect("wallets must rewind to a shorter active chain"); + + let shorter_height = + bitcoind.client.get_blockchain_info().expect("bitcoind info").blocks as u32; + assert_eq!(shorter_height, original_height - 2); + assert_eq!(node.status().current_best_block.height, shorter_height); + let rewound_balance = + node.get_balance_for_onchain_wallet_account(AddressType::NativeSegwit, 1).unwrap(); + assert!(rewound_balance.total_sats >= 69_000); + assert!(rewound_balance.spendable_sats < confirmed_balance.spendable_sats); + let next_address = + node.onchain_payment().new_address_for_account(AddressType::NativeSegwit, 1).unwrap(); + assert_ne!(next_address, derived_address); + + generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 2).await; + node.sync_wallets().expect("wallets must extend from the rewound checkpoint"); + assert_eq!(node.status().current_best_block.height, original_height); + let reconfirmed_balance = + node.get_balance_for_onchain_wallet_account(AddressType::NativeSegwit, 1).unwrap(); + assert!(reconfirmed_balance.spendable_sats >= 69_000); + assert!(node.list_onchain_wallet_accounts().iter().any(|account| { + account.address_type == AddressType::NativeSegwit && account.account_index == 1 + })); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_bitcoind_readd_after_equal_height_reorg_recovers_replacement_funds() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::BitcoindRpcSync(&bitcoind); + + let mut config = node_config(AddressType::NativeSegwit, vec![]); + config.store_type = crate::common::TestStoreType::Sqlite; + let storage_path = config.node_config.storage_dir_path.clone(); + let node = setup_node(&chain_source, config, None); + let seed = read_node_seed(&node); + + let xpub = node.export_onchain_wallet_account_xpub(AddressType::NativeSegwit, 1).unwrap(); + node.add_onchain_wallet_account(AddressType::NativeSegwit, 1, xpub.clone()).unwrap(); + + let first_addr = + node.onchain_payment().new_address_for_account(AddressType::NativeSegwit, 1).unwrap(); + let second_addr = + node.onchain_payment().new_address_for_account(AddressType::NativeSegwit, 1).unwrap(); + // fund_and_sync confirms with 6 blocks so a later 2-block invalidate keeps the 100k UTXO. + fund_and_sync(&bitcoind, &electrsd, &node, first_addr, 100_000).await; + let balance_before = node + .get_balance_for_onchain_wallet_account(AddressType::NativeSegwit, 1) + .unwrap() + .total_sats; + assert!(balance_before >= 99_000); + + let height_before = + bitcoind.client.get_blockchain_info().expect("bitcoind info").blocks as u32; + let tip_before = bitcoind + .client + .get_block_hash(height_before as u64) + .expect("tip hash") + .block_hash() + .expect("tip hash present"); + node.stop().unwrap(); + drop(node); + + // Restart without the derived account so only the primary advances through the reorg. + let mut config2 = node_config(AddressType::NativeSegwit, vec![]); + config2.store_type = crate::common::TestStoreType::Sqlite; + config2.node_config.storage_dir_path = storage_path.clone(); + let node2 = setup_node(&chain_source, config2, Some(seed.to_vec())); + node2.sync_wallets().unwrap(); + + invalidate_blocks(&bitcoind.client, 2); + // Avoid electrs mempool polling immediately after invalidate (connection can drop during + // reorg). Submit via bitcoind, then mine the replacement tip and wait on block height. + let mut amounts = std::collections::HashMap::::new(); + amounts.insert(second_addr.to_string(), Amount::from_sat(70_000).to_btc()); + let _txid = bitcoind + .client + .call::( + "sendmany", + &[serde_json::json!(""), serde_json::json!(amounts)], + ) + .expect("send replacement payment") + .as_str() + .expect("txid string") + .to_string(); + generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 2).await; + let height_after = + bitcoind.client.get_blockchain_info().expect("bitcoind info").blocks as u32; + let tip_after = bitcoind + .client + .get_block_hash(height_after as u64) + .expect("tip hash") + .block_hash() + .expect("tip hash present"); + assert_eq!(height_after, height_before, "replacement chain must keep tip height"); + assert_ne!(tip_before, tip_after, "replacement chain must change tip hash"); + node2.sync_wallets().unwrap(); + node2.stop().unwrap(); + drop(node2); + + // Re-add account 1 while primary sits on the canonical equal-height tip. Catch-up must + // start from account 1's stale checkpoint (not the primary tip) so replacement funds apply. + let mut config3 = node_config(AddressType::NativeSegwit, vec![]); + config3.store_type = crate::common::TestStoreType::Sqlite; + config3.node_config.storage_dir_path = storage_path; + let node3 = setup_node(&chain_source, config3, Some(seed.to_vec())); + node3.sync_wallets().unwrap(); + node3.add_onchain_wallet_account(AddressType::NativeSegwit, 1, xpub).unwrap(); + node3.sync_wallets().expect("equal-height reorg catch-up must replay replacement blocks"); + + let balance_after = node3 + .get_balance_for_onchain_wallet_account(AddressType::NativeSegwit, 1) + .unwrap() + .total_sats; + assert!( + balance_after >= balance_before + 69_000, + "derived account must recover persisted funds and equal-height replacement payment immediately after catch-up, before={}, after={}", + balance_before, + balance_after + ); + + node3.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_bitcoind_equal_height_reorg_updates_primary_and_derived() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::BitcoindRpcSync(&bitcoind); + + let config = node_config(AddressType::NativeSegwit, vec![]); + let node = setup_node(&chain_source, config, None); + let xpub = node.export_onchain_wallet_account_xpub(AddressType::NativeSegwit, 1).unwrap(); + node.add_onchain_wallet_account(AddressType::NativeSegwit, 1, xpub).unwrap(); + + let primary_addr = node.onchain_payment().new_address().unwrap(); + let derived_addr = + node.onchain_payment().new_address_for_account(AddressType::NativeSegwit, 1).unwrap(); + premine_and_distribute_funds( + &bitcoind.client, + &electrsd.client, + vec![primary_addr, derived_addr], + Amount::from_sat(100_000), + ) + .await; + generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 1).await; + node.sync_wallets().unwrap(); + + let primary_before = + node.get_balance_for_address_type(AddressType::NativeSegwit).unwrap().total_sats; + let derived_before = node + .get_balance_for_onchain_wallet_account(AddressType::NativeSegwit, 1) + .unwrap() + .total_sats; + assert!(primary_before >= 99_000); + assert!(derived_before >= 99_000); + + let height_before = + bitcoind.client.get_blockchain_info().expect("bitcoind info").blocks as u32; + let tip_before = bitcoind + .client + .get_block_hash(height_before as u64) + .expect("tip hash") + .block_hash() + .expect("tip hash present"); + + // Two-block fork: invalidate and replace so same heights get new hashes. + invalidate_blocks(&bitcoind.client, 2); + generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 2).await; + let reorg_tip = bitcoind + .client + .get_block_hash( + bitcoind.client.get_blockchain_info().expect("bitcoind info").blocks as u64, + ) + .expect("tip hash") + .block_hash() + .expect("tip hash present"); + assert_ne!(tip_before, reorg_tip, "bitcoind must be on a replacement tip"); + assert_eq!( + bitcoind.client.get_blockchain_info().expect("bitcoind info").blocks as u32, + height_before, + "reorg should preserve tip height" + ); + + node.sync_wallets().expect("bitcoind reorg sync must apply replacement blocks"); + + let height_after = + bitcoind.client.get_blockchain_info().expect("bitcoind info").blocks as u32; + let tip_after = bitcoind + .client + .get_block_hash(height_after as u64) + .expect("tip hash") + .block_hash() + .expect("tip hash present"); + assert_eq!(height_after, height_before); + assert_eq!(node.status().current_best_block.height, height_after); + assert_ne!( + node.status().current_best_block.block_hash, + tip_before, + "node must leave the invalidated tip" + ); + assert_eq!( + node.status().current_best_block.block_hash, + tip_after, + "Lightning tip must follow the replacement chain" + ); + + let primary_after = + node.get_balance_for_address_type(AddressType::NativeSegwit).unwrap().total_sats; + let derived_after = node + .get_balance_for_onchain_wallet_account(AddressType::NativeSegwit, 1) + .unwrap() + .total_sats; + assert_eq!(primary_after, primary_before, "primary funds must survive equal-height reorg"); + assert_eq!(derived_after, derived_before, "derived funds must survive equal-height reorg"); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_derived_account_discovers_revealed_external_xpub_address_after_prior_sync() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Electrum(&electrsd); + let config = node_config(AddressType::NativeSegwit, vec![]); + let node = setup_node(&chain_source, config, None); + + let xpub = node.export_onchain_wallet_account_xpub(AddressType::NativeSegwit, 1).unwrap(); + node.add_onchain_wallet_account(AddressType::NativeSegwit, 1, xpub.clone()).unwrap(); + + let first = native_segwit_receive_address_from_xpub(&xpub, 0); + fund_and_sync(&bitcoind, &electrsd, &node, first, 60_000).await; + assert!( + node.get_balance_for_onchain_wallet_account(AddressType::NativeSegwit, 1) + .unwrap() + .total_sats >= 59_000 + ); + + let external_index = 30; + node.onchain_payment() + .reveal_receive_addresses_to_account(AddressType::NativeSegwit, 1, external_index) + .unwrap(); + let second = native_segwit_receive_address_from_xpub(&xpub, external_index); + fund_and_sync(&bitcoind, &electrsd, &node, second, 70_000).await; + assert!( + node.get_balance_for_onchain_wallet_account(AddressType::NativeSegwit, 1) + .unwrap() + .total_sats >= 129_000 + ); + let next = node + .onchain_payment() + .new_address_info_for_account(AddressType::NativeSegwit, 1) + .unwrap(); + assert_eq!(next.index, external_index + 1); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_derived_account_rejects_hardened_range_account_index() { + let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + let config = node_config(AddressType::NativeSegwit, vec![]); + let node = setup_node(&chain_source, config, None); + + let too_high = ldk_node::config::MAX_ONCHAIN_WALLET_ACCOUNT_INDEX + 1; + assert_eq!( + node.export_onchain_wallet_account_xpub(AddressType::NativeSegwit, too_high) + .unwrap_err(), + NodeError::InvalidQuantity + ); + assert_eq!( + node.add_onchain_wallet_account(AddressType::NativeSegwit, too_high, "tpub".into()) + .unwrap_err(), + NodeError::InvalidQuantity + ); + + node.stop().unwrap(); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn test_legacy_primary_preflight_ignores_derived_only_segwit_funds() { + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let chain_source = TestChainSource::Esplora(&electrsd); + let node_a = setup_node(&chain_source, node_config(AddressType::Legacy, vec![]), None); + let node_b = setup_node(&chain_source, crate::common::random_config(true), None); + + let xpub = node_a.export_onchain_wallet_account_xpub(AddressType::NativeSegwit, 1).unwrap(); + node_a.add_onchain_wallet_account(AddressType::NativeSegwit, 1, xpub.clone()).unwrap(); + + let derived_addr = native_segwit_receive_address_from_xpub(&xpub, 0); + fund_and_sync(&bitcoind, &electrsd, &node_a, derived_addr, 200_000).await; + fund_peer_node_and_sync( + &bitcoind, + &electrsd, + &node_b, + node_b.onchain_payment().new_address().unwrap(), + CHANNEL_PEER_FUNDING_SATS, + ) + .await; + + // Only derived SegWit is funded; Legacy-primary funding needs an account-0 SegWit builder. + assert_eq!( + node_a.open_channel( + node_b.node_id(), + node_b.listening_addresses().unwrap().first().unwrap().clone(), + 100_000, + None, + None, + ), + Err(NodeError::InsufficientFunds) + ); + + node_a.stop().unwrap(); + node_b.stop().unwrap(); + } +} diff --git a/tests/reorg_test.rs b/tests/reorg_test.rs index 491a37fd42..2abf01cccf 100644 --- a/tests/reorg_test.rs +++ b/tests/reorg_test.rs @@ -8,9 +8,9 @@ use proptest::prelude::prop; use proptest::proptest; use crate::common::{ - expect_event, generate_blocks_and_wait, invalidate_blocks, open_channel, - premine_and_distribute_funds, random_config, setup_bitcoind_and_electrsd, setup_node, - wait_for_outpoint_spend, TestChainSource, + expect_event, generate_blocks_and_wait, invalidate_blocks, is_informational_event, + open_channel, premine_and_distribute_funds, random_config, setup_bitcoind_and_electrsd, + setup_node, wait_for_outpoint_spend, TestChainSource, }; proptest! { @@ -85,12 +85,15 @@ proptest! { macro_rules! collect_channel_ready_events { ($node:expr, $expected:expr) => {{ let mut user_channels = HashMap::new(); - for _ in 0..$expected { + while user_channels.len() < $expected { match $node.next_event_async().await { Event::ChannelReady { user_channel_id, counterparty_node_id, .. } => { $node.event_handled().unwrap(); user_channels.insert(counterparty_node_id, user_channel_id); }, + ref event if is_informational_event(event) => { + $node.event_handled().unwrap(); + }, other => panic!("Unexpected event: {:?}", other), } } @@ -196,8 +199,11 @@ proptest! { assert_eq!(node.list_balances().total_anchor_channels_reserve_sats, 0); assert!(node.list_balances().lightning_balances.is_empty()); - assert_eq!(node.next_event(), None); - }); + while let Some(event) = node.next_event() { + assert!(is_informational_event(&event), "Unexpected event: {:?}", event); + node.event_handled().unwrap(); + } + }); }) } } diff --git a/uniffi-android.toml b/uniffi-android.toml index a8b1c95896..d1294008f6 100644 --- a/uniffi-android.toml +++ b/uniffi-android.toml @@ -1,3 +1,11 @@ +package_name = "org.lightningdevkit.ldknode" +cdylib_name = "ldk_node" +kotlin_targets = ["android"] +kotlin_target_version = "2.0" +kotlin_multiplatform = false +generate_serializable_types = true +generate_immutable_records = true + [bindings.kotlin] android = true android_cleaner = true diff --git a/uniffi-jvm.toml b/uniffi-jvm.toml new file mode 100644 index 0000000000..eb368f721c --- /dev/null +++ b/uniffi-jvm.toml @@ -0,0 +1,7 @@ +package_name = "org.lightningdevkit.ldknode" +cdylib_name = "ldk_node" +kotlin_targets = ["jvm"] +kotlin_target_version = "2.0" +kotlin_multiplatform = false +generate_serializable_types = true +generate_immutable_records = true