From 79cb0bf2b2a9a4acbbff68f83becc64cdc6273c2 Mon Sep 17 00:00:00 2001 From: Angelos Veglektsis Date: Fri, 18 Sep 2026 19:15:11 +0200 Subject: [PATCH] gl-sdk-android: Update Gradle, AGP and dependencies Update the Gradle wrapper to 9.7.1 and AGP to 9.4.1, along with coroutines, okio, jna, atomicfu and the maven-publish plugin. Replace com.android.library with com.android.kotlin.multiplatform.library and move the Android configuration into the kotlin { android { } } block. Instrumented tests live in the androidDeviceTest source set, and the android.builtInKotlin / android.newDsl opt-outs are no longer needed. Kotlin stays at 2.2.21 because 2.3.0 - 2.4.x reject the generated bindings in compileNativeMainKotlinMetadata (KT-88548), which also holds back annotation and kotlinx-serialization. Stop tracking the generated Kotlin binding in gl-sdk/bindings. --- libs/gl-sdk-android/.gitignore | 1 + libs/gl-sdk-android/build.gradle.kts | 2 +- libs/gl-sdk-android/gradle.properties | 11 +- libs/gl-sdk-android/gradle/libs.versions.toml | 17 +- .../gradle/wrapper/gradle-wrapper.jar | Bin 59203 -> 47505 bytes .../gradle/wrapper/gradle-wrapper.properties | 4 +- libs/gl-sdk-android/gradlew | 283 +- libs/gl-sdk-android/gradlew.bat | 82 + libs/gl-sdk-android/lib/build.gradle.kts | 43 +- .../com/blockstream/glsdk/AuthApiTest.kt | 0 .../com/blockstream/glsdk/ListPaymentTest.kt | 0 .../com/blockstream/glsdk/LnurlParseTest.kt | 0 .../com/blockstream/glsdk/LoggingTest.kt | 0 .../blockstream/glsdk/NodeOperationsTest.kt | 0 .../com/blockstream/glsdk/ParseInputTest.kt | 0 libs/gl-sdk/bindings/uniffi/glsdk/glsdk.kt | 9496 ----------------- 16 files changed, 294 insertions(+), 9645 deletions(-) create mode 100644 libs/gl-sdk-android/gradlew.bat rename libs/gl-sdk-android/lib/src/{androidInstrumentedTest => androidDeviceTest}/kotlin/com/blockstream/glsdk/AuthApiTest.kt (100%) rename libs/gl-sdk-android/lib/src/{androidInstrumentedTest => androidDeviceTest}/kotlin/com/blockstream/glsdk/ListPaymentTest.kt (100%) rename libs/gl-sdk-android/lib/src/{androidInstrumentedTest => androidDeviceTest}/kotlin/com/blockstream/glsdk/LnurlParseTest.kt (100%) rename libs/gl-sdk-android/lib/src/{androidInstrumentedTest => androidDeviceTest}/kotlin/com/blockstream/glsdk/LoggingTest.kt (100%) rename libs/gl-sdk-android/lib/src/{androidInstrumentedTest => androidDeviceTest}/kotlin/com/blockstream/glsdk/NodeOperationsTest.kt (100%) rename libs/gl-sdk-android/lib/src/{androidInstrumentedTest => androidDeviceTest}/kotlin/com/blockstream/glsdk/ParseInputTest.kt (100%) delete mode 100644 libs/gl-sdk/bindings/uniffi/glsdk/glsdk.kt diff --git a/libs/gl-sdk-android/.gitignore b/libs/gl-sdk-android/.gitignore index 590ab7fde..f2e44fa28 100644 --- a/libs/gl-sdk-android/.gitignore +++ b/libs/gl-sdk-android/.gitignore @@ -72,3 +72,4 @@ glsdk.common.kt glsdk.android.kt glsdk.jvm.kt glsdk.native.kt +glsdk.kt diff --git a/libs/gl-sdk-android/build.gradle.kts b/libs/gl-sdk-android/build.gradle.kts index adfd2a530..538ae11b6 100644 --- a/libs/gl-sdk-android/build.gradle.kts +++ b/libs/gl-sdk-android/build.gradle.kts @@ -1,6 +1,6 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - alias(libs.plugins.androidLibrary) apply false + alias(libs.plugins.androidKotlinMultiplatformLibrary) apply false alias(libs.plugins.kotlinMultiplatform) apply false alias(libs.plugins.kotlinSerialization) apply false alias(libs.plugins.mavenPublish) apply false diff --git a/libs/gl-sdk-android/gradle.properties b/libs/gl-sdk-android/gradle.properties index 4c66e37fe..16510a5ed 100644 --- a/libs/gl-sdk-android/gradle.properties +++ b/libs/gl-sdk-android/gradle.properties @@ -17,16 +17,13 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 android.useAndroidX=true # Kotlin code style for this project: "official" or "obsolete": kotlin.code.style=official -# Enables namespacing of each library's R class so that its R class includes only the -# resources declared in the library itself and none from the library's dependencies, -# thereby reducing the size of the R class for that library -android.nonTransitiveRClass=true - +# The generated bindings use kotlinx.atomicfu. These flags (default: false) make the atomicfu +# Kotlin compiler plugin replace atomics with plain fields and intrinsics during compilation. +# Without them, JVM/Android fall back to post-compilation bytecode transformation and +# Kotlin/Native keeps every atomic as a boxed wrapper object. kotlinx.atomicfu.enableJvmIrTransformation=true kotlinx.atomicfu.enableNativeIrTransformation=true kotlin.mpp.enableCInteropCommonization=true -android.builtInKotlin=false -android.newDsl=false libraryVersion=0.4.0 \ No newline at end of file diff --git a/libs/gl-sdk-android/gradle/libs.versions.toml b/libs/gl-sdk-android/gradle/libs.versions.toml index 47d184705..ac8ebc77c 100644 --- a/libs/gl-sdk-android/gradle/libs.versions.toml +++ b/libs/gl-sdk-android/gradle/libs.versions.toml @@ -1,16 +1,19 @@ [versions] +# Kotlin 2.3.0 - 2.4.x reject the generated bindings in compileNativeMainKotlinMetadata with a +# false positive "Member overrides different '@Throws' filter" (KT-88548, fixed in Kotlin 2.5.0). +# annotation >= 1.10.0 and kotlinx-serialization >= 1.10.0 publish klibs that require Kotlin 2.3. annotation = "1.9.1" kotlin = "2.2.21" kotlinx-serialization = "1.9.0" -kotlinx-coroutines = "1.10.2" -android-gradle-plugin = "9.0.0" -okio = "3.16.4" +kotlinx-coroutines = "1.11.0" +android-gradle-plugin = "9.4.1" +okio = "3.18.2" espresso = "3.7.0" -jna = "5.18.1" +jna = "5.19.1" junit = "4.13.2" junit-ext = "1.3.0" -maven-publish = "0.36.0" -atomicfu = "0.31.0" +maven-publish = "0.37.0" +atomicfu = "0.33.0" [libraries] annotation = { module = "androidx.annotation:annotation", version.ref = "annotation" } @@ -24,7 +27,7 @@ junit-ext = { module = "androidx.test.ext:junit", version.ref = "junit-ext" } junit = { module = "junit:junit", version.ref = "junit" } [plugins] -androidLibrary = { id = "com.android.library", version.ref = "android-gradle-plugin" } +androidKotlinMultiplatformLibrary = { id = "com.android.kotlin.multiplatform.library", version.ref = "android-gradle-plugin" } kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } kotlinSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } atomicfu = { id = "org.jetbrains.kotlinx.atomicfu", version.ref = "atomicfu" } diff --git a/libs/gl-sdk-android/gradle/wrapper/gradle-wrapper.jar b/libs/gl-sdk-android/gradle/wrapper/gradle-wrapper.jar index e708b1c023ec8b20f512888fe07c5bd3ff77bb8f..eddabd2eef8d94a5437d6168ff9c87a78ff725b3 100644 GIT binary patch literal 47505 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

K7UpUK$>l@ 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 E2O(~oYXATM diff --git a/libs/gl-sdk-android/gradle/wrapper/gradle-wrapper.properties b/libs/gl-sdk-android/gradle/wrapper/gradle-wrapper.properties index 23449a2b5..ad7845be3 100644 --- a/libs/gl-sdk-android/gradle/wrapper/gradle-wrapper.properties +++ b/libs/gl-sdk-android/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,9 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.1-bin.zip networkTimeout=10000 +retries=0 +retryBackOffMs=500 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/libs/gl-sdk-android/gradlew b/libs/gl-sdk-android/gradlew index 4f906e0c8..249efbb03 100755 --- a/libs/gl-sdk-android/gradlew +++ b/libs/gl-sdk-android/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,81 +15,114 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## -## -## Gradle start up script for UN*X -## +# +# gradlew start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh gradlew +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,88 +131,118 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/libs/gl-sdk-android/gradlew.bat b/libs/gl-sdk-android/gradlew.bat new file mode 100644 index 000000000..8508ef684 --- /dev/null +++ b/libs/gl-sdk-android/gradlew.bat @@ -0,0 +1,82 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem gradlew startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables, and ensure extensions are enabled +setlocal EnableExtensions + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +"%COMSPEC%" /c exit 1 + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +"%COMSPEC%" /c exit 1 + +:execute +@rem Setup the command line + + + +@rem Execute gradlew +@rem endlocal doesn't take effect until after the line is parsed and variables are expanded +@rem which allows us to clear the local environment before executing the java command +endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel + +:exitWithErrorLevel +@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts +"%COMSPEC%" /c exit %ERRORLEVEL% diff --git a/libs/gl-sdk-android/lib/build.gradle.kts b/libs/gl-sdk-android/lib/build.gradle.kts index 29c04f733..2b7b49064 100644 --- a/libs/gl-sdk-android/lib/build.gradle.kts +++ b/libs/gl-sdk-android/lib/build.gradle.kts @@ -1,9 +1,8 @@ -import com.vanniktech.maven.publish.AndroidSingleVariantLibrary import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework plugins { - alias(libs.plugins.androidLibrary) + alias(libs.plugins.androidKotlinMultiplatformLibrary) alias(libs.plugins.kotlinMultiplatform) alias(libs.plugins.kotlinSerialization) alias(libs.plugins.atomicfu) @@ -12,9 +11,24 @@ plugins { } kotlin { - androidTarget { - publishLibraryVariants("release") + android { + namespace = "com.blockstream.glsdk" + compileSdk = 37 + minSdk = 24 + compilerOptions { jvmTarget.set(JvmTarget.JVM_1_8) } + + withHostTestBuilder {}.configure {} + withDeviceTestBuilder { + sourceSetTreeName = "test" + }.configure { + instrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + optimization { + consumerKeepRules.publish = true + consumerKeepRules.file("consumer-rules.pro") + } } jvm() @@ -69,33 +83,16 @@ kotlin { jvmMain.dependencies { implementation(libs.jna) } - androidUnitTest.dependencies { + getByName("androidHostTest").dependencies { implementation(libs.junit) } - androidInstrumentedTest.dependencies { + getByName("androidDeviceTest").dependencies { implementation(libs.junit.ext) implementation(libs.espresso.core) } } } -android { - namespace = "com.blockstream.glsdk" - compileSdk = 36 - - defaultConfig { - minSdk = 24 - - testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" - consumerProguardFiles("consumer-rules.pro") - } - - compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 - } -} - val libraryVersion: String by project mavenPublishing { diff --git a/libs/gl-sdk-android/lib/src/androidInstrumentedTest/kotlin/com/blockstream/glsdk/AuthApiTest.kt b/libs/gl-sdk-android/lib/src/androidDeviceTest/kotlin/com/blockstream/glsdk/AuthApiTest.kt similarity index 100% rename from libs/gl-sdk-android/lib/src/androidInstrumentedTest/kotlin/com/blockstream/glsdk/AuthApiTest.kt rename to libs/gl-sdk-android/lib/src/androidDeviceTest/kotlin/com/blockstream/glsdk/AuthApiTest.kt diff --git a/libs/gl-sdk-android/lib/src/androidInstrumentedTest/kotlin/com/blockstream/glsdk/ListPaymentTest.kt b/libs/gl-sdk-android/lib/src/androidDeviceTest/kotlin/com/blockstream/glsdk/ListPaymentTest.kt similarity index 100% rename from libs/gl-sdk-android/lib/src/androidInstrumentedTest/kotlin/com/blockstream/glsdk/ListPaymentTest.kt rename to libs/gl-sdk-android/lib/src/androidDeviceTest/kotlin/com/blockstream/glsdk/ListPaymentTest.kt diff --git a/libs/gl-sdk-android/lib/src/androidInstrumentedTest/kotlin/com/blockstream/glsdk/LnurlParseTest.kt b/libs/gl-sdk-android/lib/src/androidDeviceTest/kotlin/com/blockstream/glsdk/LnurlParseTest.kt similarity index 100% rename from libs/gl-sdk-android/lib/src/androidInstrumentedTest/kotlin/com/blockstream/glsdk/LnurlParseTest.kt rename to libs/gl-sdk-android/lib/src/androidDeviceTest/kotlin/com/blockstream/glsdk/LnurlParseTest.kt diff --git a/libs/gl-sdk-android/lib/src/androidInstrumentedTest/kotlin/com/blockstream/glsdk/LoggingTest.kt b/libs/gl-sdk-android/lib/src/androidDeviceTest/kotlin/com/blockstream/glsdk/LoggingTest.kt similarity index 100% rename from libs/gl-sdk-android/lib/src/androidInstrumentedTest/kotlin/com/blockstream/glsdk/LoggingTest.kt rename to libs/gl-sdk-android/lib/src/androidDeviceTest/kotlin/com/blockstream/glsdk/LoggingTest.kt diff --git a/libs/gl-sdk-android/lib/src/androidInstrumentedTest/kotlin/com/blockstream/glsdk/NodeOperationsTest.kt b/libs/gl-sdk-android/lib/src/androidDeviceTest/kotlin/com/blockstream/glsdk/NodeOperationsTest.kt similarity index 100% rename from libs/gl-sdk-android/lib/src/androidInstrumentedTest/kotlin/com/blockstream/glsdk/NodeOperationsTest.kt rename to libs/gl-sdk-android/lib/src/androidDeviceTest/kotlin/com/blockstream/glsdk/NodeOperationsTest.kt diff --git a/libs/gl-sdk-android/lib/src/androidInstrumentedTest/kotlin/com/blockstream/glsdk/ParseInputTest.kt b/libs/gl-sdk-android/lib/src/androidDeviceTest/kotlin/com/blockstream/glsdk/ParseInputTest.kt similarity index 100% rename from libs/gl-sdk-android/lib/src/androidInstrumentedTest/kotlin/com/blockstream/glsdk/ParseInputTest.kt rename to libs/gl-sdk-android/lib/src/androidDeviceTest/kotlin/com/blockstream/glsdk/ParseInputTest.kt diff --git a/libs/gl-sdk/bindings/uniffi/glsdk/glsdk.kt b/libs/gl-sdk/bindings/uniffi/glsdk/glsdk.kt deleted file mode 100644 index f09b505e9..000000000 --- a/libs/gl-sdk/bindings/uniffi/glsdk/glsdk.kt +++ /dev/null @@ -1,9496 +0,0 @@ -// This file was autogenerated by some hot garbage in the `uniffi` crate. -// Trust me, you don't want to mess with it! - -@file:Suppress("NAME_SHADOWING") - -package uniffi.glsdk - -// 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.IntegerType -import com.sun.jna.Native -import com.sun.jna.Pointer -import com.sun.jna.Structure -import com.sun.jna.Callback -import com.sun.jna.ptr.* -import java.nio.ByteBuffer -import java.nio.ByteOrder -import java.nio.CharBuffer -import java.nio.charset.CodingErrorAction -import java.util.concurrent.atomic.AtomicLong -import java.util.concurrent.ConcurrentHashMap -import java.util.concurrent.atomic.AtomicBoolean - -// This is a helper for safely working with byte buffers returned from the Rust code. -// A rust-owned buffer is represented by its capacity, its current length, and a -// pointer to the underlying data. - -/** - * @suppress - */ -@Structure.FieldOrder("capacity", "len", "data") -open class RustBuffer : Structure() { - // 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 var capacity: Long = 0 - @JvmField var len: Long = 0 - @JvmField var data: Pointer? = null - - class ByValue: RustBuffer(), Structure.ByValue - class ByReference: RustBuffer(), Structure.ByReference - - internal fun setValue(other: RustBuffer) { - capacity = other.capacity - len = other.len - data = other.data - } - - companion object { - internal fun alloc(size: ULong = 0UL) = uniffiRustCall() { status -> - // Note: need to convert the size to a `Long` value to make this work with JVM. - UniffiLib.INSTANCE.ffi_glsdk_rustbuffer_alloc(size.toLong(), status) - }.also { - if(it.data == null) { - throw RuntimeException("RustBuffer.alloc() returned null data pointer (size=${size})") - } - } - - internal fun create(capacity: ULong, len: ULong, data: Pointer?): RustBuffer.ByValue { - var buf = RustBuffer.ByValue() - buf.capacity = capacity.toLong() - buf.len = len.toLong() - buf.data = data - return buf - } - - internal fun free(buf: RustBuffer.ByValue) = uniffiRustCall() { status -> - UniffiLib.INSTANCE.ffi_glsdk_rustbuffer_free(buf, status) - } - } - - @Suppress("TooGenericExceptionThrown") - fun asByteBuffer() = - this.data?.getByteBuffer(0, this.len.toLong())?.also { - it.order(ByteOrder.BIG_ENDIAN) - } -} - -/** - * 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. - * - * @suppress - */ -class RustBufferByReference : ByReference(16) { - /** - * Set the pointed-to `RustBuffer` to the given value. - */ - fun setValue(value: RustBuffer.ByValue) { - // 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) - } - - /** - * Get a `RustBuffer.ByValue` from this reference. - */ - fun getValue(): RustBuffer.ByValue { - val pointer = getPointer() - val value = RustBuffer.ByValue() - 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 ForeignBytes : Structure() { - @JvmField var len: Int = 0 - @JvmField var data: Pointer? = null - - class ByValue : ForeignBytes(), Structure.ByValue -} -/** - * The FfiConverter interface handles converter types to and from the FFI - * - * All implementing objects should be public to support external types. When a - * type is external we need to import it's FfiConverter. - * - * @suppress - */ -public 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): RustBuffer.ByValue { - val rbuf = RustBuffer.alloc(allocationSize(value)) - try { - val bbuf = rbuf.data!!.getByteBuffer(0, rbuf.capacity).also { - it.order(ByteOrder.BIG_ENDIAN) - } - write(value, bbuf) - rbuf.writeField("len", bbuf.position().toLong()) - return rbuf - } catch (e: Throwable) { - RustBuffer.free(rbuf) - throw e - } - } - - // 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: RustBuffer.ByValue): 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 { - RustBuffer.free(rbuf) - } - } -} - -/** - * FfiConverter that uses `RustBuffer` as the FfiType - * - * @suppress - */ -public interface FfiConverterRustBuffer: FfiConverter { - override fun lift(value: RustBuffer.ByValue) = liftFromRustBuffer(value) - override fun lower(value: KotlinType) = lowerIntoRustBuffer(value) -} -// 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. - -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() - -@Structure.FieldOrder("code", "error_buf") -internal open class UniffiRustCallStatus : Structure() { - @JvmField var code: Byte = 0 - @JvmField var error_buf: RustBuffer.ByValue = RustBuffer.ByValue() - - class ByValue: UniffiRustCallStatus(), Structure.ByValue - - fun isSuccess(): Boolean { - return code == UNIFFI_CALL_SUCCESS - } - - fun isError(): Boolean { - return code == UNIFFI_CALL_ERROR - } - - fun isPanic(): Boolean { - return code == UNIFFI_CALL_UNEXPECTED_ERROR - } - - companion object { - fun create(code: Byte, errorBuf: RustBuffer.ByValue): UniffiRustCallStatus.ByValue { - val callStatus = UniffiRustCallStatus.ByValue() - callStatus.code = code - callStatus.error_buf = errorBuf - return callStatus - } - } -} - -class InternalException(message: String) : kotlin.Exception(message) - -/** - * Each top-level error class has a companion object that can lift the error from the call status's rust buffer - * - * @suppress - */ -interface UniffiRustCallStatusErrorHandler { - fun lift(error_buf: RustBuffer.ByValue): 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 -private inline fun uniffiRustCallWithError(errorHandler: UniffiRustCallStatusErrorHandler, callback: (UniffiRustCallStatus) -> U): U { - var status = UniffiRustCallStatus() - val return_value = callback(status) - uniffiCheckCallStatus(errorHandler, status) - return return_value -} - -// Check UniffiRustCallStatus and throw an error if the call wasn't successful -private fun uniffiCheckCallStatus(errorHandler: UniffiRustCallStatusErrorHandler, status: UniffiRustCallStatus) { - if (status.isSuccess()) { - return - } else if (status.isError()) { - throw errorHandler.lift(status.error_buf) - } 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.error_buf.len > 0) { - throw InternalException(FfiConverterString.lift(status.error_buf)) - } 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 - * - * @suppress - */ -object UniffiNullRustCallStatusErrorHandler: UniffiRustCallStatusErrorHandler { - override fun lift(error_buf: RustBuffer.ByValue): InternalException { - RustBuffer.free(error_buf) - return InternalException("Unexpected CALL_ERROR") - } -} - -// Call a rust function that returns a plain value -private inline fun uniffiRustCall(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.error_buf = FfiConverterString.lower(e.toString()) - } -} - -internal inline fun uniffiTraitInterfaceCallWithError( - callStatus: UniffiRustCallStatus, - makeCall: () -> T, - writeReturn: (T) -> Unit, - lowerError: (E) -> RustBuffer.ByValue -) { - try { - writeReturn(makeCall()) - } catch(e: kotlin.Exception) { - if (e is E) { - callStatus.code = UNIFFI_CALL_ERROR - callStatus.error_buf = lowerError(e) - } else { - callStatus.code = UNIFFI_CALL_UNEXPECTED_ERROR - callStatus.error_buf = FfiConverterString.lower(e.toString()) - } - } -} -// Map handles to objects -// -// This is used pass an opaque 64-bit handle representing a foreign object to the Rust code. -internal class UniffiHandleMap { - private val map = ConcurrentHashMap() - private val counter = java.util.concurrent.atomic.AtomicLong(0) - - 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.put(handle, obj) - return handle - } - - // Get an object from the handle map - fun get(handle: Long): T { - return map.get(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: Invalid handle") - } -} - -// Contains loading, initialization code, -// and the FFI Function declarations in a com.sun.jna.Library. -@Synchronized -private fun findLibraryName(componentName: String): String { - val libOverride = System.getProperty("uniffi.component.$componentName.libraryOverride") - if (libOverride != null) { - return libOverride - } - return "glsdk" -} - -private inline fun loadIndirect( - componentName: String -): Lib { - return Native.load(findLibraryName(componentName), Lib::class.java) -} - -// 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 UniffiForeignFuture( - @JvmField internal var `handle`: Long = 0.toLong(), - @JvmField internal var `free`: UniffiForeignFutureFree? = null, -) : Structure() { - class UniffiByValue( - `handle`: Long = 0.toLong(), - `free`: UniffiForeignFutureFree? = null, - ): UniffiForeignFuture(`handle`,`free`,), Structure.ByValue - - internal fun uniffiSetValue(other: UniffiForeignFuture) { - `handle` = other.`handle` - `free` = other.`free` - } - -} -@Structure.FieldOrder("returnValue", "callStatus") -internal open class UniffiForeignFutureStructU8( - @JvmField internal var `returnValue`: Byte = 0.toByte(), - @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), -) : Structure() { - class UniffiByValue( - `returnValue`: Byte = 0.toByte(), - `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), - ): UniffiForeignFutureStructU8(`returnValue`,`callStatus`,), Structure.ByValue - - internal fun uniffiSetValue(other: UniffiForeignFutureStructU8) { - `returnValue` = other.`returnValue` - `callStatus` = other.`callStatus` - } - -} -internal interface UniffiForeignFutureCompleteU8 : com.sun.jna.Callback { - fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructU8.UniffiByValue,) -} -@Structure.FieldOrder("returnValue", "callStatus") -internal open class UniffiForeignFutureStructI8( - @JvmField internal var `returnValue`: Byte = 0.toByte(), - @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), -) : Structure() { - class UniffiByValue( - `returnValue`: Byte = 0.toByte(), - `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), - ): UniffiForeignFutureStructI8(`returnValue`,`callStatus`,), Structure.ByValue - - internal fun uniffiSetValue(other: UniffiForeignFutureStructI8) { - `returnValue` = other.`returnValue` - `callStatus` = other.`callStatus` - } - -} -internal interface UniffiForeignFutureCompleteI8 : com.sun.jna.Callback { - fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructI8.UniffiByValue,) -} -@Structure.FieldOrder("returnValue", "callStatus") -internal open class UniffiForeignFutureStructU16( - @JvmField internal var `returnValue`: Short = 0.toShort(), - @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), -) : Structure() { - class UniffiByValue( - `returnValue`: Short = 0.toShort(), - `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), - ): UniffiForeignFutureStructU16(`returnValue`,`callStatus`,), Structure.ByValue - - internal fun uniffiSetValue(other: UniffiForeignFutureStructU16) { - `returnValue` = other.`returnValue` - `callStatus` = other.`callStatus` - } - -} -internal interface UniffiForeignFutureCompleteU16 : com.sun.jna.Callback { - fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructU16.UniffiByValue,) -} -@Structure.FieldOrder("returnValue", "callStatus") -internal open class UniffiForeignFutureStructI16( - @JvmField internal var `returnValue`: Short = 0.toShort(), - @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), -) : Structure() { - class UniffiByValue( - `returnValue`: Short = 0.toShort(), - `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), - ): UniffiForeignFutureStructI16(`returnValue`,`callStatus`,), Structure.ByValue - - internal fun uniffiSetValue(other: UniffiForeignFutureStructI16) { - `returnValue` = other.`returnValue` - `callStatus` = other.`callStatus` - } - -} -internal interface UniffiForeignFutureCompleteI16 : com.sun.jna.Callback { - fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructI16.UniffiByValue,) -} -@Structure.FieldOrder("returnValue", "callStatus") -internal open class UniffiForeignFutureStructU32( - @JvmField internal var `returnValue`: Int = 0, - @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), -) : Structure() { - class UniffiByValue( - `returnValue`: Int = 0, - `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), - ): UniffiForeignFutureStructU32(`returnValue`,`callStatus`,), Structure.ByValue - - internal fun uniffiSetValue(other: UniffiForeignFutureStructU32) { - `returnValue` = other.`returnValue` - `callStatus` = other.`callStatus` - } - -} -internal interface UniffiForeignFutureCompleteU32 : com.sun.jna.Callback { - fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructU32.UniffiByValue,) -} -@Structure.FieldOrder("returnValue", "callStatus") -internal open class UniffiForeignFutureStructI32( - @JvmField internal var `returnValue`: Int = 0, - @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), -) : Structure() { - class UniffiByValue( - `returnValue`: Int = 0, - `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), - ): UniffiForeignFutureStructI32(`returnValue`,`callStatus`,), Structure.ByValue - - internal fun uniffiSetValue(other: UniffiForeignFutureStructI32) { - `returnValue` = other.`returnValue` - `callStatus` = other.`callStatus` - } - -} -internal interface UniffiForeignFutureCompleteI32 : com.sun.jna.Callback { - fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructI32.UniffiByValue,) -} -@Structure.FieldOrder("returnValue", "callStatus") -internal open class UniffiForeignFutureStructU64( - @JvmField internal var `returnValue`: Long = 0.toLong(), - @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), -) : Structure() { - class UniffiByValue( - `returnValue`: Long = 0.toLong(), - `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), - ): UniffiForeignFutureStructU64(`returnValue`,`callStatus`,), Structure.ByValue - - internal fun uniffiSetValue(other: UniffiForeignFutureStructU64) { - `returnValue` = other.`returnValue` - `callStatus` = other.`callStatus` - } - -} -internal interface UniffiForeignFutureCompleteU64 : com.sun.jna.Callback { - fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructU64.UniffiByValue,) -} -@Structure.FieldOrder("returnValue", "callStatus") -internal open class UniffiForeignFutureStructI64( - @JvmField internal var `returnValue`: Long = 0.toLong(), - @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), -) : Structure() { - class UniffiByValue( - `returnValue`: Long = 0.toLong(), - `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), - ): UniffiForeignFutureStructI64(`returnValue`,`callStatus`,), Structure.ByValue - - internal fun uniffiSetValue(other: UniffiForeignFutureStructI64) { - `returnValue` = other.`returnValue` - `callStatus` = other.`callStatus` - } - -} -internal interface UniffiForeignFutureCompleteI64 : com.sun.jna.Callback { - fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructI64.UniffiByValue,) -} -@Structure.FieldOrder("returnValue", "callStatus") -internal open class UniffiForeignFutureStructF32( - @JvmField internal var `returnValue`: Float = 0.0f, - @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), -) : Structure() { - class UniffiByValue( - `returnValue`: Float = 0.0f, - `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), - ): UniffiForeignFutureStructF32(`returnValue`,`callStatus`,), Structure.ByValue - - internal fun uniffiSetValue(other: UniffiForeignFutureStructF32) { - `returnValue` = other.`returnValue` - `callStatus` = other.`callStatus` - } - -} -internal interface UniffiForeignFutureCompleteF32 : com.sun.jna.Callback { - fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructF32.UniffiByValue,) -} -@Structure.FieldOrder("returnValue", "callStatus") -internal open class UniffiForeignFutureStructF64( - @JvmField internal var `returnValue`: Double = 0.0, - @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), -) : Structure() { - class UniffiByValue( - `returnValue`: Double = 0.0, - `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), - ): UniffiForeignFutureStructF64(`returnValue`,`callStatus`,), Structure.ByValue - - internal fun uniffiSetValue(other: UniffiForeignFutureStructF64) { - `returnValue` = other.`returnValue` - `callStatus` = other.`callStatus` - } - -} -internal interface UniffiForeignFutureCompleteF64 : com.sun.jna.Callback { - fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructF64.UniffiByValue,) -} -@Structure.FieldOrder("returnValue", "callStatus") -internal open class UniffiForeignFutureStructPointer( - @JvmField internal var `returnValue`: Pointer = Pointer.NULL, - @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), -) : Structure() { - class UniffiByValue( - `returnValue`: Pointer = Pointer.NULL, - `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), - ): UniffiForeignFutureStructPointer(`returnValue`,`callStatus`,), Structure.ByValue - - internal fun uniffiSetValue(other: UniffiForeignFutureStructPointer) { - `returnValue` = other.`returnValue` - `callStatus` = other.`callStatus` - } - -} -internal interface UniffiForeignFutureCompletePointer : com.sun.jna.Callback { - fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructPointer.UniffiByValue,) -} -@Structure.FieldOrder("returnValue", "callStatus") -internal open class UniffiForeignFutureStructRustBuffer( - @JvmField internal var `returnValue`: RustBuffer.ByValue = RustBuffer.ByValue(), - @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), -) : Structure() { - class UniffiByValue( - `returnValue`: RustBuffer.ByValue = RustBuffer.ByValue(), - `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), - ): UniffiForeignFutureStructRustBuffer(`returnValue`,`callStatus`,), Structure.ByValue - - internal fun uniffiSetValue(other: UniffiForeignFutureStructRustBuffer) { - `returnValue` = other.`returnValue` - `callStatus` = other.`callStatus` - } - -} -internal interface UniffiForeignFutureCompleteRustBuffer : com.sun.jna.Callback { - fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructRustBuffer.UniffiByValue,) -} -@Structure.FieldOrder("callStatus") -internal open class UniffiForeignFutureStructVoid( - @JvmField internal var `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), -) : Structure() { - class UniffiByValue( - `callStatus`: UniffiRustCallStatus.ByValue = UniffiRustCallStatus.ByValue(), - ): UniffiForeignFutureStructVoid(`callStatus`,), Structure.ByValue - - internal fun uniffiSetValue(other: UniffiForeignFutureStructVoid) { - `callStatus` = other.`callStatus` - } - -} -internal interface UniffiForeignFutureCompleteVoid : com.sun.jna.Callback { - fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructVoid.UniffiByValue,) -} -internal interface UniffiCallbackInterfaceLogListenerMethod0 : com.sun.jna.Callback { - fun callback(`uniffiHandle`: Long,`entry`: RustBuffer.ByValue,`uniffiOutReturn`: Pointer,uniffiCallStatus: UniffiRustCallStatus,) -} -internal interface UniffiCallbackInterfaceNodeEventListenerMethod0 : com.sun.jna.Callback { - fun callback(`uniffiHandle`: Long,`event`: RustBuffer.ByValue,`uniffiOutReturn`: Pointer,uniffiCallStatus: UniffiRustCallStatus,) -} -@Structure.FieldOrder("onLog", "uniffiFree") -internal open class UniffiVTableCallbackInterfaceLogListener( - @JvmField internal var `onLog`: UniffiCallbackInterfaceLogListenerMethod0? = null, - @JvmField internal var `uniffiFree`: UniffiCallbackInterfaceFree? = null, -) : Structure() { - class UniffiByValue( - `onLog`: UniffiCallbackInterfaceLogListenerMethod0? = null, - `uniffiFree`: UniffiCallbackInterfaceFree? = null, - ): UniffiVTableCallbackInterfaceLogListener(`onLog`,`uniffiFree`,), Structure.ByValue - - internal fun uniffiSetValue(other: UniffiVTableCallbackInterfaceLogListener) { - `onLog` = other.`onLog` - `uniffiFree` = other.`uniffiFree` - } - -} -@Structure.FieldOrder("onEvent", "uniffiFree") -internal open class UniffiVTableCallbackInterfaceNodeEventListener( - @JvmField internal var `onEvent`: UniffiCallbackInterfaceNodeEventListenerMethod0? = null, - @JvmField internal var `uniffiFree`: UniffiCallbackInterfaceFree? = null, -) : Structure() { - class UniffiByValue( - `onEvent`: UniffiCallbackInterfaceNodeEventListenerMethod0? = null, - `uniffiFree`: UniffiCallbackInterfaceFree? = null, - ): UniffiVTableCallbackInterfaceNodeEventListener(`onEvent`,`uniffiFree`,), Structure.ByValue - - internal fun uniffiSetValue(other: UniffiVTableCallbackInterfaceNodeEventListener) { - `onEvent` = other.`onEvent` - `uniffiFree` = other.`uniffiFree` - } - -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// For large crates we prevent `MethodTooLargeException` (see #2340) -// N.B. the name of the extension is very misleading, since it is -// rather `InterfaceTooLargeException`, caused by too many methods -// in the interface for large crates. -// -// By splitting the otherwise huge interface into two parts -// * UniffiLib -// * IntegrityCheckingUniffiLib (this) -// we allow for ~2x as many methods in the UniffiLib interface. -// -// The `ffi_uniffi_contract_version` method and all checksum methods are put -// into `IntegrityCheckingUniffiLib` and these methods are called only once, -// when the library is loaded. -internal interface IntegrityCheckingUniffiLib : Library { - // Integrity check functions only - fun uniffi_glsdk_checksum_func_parse_input( -): Short -fun uniffi_glsdk_checksum_func_resolve_input( -): Short -fun uniffi_glsdk_checksum_func_set_log_level( -): Short -fun uniffi_glsdk_checksum_func_set_logger( -): Short -fun uniffi_glsdk_checksum_method_config_with_developer_cert( -): Short -fun uniffi_glsdk_checksum_method_config_with_network( -): Short -fun uniffi_glsdk_checksum_method_credentials_node_id( -): Short -fun uniffi_glsdk_checksum_method_credentials_save( -): Short -fun uniffi_glsdk_checksum_method_handle_stop( -): Short -fun uniffi_glsdk_checksum_method_node_credentials( -): Short -fun uniffi_glsdk_checksum_method_node_disconnect( -): Short -fun uniffi_glsdk_checksum_method_node_generate_diagnostic_data( -): Short -fun uniffi_glsdk_checksum_method_node_get_info( -): Short -fun uniffi_glsdk_checksum_method_node_list_funds( -): Short -fun uniffi_glsdk_checksum_method_node_list_invoices( -): Short -fun uniffi_glsdk_checksum_method_node_list_payments( -): Short -fun uniffi_glsdk_checksum_method_node_list_pays( -): Short -fun uniffi_glsdk_checksum_method_node_list_peer_channels( -): Short -fun uniffi_glsdk_checksum_method_node_list_peers( -): Short -fun uniffi_glsdk_checksum_method_node_lnurl_pay( -): Short -fun uniffi_glsdk_checksum_method_node_lnurl_withdraw( -): Short -fun uniffi_glsdk_checksum_method_node_node_state( -): Short -fun uniffi_glsdk_checksum_method_node_onchain_balance_state( -): Short -fun uniffi_glsdk_checksum_method_node_onchain_fee_rates( -): Short -fun uniffi_glsdk_checksum_method_node_onchain_receive( -): Short -fun uniffi_glsdk_checksum_method_node_onchain_send( -): Short -fun uniffi_glsdk_checksum_method_node_prepare_onchain_send( -): Short -fun uniffi_glsdk_checksum_method_node_receive( -): Short -fun uniffi_glsdk_checksum_method_node_send( -): Short -fun uniffi_glsdk_checksum_method_node_stop( -): Short -fun uniffi_glsdk_checksum_method_node_stream_node_events( -): Short -fun uniffi_glsdk_checksum_method_nodebuilder_connect( -): Short -fun uniffi_glsdk_checksum_method_nodebuilder_recover( -): Short -fun uniffi_glsdk_checksum_method_nodebuilder_register( -): Short -fun uniffi_glsdk_checksum_method_nodebuilder_register_or_recover( -): Short -fun uniffi_glsdk_checksum_method_nodebuilder_with_event_listener( -): Short -fun uniffi_glsdk_checksum_method_nodeeventstream_next( -): Short -fun uniffi_glsdk_checksum_method_scheduler_lightning_available( -): Short -fun uniffi_glsdk_checksum_method_scheduler_recover( -): Short -fun uniffi_glsdk_checksum_method_scheduler_register( -): Short -fun uniffi_glsdk_checksum_method_scheduler_with_developer_cert( -): Short -fun uniffi_glsdk_checksum_method_signer_authenticate( -): Short -fun uniffi_glsdk_checksum_method_signer_node_id( -): Short -fun uniffi_glsdk_checksum_method_signer_start( -): Short -fun uniffi_glsdk_checksum_constructor_config_new( -): Short -fun uniffi_glsdk_checksum_constructor_credentials_load( -): Short -fun uniffi_glsdk_checksum_constructor_developercert_new( -): Short -fun uniffi_glsdk_checksum_constructor_nodebuilder_new( -): Short -fun uniffi_glsdk_checksum_constructor_scheduler_new( -): Short -fun uniffi_glsdk_checksum_constructor_signer_new( -): Short -fun uniffi_glsdk_checksum_constructor_signer_new_from_seed( -): Short -fun uniffi_glsdk_checksum_method_loglistener_on_log( -): Short -fun uniffi_glsdk_checksum_method_nodeeventlistener_on_event( -): Short -fun ffi_glsdk_uniffi_contract_version( -): Int - -} - -// 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 { - val componentName = "glsdk" - // For large crates we prevent `MethodTooLargeException` (see #2340) - // N.B. the name of the extension is very misleading, since it is - // rather `InterfaceTooLargeException`, caused by too many methods - // in the interface for large crates. - // - // By splitting the otherwise huge interface into two parts - // * UniffiLib (this) - // * IntegrityCheckingUniffiLib - // And all checksum methods are put into `IntegrityCheckingUniffiLib` - // we allow for ~2x as many methods in the UniffiLib interface. - // - // Thus we first load the library with `loadIndirect` as `IntegrityCheckingUniffiLib` - // so that we can (optionally!) call `uniffiCheckApiChecksums`... - loadIndirect(componentName) - .also { lib: IntegrityCheckingUniffiLib -> - uniffiCheckContractApiVersion(lib) - uniffiCheckApiChecksums(lib) - } - // ... and then we load the library as `UniffiLib` - // N.B. we cannot use `loadIndirect` once and then try to cast it to `UniffiLib` - // => results in `java.lang.ClassCastException: com.sun.proxy.$Proxy cannot be cast to ...` - // error. So we must call `loadIndirect` twice. For crates large enough - // to trigger this issue, the performance impact is negligible, running on - // a macOS M1 machine the `loadIndirect` call takes ~50ms. - val lib = loadIndirect(componentName) - // No need to check the contract version and checksums, since - // we already did that with `IntegrityCheckingUniffiLib` above. - uniffiCallbackInterfaceLogListener.register(lib) - uniffiCallbackInterfaceNodeEventListener.register(lib) - // Loading of library with integrity check done. - lib - } - - // The Cleaner for the whole library - internal val CLEANER: UniffiCleaner by lazy { - UniffiCleaner.create() - } - } - - // FFI functions - fun uniffi_glsdk_fn_clone_config(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun uniffi_glsdk_fn_free_config(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): Unit -fun uniffi_glsdk_fn_constructor_config_new(uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun uniffi_glsdk_fn_method_config_with_developer_cert(`ptr`: Pointer,`cert`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun uniffi_glsdk_fn_method_config_with_network(`ptr`: Pointer,`network`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun uniffi_glsdk_fn_clone_credentials(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun uniffi_glsdk_fn_free_credentials(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): Unit -fun uniffi_glsdk_fn_constructor_credentials_load(`raw`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun uniffi_glsdk_fn_method_credentials_node_id(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): RustBuffer.ByValue -fun uniffi_glsdk_fn_method_credentials_save(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): RustBuffer.ByValue -fun uniffi_glsdk_fn_clone_developercert(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun uniffi_glsdk_fn_free_developercert(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): Unit -fun uniffi_glsdk_fn_constructor_developercert_new(`cert`: RustBuffer.ByValue,`key`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun uniffi_glsdk_fn_clone_handle(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun uniffi_glsdk_fn_free_handle(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): Unit -fun uniffi_glsdk_fn_method_handle_stop(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): Unit -fun uniffi_glsdk_fn_clone_node(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun uniffi_glsdk_fn_free_node(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): Unit -fun uniffi_glsdk_fn_method_node_credentials(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): RustBuffer.ByValue -fun uniffi_glsdk_fn_method_node_disconnect(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): Unit -fun uniffi_glsdk_fn_method_node_generate_diagnostic_data(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): RustBuffer.ByValue -fun uniffi_glsdk_fn_method_node_get_info(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): RustBuffer.ByValue -fun uniffi_glsdk_fn_method_node_list_funds(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): RustBuffer.ByValue -fun uniffi_glsdk_fn_method_node_list_invoices(`ptr`: Pointer,`label`: RustBuffer.ByValue,`invstring`: RustBuffer.ByValue,`paymentHash`: RustBuffer.ByValue,`offerId`: RustBuffer.ByValue,`index`: RustBuffer.ByValue,`start`: RustBuffer.ByValue,`limit`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, -): RustBuffer.ByValue -fun uniffi_glsdk_fn_method_node_list_payments(`ptr`: Pointer,`req`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, -): RustBuffer.ByValue -fun uniffi_glsdk_fn_method_node_list_pays(`ptr`: Pointer,`bolt11`: RustBuffer.ByValue,`paymentHash`: RustBuffer.ByValue,`status`: RustBuffer.ByValue,`index`: RustBuffer.ByValue,`start`: RustBuffer.ByValue,`limit`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, -): RustBuffer.ByValue -fun uniffi_glsdk_fn_method_node_list_peer_channels(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): RustBuffer.ByValue -fun uniffi_glsdk_fn_method_node_list_peers(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): RustBuffer.ByValue -fun uniffi_glsdk_fn_method_node_lnurl_pay(`ptr`: Pointer,`request`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, -): RustBuffer.ByValue -fun uniffi_glsdk_fn_method_node_lnurl_withdraw(`ptr`: Pointer,`request`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, -): RustBuffer.ByValue -fun uniffi_glsdk_fn_method_node_node_state(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): RustBuffer.ByValue -fun uniffi_glsdk_fn_method_node_onchain_balance_state(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): RustBuffer.ByValue -fun uniffi_glsdk_fn_method_node_onchain_fee_rates(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): RustBuffer.ByValue -fun uniffi_glsdk_fn_method_node_onchain_receive(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): RustBuffer.ByValue -fun uniffi_glsdk_fn_method_node_onchain_send(`ptr`: Pointer,`destination`: RustBuffer.ByValue,`amountOrAll`: RustBuffer.ByValue,`satPerVbyte`: RustBuffer.ByValue,`utxos`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, -): RustBuffer.ByValue -fun uniffi_glsdk_fn_method_node_prepare_onchain_send(`ptr`: Pointer,`destination`: RustBuffer.ByValue,`amountOrAll`: RustBuffer.ByValue,`satPerVbyte`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, -): RustBuffer.ByValue -fun uniffi_glsdk_fn_method_node_receive(`ptr`: Pointer,`label`: RustBuffer.ByValue,`description`: RustBuffer.ByValue,`amountMsat`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, -): RustBuffer.ByValue -fun uniffi_glsdk_fn_method_node_send(`ptr`: Pointer,`invoice`: RustBuffer.ByValue,`amountMsat`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, -): RustBuffer.ByValue -fun uniffi_glsdk_fn_method_node_stop(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): Unit -fun uniffi_glsdk_fn_method_node_stream_node_events(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun uniffi_glsdk_fn_clone_nodebuilder(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun uniffi_glsdk_fn_free_nodebuilder(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): Unit -fun uniffi_glsdk_fn_constructor_nodebuilder_new(`config`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun uniffi_glsdk_fn_method_nodebuilder_connect(`ptr`: Pointer,`credentials`: RustBuffer.ByValue,`mnemonic`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun uniffi_glsdk_fn_method_nodebuilder_recover(`ptr`: Pointer,`mnemonic`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun uniffi_glsdk_fn_method_nodebuilder_register(`ptr`: Pointer,`mnemonic`: RustBuffer.ByValue,`inviteCode`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun uniffi_glsdk_fn_method_nodebuilder_register_or_recover(`ptr`: Pointer,`mnemonic`: RustBuffer.ByValue,`inviteCode`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun uniffi_glsdk_fn_method_nodebuilder_with_event_listener(`ptr`: Pointer,`listener`: Long,uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun uniffi_glsdk_fn_clone_nodeeventstream(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun uniffi_glsdk_fn_free_nodeeventstream(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): Unit -fun uniffi_glsdk_fn_method_nodeeventstream_next(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): RustBuffer.ByValue -fun uniffi_glsdk_fn_clone_scheduler(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun uniffi_glsdk_fn_free_scheduler(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): Unit -fun uniffi_glsdk_fn_constructor_scheduler_new(`network`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun uniffi_glsdk_fn_method_scheduler_lightning_available(`ptr`: Pointer,`nodeId`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, -): Byte -fun uniffi_glsdk_fn_method_scheduler_recover(`ptr`: Pointer,`signer`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun uniffi_glsdk_fn_method_scheduler_register(`ptr`: Pointer,`signer`: Pointer,`code`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun uniffi_glsdk_fn_method_scheduler_with_developer_cert(`ptr`: Pointer,`cert`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun uniffi_glsdk_fn_clone_signer(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun uniffi_glsdk_fn_free_signer(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): Unit -fun uniffi_glsdk_fn_constructor_signer_new(`phrase`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun uniffi_glsdk_fn_constructor_signer_new_from_seed(`seed`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun uniffi_glsdk_fn_method_signer_authenticate(`ptr`: Pointer,`creds`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun uniffi_glsdk_fn_method_signer_node_id(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): RustBuffer.ByValue -fun uniffi_glsdk_fn_method_signer_start(`ptr`: Pointer,uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun uniffi_glsdk_fn_init_callback_vtable_loglistener(`vtable`: UniffiVTableCallbackInterfaceLogListener, -): Unit -fun uniffi_glsdk_fn_init_callback_vtable_nodeeventlistener(`vtable`: UniffiVTableCallbackInterfaceNodeEventListener, -): Unit -fun uniffi_glsdk_fn_func_parse_input(`input`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, -): RustBuffer.ByValue -fun uniffi_glsdk_fn_func_resolve_input(`input`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, -): RustBuffer.ByValue -fun uniffi_glsdk_fn_func_set_log_level(`level`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, -): Unit -fun uniffi_glsdk_fn_func_set_logger(`level`: RustBuffer.ByValue,`listener`: Long,uniffi_out_err: UniffiRustCallStatus, -): Unit -fun ffi_glsdk_rustbuffer_alloc(`size`: Long,uniffi_out_err: UniffiRustCallStatus, -): RustBuffer.ByValue -fun ffi_glsdk_rustbuffer_from_bytes(`bytes`: ForeignBytes.ByValue,uniffi_out_err: UniffiRustCallStatus, -): RustBuffer.ByValue -fun ffi_glsdk_rustbuffer_free(`buf`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, -): Unit -fun ffi_glsdk_rustbuffer_reserve(`buf`: RustBuffer.ByValue,`additional`: Long,uniffi_out_err: UniffiRustCallStatus, -): RustBuffer.ByValue -fun ffi_glsdk_rust_future_poll_u8(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, -): Unit -fun ffi_glsdk_rust_future_cancel_u8(`handle`: Long, -): Unit -fun ffi_glsdk_rust_future_free_u8(`handle`: Long, -): Unit -fun ffi_glsdk_rust_future_complete_u8(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, -): Byte -fun ffi_glsdk_rust_future_poll_i8(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, -): Unit -fun ffi_glsdk_rust_future_cancel_i8(`handle`: Long, -): Unit -fun ffi_glsdk_rust_future_free_i8(`handle`: Long, -): Unit -fun ffi_glsdk_rust_future_complete_i8(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, -): Byte -fun ffi_glsdk_rust_future_poll_u16(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, -): Unit -fun ffi_glsdk_rust_future_cancel_u16(`handle`: Long, -): Unit -fun ffi_glsdk_rust_future_free_u16(`handle`: Long, -): Unit -fun ffi_glsdk_rust_future_complete_u16(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, -): Short -fun ffi_glsdk_rust_future_poll_i16(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, -): Unit -fun ffi_glsdk_rust_future_cancel_i16(`handle`: Long, -): Unit -fun ffi_glsdk_rust_future_free_i16(`handle`: Long, -): Unit -fun ffi_glsdk_rust_future_complete_i16(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, -): Short -fun ffi_glsdk_rust_future_poll_u32(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, -): Unit -fun ffi_glsdk_rust_future_cancel_u32(`handle`: Long, -): Unit -fun ffi_glsdk_rust_future_free_u32(`handle`: Long, -): Unit -fun ffi_glsdk_rust_future_complete_u32(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, -): Int -fun ffi_glsdk_rust_future_poll_i32(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, -): Unit -fun ffi_glsdk_rust_future_cancel_i32(`handle`: Long, -): Unit -fun ffi_glsdk_rust_future_free_i32(`handle`: Long, -): Unit -fun ffi_glsdk_rust_future_complete_i32(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, -): Int -fun ffi_glsdk_rust_future_poll_u64(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, -): Unit -fun ffi_glsdk_rust_future_cancel_u64(`handle`: Long, -): Unit -fun ffi_glsdk_rust_future_free_u64(`handle`: Long, -): Unit -fun ffi_glsdk_rust_future_complete_u64(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, -): Long -fun ffi_glsdk_rust_future_poll_i64(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, -): Unit -fun ffi_glsdk_rust_future_cancel_i64(`handle`: Long, -): Unit -fun ffi_glsdk_rust_future_free_i64(`handle`: Long, -): Unit -fun ffi_glsdk_rust_future_complete_i64(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, -): Long -fun ffi_glsdk_rust_future_poll_f32(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, -): Unit -fun ffi_glsdk_rust_future_cancel_f32(`handle`: Long, -): Unit -fun ffi_glsdk_rust_future_free_f32(`handle`: Long, -): Unit -fun ffi_glsdk_rust_future_complete_f32(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, -): Float -fun ffi_glsdk_rust_future_poll_f64(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, -): Unit -fun ffi_glsdk_rust_future_cancel_f64(`handle`: Long, -): Unit -fun ffi_glsdk_rust_future_free_f64(`handle`: Long, -): Unit -fun ffi_glsdk_rust_future_complete_f64(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, -): Double -fun ffi_glsdk_rust_future_poll_pointer(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, -): Unit -fun ffi_glsdk_rust_future_cancel_pointer(`handle`: Long, -): Unit -fun ffi_glsdk_rust_future_free_pointer(`handle`: Long, -): Unit -fun ffi_glsdk_rust_future_complete_pointer(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, -): Pointer -fun ffi_glsdk_rust_future_poll_rust_buffer(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, -): Unit -fun ffi_glsdk_rust_future_cancel_rust_buffer(`handle`: Long, -): Unit -fun ffi_glsdk_rust_future_free_rust_buffer(`handle`: Long, -): Unit -fun ffi_glsdk_rust_future_complete_rust_buffer(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, -): RustBuffer.ByValue -fun ffi_glsdk_rust_future_poll_void(`handle`: Long,`callback`: UniffiRustFutureContinuationCallback,`callbackData`: Long, -): Unit -fun ffi_glsdk_rust_future_cancel_void(`handle`: Long, -): Unit -fun ffi_glsdk_rust_future_free_void(`handle`: Long, -): Unit -fun ffi_glsdk_rust_future_complete_void(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, -): Unit - -} - -private fun uniffiCheckContractApiVersion(lib: IntegrityCheckingUniffiLib) { - // Get the bindings contract version from our ComponentInterface - val bindings_contract_version = 29 - // Get the scaffolding contract version by calling the into the dylib - val scaffolding_contract_version = lib.ffi_glsdk_uniffi_contract_version() - if (bindings_contract_version != scaffolding_contract_version) { - throw RuntimeException("UniFFI contract version mismatch: try cleaning and rebuilding your project") - } -} -@Suppress("UNUSED_PARAMETER") -private fun uniffiCheckApiChecksums(lib: IntegrityCheckingUniffiLib) { - if (lib.uniffi_glsdk_checksum_func_parse_input() != 49187.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_func_resolve_input() != 54924.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_func_set_log_level() != 52328.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_func_set_logger() != 10523.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_config_with_developer_cert() != 64194.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_config_with_network() != 35643.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_credentials_node_id() != 16312.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_credentials_save() != 26677.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_handle_stop() != 36432.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_node_credentials() != 39165.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_node_disconnect() != 43626.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_node_generate_diagnostic_data() != 10944.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_node_get_info() != 39460.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_node_list_funds() != 21692.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_node_list_invoices() != 44803.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_node_list_payments() != 43756.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_node_list_pays() != 3970.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_node_list_peer_channels() != 35210.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_node_list_peers() != 29567.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_node_lnurl_pay() != 61306.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_node_lnurl_withdraw() != 61467.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_node_node_state() != 41833.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_node_onchain_balance_state() != 52276.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_node_onchain_fee_rates() != 57819.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_node_onchain_receive() != 46432.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_node_onchain_send() != 63330.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_node_prepare_onchain_send() != 37850.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_node_receive() != 39761.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_node_send() != 4348.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_node_stop() != 20186.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_node_stream_node_events() != 5933.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_nodebuilder_connect() != 47474.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_nodebuilder_recover() != 46087.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_nodebuilder_register() != 49580.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_nodebuilder_register_or_recover() != 5543.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_nodebuilder_with_event_listener() != 56969.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_nodeeventstream_next() != 12635.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_scheduler_lightning_available() != 7327.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_scheduler_recover() != 55514.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_scheduler_register() != 20821.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_scheduler_with_developer_cert() != 64139.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_signer_authenticate() != 55935.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_signer_node_id() != 43931.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_signer_start() != 9404.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_constructor_config_new() != 25640.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_constructor_credentials_load() != 25306.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_constructor_developercert_new() != 57793.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_constructor_nodebuilder_new() != 34740.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_constructor_scheduler_new() != 15239.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_constructor_signer_new() != 62159.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_constructor_signer_new_from_seed() != 6776.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_loglistener_on_log() != 34844.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } - if (lib.uniffi_glsdk_checksum_method_nodeeventlistener_on_event() != 17790.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } -} - -/** - * @suppress - */ -public fun uniffiEnsureInitialized() { - UniffiLib.INSTANCE -} - -// Async support - -// 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. -interface Disposable { - fun destroy() - companion object { - fun destroy(vararg args: Any?) { - for (arg in args) { - when (arg) { - is Disposable -> arg.destroy() - is ArrayList<*> -> { - for (idx in arg.indices) { - val element = arg[idx] - if (element is Disposable) { - element.destroy() - } - } - } - is Map<*, *> -> { - for (element in arg.values) { - if (element is Disposable) { - element.destroy() - } - } - } - is Iterable<*> -> { - for (element in arg) { - if (element is Disposable) { - element.destroy() - } - } - } - } - } - } - } -} - -/** - * @suppress - */ -inline fun T.use(block: (T) -> R) = - 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. - * - * @suppress - * */ -object NoPointer// 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. -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 - -/** - * @suppress - */ -public 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)) - } -} -/** - * The cleaner interface for Object finalization code to run. - * This is the entry point to any implementation that we're using. - * - * The cleaner registers objects and returns cleanables, so now we are - * defining a `UniffiCleaner` with a `UniffiClenaer.Cleanable` to abstract the - * different implmentations available at compile time. - * - * @suppress - */ -interface UniffiCleaner { - interface Cleanable { - fun clean() - } - - fun register(value: Any, cleanUpTask: Runnable): 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(value: Any, cleanUpTask: Runnable): UniffiCleaner.Cleanable = - UniffiJnaCleanable(cleaner.register(value, cleanUpTask)) -} - -private class UniffiJnaCleanable( - private val cleanable: com.sun.jna.internal.Cleaner.Cleanable, -) : UniffiCleaner.Cleanable { - override fun clean() = cleanable.clean() -} - - -// We decide at uniffi binding generation time whether we were -// using Android or not. -// There are further runtime checks to chose the correct implementation -// of the cleaner. -private fun UniffiCleaner.Companion.create(): UniffiCleaner = - try { - // For safety's sake: if the library hasn't been run in android_cleaner = true - // mode, but is being run on Android, then we still need to think about - // Android API versions. - // So we check if java.lang.ref.Cleaner is there, and use that… - java.lang.Class.forName("java.lang.ref.Cleaner") - JavaLangRefCleaner() - } catch (e: ClassNotFoundException) { - // … otherwise, fallback to the JNA cleaner. - UniffiJnaCleaner() - } - -private class JavaLangRefCleaner : UniffiCleaner { - val cleaner = java.lang.ref.Cleaner.create() - - override fun register(value: Any, cleanUpTask: Runnable): UniffiCleaner.Cleanable = - JavaLangRefCleanable(cleaner.register(value, cleanUpTask)) -} - -private class JavaLangRefCleanable( - val cleanable: java.lang.ref.Cleaner.Cleanable -) : UniffiCleaner.Cleanable { - override fun clean() = cleanable.clean() -} - -/** - * @suppress - */ -public 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()) - } -} - -/** - * @suppress - */ -public object FfiConverterInt: FfiConverter { - override fun lift(value: Int): Int { - return value - } - - override fun read(buf: ByteBuffer): Int { - return buf.getInt() - } - - override fun lower(value: Int): Int { - return value - } - - override fun allocationSize(value: Int) = 4UL - - override fun write(value: Int, buf: ByteBuffer) { - buf.putInt(value) - } -} - -/** - * @suppress - */ -public 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()) - } -} - -/** - * @suppress - */ -public 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)) - } -} - -/** - * @suppress - */ -public 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: RustBuffer.ByValue): String { - try { - val byteArr = ByteArray(value.len.toInt()) - value.asByteBuffer()!!.get(byteArr) - return byteArr.toString(Charsets.UTF_8) - } finally { - RustBuffer.free(value) - } - } - - override fun read(buf: ByteBuffer): String { - val len = buf.getInt() - val byteArr = ByteArray(len) - buf.get(byteArr) - return byteArr.toString(Charsets.UTF_8) - } - - fun toUtf8(value: String): ByteBuffer { - // Make sure we don't have invalid UTF-16, check for lone surrogates. - return Charsets.UTF_8.newEncoder().run { - onMalformedInput(CodingErrorAction.REPORT) - encode(CharBuffer.wrap(value)) - } - } - - override fun lower(value: String): RustBuffer.ByValue { - val byteBuf = toUtf8(value) - // Ideally we'd pass these bytes to `ffi_bytebuffer_from_bytes`, but doing so would require us - // to copy them into a JNA `Memory`. So we might as well directly copy them into a `RustBuffer`. - val rbuf = RustBuffer.alloc(byteBuf.limit().toULong()) - rbuf.asByteBuffer()!!.put(byteBuf) - return rbuf - } - - // 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) { - val byteBuf = toUtf8(value) - buf.putInt(byteBuf.limit()) - buf.put(byteBuf) - } -} - -/** - * @suppress - */ -public object FfiConverterByteArray: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): ByteArray { - val len = buf.getInt() - val byteArr = ByteArray(len) - buf.get(byteArr) - 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) - } -} - - -// This template implements a class for working with a Rust struct via a Pointer/Arc -// to the live Rust struct on the other side of the FFI. -// -// Each instance implements core operations for working with the Rust `Arc` and the -// Kotlin Pointer to work with the live Rust struct on the other side of the FFI. -// -// There's some subtlety here, because we have to be careful not to operate on a Rust -// struct after it has been dropped, and because we must expose a public API for freeing -// theq Kotlin wrapper object in lieu of reliable finalizers. The core requirements are: -// -// * Each instance holds an opaque pointer to the underlying Rust struct. -// Method calls need to read this pointer from the object's state and pass it in to -// the Rust FFI. -// -// * When an instance is no longer needed, its pointer should be passed to a -// special destructor function provided by the Rust FFI, which will drop the -// underlying Rust struct. -// -// * Given an instance, calling code is expected to call the special -// `destroy` method in order to free it after use, either by calling it explicitly -// or by using a higher-level helper like the `use` method. Failing to do so risks -// leaking the underlying Rust struct. -// -// * We can't assume that calling code will do the right thing, and must be prepared -// to handle Kotlin method calls executing concurrently with or even after a call to -// `destroy`, and to handle multiple (possibly concurrent!) calls to `destroy`. -// -// * We must never allow Rust code to operate on the underlying Rust struct after -// the destructor has been called, and must never call the destructor more than once. -// Doing so may trigger memory unsafety. -// -// * To mitigate many of the risks of leaking memory and use-after-free unsafety, a `Cleaner` -// is implemented to call the destructor when the Kotlin object becomes unreachable. -// This is done in a background thread. This is not a panacea, and client code should be aware that -// 1. the thread may starve if some there are objects that have poorly performing -// `drop` methods or do significant work in their `drop` methods. -// 2. the thread is shared across the whole library. This can be tuned by using `android_cleaner = true`, -// or `android = true` in the [`kotlin` section of the `uniffi.toml` file](https://mozilla.github.io/uniffi-rs/kotlin/configuration.html). -// -// If we try to implement this with mutual exclusion on access to the pointer, there is the -// possibility of a race between a method call and a concurrent call to `destroy`: -// -// * Thread A starts a method call, reads the value of the pointer, but is interrupted -// before it can pass the pointer over the FFI to Rust. -// * Thread B calls `destroy` and frees the underlying Rust struct. -// * Thread A resumes, passing the already-read pointer value to Rust and triggering -// a use-after-free. -// -// One possible solution would be to use a `ReadWriteLock`, with each method call taking -// a read lock (and thus allowed to run concurrently) and the special `destroy` method -// taking a write lock (and thus blocking on live method calls). However, we aim not to -// generate methods with any hidden blocking semantics, and a `destroy` method that might -// block if called incorrectly seems to meet that bar. -// -// So, we achieve our goals by giving each instance an associated `AtomicLong` counter to track -// the number of in-flight method calls, and an `AtomicBoolean` flag to indicate whether `destroy` -// has been called. These are updated according to the following rules: -// -// * The initial value of the counter is 1, indicating a live object with no in-flight calls. -// The initial value for the flag is false. -// -// * At the start of each method call, we atomically check the counter. -// If it is 0 then the underlying Rust struct has already been destroyed and the call is aborted. -// If it is nonzero them we atomically increment it by 1 and proceed with the method call. -// -// * At the end of each method call, we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// * When `destroy` is called, we atomically flip the flag from false to true. -// If the flag was already true we silently fail. -// Otherwise we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// Astute readers may observe that this all sounds very similar to the way that Rust's `Arc` works, -// and indeed it is, with the addition of a flag to guard against multiple calls to `destroy`. -// -// The overall effect is that the underlying Rust struct is destroyed only when `destroy` has been -// called *and* all in-flight method calls have completed, avoiding violating any of the expectations -// of the underlying Rust code. -// -// This makes a cleaner a better alternative to _not_ calling `destroy()` as -// and when the object is finished with, but the abstraction is not perfect: if the Rust object's `drop` -// method is slow, and/or there are many objects to cleanup, and it's on a low end Android device, then the cleaner -// thread may be starved, and the app will leak memory. -// -// In this case, `destroy`ing manually may be a better solution. -// -// The cleaner can live side by side with the manual calling of `destroy`. In the order of responsiveness, uniffi objects -// with Rust peers are reclaimed: -// -// 1. By calling the `destroy` method of the object, which calls `rustObject.free()`. If that doesn't happen: -// 2. When the object becomes unreachable, AND the Cleaner thread gets to call `rustObject.free()`. If the thread is starved then: -// 3. The memory is reclaimed when the process terminates. -// -// [1] https://stackoverflow.com/questions/24376768/can-java-finalize-an-object-when-it-is-still-in-scope/24380219 -// - - -public interface ConfigInterface { - - /** - * Return a new Config with the given developer certificate. - * Nodes registered through this config will be associated with the developer's account. - */ - fun `withDeveloperCert`(`cert`: DeveloperCert): Config - - /** - * Return a new Config with the given network. - */ - fun `withNetwork`(`network`: Network): Config - - companion object -} - -open class Config: Disposable, AutoCloseable, ConfigInterface -{ - - constructor(pointer: Pointer) { - this.pointer = pointer - this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(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. - */ - @Suppress("UNUSED_PARAMETER") - constructor(noPointer: NoPointer) { - this.pointer = null - this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(pointer)) - } - /** - * Create a Config with default settings: BITCOIN network, no developer certificate. - */ - constructor() : - this( - uniffiRustCall() { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_constructor_config_new( - _status) -} - ) - - protected val pointer: Pointer? - protected val cleanable: UniffiCleaner.Cleanable - - private val wasDestroyed = AtomicBoolean(false) - private val callCounter = AtomicLong(1) - - 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() - } - } - } - - @Synchronized - override fun close() { - 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.get() - if (c == 0L) { - throw IllegalStateException("${this.javaClass.simpleName} object has already been destroyed") - } - if (c == Long.MAX_VALUE) { - throw IllegalStateException("${this.javaClass.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 UniffiCleanAction(private val pointer: Pointer?) : Runnable { - override fun run() { - pointer?.let { ptr -> - uniffiRustCall { status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_free_config(ptr, status) - } - } - } - } - - fun uniffiClonePointer(): Pointer { - return uniffiRustCall() { status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_clone_config(pointer!!, status) - } - } - - - /** - * Return a new Config with the given developer certificate. - * Nodes registered through this config will be associated with the developer's account. - */override fun `withDeveloperCert`(`cert`: DeveloperCert): Config { - return FfiConverterTypeConfig.lift( - callWithPointer { - uniffiRustCall() { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_config_with_developer_cert( - it, FfiConverterTypeDeveloperCert.lower(`cert`),_status) -} - } - ) - } - - - - /** - * Return a new Config with the given network. - */override fun `withNetwork`(`network`: Network): Config { - return FfiConverterTypeConfig.lift( - callWithPointer { - uniffiRustCall() { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_config_with_network( - it, FfiConverterTypeNetwork.lower(`network`),_status) -} - } - ) - } - - - - - - - companion object - -} - -/** - * @suppress - */ -public object FfiConverterTypeConfig: FfiConverter { - - override fun lower(value: Config): Pointer { - return value.uniffiClonePointer() - } - - override fun lift(value: Pointer): Config { - return Config(value) - } - - override fun read(buf: ByteBuffer): Config { - // The Rust code always writes pointers as 8 bytes, and will - // fail to compile if they don't fit. - return lift(Pointer(buf.getLong())) - } - - override fun allocationSize(value: Config) = 8UL - - override fun write(value: Config, buf: ByteBuffer) { - // The Rust code always expects pointers written as 8 bytes, - // and will fail to compile if they don't fit. - buf.putLong(Pointer.nativeValue(lower(value))) - } -} - - -// This template implements a class for working with a Rust struct via a Pointer/Arc -// to the live Rust struct on the other side of the FFI. -// -// Each instance implements core operations for working with the Rust `Arc` and the -// Kotlin Pointer to work with the live Rust struct on the other side of the FFI. -// -// There's some subtlety here, because we have to be careful not to operate on a Rust -// struct after it has been dropped, and because we must expose a public API for freeing -// theq Kotlin wrapper object in lieu of reliable finalizers. The core requirements are: -// -// * Each instance holds an opaque pointer to the underlying Rust struct. -// Method calls need to read this pointer from the object's state and pass it in to -// the Rust FFI. -// -// * When an instance is no longer needed, its pointer should be passed to a -// special destructor function provided by the Rust FFI, which will drop the -// underlying Rust struct. -// -// * Given an instance, calling code is expected to call the special -// `destroy` method in order to free it after use, either by calling it explicitly -// or by using a higher-level helper like the `use` method. Failing to do so risks -// leaking the underlying Rust struct. -// -// * We can't assume that calling code will do the right thing, and must be prepared -// to handle Kotlin method calls executing concurrently with or even after a call to -// `destroy`, and to handle multiple (possibly concurrent!) calls to `destroy`. -// -// * We must never allow Rust code to operate on the underlying Rust struct after -// the destructor has been called, and must never call the destructor more than once. -// Doing so may trigger memory unsafety. -// -// * To mitigate many of the risks of leaking memory and use-after-free unsafety, a `Cleaner` -// is implemented to call the destructor when the Kotlin object becomes unreachable. -// This is done in a background thread. This is not a panacea, and client code should be aware that -// 1. the thread may starve if some there are objects that have poorly performing -// `drop` methods or do significant work in their `drop` methods. -// 2. the thread is shared across the whole library. This can be tuned by using `android_cleaner = true`, -// or `android = true` in the [`kotlin` section of the `uniffi.toml` file](https://mozilla.github.io/uniffi-rs/kotlin/configuration.html). -// -// If we try to implement this with mutual exclusion on access to the pointer, there is the -// possibility of a race between a method call and a concurrent call to `destroy`: -// -// * Thread A starts a method call, reads the value of the pointer, but is interrupted -// before it can pass the pointer over the FFI to Rust. -// * Thread B calls `destroy` and frees the underlying Rust struct. -// * Thread A resumes, passing the already-read pointer value to Rust and triggering -// a use-after-free. -// -// One possible solution would be to use a `ReadWriteLock`, with each method call taking -// a read lock (and thus allowed to run concurrently) and the special `destroy` method -// taking a write lock (and thus blocking on live method calls). However, we aim not to -// generate methods with any hidden blocking semantics, and a `destroy` method that might -// block if called incorrectly seems to meet that bar. -// -// So, we achieve our goals by giving each instance an associated `AtomicLong` counter to track -// the number of in-flight method calls, and an `AtomicBoolean` flag to indicate whether `destroy` -// has been called. These are updated according to the following rules: -// -// * The initial value of the counter is 1, indicating a live object with no in-flight calls. -// The initial value for the flag is false. -// -// * At the start of each method call, we atomically check the counter. -// If it is 0 then the underlying Rust struct has already been destroyed and the call is aborted. -// If it is nonzero them we atomically increment it by 1 and proceed with the method call. -// -// * At the end of each method call, we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// * When `destroy` is called, we atomically flip the flag from false to true. -// If the flag was already true we silently fail. -// Otherwise we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// Astute readers may observe that this all sounds very similar to the way that Rust's `Arc` works, -// and indeed it is, with the addition of a flag to guard against multiple calls to `destroy`. -// -// The overall effect is that the underlying Rust struct is destroyed only when `destroy` has been -// called *and* all in-flight method calls have completed, avoiding violating any of the expectations -// of the underlying Rust code. -// -// This makes a cleaner a better alternative to _not_ calling `destroy()` as -// and when the object is finished with, but the abstraction is not perfect: if the Rust object's `drop` -// method is slow, and/or there are many objects to cleanup, and it's on a low end Android device, then the cleaner -// thread may be starved, and the app will leak memory. -// -// In this case, `destroy`ing manually may be a better solution. -// -// The cleaner can live side by side with the manual calling of `destroy`. In the order of responsiveness, uniffi objects -// with Rust peers are reclaimed: -// -// 1. By calling the `destroy` method of the object, which calls `rustObject.free()`. If that doesn't happen: -// 2. When the object becomes unreachable, AND the Cleaner thread gets to call `rustObject.free()`. If the thread is starved then: -// 3. The memory is reclaimed when the process terminates. -// -// [1] https://stackoverflow.com/questions/24376768/can-java-finalize-an-object-when-it-is-still-in-scope/24380219 -// - - -/** - * `Credentials` is a container for `node_id`, the mTLS client - * certificate used to authenticate a client against a node, as well - * as the seed secret if present. If no seed is present in the - * credentials, then the `Client` will not start a signer in the - * background. - */ -public interface CredentialsInterface { - - fun `nodeId`(): kotlin.ByteArray - - fun `save`(): kotlin.ByteArray - - companion object -} - -/** - * `Credentials` is a container for `node_id`, the mTLS client - * certificate used to authenticate a client against a node, as well - * as the seed secret if present. If no seed is present in the - * credentials, then the `Client` will not start a signer in the - * background. - */ -open class Credentials: Disposable, AutoCloseable, CredentialsInterface -{ - - constructor(pointer: Pointer) { - this.pointer = pointer - this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(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. - */ - @Suppress("UNUSED_PARAMETER") - constructor(noPointer: NoPointer) { - this.pointer = null - this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(pointer)) - } - - protected val pointer: Pointer? - protected val cleanable: UniffiCleaner.Cleanable - - private val wasDestroyed = AtomicBoolean(false) - private val callCounter = AtomicLong(1) - - 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() - } - } - } - - @Synchronized - override fun close() { - 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.get() - if (c == 0L) { - throw IllegalStateException("${this.javaClass.simpleName} object has already been destroyed") - } - if (c == Long.MAX_VALUE) { - throw IllegalStateException("${this.javaClass.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 UniffiCleanAction(private val pointer: Pointer?) : Runnable { - override fun run() { - pointer?.let { ptr -> - uniffiRustCall { status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_free_credentials(ptr, status) - } - } - } - } - - fun uniffiClonePointer(): Pointer { - return uniffiRustCall() { status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_clone_credentials(pointer!!, status) - } - } - - - @Throws(Exception::class)override fun `nodeId`(): kotlin.ByteArray { - return FfiConverterByteArray.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_credentials_node_id( - it, _status) -} - } - ) - } - - - - @Throws(Exception::class)override fun `save`(): kotlin.ByteArray { - return FfiConverterByteArray.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_credentials_save( - it, _status) -} - } - ) - } - - - - - - companion object { - - @Throws(Exception::class) fun `load`(`raw`: kotlin.ByteArray): Credentials { - return FfiConverterTypeCredentials.lift( - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_constructor_credentials_load( - FfiConverterByteArray.lower(`raw`),_status) -} - ) - } - - - - } - -} - -/** - * @suppress - */ -public object FfiConverterTypeCredentials: FfiConverter { - - override fun lower(value: Credentials): Pointer { - return value.uniffiClonePointer() - } - - override fun lift(value: Pointer): Credentials { - return Credentials(value) - } - - override fun read(buf: ByteBuffer): Credentials { - // The Rust code always writes pointers as 8 bytes, and will - // fail to compile if they don't fit. - return lift(Pointer(buf.getLong())) - } - - override fun allocationSize(value: Credentials) = 8UL - - override fun write(value: Credentials, buf: ByteBuffer) { - // The Rust code always expects pointers written as 8 bytes, - // and will fail to compile if they don't fit. - buf.putLong(Pointer.nativeValue(lower(value))) - } -} - - -// This template implements a class for working with a Rust struct via a Pointer/Arc -// to the live Rust struct on the other side of the FFI. -// -// Each instance implements core operations for working with the Rust `Arc` and the -// Kotlin Pointer to work with the live Rust struct on the other side of the FFI. -// -// There's some subtlety here, because we have to be careful not to operate on a Rust -// struct after it has been dropped, and because we must expose a public API for freeing -// theq Kotlin wrapper object in lieu of reliable finalizers. The core requirements are: -// -// * Each instance holds an opaque pointer to the underlying Rust struct. -// Method calls need to read this pointer from the object's state and pass it in to -// the Rust FFI. -// -// * When an instance is no longer needed, its pointer should be passed to a -// special destructor function provided by the Rust FFI, which will drop the -// underlying Rust struct. -// -// * Given an instance, calling code is expected to call the special -// `destroy` method in order to free it after use, either by calling it explicitly -// or by using a higher-level helper like the `use` method. Failing to do so risks -// leaking the underlying Rust struct. -// -// * We can't assume that calling code will do the right thing, and must be prepared -// to handle Kotlin method calls executing concurrently with or even after a call to -// `destroy`, and to handle multiple (possibly concurrent!) calls to `destroy`. -// -// * We must never allow Rust code to operate on the underlying Rust struct after -// the destructor has been called, and must never call the destructor more than once. -// Doing so may trigger memory unsafety. -// -// * To mitigate many of the risks of leaking memory and use-after-free unsafety, a `Cleaner` -// is implemented to call the destructor when the Kotlin object becomes unreachable. -// This is done in a background thread. This is not a panacea, and client code should be aware that -// 1. the thread may starve if some there are objects that have poorly performing -// `drop` methods or do significant work in their `drop` methods. -// 2. the thread is shared across the whole library. This can be tuned by using `android_cleaner = true`, -// or `android = true` in the [`kotlin` section of the `uniffi.toml` file](https://mozilla.github.io/uniffi-rs/kotlin/configuration.html). -// -// If we try to implement this with mutual exclusion on access to the pointer, there is the -// possibility of a race between a method call and a concurrent call to `destroy`: -// -// * Thread A starts a method call, reads the value of the pointer, but is interrupted -// before it can pass the pointer over the FFI to Rust. -// * Thread B calls `destroy` and frees the underlying Rust struct. -// * Thread A resumes, passing the already-read pointer value to Rust and triggering -// a use-after-free. -// -// One possible solution would be to use a `ReadWriteLock`, with each method call taking -// a read lock (and thus allowed to run concurrently) and the special `destroy` method -// taking a write lock (and thus blocking on live method calls). However, we aim not to -// generate methods with any hidden blocking semantics, and a `destroy` method that might -// block if called incorrectly seems to meet that bar. -// -// So, we achieve our goals by giving each instance an associated `AtomicLong` counter to track -// the number of in-flight method calls, and an `AtomicBoolean` flag to indicate whether `destroy` -// has been called. These are updated according to the following rules: -// -// * The initial value of the counter is 1, indicating a live object with no in-flight calls. -// The initial value for the flag is false. -// -// * At the start of each method call, we atomically check the counter. -// If it is 0 then the underlying Rust struct has already been destroyed and the call is aborted. -// If it is nonzero them we atomically increment it by 1 and proceed with the method call. -// -// * At the end of each method call, we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// * When `destroy` is called, we atomically flip the flag from false to true. -// If the flag was already true we silently fail. -// Otherwise we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// Astute readers may observe that this all sounds very similar to the way that Rust's `Arc` works, -// and indeed it is, with the addition of a flag to guard against multiple calls to `destroy`. -// -// The overall effect is that the underlying Rust struct is destroyed only when `destroy` has been -// called *and* all in-flight method calls have completed, avoiding violating any of the expectations -// of the underlying Rust code. -// -// This makes a cleaner a better alternative to _not_ calling `destroy()` as -// and when the object is finished with, but the abstraction is not perfect: if the Rust object's `drop` -// method is slow, and/or there are many objects to cleanup, and it's on a low end Android device, then the cleaner -// thread may be starved, and the app will leak memory. -// -// In this case, `destroy`ing manually may be a better solution. -// -// The cleaner can live side by side with the manual calling of `destroy`. In the order of responsiveness, uniffi objects -// with Rust peers are reclaimed: -// -// 1. By calling the `destroy` method of the object, which calls `rustObject.free()`. If that doesn't happen: -// 2. When the object becomes unreachable, AND the Cleaner thread gets to call `rustObject.free()`. If the thread is starved then: -// 3. The memory is reclaimed when the process terminates. -// -// [1] https://stackoverflow.com/questions/24376768/can-java-finalize-an-object-when-it-is-still-in-scope/24380219 -// - - -/** - * A developer certificate obtained from the Greenlight Developer - * Console (GDC). When provided to a `Scheduler` via - * `with_developer_cert()`, nodes registered through that scheduler - * will be associated with the developer's account. - * - * If no developer certificate is provided, the scheduler falls back - * to the compiled-in default certificate, which may be sufficient - * when using an invite code instead. - */ -public interface DeveloperCertInterface { - - companion object -} - -/** - * A developer certificate obtained from the Greenlight Developer - * Console (GDC). When provided to a `Scheduler` via - * `with_developer_cert()`, nodes registered through that scheduler - * will be associated with the developer's account. - * - * If no developer certificate is provided, the scheduler falls back - * to the compiled-in default certificate, which may be sufficient - * when using an invite code instead. - */ -open class DeveloperCert: Disposable, AutoCloseable, DeveloperCertInterface -{ - - constructor(pointer: Pointer) { - this.pointer = pointer - this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(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. - */ - @Suppress("UNUSED_PARAMETER") - constructor(noPointer: NoPointer) { - this.pointer = null - this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(pointer)) - } - /** - * Create a new `DeveloperCert` from the certificate and private - * key PEM bytes obtained from the Greenlight Developer Console. - */ - constructor(`cert`: kotlin.ByteArray, `key`: kotlin.ByteArray) : - this( - uniffiRustCall() { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_constructor_developercert_new( - FfiConverterByteArray.lower(`cert`),FfiConverterByteArray.lower(`key`),_status) -} - ) - - protected val pointer: Pointer? - protected val cleanable: UniffiCleaner.Cleanable - - private val wasDestroyed = AtomicBoolean(false) - private val callCounter = AtomicLong(1) - - 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() - } - } - } - - @Synchronized - override fun close() { - 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.get() - if (c == 0L) { - throw IllegalStateException("${this.javaClass.simpleName} object has already been destroyed") - } - if (c == Long.MAX_VALUE) { - throw IllegalStateException("${this.javaClass.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 UniffiCleanAction(private val pointer: Pointer?) : Runnable { - override fun run() { - pointer?.let { ptr -> - uniffiRustCall { status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_free_developercert(ptr, status) - } - } - } - } - - fun uniffiClonePointer(): Pointer { - return uniffiRustCall() { status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_clone_developercert(pointer!!, status) - } - } - - - - - - companion object - -} - -/** - * @suppress - */ -public object FfiConverterTypeDeveloperCert: FfiConverter { - - override fun lower(value: DeveloperCert): Pointer { - return value.uniffiClonePointer() - } - - override fun lift(value: Pointer): DeveloperCert { - return DeveloperCert(value) - } - - override fun read(buf: ByteBuffer): DeveloperCert { - // The Rust code always writes pointers as 8 bytes, and will - // fail to compile if they don't fit. - return lift(Pointer(buf.getLong())) - } - - override fun allocationSize(value: DeveloperCert) = 8UL - - override fun write(value: DeveloperCert, buf: ByteBuffer) { - // The Rust code always expects pointers written as 8 bytes, - // and will fail to compile if they don't fit. - buf.putLong(Pointer.nativeValue(lower(value))) - } -} - - -// This template implements a class for working with a Rust struct via a Pointer/Arc -// to the live Rust struct on the other side of the FFI. -// -// Each instance implements core operations for working with the Rust `Arc` and the -// Kotlin Pointer to work with the live Rust struct on the other side of the FFI. -// -// There's some subtlety here, because we have to be careful not to operate on a Rust -// struct after it has been dropped, and because we must expose a public API for freeing -// theq Kotlin wrapper object in lieu of reliable finalizers. The core requirements are: -// -// * Each instance holds an opaque pointer to the underlying Rust struct. -// Method calls need to read this pointer from the object's state and pass it in to -// the Rust FFI. -// -// * When an instance is no longer needed, its pointer should be passed to a -// special destructor function provided by the Rust FFI, which will drop the -// underlying Rust struct. -// -// * Given an instance, calling code is expected to call the special -// `destroy` method in order to free it after use, either by calling it explicitly -// or by using a higher-level helper like the `use` method. Failing to do so risks -// leaking the underlying Rust struct. -// -// * We can't assume that calling code will do the right thing, and must be prepared -// to handle Kotlin method calls executing concurrently with or even after a call to -// `destroy`, and to handle multiple (possibly concurrent!) calls to `destroy`. -// -// * We must never allow Rust code to operate on the underlying Rust struct after -// the destructor has been called, and must never call the destructor more than once. -// Doing so may trigger memory unsafety. -// -// * To mitigate many of the risks of leaking memory and use-after-free unsafety, a `Cleaner` -// is implemented to call the destructor when the Kotlin object becomes unreachable. -// This is done in a background thread. This is not a panacea, and client code should be aware that -// 1. the thread may starve if some there are objects that have poorly performing -// `drop` methods or do significant work in their `drop` methods. -// 2. the thread is shared across the whole library. This can be tuned by using `android_cleaner = true`, -// or `android = true` in the [`kotlin` section of the `uniffi.toml` file](https://mozilla.github.io/uniffi-rs/kotlin/configuration.html). -// -// If we try to implement this with mutual exclusion on access to the pointer, there is the -// possibility of a race between a method call and a concurrent call to `destroy`: -// -// * Thread A starts a method call, reads the value of the pointer, but is interrupted -// before it can pass the pointer over the FFI to Rust. -// * Thread B calls `destroy` and frees the underlying Rust struct. -// * Thread A resumes, passing the already-read pointer value to Rust and triggering -// a use-after-free. -// -// One possible solution would be to use a `ReadWriteLock`, with each method call taking -// a read lock (and thus allowed to run concurrently) and the special `destroy` method -// taking a write lock (and thus blocking on live method calls). However, we aim not to -// generate methods with any hidden blocking semantics, and a `destroy` method that might -// block if called incorrectly seems to meet that bar. -// -// So, we achieve our goals by giving each instance an associated `AtomicLong` counter to track -// the number of in-flight method calls, and an `AtomicBoolean` flag to indicate whether `destroy` -// has been called. These are updated according to the following rules: -// -// * The initial value of the counter is 1, indicating a live object with no in-flight calls. -// The initial value for the flag is false. -// -// * At the start of each method call, we atomically check the counter. -// If it is 0 then the underlying Rust struct has already been destroyed and the call is aborted. -// If it is nonzero them we atomically increment it by 1 and proceed with the method call. -// -// * At the end of each method call, we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// * When `destroy` is called, we atomically flip the flag from false to true. -// If the flag was already true we silently fail. -// Otherwise we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// Astute readers may observe that this all sounds very similar to the way that Rust's `Arc` works, -// and indeed it is, with the addition of a flag to guard against multiple calls to `destroy`. -// -// The overall effect is that the underlying Rust struct is destroyed only when `destroy` has been -// called *and* all in-flight method calls have completed, avoiding violating any of the expectations -// of the underlying Rust code. -// -// This makes a cleaner a better alternative to _not_ calling `destroy()` as -// and when the object is finished with, but the abstraction is not perfect: if the Rust object's `drop` -// method is slow, and/or there are many objects to cleanup, and it's on a low end Android device, then the cleaner -// thread may be starved, and the app will leak memory. -// -// In this case, `destroy`ing manually may be a better solution. -// -// The cleaner can live side by side with the manual calling of `destroy`. In the order of responsiveness, uniffi objects -// with Rust peers are reclaimed: -// -// 1. By calling the `destroy` method of the object, which calls `rustObject.free()`. If that doesn't happen: -// 2. When the object becomes unreachable, AND the Cleaner thread gets to call `rustObject.free()`. If the thread is starved then: -// 3. The memory is reclaimed when the process terminates. -// -// [1] https://stackoverflow.com/questions/24376768/can-java-finalize-an-object-when-it-is-still-in-scope/24380219 -// - - -/** - * A handle to interact with a signer loop running and processing - * requests in the background. Used primarily to stop the loop and - * exiting the signer. - */ -public interface HandleInterface { - - fun `stop`() - - companion object -} - -/** - * A handle to interact with a signer loop running and processing - * requests in the background. Used primarily to stop the loop and - * exiting the signer. - */ -open class Handle: Disposable, AutoCloseable, HandleInterface -{ - - constructor(pointer: Pointer) { - this.pointer = pointer - this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(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. - */ - @Suppress("UNUSED_PARAMETER") - constructor(noPointer: NoPointer) { - this.pointer = null - this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(pointer)) - } - - protected val pointer: Pointer? - protected val cleanable: UniffiCleaner.Cleanable - - private val wasDestroyed = AtomicBoolean(false) - private val callCounter = AtomicLong(1) - - 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() - } - } - } - - @Synchronized - override fun close() { - 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.get() - if (c == 0L) { - throw IllegalStateException("${this.javaClass.simpleName} object has already been destroyed") - } - if (c == Long.MAX_VALUE) { - throw IllegalStateException("${this.javaClass.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 UniffiCleanAction(private val pointer: Pointer?) : Runnable { - override fun run() { - pointer?.let { ptr -> - uniffiRustCall { status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_free_handle(ptr, status) - } - } - } - } - - fun uniffiClonePointer(): Pointer { - return uniffiRustCall() { status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_clone_handle(pointer!!, status) - } - } - - override fun `stop`() - = - callWithPointer { - uniffiRustCall() { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_handle_stop( - it, _status) -} - } - - - - - - - - companion object - -} - -/** - * @suppress - */ -public object FfiConverterTypeHandle: FfiConverter { - - override fun lower(value: Handle): Pointer { - return value.uniffiClonePointer() - } - - override fun lift(value: Pointer): Handle { - return Handle(value) - } - - override fun read(buf: ByteBuffer): Handle { - // The Rust code always writes pointers as 8 bytes, and will - // fail to compile if they don't fit. - return lift(Pointer(buf.getLong())) - } - - override fun allocationSize(value: Handle) = 8UL - - override fun write(value: Handle, buf: ByteBuffer) { - // The Rust code always expects pointers written as 8 bytes, - // and will fail to compile if they don't fit. - buf.putLong(Pointer.nativeValue(lower(value))) - } -} - - -// This template implements a class for working with a Rust struct via a Pointer/Arc -// to the live Rust struct on the other side of the FFI. -// -// Each instance implements core operations for working with the Rust `Arc` and the -// Kotlin Pointer to work with the live Rust struct on the other side of the FFI. -// -// There's some subtlety here, because we have to be careful not to operate on a Rust -// struct after it has been dropped, and because we must expose a public API for freeing -// theq Kotlin wrapper object in lieu of reliable finalizers. The core requirements are: -// -// * Each instance holds an opaque pointer to the underlying Rust struct. -// Method calls need to read this pointer from the object's state and pass it in to -// the Rust FFI. -// -// * When an instance is no longer needed, its pointer should be passed to a -// special destructor function provided by the Rust FFI, which will drop the -// underlying Rust struct. -// -// * Given an instance, calling code is expected to call the special -// `destroy` method in order to free it after use, either by calling it explicitly -// or by using a higher-level helper like the `use` method. Failing to do so risks -// leaking the underlying Rust struct. -// -// * We can't assume that calling code will do the right thing, and must be prepared -// to handle Kotlin method calls executing concurrently with or even after a call to -// `destroy`, and to handle multiple (possibly concurrent!) calls to `destroy`. -// -// * We must never allow Rust code to operate on the underlying Rust struct after -// the destructor has been called, and must never call the destructor more than once. -// Doing so may trigger memory unsafety. -// -// * To mitigate many of the risks of leaking memory and use-after-free unsafety, a `Cleaner` -// is implemented to call the destructor when the Kotlin object becomes unreachable. -// This is done in a background thread. This is not a panacea, and client code should be aware that -// 1. the thread may starve if some there are objects that have poorly performing -// `drop` methods or do significant work in their `drop` methods. -// 2. the thread is shared across the whole library. This can be tuned by using `android_cleaner = true`, -// or `android = true` in the [`kotlin` section of the `uniffi.toml` file](https://mozilla.github.io/uniffi-rs/kotlin/configuration.html). -// -// If we try to implement this with mutual exclusion on access to the pointer, there is the -// possibility of a race between a method call and a concurrent call to `destroy`: -// -// * Thread A starts a method call, reads the value of the pointer, but is interrupted -// before it can pass the pointer over the FFI to Rust. -// * Thread B calls `destroy` and frees the underlying Rust struct. -// * Thread A resumes, passing the already-read pointer value to Rust and triggering -// a use-after-free. -// -// One possible solution would be to use a `ReadWriteLock`, with each method call taking -// a read lock (and thus allowed to run concurrently) and the special `destroy` method -// taking a write lock (and thus blocking on live method calls). However, we aim not to -// generate methods with any hidden blocking semantics, and a `destroy` method that might -// block if called incorrectly seems to meet that bar. -// -// So, we achieve our goals by giving each instance an associated `AtomicLong` counter to track -// the number of in-flight method calls, and an `AtomicBoolean` flag to indicate whether `destroy` -// has been called. These are updated according to the following rules: -// -// * The initial value of the counter is 1, indicating a live object with no in-flight calls. -// The initial value for the flag is false. -// -// * At the start of each method call, we atomically check the counter. -// If it is 0 then the underlying Rust struct has already been destroyed and the call is aborted. -// If it is nonzero them we atomically increment it by 1 and proceed with the method call. -// -// * At the end of each method call, we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// * When `destroy` is called, we atomically flip the flag from false to true. -// If the flag was already true we silently fail. -// Otherwise we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// Astute readers may observe that this all sounds very similar to the way that Rust's `Arc` works, -// and indeed it is, with the addition of a flag to guard against multiple calls to `destroy`. -// -// The overall effect is that the underlying Rust struct is destroyed only when `destroy` has been -// called *and* all in-flight method calls have completed, avoiding violating any of the expectations -// of the underlying Rust code. -// -// This makes a cleaner a better alternative to _not_ calling `destroy()` as -// and when the object is finished with, but the abstraction is not perfect: if the Rust object's `drop` -// method is slow, and/or there are many objects to cleanup, and it's on a low end Android device, then the cleaner -// thread may be starved, and the app will leak memory. -// -// In this case, `destroy`ing manually may be a better solution. -// -// The cleaner can live side by side with the manual calling of `destroy`. In the order of responsiveness, uniffi objects -// with Rust peers are reclaimed: -// -// 1. By calling the `destroy` method of the object, which calls `rustObject.free()`. If that doesn't happen: -// 2. When the object becomes unreachable, AND the Cleaner thread gets to call `rustObject.free()`. If the thread is starved then: -// 3. The memory is reclaimed when the process terminates. -// -// [1] https://stackoverflow.com/questions/24376768/can-java-finalize-an-object-when-it-is-still-in-scope/24380219 -// - - -/** - * The `Node` is an RPC stub representing the node running in the - * cloud. It is the main entrypoint to interact with the node. - */ -public interface NodeInterface { - - /** - * Returns the serialized credentials for this node. - * The app should persist these bytes and pass them to connect() on next launch. - */ - fun `credentials`(): kotlin.ByteArray - - /** - * Disconnects from the node and stops the signer if running. - * After disconnect, all RPC methods will return an error. - * Safe to call multiple times. - */ - fun `disconnect`() - - /** - * Collect a diagnostic snapshot of the node and SDK state. - * - * Returns a pretty-printed JSON string with shape: - * `{ "timestamp": , "node": { ... }, "sdk": { "version": ..., "node_state": ... } }`. - * The `node` object contains one entry per CLN RPC (`getinfo`, - * `listpeerchannels`, `listfunds`); each value is the serialized - * response, or `{ "error": "..." }` if that RPC failed. Payment and - * invoice history are deliberately excluded to avoid leaking - * preimages, payment hashes, bolt11 strings, and labels into support - * dumps. Intended for support tickets. - */ - fun `generateDiagnosticData`(): kotlin.String - - /** - * Get information about the node. - * - * Returns basic information about the node including its ID, - * alias, network, and channel counts. - */ - fun `getInfo`(): GetInfoResponse - - /** - * List all funds available to the node. - * - * Returns information about on-chain outputs and channel funds - * that are available or pending. - */ - fun `listFunds`(): ListFundsResponse - - /** - * List invoices (received payment requests). - * All parameters are optional filters; pass None to fetch all. - */ - fun `listInvoices`(`label`: kotlin.String?, `invstring`: kotlin.String?, `paymentHash`: kotlin.ByteArray?, `offerId`: kotlin.String?, `index`: ListIndex?, `start`: kotlin.ULong?, `limit`: kotlin.UInt?): ListInvoicesResponse - - /** - * List payments (sent and received), merged into a single timeline. - * - * Fetches invoices and outgoing payments from the node, merges - * them into a unified list, and applies optional filters. - * Use `list_invoices`/`list_pays` for direct CLN access. - * Results are sorted newest-first. - */ - fun `listPayments`(`req`: ListPaymentsRequest): List - - /** - * List outgoing payments. - * All parameters are optional filters; pass None to fetch all. - */ - fun `listPays`(`bolt11`: kotlin.String?, `paymentHash`: kotlin.ByteArray?, `status`: PayStatus?, `index`: ListIndex?, `start`: kotlin.ULong?, `limit`: kotlin.UInt?): ListPaysResponse - - /** - * List all channels with peers. - * - * Returns detailed information about all channels including their - * state, capacity, and balances. - */ - fun `listPeerChannels`(): ListPeerChannelsResponse - - /** - * List all peers connected to this node. - * - * Returns information about all peers including their connection - * status. - */ - fun `listPeers`(): ListPeersResponse - - /** - * Execute an LNURL-pay flow (LUD-06). - * - * Sends the chosen amount (and optional comment) to the service's - * callback, receives and validates a BOLT11 invoice, pays it, and - * processes any success action (LUD-09/10). - * - * Call the top-level `parse_input` first to obtain the - * `LnUrlPayRequestData`, then build an `LnUrlPayRequest` with the - * user's chosen amount. - */ - fun `lnurlPay`(`request`: LnUrlPayRequest): LnUrlPayResult - - /** - * Execute an LNURL-withdraw flow (LUD-03). - * - * Creates an invoice on this node for the requested amount, sends - * it to the service's callback URL, and the service pays it - * asynchronously. - * - * Call the top-level `parse_input` first to obtain the - * `LnUrlWithdrawRequestData`, then build an `LnUrlWithdrawRequest` - * with the user's chosen amount. - */ - fun `lnurlWithdraw`(`request`: LnUrlWithdrawRequest): LnUrlWithdrawResult - - /** - * Get a snapshot of the node's balances, capacity, and connectivity. - * - * Aggregates data from multiple RPCs into a single `NodeState`. - * Queries the node live on each call — not cached. - */ - fun `nodeState`(): NodeState - - /** - * Classify the on-chain wallet for the withdraw entry-point UI. - * - * Runs three RPCs concurrently: - * * `list_funds` — current confirmed/unconfirmed/immature on-chain - * balances. - * * `list_peer_channels` — pending channel-close payouts that - * haven't yet hit the wallet. - * * `fund_psbt(satoshi=All, reserve=0, normal feerate)` — a - * non-locking probe whose response tells us **exactly** how - * much CLN will carve as the anchor-channel emergency reserve - * for this specific node, no client-side guessing required. - * The carved amount is computed from the response as - * `total_inputs − excess − fee`, which is identical to what - * CLN would carve on a real broadcast. - * - * Cheaper to call than `node_state()` and answers a different - * question. Wallets typically call it once per render of the - * home screen. - * - * For the *exact* post-fee recipient amount of a withdraw, use - * `prepare_onchain_send`; the `withdrawable_sat` returned here - * is a pre-fee, reserve-aware figure for the entry-point label. - */ - fun `onchainBalanceState`(): OnchainBalanceState - - /** - * On-chain fee rates, in sats per virtual byte, at several - * confirmation targets. - * - * Sourced from the connected node's view of the network — no - * 3rd-party HTTP calls. Use as the basis for a fee-picker UI; - * `minimum_relay_sat_per_vbyte` is the relay floor enforced at - * broadcast time and should be the lower bound of any slider. - */ - fun `onchainFeeRates`(): OnchainFeeRates - - /** - * Generate a fresh on-chain Bitcoin address for receiving funds. - * - * Returns both a bech32 (SegWit v0) and a p2tr (Taproot) address. - * Either can be shared with a sender. Deposited funds will appear - * in `node_state().onchain_balance_msat` once confirmed. - */ - fun `onchainReceive`(): OnchainReceiveResponse - - /** - * Send bitcoin on-chain to a destination address. - * - * # Arguments - * * `destination` — A Bitcoin address (bech32, p2sh, or p2tr). - * * `amount_or_all` — Amount to send. Accepts: - * - `"50000"` or `"50000sat"` — 50,000 satoshis - * - `"50000msat"` — 50,000 millisatoshis - * - `"all"` — sweep the entire on-chain balance - * * `sat_per_vbyte` — Optional fee rate in sats per virtual byte. - * Pass `None` to let the node pick. Pass the value from a prior - * `prepare_onchain_send` to reproduce the previewed fee. - * * `utxos` — Optional pinned input set. Pass the `utxos` returned - * by `prepare_onchain_send` (together with the same - * `sat_per_vbyte`) to broadcast a transaction with the exact - * inputs and fee shown in the preview. Pass `None` to let the - * node coin-select. - * - * Returns the raw transaction, txid, and PSBT once broadcast. - * The transaction is broadcast immediately — this is not a dry run. - */ - fun `onchainSend`(`destination`: kotlin.String, `amountOrAll`: kotlin.String, `satPerVbyte`: kotlin.UInt?, `utxos`: List?): OnchainSendResponse - - /** - * Preview an on-chain send without broadcasting or reserving UTXOs. - * - * Runs CLN's coin selection at the given fee rate and returns the - * inputs that would be spent, the fee, and the amount the recipient - * would receive. Safe to call repeatedly (e.g. while the user - * adjusts a fee slider) — nothing is locked. - * - * To broadcast with the previewed values, pass the returned - * `utxos` and `sat_per_vbyte` back to `onchain_send`. Identical - * inputs at the same fee rate yield the same fee. - * - * **Use this for "Send Max" UIs.** `recipient_sat` is the only - * authoritative post-fee amount the destination will receive - * for a sweep. `NodeState.onchain_balance_msat` includes the - * emergency reserve and the fee — neither of which leaves the - * wallet with the recipient. For the entry-point button label - * (a pre-fee approximation that updates without an RPC), use - * `OnchainBalanceState::Available.withdrawable_sat`. - * - * # Arguments - * * `destination` — A Bitcoin address (bech32, p2sh, or p2tr). - * * `amount_or_all` — Amount to send. Accepts: - * - `"50000"` or `"50000sat"` — 50,000 satoshis - * - `"50000msat"` — 50,000 millisatoshis - * - `"all"` — sweep the entire on-chain balance - * * `sat_per_vbyte` — Fee rate in sats per virtual byte. Pass - * `None` to use the node's "normal" priority feerate; the - * effective rate CLN picked is reported back in the result's - * `sat_per_vbyte` field, which can be passed to `onchain_send` - * to reproduce it. - */ - fun `prepareOnchainSend`(`destination`: kotlin.String, `amountOrAll`: kotlin.String, `satPerVbyte`: kotlin.UInt?): PreparedOnchainSend - - /** - * Receive an off-chain payment. - * - * This method generates a request for a payment, also called an - * invoice, that encodes all the information, including amount - * and destination, for a prospective sender to send a lightning - * payment. The invoice includes negotiation of an LSPS2 / JIT - * channel, meaning that if there is no channel sufficient to - * receive the requested funds, the node will negotiate an - * opening, and when/if executed the payment will cause a channel - * to be created, and the incoming payment to be forwarded. - */ - fun `receive`(`label`: kotlin.String, `description`: kotlin.String, `amountMsat`: kotlin.ULong?): ReceiveResponse - - fun `send`(`invoice`: kotlin.String, `amountMsat`: kotlin.ULong?): SendResponse - - /** - * Stop the node if it is currently running. - */ - fun `stop`() - - /** - * Stream real-time events from the node. - * - * Returns a `NodeEventStream` iterator. Call `next()` repeatedly - * to receive events as they occur (e.g., invoice payments). - * - * The `next()` method blocks the calling thread until an event - * is available, but does not block the underlying async runtime, - * so other node methods can be called concurrently from other - * threads. - */ - fun `streamNodeEvents`(): NodeEventStream - - companion object -} - -/** - * The `Node` is an RPC stub representing the node running in the - * cloud. It is the main entrypoint to interact with the node. - */ -open class Node: Disposable, AutoCloseable, NodeInterface -{ - - constructor(pointer: Pointer) { - this.pointer = pointer - this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(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. - */ - @Suppress("UNUSED_PARAMETER") - constructor(noPointer: NoPointer) { - this.pointer = null - this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(pointer)) - } - - protected val pointer: Pointer? - protected val cleanable: UniffiCleaner.Cleanable - - private val wasDestroyed = AtomicBoolean(false) - private val callCounter = AtomicLong(1) - - 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() - } - } - } - - @Synchronized - override fun close() { - 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.get() - if (c == 0L) { - throw IllegalStateException("${this.javaClass.simpleName} object has already been destroyed") - } - if (c == Long.MAX_VALUE) { - throw IllegalStateException("${this.javaClass.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 UniffiCleanAction(private val pointer: Pointer?) : Runnable { - override fun run() { - pointer?.let { ptr -> - uniffiRustCall { status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_free_node(ptr, status) - } - } - } - } - - fun uniffiClonePointer(): Pointer { - return uniffiRustCall() { status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_clone_node(pointer!!, status) - } - } - - - /** - * Returns the serialized credentials for this node. - * The app should persist these bytes and pass them to connect() on next launch. - */ - @Throws(Exception::class)override fun `credentials`(): kotlin.ByteArray { - return FfiConverterByteArray.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_node_credentials( - it, _status) -} - } - ) - } - - - - /** - * Disconnects from the node and stops the signer if running. - * After disconnect, all RPC methods will return an error. - * Safe to call multiple times. - */ - @Throws(Exception::class)override fun `disconnect`() - = - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_node_disconnect( - it, _status) -} - } - - - - - /** - * Collect a diagnostic snapshot of the node and SDK state. - * - * Returns a pretty-printed JSON string with shape: - * `{ "timestamp": , "node": { ... }, "sdk": { "version": ..., "node_state": ... } }`. - * The `node` object contains one entry per CLN RPC (`getinfo`, - * `listpeerchannels`, `listfunds`); each value is the serialized - * response, or `{ "error": "..." }` if that RPC failed. Payment and - * invoice history are deliberately excluded to avoid leaking - * preimages, payment hashes, bolt11 strings, and labels into support - * dumps. Intended for support tickets. - */ - @Throws(Exception::class)override fun `generateDiagnosticData`(): kotlin.String { - return FfiConverterString.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_node_generate_diagnostic_data( - it, _status) -} - } - ) - } - - - - /** - * Get information about the node. - * - * Returns basic information about the node including its ID, - * alias, network, and channel counts. - */ - @Throws(Exception::class)override fun `getInfo`(): GetInfoResponse { - return FfiConverterTypeGetInfoResponse.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_node_get_info( - it, _status) -} - } - ) - } - - - - /** - * List all funds available to the node. - * - * Returns information about on-chain outputs and channel funds - * that are available or pending. - */ - @Throws(Exception::class)override fun `listFunds`(): ListFundsResponse { - return FfiConverterTypeListFundsResponse.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_node_list_funds( - it, _status) -} - } - ) - } - - - - /** - * List invoices (received payment requests). - * All parameters are optional filters; pass None to fetch all. - */ - @Throws(Exception::class)override fun `listInvoices`(`label`: kotlin.String?, `invstring`: kotlin.String?, `paymentHash`: kotlin.ByteArray?, `offerId`: kotlin.String?, `index`: ListIndex?, `start`: kotlin.ULong?, `limit`: kotlin.UInt?): ListInvoicesResponse { - return FfiConverterTypeListInvoicesResponse.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_node_list_invoices( - it, FfiConverterOptionalString.lower(`label`),FfiConverterOptionalString.lower(`invstring`),FfiConverterOptionalByteArray.lower(`paymentHash`),FfiConverterOptionalString.lower(`offerId`),FfiConverterOptionalTypeListIndex.lower(`index`),FfiConverterOptionalULong.lower(`start`),FfiConverterOptionalUInt.lower(`limit`),_status) -} - } - ) - } - - - - /** - * List payments (sent and received), merged into a single timeline. - * - * Fetches invoices and outgoing payments from the node, merges - * them into a unified list, and applies optional filters. - * Use `list_invoices`/`list_pays` for direct CLN access. - * Results are sorted newest-first. - */ - @Throws(Exception::class)override fun `listPayments`(`req`: ListPaymentsRequest): List { - return FfiConverterSequenceTypePayment.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_node_list_payments( - it, FfiConverterTypeListPaymentsRequest.lower(`req`),_status) -} - } - ) - } - - - - /** - * List outgoing payments. - * All parameters are optional filters; pass None to fetch all. - */ - @Throws(Exception::class)override fun `listPays`(`bolt11`: kotlin.String?, `paymentHash`: kotlin.ByteArray?, `status`: PayStatus?, `index`: ListIndex?, `start`: kotlin.ULong?, `limit`: kotlin.UInt?): ListPaysResponse { - return FfiConverterTypeListPaysResponse.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_node_list_pays( - it, FfiConverterOptionalString.lower(`bolt11`),FfiConverterOptionalByteArray.lower(`paymentHash`),FfiConverterOptionalTypePayStatus.lower(`status`),FfiConverterOptionalTypeListIndex.lower(`index`),FfiConverterOptionalULong.lower(`start`),FfiConverterOptionalUInt.lower(`limit`),_status) -} - } - ) - } - - - - /** - * List all channels with peers. - * - * Returns detailed information about all channels including their - * state, capacity, and balances. - */ - @Throws(Exception::class)override fun `listPeerChannels`(): ListPeerChannelsResponse { - return FfiConverterTypeListPeerChannelsResponse.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_node_list_peer_channels( - it, _status) -} - } - ) - } - - - - /** - * List all peers connected to this node. - * - * Returns information about all peers including their connection - * status. - */ - @Throws(Exception::class)override fun `listPeers`(): ListPeersResponse { - return FfiConverterTypeListPeersResponse.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_node_list_peers( - it, _status) -} - } - ) - } - - - - /** - * Execute an LNURL-pay flow (LUD-06). - * - * Sends the chosen amount (and optional comment) to the service's - * callback, receives and validates a BOLT11 invoice, pays it, and - * processes any success action (LUD-09/10). - * - * Call the top-level `parse_input` first to obtain the - * `LnUrlPayRequestData`, then build an `LnUrlPayRequest` with the - * user's chosen amount. - */ - @Throws(Exception::class)override fun `lnurlPay`(`request`: LnUrlPayRequest): LnUrlPayResult { - return FfiConverterTypeLnUrlPayResult.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_node_lnurl_pay( - it, FfiConverterTypeLnUrlPayRequest.lower(`request`),_status) -} - } - ) - } - - - - /** - * Execute an LNURL-withdraw flow (LUD-03). - * - * Creates an invoice on this node for the requested amount, sends - * it to the service's callback URL, and the service pays it - * asynchronously. - * - * Call the top-level `parse_input` first to obtain the - * `LnUrlWithdrawRequestData`, then build an `LnUrlWithdrawRequest` - * with the user's chosen amount. - */ - @Throws(Exception::class)override fun `lnurlWithdraw`(`request`: LnUrlWithdrawRequest): LnUrlWithdrawResult { - return FfiConverterTypeLnUrlWithdrawResult.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_node_lnurl_withdraw( - it, FfiConverterTypeLnUrlWithdrawRequest.lower(`request`),_status) -} - } - ) - } - - - - /** - * Get a snapshot of the node's balances, capacity, and connectivity. - * - * Aggregates data from multiple RPCs into a single `NodeState`. - * Queries the node live on each call — not cached. - */ - @Throws(Exception::class)override fun `nodeState`(): NodeState { - return FfiConverterTypeNodeState.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_node_node_state( - it, _status) -} - } - ) - } - - - - /** - * Classify the on-chain wallet for the withdraw entry-point UI. - * - * Runs three RPCs concurrently: - * * `list_funds` — current confirmed/unconfirmed/immature on-chain - * balances. - * * `list_peer_channels` — pending channel-close payouts that - * haven't yet hit the wallet. - * * `fund_psbt(satoshi=All, reserve=0, normal feerate)` — a - * non-locking probe whose response tells us **exactly** how - * much CLN will carve as the anchor-channel emergency reserve - * for this specific node, no client-side guessing required. - * The carved amount is computed from the response as - * `total_inputs − excess − fee`, which is identical to what - * CLN would carve on a real broadcast. - * - * Cheaper to call than `node_state()` and answers a different - * question. Wallets typically call it once per render of the - * home screen. - * - * For the *exact* post-fee recipient amount of a withdraw, use - * `prepare_onchain_send`; the `withdrawable_sat` returned here - * is a pre-fee, reserve-aware figure for the entry-point label. - */ - @Throws(Exception::class)override fun `onchainBalanceState`(): OnchainBalanceState { - return FfiConverterTypeOnchainBalanceState.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_node_onchain_balance_state( - it, _status) -} - } - ) - } - - - - /** - * On-chain fee rates, in sats per virtual byte, at several - * confirmation targets. - * - * Sourced from the connected node's view of the network — no - * 3rd-party HTTP calls. Use as the basis for a fee-picker UI; - * `minimum_relay_sat_per_vbyte` is the relay floor enforced at - * broadcast time and should be the lower bound of any slider. - */ - @Throws(Exception::class)override fun `onchainFeeRates`(): OnchainFeeRates { - return FfiConverterTypeOnchainFeeRates.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_node_onchain_fee_rates( - it, _status) -} - } - ) - } - - - - /** - * Generate a fresh on-chain Bitcoin address for receiving funds. - * - * Returns both a bech32 (SegWit v0) and a p2tr (Taproot) address. - * Either can be shared with a sender. Deposited funds will appear - * in `node_state().onchain_balance_msat` once confirmed. - */ - @Throws(Exception::class)override fun `onchainReceive`(): OnchainReceiveResponse { - return FfiConverterTypeOnchainReceiveResponse.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_node_onchain_receive( - it, _status) -} - } - ) - } - - - - /** - * Send bitcoin on-chain to a destination address. - * - * # Arguments - * * `destination` — A Bitcoin address (bech32, p2sh, or p2tr). - * * `amount_or_all` — Amount to send. Accepts: - * - `"50000"` or `"50000sat"` — 50,000 satoshis - * - `"50000msat"` — 50,000 millisatoshis - * - `"all"` — sweep the entire on-chain balance - * * `sat_per_vbyte` — Optional fee rate in sats per virtual byte. - * Pass `None` to let the node pick. Pass the value from a prior - * `prepare_onchain_send` to reproduce the previewed fee. - * * `utxos` — Optional pinned input set. Pass the `utxos` returned - * by `prepare_onchain_send` (together with the same - * `sat_per_vbyte`) to broadcast a transaction with the exact - * inputs and fee shown in the preview. Pass `None` to let the - * node coin-select. - * - * Returns the raw transaction, txid, and PSBT once broadcast. - * The transaction is broadcast immediately — this is not a dry run. - */ - @Throws(Exception::class)override fun `onchainSend`(`destination`: kotlin.String, `amountOrAll`: kotlin.String, `satPerVbyte`: kotlin.UInt?, `utxos`: List?): OnchainSendResponse { - return FfiConverterTypeOnchainSendResponse.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_node_onchain_send( - it, FfiConverterString.lower(`destination`),FfiConverterString.lower(`amountOrAll`),FfiConverterOptionalUInt.lower(`satPerVbyte`),FfiConverterOptionalSequenceTypeOutpoint.lower(`utxos`),_status) -} - } - ) - } - - - - /** - * Preview an on-chain send without broadcasting or reserving UTXOs. - * - * Runs CLN's coin selection at the given fee rate and returns the - * inputs that would be spent, the fee, and the amount the recipient - * would receive. Safe to call repeatedly (e.g. while the user - * adjusts a fee slider) — nothing is locked. - * - * To broadcast with the previewed values, pass the returned - * `utxos` and `sat_per_vbyte` back to `onchain_send`. Identical - * inputs at the same fee rate yield the same fee. - * - * **Use this for "Send Max" UIs.** `recipient_sat` is the only - * authoritative post-fee amount the destination will receive - * for a sweep. `NodeState.onchain_balance_msat` includes the - * emergency reserve and the fee — neither of which leaves the - * wallet with the recipient. For the entry-point button label - * (a pre-fee approximation that updates without an RPC), use - * `OnchainBalanceState::Available.withdrawable_sat`. - * - * # Arguments - * * `destination` — A Bitcoin address (bech32, p2sh, or p2tr). - * * `amount_or_all` — Amount to send. Accepts: - * - `"50000"` or `"50000sat"` — 50,000 satoshis - * - `"50000msat"` — 50,000 millisatoshis - * - `"all"` — sweep the entire on-chain balance - * * `sat_per_vbyte` — Fee rate in sats per virtual byte. Pass - * `None` to use the node's "normal" priority feerate; the - * effective rate CLN picked is reported back in the result's - * `sat_per_vbyte` field, which can be passed to `onchain_send` - * to reproduce it. - */ - @Throws(Exception::class)override fun `prepareOnchainSend`(`destination`: kotlin.String, `amountOrAll`: kotlin.String, `satPerVbyte`: kotlin.UInt?): PreparedOnchainSend { - return FfiConverterTypePreparedOnchainSend.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_node_prepare_onchain_send( - it, FfiConverterString.lower(`destination`),FfiConverterString.lower(`amountOrAll`),FfiConverterOptionalUInt.lower(`satPerVbyte`),_status) -} - } - ) - } - - - - /** - * Receive an off-chain payment. - * - * This method generates a request for a payment, also called an - * invoice, that encodes all the information, including amount - * and destination, for a prospective sender to send a lightning - * payment. The invoice includes negotiation of an LSPS2 / JIT - * channel, meaning that if there is no channel sufficient to - * receive the requested funds, the node will negotiate an - * opening, and when/if executed the payment will cause a channel - * to be created, and the incoming payment to be forwarded. - */ - @Throws(Exception::class)override fun `receive`(`label`: kotlin.String, `description`: kotlin.String, `amountMsat`: kotlin.ULong?): ReceiveResponse { - return FfiConverterTypeReceiveResponse.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_node_receive( - it, FfiConverterString.lower(`label`),FfiConverterString.lower(`description`),FfiConverterOptionalULong.lower(`amountMsat`),_status) -} - } - ) - } - - - - @Throws(Exception::class)override fun `send`(`invoice`: kotlin.String, `amountMsat`: kotlin.ULong?): SendResponse { - return FfiConverterTypeSendResponse.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_node_send( - it, FfiConverterString.lower(`invoice`),FfiConverterOptionalULong.lower(`amountMsat`),_status) -} - } - ) - } - - - - /** - * Stop the node if it is currently running. - */ - @Throws(Exception::class)override fun `stop`() - = - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_node_stop( - it, _status) -} - } - - - - - /** - * Stream real-time events from the node. - * - * Returns a `NodeEventStream` iterator. Call `next()` repeatedly - * to receive events as they occur (e.g., invoice payments). - * - * The `next()` method blocks the calling thread until an event - * is available, but does not block the underlying async runtime, - * so other node methods can be called concurrently from other - * threads. - */ - @Throws(Exception::class)override fun `streamNodeEvents`(): NodeEventStream { - return FfiConverterTypeNodeEventStream.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_node_stream_node_events( - it, _status) -} - } - ) - } - - - - - - - companion object - -} - -/** - * @suppress - */ -public 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(Pointer(buf.getLong())) - } - - 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(Pointer.nativeValue(lower(value))) - } -} - - -// This template implements a class for working with a Rust struct via a Pointer/Arc -// to the live Rust struct on the other side of the FFI. -// -// Each instance implements core operations for working with the Rust `Arc` and the -// Kotlin Pointer to work with the live Rust struct on the other side of the FFI. -// -// There's some subtlety here, because we have to be careful not to operate on a Rust -// struct after it has been dropped, and because we must expose a public API for freeing -// theq Kotlin wrapper object in lieu of reliable finalizers. The core requirements are: -// -// * Each instance holds an opaque pointer to the underlying Rust struct. -// Method calls need to read this pointer from the object's state and pass it in to -// the Rust FFI. -// -// * When an instance is no longer needed, its pointer should be passed to a -// special destructor function provided by the Rust FFI, which will drop the -// underlying Rust struct. -// -// * Given an instance, calling code is expected to call the special -// `destroy` method in order to free it after use, either by calling it explicitly -// or by using a higher-level helper like the `use` method. Failing to do so risks -// leaking the underlying Rust struct. -// -// * We can't assume that calling code will do the right thing, and must be prepared -// to handle Kotlin method calls executing concurrently with or even after a call to -// `destroy`, and to handle multiple (possibly concurrent!) calls to `destroy`. -// -// * We must never allow Rust code to operate on the underlying Rust struct after -// the destructor has been called, and must never call the destructor more than once. -// Doing so may trigger memory unsafety. -// -// * To mitigate many of the risks of leaking memory and use-after-free unsafety, a `Cleaner` -// is implemented to call the destructor when the Kotlin object becomes unreachable. -// This is done in a background thread. This is not a panacea, and client code should be aware that -// 1. the thread may starve if some there are objects that have poorly performing -// `drop` methods or do significant work in their `drop` methods. -// 2. the thread is shared across the whole library. This can be tuned by using `android_cleaner = true`, -// or `android = true` in the [`kotlin` section of the `uniffi.toml` file](https://mozilla.github.io/uniffi-rs/kotlin/configuration.html). -// -// If we try to implement this with mutual exclusion on access to the pointer, there is the -// possibility of a race between a method call and a concurrent call to `destroy`: -// -// * Thread A starts a method call, reads the value of the pointer, but is interrupted -// before it can pass the pointer over the FFI to Rust. -// * Thread B calls `destroy` and frees the underlying Rust struct. -// * Thread A resumes, passing the already-read pointer value to Rust and triggering -// a use-after-free. -// -// One possible solution would be to use a `ReadWriteLock`, with each method call taking -// a read lock (and thus allowed to run concurrently) and the special `destroy` method -// taking a write lock (and thus blocking on live method calls). However, we aim not to -// generate methods with any hidden blocking semantics, and a `destroy` method that might -// block if called incorrectly seems to meet that bar. -// -// So, we achieve our goals by giving each instance an associated `AtomicLong` counter to track -// the number of in-flight method calls, and an `AtomicBoolean` flag to indicate whether `destroy` -// has been called. These are updated according to the following rules: -// -// * The initial value of the counter is 1, indicating a live object with no in-flight calls. -// The initial value for the flag is false. -// -// * At the start of each method call, we atomically check the counter. -// If it is 0 then the underlying Rust struct has already been destroyed and the call is aborted. -// If it is nonzero them we atomically increment it by 1 and proceed with the method call. -// -// * At the end of each method call, we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// * When `destroy` is called, we atomically flip the flag from false to true. -// If the flag was already true we silently fail. -// Otherwise we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// Astute readers may observe that this all sounds very similar to the way that Rust's `Arc` works, -// and indeed it is, with the addition of a flag to guard against multiple calls to `destroy`. -// -// The overall effect is that the underlying Rust struct is destroyed only when `destroy` has been -// called *and* all in-flight method calls have completed, avoiding violating any of the expectations -// of the underlying Rust code. -// -// This makes a cleaner a better alternative to _not_ calling `destroy()` as -// and when the object is finished with, but the abstraction is not perfect: if the Rust object's `drop` -// method is slow, and/or there are many objects to cleanup, and it's on a low end Android device, then the cleaner -// thread may be starved, and the app will leak memory. -// -// In this case, `destroy`ing manually may be a better solution. -// -// The cleaner can live side by side with the manual calling of `destroy`. In the order of responsiveness, uniffi objects -// with Rust peers are reclaimed: -// -// 1. By calling the `destroy` method of the object, which calls `rustObject.free()`. If that doesn't happen: -// 2. When the object becomes unreachable, AND the Cleaner thread gets to call `rustObject.free()`. If the thread is starved then: -// 3. The memory is reclaimed when the process terminates. -// -// [1] https://stackoverflow.com/questions/24376768/can-java-finalize-an-object-when-it-is-still-in-scope/24380219 -// - - -/** - * Configurable Node construction. See module docs. - * - * All fields are immutable after construction. Each `with_*` setter - * returns a fresh `Arc` that shares ownership of any - * previously-installed modifiers via `Arc`. No interior - * mutability, no locks — the builder is a value, not a state - * machine. - */ -public interface NodeBuilderInterface { - - /** - * Connect to an existing node using saved credentials and return - * a connected Node with any configured modifiers applied. - * - * If `mnemonic` is `Some(...)`, the SDK spawns a signer for the - * connected Node. If `None`, the Node is signerless and signing - * happens elsewhere (paired device, CLN node's local signer, - * hardware signer). - */ - fun `connect`(`credentials`: kotlin.ByteArray, `mnemonic`: kotlin.String?): Node - - /** - * Recover credentials for an existing node and return a - * connected Node with any configured modifiers applied. - * - * `mnemonic` is required — recovery drives the signer to - * authenticate. - */ - fun `recover`(`mnemonic`: kotlin.String): Node - - /** - * Register a new Greenlight node and return a connected Node - * with the SDK signer running and any configured modifiers - * applied. - * - * `mnemonic` is required — registration drives the signer to - * sign the registration challenge, so the SDK must hold the - * seed for this call. - */ - fun `register`(`mnemonic`: kotlin.String, `inviteCode`: kotlin.String?): Node - - /** - * Try to recover; if the node doesn't exist, register a new one. - * - * `mnemonic` is required — both recover and register drive the - * signer. - */ - fun `registerOrRecover`(`mnemonic`: kotlin.String, `inviteCode`: kotlin.String?): Node - - /** - * Install a node event listener. Events fire from the moment the - * gRPC stream is established by the build call (`register` / - * `recover` / `connect` / …), so attach the listener via the - * builder rather than after the fact to capture events from the - * very first moment. - * - * Returns a new builder that shares the rest of the - * configuration. Build calls on the returned builder will - * install the listener; the original builder is unchanged. - */ - fun `withEventListener`(`listener`: NodeEventListener): NodeBuilder - - companion object -} - -/** - * Configurable Node construction. See module docs. - * - * All fields are immutable after construction. Each `with_*` setter - * returns a fresh `Arc` that shares ownership of any - * previously-installed modifiers via `Arc`. No interior - * mutability, no locks — the builder is a value, not a state - * machine. - */ -open class NodeBuilder: Disposable, AutoCloseable, NodeBuilderInterface -{ - - constructor(pointer: Pointer) { - this.pointer = pointer - this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(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. - */ - @Suppress("UNUSED_PARAMETER") - constructor(noPointer: NoPointer) { - this.pointer = null - this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(pointer)) - } - /** - * Create a builder for a Node with `config`. No I/O happens - * until you call `connect` / `register` / `recover` / - * `register_or_recover`. - */ - constructor(`config`: Config) : - this( - uniffiRustCall() { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_constructor_nodebuilder_new( - FfiConverterTypeConfig.lower(`config`),_status) -} - ) - - protected val pointer: Pointer? - protected val cleanable: UniffiCleaner.Cleanable - - private val wasDestroyed = AtomicBoolean(false) - private val callCounter = AtomicLong(1) - - 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() - } - } - } - - @Synchronized - override fun close() { - 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.get() - if (c == 0L) { - throw IllegalStateException("${this.javaClass.simpleName} object has already been destroyed") - } - if (c == Long.MAX_VALUE) { - throw IllegalStateException("${this.javaClass.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 UniffiCleanAction(private val pointer: Pointer?) : Runnable { - override fun run() { - pointer?.let { ptr -> - uniffiRustCall { status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_free_nodebuilder(ptr, status) - } - } - } - } - - fun uniffiClonePointer(): Pointer { - return uniffiRustCall() { status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_clone_nodebuilder(pointer!!, status) - } - } - - - /** - * Connect to an existing node using saved credentials and return - * a connected Node with any configured modifiers applied. - * - * If `mnemonic` is `Some(...)`, the SDK spawns a signer for the - * connected Node. If `None`, the Node is signerless and signing - * happens elsewhere (paired device, CLN node's local signer, - * hardware signer). - */ - @Throws(Exception::class)override fun `connect`(`credentials`: kotlin.ByteArray, `mnemonic`: kotlin.String?): Node { - return FfiConverterTypeNode.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_nodebuilder_connect( - it, FfiConverterByteArray.lower(`credentials`),FfiConverterOptionalString.lower(`mnemonic`),_status) -} - } - ) - } - - - - /** - * Recover credentials for an existing node and return a - * connected Node with any configured modifiers applied. - * - * `mnemonic` is required — recovery drives the signer to - * authenticate. - */ - @Throws(Exception::class)override fun `recover`(`mnemonic`: kotlin.String): Node { - return FfiConverterTypeNode.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_nodebuilder_recover( - it, FfiConverterString.lower(`mnemonic`),_status) -} - } - ) - } - - - - /** - * Register a new Greenlight node and return a connected Node - * with the SDK signer running and any configured modifiers - * applied. - * - * `mnemonic` is required — registration drives the signer to - * sign the registration challenge, so the SDK must hold the - * seed for this call. - */ - @Throws(Exception::class)override fun `register`(`mnemonic`: kotlin.String, `inviteCode`: kotlin.String?): Node { - return FfiConverterTypeNode.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_nodebuilder_register( - it, FfiConverterString.lower(`mnemonic`),FfiConverterOptionalString.lower(`inviteCode`),_status) -} - } - ) - } - - - - /** - * Try to recover; if the node doesn't exist, register a new one. - * - * `mnemonic` is required — both recover and register drive the - * signer. - */ - @Throws(Exception::class)override fun `registerOrRecover`(`mnemonic`: kotlin.String, `inviteCode`: kotlin.String?): Node { - return FfiConverterTypeNode.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_nodebuilder_register_or_recover( - it, FfiConverterString.lower(`mnemonic`),FfiConverterOptionalString.lower(`inviteCode`),_status) -} - } - ) - } - - - - /** - * Install a node event listener. Events fire from the moment the - * gRPC stream is established by the build call (`register` / - * `recover` / `connect` / …), so attach the listener via the - * builder rather than after the fact to capture events from the - * very first moment. - * - * Returns a new builder that shares the rest of the - * configuration. Build calls on the returned builder will - * install the listener; the original builder is unchanged. - */override fun `withEventListener`(`listener`: NodeEventListener): NodeBuilder { - return FfiConverterTypeNodeBuilder.lift( - callWithPointer { - uniffiRustCall() { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_nodebuilder_with_event_listener( - it, FfiConverterTypeNodeEventListener.lower(`listener`),_status) -} - } - ) - } - - - - - - - companion object - -} - -/** - * @suppress - */ -public object FfiConverterTypeNodeBuilder: FfiConverter { - - override fun lower(value: NodeBuilder): Pointer { - return value.uniffiClonePointer() - } - - override fun lift(value: Pointer): NodeBuilder { - return NodeBuilder(value) - } - - override fun read(buf: ByteBuffer): NodeBuilder { - // The Rust code always writes pointers as 8 bytes, and will - // fail to compile if they don't fit. - return lift(Pointer(buf.getLong())) - } - - override fun allocationSize(value: NodeBuilder) = 8UL - - override fun write(value: NodeBuilder, buf: ByteBuffer) { - // The Rust code always expects pointers written as 8 bytes, - // and will fail to compile if they don't fit. - buf.putLong(Pointer.nativeValue(lower(value))) - } -} - - -// This template implements a class for working with a Rust struct via a Pointer/Arc -// to the live Rust struct on the other side of the FFI. -// -// Each instance implements core operations for working with the Rust `Arc` and the -// Kotlin Pointer to work with the live Rust struct on the other side of the FFI. -// -// There's some subtlety here, because we have to be careful not to operate on a Rust -// struct after it has been dropped, and because we must expose a public API for freeing -// theq Kotlin wrapper object in lieu of reliable finalizers. The core requirements are: -// -// * Each instance holds an opaque pointer to the underlying Rust struct. -// Method calls need to read this pointer from the object's state and pass it in to -// the Rust FFI. -// -// * When an instance is no longer needed, its pointer should be passed to a -// special destructor function provided by the Rust FFI, which will drop the -// underlying Rust struct. -// -// * Given an instance, calling code is expected to call the special -// `destroy` method in order to free it after use, either by calling it explicitly -// or by using a higher-level helper like the `use` method. Failing to do so risks -// leaking the underlying Rust struct. -// -// * We can't assume that calling code will do the right thing, and must be prepared -// to handle Kotlin method calls executing concurrently with or even after a call to -// `destroy`, and to handle multiple (possibly concurrent!) calls to `destroy`. -// -// * We must never allow Rust code to operate on the underlying Rust struct after -// the destructor has been called, and must never call the destructor more than once. -// Doing so may trigger memory unsafety. -// -// * To mitigate many of the risks of leaking memory and use-after-free unsafety, a `Cleaner` -// is implemented to call the destructor when the Kotlin object becomes unreachable. -// This is done in a background thread. This is not a panacea, and client code should be aware that -// 1. the thread may starve if some there are objects that have poorly performing -// `drop` methods or do significant work in their `drop` methods. -// 2. the thread is shared across the whole library. This can be tuned by using `android_cleaner = true`, -// or `android = true` in the [`kotlin` section of the `uniffi.toml` file](https://mozilla.github.io/uniffi-rs/kotlin/configuration.html). -// -// If we try to implement this with mutual exclusion on access to the pointer, there is the -// possibility of a race between a method call and a concurrent call to `destroy`: -// -// * Thread A starts a method call, reads the value of the pointer, but is interrupted -// before it can pass the pointer over the FFI to Rust. -// * Thread B calls `destroy` and frees the underlying Rust struct. -// * Thread A resumes, passing the already-read pointer value to Rust and triggering -// a use-after-free. -// -// One possible solution would be to use a `ReadWriteLock`, with each method call taking -// a read lock (and thus allowed to run concurrently) and the special `destroy` method -// taking a write lock (and thus blocking on live method calls). However, we aim not to -// generate methods with any hidden blocking semantics, and a `destroy` method that might -// block if called incorrectly seems to meet that bar. -// -// So, we achieve our goals by giving each instance an associated `AtomicLong` counter to track -// the number of in-flight method calls, and an `AtomicBoolean` flag to indicate whether `destroy` -// has been called. These are updated according to the following rules: -// -// * The initial value of the counter is 1, indicating a live object with no in-flight calls. -// The initial value for the flag is false. -// -// * At the start of each method call, we atomically check the counter. -// If it is 0 then the underlying Rust struct has already been destroyed and the call is aborted. -// If it is nonzero them we atomically increment it by 1 and proceed with the method call. -// -// * At the end of each method call, we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// * When `destroy` is called, we atomically flip the flag from false to true. -// If the flag was already true we silently fail. -// Otherwise we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// Astute readers may observe that this all sounds very similar to the way that Rust's `Arc` works, -// and indeed it is, with the addition of a flag to guard against multiple calls to `destroy`. -// -// The overall effect is that the underlying Rust struct is destroyed only when `destroy` has been -// called *and* all in-flight method calls have completed, avoiding violating any of the expectations -// of the underlying Rust code. -// -// This makes a cleaner a better alternative to _not_ calling `destroy()` as -// and when the object is finished with, but the abstraction is not perfect: if the Rust object's `drop` -// method is slow, and/or there are many objects to cleanup, and it's on a low end Android device, then the cleaner -// thread may be starved, and the app will leak memory. -// -// In this case, `destroy`ing manually may be a better solution. -// -// The cleaner can live side by side with the manual calling of `destroy`. In the order of responsiveness, uniffi objects -// with Rust peers are reclaimed: -// -// 1. By calling the `destroy` method of the object, which calls `rustObject.free()`. If that doesn't happen: -// 2. When the object becomes unreachable, AND the Cleaner thread gets to call `rustObject.free()`. If the thread is starved then: -// 3. The memory is reclaimed when the process terminates. -// -// [1] https://stackoverflow.com/questions/24376768/can-java-finalize-an-object-when-it-is-still-in-scope/24380219 -// - - -/** - * A stream of node events. Call `next()` to receive the next event. - * - * The stream is backed by a gRPC streaming connection to the node. - * Each call to `next()` blocks the calling thread until an event is - * available, but does not block the tokio runtime - other node - * operations can proceed concurrently from other threads. - */ -public interface NodeEventStreamInterface { - - /** - * Get the next event from the stream. - * - * Blocks the calling thread until an event is available or the - * stream ends. Returns `None` when the stream is exhausted or - * the connection is lost. - */ - fun `next`(): NodeEvent? - - companion object -} - -/** - * A stream of node events. Call `next()` to receive the next event. - * - * The stream is backed by a gRPC streaming connection to the node. - * Each call to `next()` blocks the calling thread until an event is - * available, but does not block the tokio runtime - other node - * operations can proceed concurrently from other threads. - */ -open class NodeEventStream: Disposable, AutoCloseable, NodeEventStreamInterface -{ - - constructor(pointer: Pointer) { - this.pointer = pointer - this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(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. - */ - @Suppress("UNUSED_PARAMETER") - constructor(noPointer: NoPointer) { - this.pointer = null - this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(pointer)) - } - - protected val pointer: Pointer? - protected val cleanable: UniffiCleaner.Cleanable - - private val wasDestroyed = AtomicBoolean(false) - private val callCounter = AtomicLong(1) - - 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() - } - } - } - - @Synchronized - override fun close() { - 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.get() - if (c == 0L) { - throw IllegalStateException("${this.javaClass.simpleName} object has already been destroyed") - } - if (c == Long.MAX_VALUE) { - throw IllegalStateException("${this.javaClass.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 UniffiCleanAction(private val pointer: Pointer?) : Runnable { - override fun run() { - pointer?.let { ptr -> - uniffiRustCall { status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_free_nodeeventstream(ptr, status) - } - } - } - } - - fun uniffiClonePointer(): Pointer { - return uniffiRustCall() { status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_clone_nodeeventstream(pointer!!, status) - } - } - - - /** - * Get the next event from the stream. - * - * Blocks the calling thread until an event is available or the - * stream ends. Returns `None` when the stream is exhausted or - * the connection is lost. - */ - @Throws(Exception::class)override fun `next`(): NodeEvent? { - return FfiConverterOptionalTypeNodeEvent.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_nodeeventstream_next( - it, _status) -} - } - ) - } - - - - - - - companion object - -} - -/** - * @suppress - */ -public object FfiConverterTypeNodeEventStream: FfiConverter { - - override fun lower(value: NodeEventStream): Pointer { - return value.uniffiClonePointer() - } - - override fun lift(value: Pointer): NodeEventStream { - return NodeEventStream(value) - } - - override fun read(buf: ByteBuffer): NodeEventStream { - // The Rust code always writes pointers as 8 bytes, and will - // fail to compile if they don't fit. - return lift(Pointer(buf.getLong())) - } - - override fun allocationSize(value: NodeEventStream) = 8UL - - override fun write(value: NodeEventStream, buf: ByteBuffer) { - // The Rust code always expects pointers written as 8 bytes, - // and will fail to compile if they don't fit. - buf.putLong(Pointer.nativeValue(lower(value))) - } -} - - -// This template implements a class for working with a Rust struct via a Pointer/Arc -// to the live Rust struct on the other side of the FFI. -// -// Each instance implements core operations for working with the Rust `Arc` and the -// Kotlin Pointer to work with the live Rust struct on the other side of the FFI. -// -// There's some subtlety here, because we have to be careful not to operate on a Rust -// struct after it has been dropped, and because we must expose a public API for freeing -// theq Kotlin wrapper object in lieu of reliable finalizers. The core requirements are: -// -// * Each instance holds an opaque pointer to the underlying Rust struct. -// Method calls need to read this pointer from the object's state and pass it in to -// the Rust FFI. -// -// * When an instance is no longer needed, its pointer should be passed to a -// special destructor function provided by the Rust FFI, which will drop the -// underlying Rust struct. -// -// * Given an instance, calling code is expected to call the special -// `destroy` method in order to free it after use, either by calling it explicitly -// or by using a higher-level helper like the `use` method. Failing to do so risks -// leaking the underlying Rust struct. -// -// * We can't assume that calling code will do the right thing, and must be prepared -// to handle Kotlin method calls executing concurrently with or even after a call to -// `destroy`, and to handle multiple (possibly concurrent!) calls to `destroy`. -// -// * We must never allow Rust code to operate on the underlying Rust struct after -// the destructor has been called, and must never call the destructor more than once. -// Doing so may trigger memory unsafety. -// -// * To mitigate many of the risks of leaking memory and use-after-free unsafety, a `Cleaner` -// is implemented to call the destructor when the Kotlin object becomes unreachable. -// This is done in a background thread. This is not a panacea, and client code should be aware that -// 1. the thread may starve if some there are objects that have poorly performing -// `drop` methods or do significant work in their `drop` methods. -// 2. the thread is shared across the whole library. This can be tuned by using `android_cleaner = true`, -// or `android = true` in the [`kotlin` section of the `uniffi.toml` file](https://mozilla.github.io/uniffi-rs/kotlin/configuration.html). -// -// If we try to implement this with mutual exclusion on access to the pointer, there is the -// possibility of a race between a method call and a concurrent call to `destroy`: -// -// * Thread A starts a method call, reads the value of the pointer, but is interrupted -// before it can pass the pointer over the FFI to Rust. -// * Thread B calls `destroy` and frees the underlying Rust struct. -// * Thread A resumes, passing the already-read pointer value to Rust and triggering -// a use-after-free. -// -// One possible solution would be to use a `ReadWriteLock`, with each method call taking -// a read lock (and thus allowed to run concurrently) and the special `destroy` method -// taking a write lock (and thus blocking on live method calls). However, we aim not to -// generate methods with any hidden blocking semantics, and a `destroy` method that might -// block if called incorrectly seems to meet that bar. -// -// So, we achieve our goals by giving each instance an associated `AtomicLong` counter to track -// the number of in-flight method calls, and an `AtomicBoolean` flag to indicate whether `destroy` -// has been called. These are updated according to the following rules: -// -// * The initial value of the counter is 1, indicating a live object with no in-flight calls. -// The initial value for the flag is false. -// -// * At the start of each method call, we atomically check the counter. -// If it is 0 then the underlying Rust struct has already been destroyed and the call is aborted. -// If it is nonzero them we atomically increment it by 1 and proceed with the method call. -// -// * At the end of each method call, we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// * When `destroy` is called, we atomically flip the flag from false to true. -// If the flag was already true we silently fail. -// Otherwise we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// Astute readers may observe that this all sounds very similar to the way that Rust's `Arc` works, -// and indeed it is, with the addition of a flag to guard against multiple calls to `destroy`. -// -// The overall effect is that the underlying Rust struct is destroyed only when `destroy` has been -// called *and* all in-flight method calls have completed, avoiding violating any of the expectations -// of the underlying Rust code. -// -// This makes a cleaner a better alternative to _not_ calling `destroy()` as -// and when the object is finished with, but the abstraction is not perfect: if the Rust object's `drop` -// method is slow, and/or there are many objects to cleanup, and it's on a low end Android device, then the cleaner -// thread may be starved, and the app will leak memory. -// -// In this case, `destroy`ing manually may be a better solution. -// -// The cleaner can live side by side with the manual calling of `destroy`. In the order of responsiveness, uniffi objects -// with Rust peers are reclaimed: -// -// 1. By calling the `destroy` method of the object, which calls `rustObject.free()`. If that doesn't happen: -// 2. When the object becomes unreachable, AND the Cleaner thread gets to call `rustObject.free()`. If the thread is starved then: -// 3. The memory is reclaimed when the process terminates. -// -// [1] https://stackoverflow.com/questions/24376768/can-java-finalize-an-object-when-it-is-still-in-scope/24380219 -// - - -public interface SchedulerInterface { - - /** - * Asks whether the Lightning account backed by `node_id` may be - * surfaced to the user. - * - * This is a feature gate for applications that offer Lightning - * alongside other account types. Greenlight relays the question - * to its Lightning Service Provider, which answers based on - * whether it has previously granted this node a slot, or has the - * capacity to grant one now. - * - * Deliberately callable before `register()`, since an - * application has to decide whether to offer Lightning at all - * before it creates a node. It needs no credentials, and the - * `node_id` is passed explicitly. - * - * The answer is advisory and may change over time. Treat an - * error as "unknown" rather than as a negative answer. - */ - fun `lightningAvailable`(`nodeId`: kotlin.ByteArray): kotlin.Boolean - - fun `recover`(`signer`: Signer): Credentials - - fun `register`(`signer`: Signer, `code`: kotlin.String?): Credentials - - /** - * Configure a developer certificate obtained from the Greenlight - * Developer Console. Nodes registered through this scheduler - * will be associated with the developer's account. - * - * Returns a new `Scheduler` instance with the developer - * certificate configured. - */ - fun `withDeveloperCert`(`cert`: DeveloperCert): Scheduler - - companion object -} - -open class Scheduler: Disposable, AutoCloseable, SchedulerInterface -{ - - constructor(pointer: Pointer) { - this.pointer = pointer - this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(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. - */ - @Suppress("UNUSED_PARAMETER") - constructor(noPointer: NoPointer) { - this.pointer = null - this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(pointer)) - } - /** - * Create a `Scheduler` instance configured with the Greenlight - * production service pre-configured. - */ - constructor(`network`: Network) : - this( - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_constructor_scheduler_new( - FfiConverterTypeNetwork.lower(`network`),_status) -} - ) - - protected val pointer: Pointer? - protected val cleanable: UniffiCleaner.Cleanable - - private val wasDestroyed = AtomicBoolean(false) - private val callCounter = AtomicLong(1) - - 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() - } - } - } - - @Synchronized - override fun close() { - 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.get() - if (c == 0L) { - throw IllegalStateException("${this.javaClass.simpleName} object has already been destroyed") - } - if (c == Long.MAX_VALUE) { - throw IllegalStateException("${this.javaClass.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 UniffiCleanAction(private val pointer: Pointer?) : Runnable { - override fun run() { - pointer?.let { ptr -> - uniffiRustCall { status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_free_scheduler(ptr, status) - } - } - } - } - - fun uniffiClonePointer(): Pointer { - return uniffiRustCall() { status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_clone_scheduler(pointer!!, status) - } - } - - - /** - * Asks whether the Lightning account backed by `node_id` may be - * surfaced to the user. - * - * This is a feature gate for applications that offer Lightning - * alongside other account types. Greenlight relays the question - * to its Lightning Service Provider, which answers based on - * whether it has previously granted this node a slot, or has the - * capacity to grant one now. - * - * Deliberately callable before `register()`, since an - * application has to decide whether to offer Lightning at all - * before it creates a node. It needs no credentials, and the - * `node_id` is passed explicitly. - * - * The answer is advisory and may change over time. Treat an - * error as "unknown" rather than as a negative answer. - */ - @Throws(Exception::class)override fun `lightningAvailable`(`nodeId`: kotlin.ByteArray): kotlin.Boolean { - return FfiConverterBoolean.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_scheduler_lightning_available( - it, FfiConverterByteArray.lower(`nodeId`),_status) -} - } - ) - } - - - - @Throws(Exception::class)override fun `recover`(`signer`: Signer): Credentials { - return FfiConverterTypeCredentials.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_scheduler_recover( - it, FfiConverterTypeSigner.lower(`signer`),_status) -} - } - ) - } - - - - @Throws(Exception::class)override fun `register`(`signer`: Signer, `code`: kotlin.String?): Credentials { - return FfiConverterTypeCredentials.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_scheduler_register( - it, FfiConverterTypeSigner.lower(`signer`),FfiConverterOptionalString.lower(`code`),_status) -} - } - ) - } - - - - /** - * Configure a developer certificate obtained from the Greenlight - * Developer Console. Nodes registered through this scheduler - * will be associated with the developer's account. - * - * Returns a new `Scheduler` instance with the developer - * certificate configured. - */override fun `withDeveloperCert`(`cert`: DeveloperCert): Scheduler { - return FfiConverterTypeScheduler.lift( - callWithPointer { - uniffiRustCall() { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_scheduler_with_developer_cert( - it, FfiConverterTypeDeveloperCert.lower(`cert`),_status) -} - } - ) - } - - - - - - - companion object - -} - -/** - * @suppress - */ -public object FfiConverterTypeScheduler: FfiConverter { - - override fun lower(value: Scheduler): Pointer { - return value.uniffiClonePointer() - } - - override fun lift(value: Pointer): Scheduler { - return Scheduler(value) - } - - override fun read(buf: ByteBuffer): Scheduler { - // The Rust code always writes pointers as 8 bytes, and will - // fail to compile if they don't fit. - return lift(Pointer(buf.getLong())) - } - - override fun allocationSize(value: Scheduler) = 8UL - - override fun write(value: Scheduler, buf: ByteBuffer) { - // The Rust code always expects pointers written as 8 bytes, - // and will fail to compile if they don't fit. - buf.putLong(Pointer.nativeValue(lower(value))) - } -} - - -// This template implements a class for working with a Rust struct via a Pointer/Arc -// to the live Rust struct on the other side of the FFI. -// -// Each instance implements core operations for working with the Rust `Arc` and the -// Kotlin Pointer to work with the live Rust struct on the other side of the FFI. -// -// There's some subtlety here, because we have to be careful not to operate on a Rust -// struct after it has been dropped, and because we must expose a public API for freeing -// theq Kotlin wrapper object in lieu of reliable finalizers. The core requirements are: -// -// * Each instance holds an opaque pointer to the underlying Rust struct. -// Method calls need to read this pointer from the object's state and pass it in to -// the Rust FFI. -// -// * When an instance is no longer needed, its pointer should be passed to a -// special destructor function provided by the Rust FFI, which will drop the -// underlying Rust struct. -// -// * Given an instance, calling code is expected to call the special -// `destroy` method in order to free it after use, either by calling it explicitly -// or by using a higher-level helper like the `use` method. Failing to do so risks -// leaking the underlying Rust struct. -// -// * We can't assume that calling code will do the right thing, and must be prepared -// to handle Kotlin method calls executing concurrently with or even after a call to -// `destroy`, and to handle multiple (possibly concurrent!) calls to `destroy`. -// -// * We must never allow Rust code to operate on the underlying Rust struct after -// the destructor has been called, and must never call the destructor more than once. -// Doing so may trigger memory unsafety. -// -// * To mitigate many of the risks of leaking memory and use-after-free unsafety, a `Cleaner` -// is implemented to call the destructor when the Kotlin object becomes unreachable. -// This is done in a background thread. This is not a panacea, and client code should be aware that -// 1. the thread may starve if some there are objects that have poorly performing -// `drop` methods or do significant work in their `drop` methods. -// 2. the thread is shared across the whole library. This can be tuned by using `android_cleaner = true`, -// or `android = true` in the [`kotlin` section of the `uniffi.toml` file](https://mozilla.github.io/uniffi-rs/kotlin/configuration.html). -// -// If we try to implement this with mutual exclusion on access to the pointer, there is the -// possibility of a race between a method call and a concurrent call to `destroy`: -// -// * Thread A starts a method call, reads the value of the pointer, but is interrupted -// before it can pass the pointer over the FFI to Rust. -// * Thread B calls `destroy` and frees the underlying Rust struct. -// * Thread A resumes, passing the already-read pointer value to Rust and triggering -// a use-after-free. -// -// One possible solution would be to use a `ReadWriteLock`, with each method call taking -// a read lock (and thus allowed to run concurrently) and the special `destroy` method -// taking a write lock (and thus blocking on live method calls). However, we aim not to -// generate methods with any hidden blocking semantics, and a `destroy` method that might -// block if called incorrectly seems to meet that bar. -// -// So, we achieve our goals by giving each instance an associated `AtomicLong` counter to track -// the number of in-flight method calls, and an `AtomicBoolean` flag to indicate whether `destroy` -// has been called. These are updated according to the following rules: -// -// * The initial value of the counter is 1, indicating a live object with no in-flight calls. -// The initial value for the flag is false. -// -// * At the start of each method call, we atomically check the counter. -// If it is 0 then the underlying Rust struct has already been destroyed and the call is aborted. -// If it is nonzero them we atomically increment it by 1 and proceed with the method call. -// -// * At the end of each method call, we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// * When `destroy` is called, we atomically flip the flag from false to true. -// If the flag was already true we silently fail. -// Otherwise we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// Astute readers may observe that this all sounds very similar to the way that Rust's `Arc` works, -// and indeed it is, with the addition of a flag to guard against multiple calls to `destroy`. -// -// The overall effect is that the underlying Rust struct is destroyed only when `destroy` has been -// called *and* all in-flight method calls have completed, avoiding violating any of the expectations -// of the underlying Rust code. -// -// This makes a cleaner a better alternative to _not_ calling `destroy()` as -// and when the object is finished with, but the abstraction is not perfect: if the Rust object's `drop` -// method is slow, and/or there are many objects to cleanup, and it's on a low end Android device, then the cleaner -// thread may be starved, and the app will leak memory. -// -// In this case, `destroy`ing manually may be a better solution. -// -// The cleaner can live side by side with the manual calling of `destroy`. In the order of responsiveness, uniffi objects -// with Rust peers are reclaimed: -// -// 1. By calling the `destroy` method of the object, which calls `rustObject.free()`. If that doesn't happen: -// 2. When the object becomes unreachable, AND the Cleaner thread gets to call `rustObject.free()`. If the thread is starved then: -// 3. The memory is reclaimed when the process terminates. -// -// [1] https://stackoverflow.com/questions/24376768/can-java-finalize-an-object-when-it-is-still-in-scope/24380219 -// - - -public interface SignerInterface { - - fun `authenticate`(`creds`: Credentials): Signer - - fun `nodeId`(): kotlin.ByteArray - - fun `start`(): Handle - - companion object -} - -open class Signer: Disposable, AutoCloseable, SignerInterface -{ - - constructor(pointer: Pointer) { - this.pointer = pointer - this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(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. - */ - @Suppress("UNUSED_PARAMETER") - constructor(noPointer: NoPointer) { - this.pointer = null - this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(pointer)) - } - constructor(`phrase`: kotlin.String) : - this( - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_constructor_signer_new( - FfiConverterString.lower(`phrase`),_status) -} - ) - - protected val pointer: Pointer? - protected val cleanable: UniffiCleaner.Cleanable - - private val wasDestroyed = AtomicBoolean(false) - private val callCounter = AtomicLong(1) - - 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() - } - } - } - - @Synchronized - override fun close() { - 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.get() - if (c == 0L) { - throw IllegalStateException("${this.javaClass.simpleName} object has already been destroyed") - } - if (c == Long.MAX_VALUE) { - throw IllegalStateException("${this.javaClass.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 UniffiCleanAction(private val pointer: Pointer?) : Runnable { - override fun run() { - pointer?.let { ptr -> - uniffiRustCall { status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_free_signer(ptr, status) - } - } - } - } - - fun uniffiClonePointer(): Pointer { - return uniffiRustCall() { status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_clone_signer(pointer!!, status) - } - } - - - @Throws(Exception::class)override fun `authenticate`(`creds`: Credentials): Signer { - return FfiConverterTypeSigner.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_signer_authenticate( - it, FfiConverterTypeCredentials.lower(`creds`),_status) -} - } - ) - } - - - override fun `nodeId`(): kotlin.ByteArray { - return FfiConverterByteArray.lift( - callWithPointer { - uniffiRustCall() { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_signer_node_id( - it, _status) -} - } - ) - } - - - - @Throws(Exception::class)override fun `start`(): Handle { - return FfiConverterTypeHandle.lift( - callWithPointer { - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_method_signer_start( - it, _status) -} - } - ) - } - - - - - - companion object { - - @Throws(Exception::class) fun `newFromSeed`(`seed`: kotlin.ByteArray): Signer { - return FfiConverterTypeSigner.lift( - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_constructor_signer_new_from_seed( - FfiConverterByteArray.lower(`seed`),_status) -} - ) - } - - - - } - -} - -/** - * @suppress - */ -public object FfiConverterTypeSigner: FfiConverter { - - override fun lower(value: Signer): Pointer { - return value.uniffiClonePointer() - } - - override fun lift(value: Pointer): Signer { - return Signer(value) - } - - override fun read(buf: ByteBuffer): Signer { - // The Rust code always writes pointers as 8 bytes, and will - // fail to compile if they don't fit. - return lift(Pointer(buf.getLong())) - } - - override fun allocationSize(value: Signer) = 8UL - - override fun write(value: Signer, buf: ByteBuffer) { - // The Rust code always expects pointers written as 8 bytes, - // and will fail to compile if they don't fit. - buf.putLong(Pointer.nativeValue(lower(value))) - } -} - - - -data class FundChannel ( - /** - * Peer node public key as lowercase hex (66 chars). - */ - var `peerId`: kotlin.String, - var `ourAmountMsat`: kotlin.ULong, - var `amountMsat`: kotlin.ULong, - /** - * Funding transaction id as lowercase hex (64 chars). - */ - var `fundingTxid`: kotlin.String, - var `fundingOutput`: kotlin.UInt, - var `connected`: kotlin.Boolean, - var `state`: ChannelState, - var `shortChannelId`: kotlin.String?, - /** - * Channel id as lowercase hex (64 chars). - */ - var `channelId`: kotlin.String? -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeFundChannel: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): FundChannel { - return FundChannel( - FfiConverterString.read(buf), - FfiConverterULong.read(buf), - FfiConverterULong.read(buf), - FfiConverterString.read(buf), - FfiConverterUInt.read(buf), - FfiConverterBoolean.read(buf), - FfiConverterTypeChannelState.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterOptionalString.read(buf), - ) - } - - override fun allocationSize(value: FundChannel) = ( - FfiConverterString.allocationSize(value.`peerId`) + - FfiConverterULong.allocationSize(value.`ourAmountMsat`) + - FfiConverterULong.allocationSize(value.`amountMsat`) + - FfiConverterString.allocationSize(value.`fundingTxid`) + - FfiConverterUInt.allocationSize(value.`fundingOutput`) + - FfiConverterBoolean.allocationSize(value.`connected`) + - FfiConverterTypeChannelState.allocationSize(value.`state`) + - FfiConverterOptionalString.allocationSize(value.`shortChannelId`) + - FfiConverterOptionalString.allocationSize(value.`channelId`) - ) - - override fun write(value: FundChannel, buf: ByteBuffer) { - FfiConverterString.write(value.`peerId`, buf) - FfiConverterULong.write(value.`ourAmountMsat`, buf) - FfiConverterULong.write(value.`amountMsat`, buf) - FfiConverterString.write(value.`fundingTxid`, buf) - FfiConverterUInt.write(value.`fundingOutput`, buf) - FfiConverterBoolean.write(value.`connected`, buf) - FfiConverterTypeChannelState.write(value.`state`, buf) - FfiConverterOptionalString.write(value.`shortChannelId`, buf) - FfiConverterOptionalString.write(value.`channelId`, buf) - } -} - - - -data class FundOutput ( - /** - * Transaction id as lowercase hex (64 chars). - */ - var `txid`: kotlin.String, - var `output`: kotlin.UInt, - var `amountMsat`: kotlin.ULong, - var `status`: OutputStatus, - var `address`: kotlin.String?, - var `blockheight`: kotlin.UInt?, - /** - * True when this UTXO is currently reserved by an in-flight PSBT - * (e.g. a channel-open or fund-send that has not been broadcast or - * abandoned). Reserved UTXOs are not spendable and must be excluded - * from the wallet's spendable balance. - */ - var `reserved`: kotlin.Boolean -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeFundOutput: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): FundOutput { - return FundOutput( - FfiConverterString.read(buf), - FfiConverterUInt.read(buf), - FfiConverterULong.read(buf), - FfiConverterTypeOutputStatus.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterOptionalUInt.read(buf), - FfiConverterBoolean.read(buf), - ) - } - - override fun allocationSize(value: FundOutput) = ( - FfiConverterString.allocationSize(value.`txid`) + - FfiConverterUInt.allocationSize(value.`output`) + - FfiConverterULong.allocationSize(value.`amountMsat`) + - FfiConverterTypeOutputStatus.allocationSize(value.`status`) + - FfiConverterOptionalString.allocationSize(value.`address`) + - FfiConverterOptionalUInt.allocationSize(value.`blockheight`) + - FfiConverterBoolean.allocationSize(value.`reserved`) - ) - - override fun write(value: FundOutput, buf: ByteBuffer) { - FfiConverterString.write(value.`txid`, buf) - FfiConverterUInt.write(value.`output`, buf) - FfiConverterULong.write(value.`amountMsat`, buf) - FfiConverterTypeOutputStatus.write(value.`status`, buf) - FfiConverterOptionalString.write(value.`address`, buf) - FfiConverterOptionalUInt.write(value.`blockheight`, buf) - FfiConverterBoolean.write(value.`reserved`, buf) - } -} - - - -data class GetInfoResponse ( - /** - * Node public key as lowercase hex (66 chars). - */ - var `id`: kotlin.String, - var `alias`: kotlin.String?, - /** - * 3-byte RGB color as lowercase hex (6 chars). - */ - var `color`: kotlin.String, - var `numPeers`: kotlin.UInt, - var `numPendingChannels`: kotlin.UInt, - var `numActiveChannels`: kotlin.UInt, - var `numInactiveChannels`: kotlin.UInt, - var `version`: kotlin.String, - var `lightningDir`: kotlin.String, - var `blockheight`: kotlin.UInt, - var `network`: kotlin.String, - var `feesCollectedMsat`: kotlin.ULong -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeGetInfoResponse: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): GetInfoResponse { - return GetInfoResponse( - FfiConverterString.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterString.read(buf), - FfiConverterUInt.read(buf), - FfiConverterUInt.read(buf), - FfiConverterUInt.read(buf), - FfiConverterUInt.read(buf), - FfiConverterString.read(buf), - FfiConverterString.read(buf), - FfiConverterUInt.read(buf), - FfiConverterString.read(buf), - FfiConverterULong.read(buf), - ) - } - - override fun allocationSize(value: GetInfoResponse) = ( - FfiConverterString.allocationSize(value.`id`) + - FfiConverterOptionalString.allocationSize(value.`alias`) + - FfiConverterString.allocationSize(value.`color`) + - FfiConverterUInt.allocationSize(value.`numPeers`) + - FfiConverterUInt.allocationSize(value.`numPendingChannels`) + - FfiConverterUInt.allocationSize(value.`numActiveChannels`) + - FfiConverterUInt.allocationSize(value.`numInactiveChannels`) + - FfiConverterString.allocationSize(value.`version`) + - FfiConverterString.allocationSize(value.`lightningDir`) + - FfiConverterUInt.allocationSize(value.`blockheight`) + - FfiConverterString.allocationSize(value.`network`) + - FfiConverterULong.allocationSize(value.`feesCollectedMsat`) - ) - - override fun write(value: GetInfoResponse, buf: ByteBuffer) { - FfiConverterString.write(value.`id`, buf) - FfiConverterOptionalString.write(value.`alias`, buf) - FfiConverterString.write(value.`color`, buf) - FfiConverterUInt.write(value.`numPeers`, buf) - FfiConverterUInt.write(value.`numPendingChannels`, buf) - FfiConverterUInt.write(value.`numActiveChannels`, buf) - FfiConverterUInt.write(value.`numInactiveChannels`, buf) - FfiConverterString.write(value.`version`, buf) - FfiConverterString.write(value.`lightningDir`, buf) - FfiConverterUInt.write(value.`blockheight`, buf) - FfiConverterString.write(value.`network`, buf) - FfiConverterULong.write(value.`feesCollectedMsat`, buf) - } -} - - - -data class Invoice ( - var `label`: kotlin.String, - var `description`: kotlin.String, - /** - * Payment hash as lowercase hex (64 chars). - */ - var `paymentHash`: kotlin.String, - var `status`: InvoiceStatus, - var `amountMsat`: kotlin.ULong?, - var `amountReceivedMsat`: kotlin.ULong?, - var `bolt11`: kotlin.String?, - var `bolt12`: kotlin.String?, - var `paidAt`: kotlin.ULong?, - var `expiresAt`: kotlin.ULong, - /** - * Payment preimage as lowercase hex (64 chars), if the invoice has been paid. - */ - var `paymentPreimage`: kotlin.String?, - /** - * Recipient node pubkey as lowercase hex (66 chars), recovered from the bolt11. - */ - var `destinationPubkey`: kotlin.String? -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeInvoice: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): Invoice { - return Invoice( - FfiConverterString.read(buf), - FfiConverterString.read(buf), - FfiConverterString.read(buf), - FfiConverterTypeInvoiceStatus.read(buf), - FfiConverterOptionalULong.read(buf), - FfiConverterOptionalULong.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterOptionalULong.read(buf), - FfiConverterULong.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterOptionalString.read(buf), - ) - } - - override fun allocationSize(value: Invoice) = ( - FfiConverterString.allocationSize(value.`label`) + - FfiConverterString.allocationSize(value.`description`) + - FfiConverterString.allocationSize(value.`paymentHash`) + - FfiConverterTypeInvoiceStatus.allocationSize(value.`status`) + - FfiConverterOptionalULong.allocationSize(value.`amountMsat`) + - FfiConverterOptionalULong.allocationSize(value.`amountReceivedMsat`) + - FfiConverterOptionalString.allocationSize(value.`bolt11`) + - FfiConverterOptionalString.allocationSize(value.`bolt12`) + - FfiConverterOptionalULong.allocationSize(value.`paidAt`) + - FfiConverterULong.allocationSize(value.`expiresAt`) + - FfiConverterOptionalString.allocationSize(value.`paymentPreimage`) + - FfiConverterOptionalString.allocationSize(value.`destinationPubkey`) - ) - - override fun write(value: Invoice, buf: ByteBuffer) { - FfiConverterString.write(value.`label`, buf) - FfiConverterString.write(value.`description`, buf) - FfiConverterString.write(value.`paymentHash`, buf) - FfiConverterTypeInvoiceStatus.write(value.`status`, buf) - FfiConverterOptionalULong.write(value.`amountMsat`, buf) - FfiConverterOptionalULong.write(value.`amountReceivedMsat`, buf) - FfiConverterOptionalString.write(value.`bolt11`, buf) - FfiConverterOptionalString.write(value.`bolt12`, buf) - FfiConverterOptionalULong.write(value.`paidAt`, buf) - FfiConverterULong.write(value.`expiresAt`, buf) - FfiConverterOptionalString.write(value.`paymentPreimage`, buf) - FfiConverterOptionalString.write(value.`destinationPubkey`, buf) - } -} - - - -/** - * Details of a paid invoice. - */ -data class InvoicePaidEvent ( - /** - * Payment hash of the paid invoice as lowercase hex (64 chars). - */ - var `paymentHash`: kotlin.String, - /** - * The bolt11 invoice string. - */ - var `bolt11`: kotlin.String, - /** - * Preimage that proves payment as lowercase hex (64 chars). - */ - var `preimage`: kotlin.String, - /** - * The label assigned to the invoice. - */ - var `label`: kotlin.String, - /** - * Amount received in millisatoshis. - */ - var `amountMsat`: kotlin.ULong -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeInvoicePaidEvent: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): InvoicePaidEvent { - return InvoicePaidEvent( - FfiConverterString.read(buf), - FfiConverterString.read(buf), - FfiConverterString.read(buf), - FfiConverterString.read(buf), - FfiConverterULong.read(buf), - ) - } - - override fun allocationSize(value: InvoicePaidEvent) = ( - FfiConverterString.allocationSize(value.`paymentHash`) + - FfiConverterString.allocationSize(value.`bolt11`) + - FfiConverterString.allocationSize(value.`preimage`) + - FfiConverterString.allocationSize(value.`label`) + - FfiConverterULong.allocationSize(value.`amountMsat`) - ) - - override fun write(value: InvoicePaidEvent, buf: ByteBuffer) { - FfiConverterString.write(value.`paymentHash`, buf) - FfiConverterString.write(value.`bolt11`, buf) - FfiConverterString.write(value.`preimage`, buf) - FfiConverterString.write(value.`label`, buf) - FfiConverterULong.write(value.`amountMsat`, buf) - } -} - - - -data class ListFundsResponse ( - var `outputs`: List, - var `channels`: List -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeListFundsResponse: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): ListFundsResponse { - return ListFundsResponse( - FfiConverterSequenceTypeFundOutput.read(buf), - FfiConverterSequenceTypeFundChannel.read(buf), - ) - } - - override fun allocationSize(value: ListFundsResponse) = ( - FfiConverterSequenceTypeFundOutput.allocationSize(value.`outputs`) + - FfiConverterSequenceTypeFundChannel.allocationSize(value.`channels`) - ) - - override fun write(value: ListFundsResponse, buf: ByteBuffer) { - FfiConverterSequenceTypeFundOutput.write(value.`outputs`, buf) - FfiConverterSequenceTypeFundChannel.write(value.`channels`, buf) - } -} - - - -data class ListInvoicesResponse ( - var `invoices`: List -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeListInvoicesResponse: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): ListInvoicesResponse { - return ListInvoicesResponse( - FfiConverterSequenceTypeInvoice.read(buf), - ) - } - - override fun allocationSize(value: ListInvoicesResponse) = ( - FfiConverterSequenceTypeInvoice.allocationSize(value.`invoices`) - ) - - override fun write(value: ListInvoicesResponse, buf: ByteBuffer) { - FfiConverterSequenceTypeInvoice.write(value.`invoices`, buf) - } -} - - - -data class ListPaymentsRequest ( - /** - * Filter by payment type (Sent, Received). None or empty = all. - */ - var `filters`: List?, - /** - * Include only payments after this epoch timestamp (seconds). - */ - var `fromTimestamp`: kotlin.ULong?, - /** - * Include only payments before this epoch timestamp (seconds). - */ - var `toTimestamp`: kotlin.ULong?, - /** - * Include failed payments. Default: false. - */ - var `includeFailures`: kotlin.Boolean?, - /** - * Pagination offset. - */ - var `offset`: kotlin.UInt?, - /** - * Pagination limit. - */ - var `limit`: kotlin.UInt? -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeListPaymentsRequest: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): ListPaymentsRequest { - return ListPaymentsRequest( - FfiConverterOptionalSequenceTypePaymentTypeFilter.read(buf), - FfiConverterOptionalULong.read(buf), - FfiConverterOptionalULong.read(buf), - FfiConverterOptionalBoolean.read(buf), - FfiConverterOptionalUInt.read(buf), - FfiConverterOptionalUInt.read(buf), - ) - } - - override fun allocationSize(value: ListPaymentsRequest) = ( - FfiConverterOptionalSequenceTypePaymentTypeFilter.allocationSize(value.`filters`) + - FfiConverterOptionalULong.allocationSize(value.`fromTimestamp`) + - FfiConverterOptionalULong.allocationSize(value.`toTimestamp`) + - FfiConverterOptionalBoolean.allocationSize(value.`includeFailures`) + - FfiConverterOptionalUInt.allocationSize(value.`offset`) + - FfiConverterOptionalUInt.allocationSize(value.`limit`) - ) - - override fun write(value: ListPaymentsRequest, buf: ByteBuffer) { - FfiConverterOptionalSequenceTypePaymentTypeFilter.write(value.`filters`, buf) - FfiConverterOptionalULong.write(value.`fromTimestamp`, buf) - FfiConverterOptionalULong.write(value.`toTimestamp`, buf) - FfiConverterOptionalBoolean.write(value.`includeFailures`, buf) - FfiConverterOptionalUInt.write(value.`offset`, buf) - FfiConverterOptionalUInt.write(value.`limit`, buf) - } -} - - - -data class ListPaysResponse ( - var `pays`: List -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeListPaysResponse: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): ListPaysResponse { - return ListPaysResponse( - FfiConverterSequenceTypePay.read(buf), - ) - } - - override fun allocationSize(value: ListPaysResponse) = ( - FfiConverterSequenceTypePay.allocationSize(value.`pays`) - ) - - override fun write(value: ListPaysResponse, buf: ByteBuffer) { - FfiConverterSequenceTypePay.write(value.`pays`, buf) - } -} - - - -data class ListPeerChannelsResponse ( - var `channels`: List -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeListPeerChannelsResponse: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): ListPeerChannelsResponse { - return ListPeerChannelsResponse( - FfiConverterSequenceTypePeerChannel.read(buf), - ) - } - - override fun allocationSize(value: ListPeerChannelsResponse) = ( - FfiConverterSequenceTypePeerChannel.allocationSize(value.`channels`) - ) - - override fun write(value: ListPeerChannelsResponse, buf: ByteBuffer) { - FfiConverterSequenceTypePeerChannel.write(value.`channels`, buf) - } -} - - - -data class ListPeersResponse ( - var `peers`: List -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeListPeersResponse: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): ListPeersResponse { - return ListPeersResponse( - FfiConverterSequenceTypePeer.read(buf), - ) - } - - override fun allocationSize(value: ListPeersResponse) = ( - FfiConverterSequenceTypePeer.allocationSize(value.`peers`) - ) - - override fun write(value: ListPeersResponse, buf: ByteBuffer) { - FfiConverterSequenceTypePeer.write(value.`peers`, buf) - } -} - - - -/** - * Error returned by an LNURL service endpoint. - */ -data class LnUrlErrorData ( - var `reason`: kotlin.String -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeLnUrlErrorData: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): LnUrlErrorData { - return LnUrlErrorData( - FfiConverterString.read(buf), - ) - } - - override fun allocationSize(value: LnUrlErrorData) = ( - FfiConverterString.allocationSize(value.`reason`) - ) - - override fun write(value: LnUrlErrorData, buf: ByteBuffer) { - FfiConverterString.write(value.`reason`, buf) - } -} - - - -/** - * Details of a failed LNURL-pay attempt on the pay phase. - */ -data class LnUrlPayErrorData ( - /** - * Hex-encoded payment hash of the invoice the service returned. - */ - var `paymentHash`: kotlin.String, - /** - * Human-readable reason the pay attempt failed. - */ - var `reason`: kotlin.String -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeLnUrlPayErrorData: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): LnUrlPayErrorData { - return LnUrlPayErrorData( - FfiConverterString.read(buf), - FfiConverterString.read(buf), - ) - } - - override fun allocationSize(value: LnUrlPayErrorData) = ( - FfiConverterString.allocationSize(value.`paymentHash`) + - FfiConverterString.allocationSize(value.`reason`) - ) - - override fun write(value: LnUrlPayErrorData, buf: ByteBuffer) { - FfiConverterString.write(value.`paymentHash`, buf) - FfiConverterString.write(value.`reason`, buf) - } -} - - - -/** - * Request to execute an LNURL-pay flow. - * - * Combines the resolved service data with the user's chosen amount. - */ -data class LnUrlPayRequest ( - /** - * The resolved pay request data from `parse_input()`. - */ - var `data`: LnUrlPayRequestData, - /** - * Amount to pay in millisatoshis. - */ - var `amountMsat`: kotlin.ULong, - /** - * Optional comment to send with the payment. - */ - var `comment`: kotlin.String?, - /** - * When true (the default), a URL success action is rejected if its - * domain differs from the callback's domain. - * - * This is a wallet-side safety convention, not a LUD-09 requirement: - * LUD-09 does not mandate same-domain URLs, but a divergent domain - * can be used to phish users, so the SDK rejects it by default. - * Set to `Some(false)` only if you have a specific reason to trust - * cross-domain success-action URLs from this service. - */ - var `validateSuccessActionUrl`: kotlin.Boolean? -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeLnUrlPayRequest: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): LnUrlPayRequest { - return LnUrlPayRequest( - FfiConverterTypeLnUrlPayRequestData.read(buf), - FfiConverterULong.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterOptionalBoolean.read(buf), - ) - } - - override fun allocationSize(value: LnUrlPayRequest) = ( - FfiConverterTypeLnUrlPayRequestData.allocationSize(value.`data`) + - FfiConverterULong.allocationSize(value.`amountMsat`) + - FfiConverterOptionalString.allocationSize(value.`comment`) + - FfiConverterOptionalBoolean.allocationSize(value.`validateSuccessActionUrl`) - ) - - override fun write(value: LnUrlPayRequest, buf: ByteBuffer) { - FfiConverterTypeLnUrlPayRequestData.write(value.`data`, buf) - FfiConverterULong.write(value.`amountMsat`, buf) - FfiConverterOptionalString.write(value.`comment`, buf) - FfiConverterOptionalBoolean.write(value.`validateSuccessActionUrl`, buf) - } -} - - - -/** - * Data from an LNURL-pay endpoint (LUD-06). - * - * Contains the service's accepted amount range and metadata. - * Returned inside `InputType::LnUrlPay` after `parse_input` resolves - * an LNURL or Lightning Address. - */ -data class LnUrlPayRequestData ( - /** - * The callback URL to request an invoice from. - */ - var `callback`: kotlin.String, - /** - * Minimum amount the service accepts, in millisatoshis. - */ - var `minSendable`: kotlin.ULong, - /** - * Maximum amount the service accepts, in millisatoshis. - */ - var `maxSendable`: kotlin.ULong, - /** - * Raw metadata JSON string (array of `["mime", "content"]` pairs). - */ - var `metadata`: kotlin.String, - /** - * Maximum comment length the service accepts. 0 means no comments. - */ - var `commentAllowed`: kotlin.ULong, - /** - * Human-readable description extracted from metadata. - */ - var `description`: kotlin.String, - /** - * The original LNURL or lightning address that was resolved. - */ - var `lnurl`: kotlin.String -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeLnUrlPayRequestData: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): LnUrlPayRequestData { - return LnUrlPayRequestData( - FfiConverterString.read(buf), - FfiConverterULong.read(buf), - FfiConverterULong.read(buf), - FfiConverterString.read(buf), - FfiConverterULong.read(buf), - FfiConverterString.read(buf), - FfiConverterString.read(buf), - ) - } - - override fun allocationSize(value: LnUrlPayRequestData) = ( - FfiConverterString.allocationSize(value.`callback`) + - FfiConverterULong.allocationSize(value.`minSendable`) + - FfiConverterULong.allocationSize(value.`maxSendable`) + - FfiConverterString.allocationSize(value.`metadata`) + - FfiConverterULong.allocationSize(value.`commentAllowed`) + - FfiConverterString.allocationSize(value.`description`) + - FfiConverterString.allocationSize(value.`lnurl`) - ) - - override fun write(value: LnUrlPayRequestData, buf: ByteBuffer) { - FfiConverterString.write(value.`callback`, buf) - FfiConverterULong.write(value.`minSendable`, buf) - FfiConverterULong.write(value.`maxSendable`, buf) - FfiConverterString.write(value.`metadata`, buf) - FfiConverterULong.write(value.`commentAllowed`, buf) - FfiConverterString.write(value.`description`, buf) - FfiConverterString.write(value.`lnurl`, buf) - } -} - - - -/** - * Successful LNURL-pay result data. - */ -data class LnUrlPaySuccessData ( - /** - * The payment preimage (proof of payment), hex-encoded. - */ - var `paymentPreimage`: kotlin.String, - /** - * Optional success action from the service (LUD-09). - */ - var `successAction`: SuccessActionProcessed? -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeLnUrlPaySuccessData: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): LnUrlPaySuccessData { - return LnUrlPaySuccessData( - FfiConverterString.read(buf), - FfiConverterOptionalTypeSuccessActionProcessed.read(buf), - ) - } - - override fun allocationSize(value: LnUrlPaySuccessData) = ( - FfiConverterString.allocationSize(value.`paymentPreimage`) + - FfiConverterOptionalTypeSuccessActionProcessed.allocationSize(value.`successAction`) - ) - - override fun write(value: LnUrlPaySuccessData, buf: ByteBuffer) { - FfiConverterString.write(value.`paymentPreimage`, buf) - FfiConverterOptionalTypeSuccessActionProcessed.write(value.`successAction`, buf) - } -} - - - -/** - * Request to execute an LNURL-withdraw flow. - * - * Combines the resolved service data with the user's chosen amount. - */ -data class LnUrlWithdrawRequest ( - /** - * The resolved withdraw request data from `parse_input()`. - */ - var `data`: LnUrlWithdrawRequestData, - /** - * Amount to withdraw in millisatoshis. - */ - var `amountMsat`: kotlin.ULong, - /** - * Optional description for the invoice (overrides default). - */ - var `description`: kotlin.String? -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeLnUrlWithdrawRequest: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): LnUrlWithdrawRequest { - return LnUrlWithdrawRequest( - FfiConverterTypeLnUrlWithdrawRequestData.read(buf), - FfiConverterULong.read(buf), - FfiConverterOptionalString.read(buf), - ) - } - - override fun allocationSize(value: LnUrlWithdrawRequest) = ( - FfiConverterTypeLnUrlWithdrawRequestData.allocationSize(value.`data`) + - FfiConverterULong.allocationSize(value.`amountMsat`) + - FfiConverterOptionalString.allocationSize(value.`description`) - ) - - override fun write(value: LnUrlWithdrawRequest, buf: ByteBuffer) { - FfiConverterTypeLnUrlWithdrawRequestData.write(value.`data`, buf) - FfiConverterULong.write(value.`amountMsat`, buf) - FfiConverterOptionalString.write(value.`description`, buf) - } -} - - - -/** - * Data from an LNURL-withdraw endpoint (LUD-03). - * - * Contains the service's accepted withdrawal range and session key. - * Returned inside `InputType::LnUrlWithdraw` after `parse_input` - * resolves an LNURL. - */ -data class LnUrlWithdrawRequestData ( - /** - * The callback URL to submit the invoice to. - */ - var `callback`: kotlin.String, - /** - * Ephemeral secret linking this wallet session to the service. - */ - var `k1`: kotlin.String, - /** - * Default description for the invoice. - */ - var `defaultDescription`: kotlin.String, - /** - * Minimum withdrawable amount in millisatoshis. - */ - var `minWithdrawable`: kotlin.ULong, - /** - * Maximum withdrawable amount in millisatoshis. - */ - var `maxWithdrawable`: kotlin.ULong, - /** - * The original LNURL that was resolved. - */ - var `lnurl`: kotlin.String -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeLnUrlWithdrawRequestData: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): LnUrlWithdrawRequestData { - return LnUrlWithdrawRequestData( - FfiConverterString.read(buf), - FfiConverterString.read(buf), - FfiConverterString.read(buf), - FfiConverterULong.read(buf), - FfiConverterULong.read(buf), - FfiConverterString.read(buf), - ) - } - - override fun allocationSize(value: LnUrlWithdrawRequestData) = ( - FfiConverterString.allocationSize(value.`callback`) + - FfiConverterString.allocationSize(value.`k1`) + - FfiConverterString.allocationSize(value.`defaultDescription`) + - FfiConverterULong.allocationSize(value.`minWithdrawable`) + - FfiConverterULong.allocationSize(value.`maxWithdrawable`) + - FfiConverterString.allocationSize(value.`lnurl`) - ) - - override fun write(value: LnUrlWithdrawRequestData, buf: ByteBuffer) { - FfiConverterString.write(value.`callback`, buf) - FfiConverterString.write(value.`k1`, buf) - FfiConverterString.write(value.`defaultDescription`, buf) - FfiConverterULong.write(value.`minWithdrawable`, buf) - FfiConverterULong.write(value.`maxWithdrawable`, buf) - FfiConverterString.write(value.`lnurl`, buf) - } -} - - - -/** - * Successful LNURL-withdraw result data. - */ -data class LnUrlWithdrawSuccessData ( - /** - * The BOLT11 invoice that was submitted for withdrawal. - */ - var `invoice`: kotlin.String -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeLnUrlWithdrawSuccessData: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): LnUrlWithdrawSuccessData { - return LnUrlWithdrawSuccessData( - FfiConverterString.read(buf), - ) - } - - override fun allocationSize(value: LnUrlWithdrawSuccessData) = ( - FfiConverterString.allocationSize(value.`invoice`) - ) - - override fun write(value: LnUrlWithdrawSuccessData, buf: ByteBuffer) { - FfiConverterString.write(value.`invoice`, buf) - } -} - - - -/** - * A single log message from the SDK. - */ -data class LogEntry ( - var `level`: LogLevel, - var `message`: kotlin.String, - /** - * The module that produced this log (e.g. "gl_client::scheduler"). - */ - var `target`: kotlin.String, - /** - * Source file path, if the log macro recorded one. - */ - var `file`: kotlin.String?, - /** - * Source line number, if the log macro recorded one. - */ - var `line`: kotlin.UInt? -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeLogEntry: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): LogEntry { - return LogEntry( - FfiConverterTypeLogLevel.read(buf), - FfiConverterString.read(buf), - FfiConverterString.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterOptionalUInt.read(buf), - ) - } - - override fun allocationSize(value: LogEntry) = ( - FfiConverterTypeLogLevel.allocationSize(value.`level`) + - FfiConverterString.allocationSize(value.`message`) + - FfiConverterString.allocationSize(value.`target`) + - FfiConverterOptionalString.allocationSize(value.`file`) + - FfiConverterOptionalUInt.allocationSize(value.`line`) - ) - - override fun write(value: LogEntry, buf: ByteBuffer) { - FfiConverterTypeLogLevel.write(value.`level`, buf) - FfiConverterString.write(value.`message`, buf) - FfiConverterString.write(value.`target`, buf) - FfiConverterOptionalString.write(value.`file`, buf) - FfiConverterOptionalUInt.write(value.`line`, buf) - } -} - - - -/** - * A point-in-time snapshot of the node's balances, capacity, and - * connectivity. Returned by `node_state()`. - * - * All amounts are in millisatoshis (1 sat = 1000 msat). - */ -data class NodeState ( - /** - * The node's public key as a lowercase hex string (66 chars). - */ - var `id`: kotlin.String, - /** - * Latest block height the node has synced to. - */ - var `blockHeight`: kotlin.UInt, - /** - * The Bitcoin network this node is running on (e.g. "bitcoin", "regtest"). - */ - var `network`: kotlin.String, - /** - * CLN version string (e.g. "v24.11"). - */ - var `version`: kotlin.String, - /** - * Human-readable node alias, if set. - */ - var `alias`: kotlin.String?, - /** - * 3-byte RGB color of the node, as a lowercase hex string (6 chars). - */ - var `color`: kotlin.String, - /** - * Number of channels that are open and operational. These are the - * channels that contribute to `channels_balance_msat`, - * `max_payable_msat`, `total_channel_capacity_msat`, and - * `total_inbound_liquidity_msat`. - */ - var `numActiveChannels`: kotlin.UInt, - /** - * Number of channels that are being opened but not yet confirmed. - * Pending channels do not contribute to any balance or capacity - * field on this snapshot; their funds show up only after they - * transition to active. - */ - var `numPendingChannels`: kotlin.UInt, - /** - * Number of channels that are open but the peer is offline. - * Inactive channels hold balance but cannot be used for payments - * until the peer reconnects; they do not contribute to - * `max_payable_msat` or `total_inbound_liquidity_msat` (those are - * computed from the live `spendable_msat` / `receivable_msat` - * reported by CLN, which goes to zero when the peer is offline). - */ - var `numInactiveChannels`: kotlin.UInt, - /** - * Total our-side balance across all open channels, including amounts - * that protocol reserves make unspendable. - * - * This is the field a wallet's home screen should show as the - * user's "Lightning balance" — it reflects what they own off-chain, - * matching what they'd expect to see at a glance. - * - * Do **not** use this to gate a send button: some of it is locked - * in channel reserves. Use `max_payable_msat` for that. - */ - var `channelsBalanceMsat`: kotlin.ULong, - /** - * Aggregate spendable amount across all open channels. Equal to - * `channels_balance_msat - max_chan_reserve_msat`. - * - * This is the field a send screen should gate against — it is what - * the user can actually move right now over Lightning in total. - * - * Caveat: a single Lightning payment is additionally bounded by - * the largest channel's own `spendable_msat`. Reaching this full - * aggregate amount in one payment requires multi-path-payment - * support from the recipient and a working route. - */ - var `maxPayableMsat`: kotlin.ULong, - /** - * Sum of all open channel capacities (your side + remote side). - */ - var `totalChannelCapacityMsat`: kotlin.ULong, - /** - * Amount locked in protocol channel reserves, computed as - * `channels_balance_msat - max_payable_msat`. These sats are yours - * on paper but cannot be spent until the channel closes. - */ - var `maxChanReserveMsat`: kotlin.ULong, - /** - * Confirmed on-chain balance available for spending or opening channels. - */ - var `onchainBalanceMsat`: kotlin.ULong, - /** - * On-chain balance from transactions that have not yet been confirmed. - */ - var `unconfirmedOnchainBalanceMsat`: kotlin.ULong, - /** - * On-chain balance confirmed but not yet spendable (e.g. coinbase - * outputs inside the 100-block maturation window). - */ - var `immatureOnchainBalanceMsat`: kotlin.ULong, - /** - * On-chain balance locked in channels that are being closed. - * These funds will become available once the close is confirmed. - */ - var `pendingOnchainBalanceMsat`: kotlin.ULong, - /** - * Largest single Lightning payment the node can receive without - * splitting across channels. Bounded by the inbound capacity of - * the largest open channel. - */ - var `maxReceivableSinglePaymentMsat`: kotlin.ULong, - /** - * Total amount you can receive across all open channels combined. - */ - var `totalInboundLiquidityMsat`: kotlin.ULong, - /** - * Lowercase hex public keys of peers we have at least one channel - * with and are currently connected to. Peers we're connected to but - * have no channel with are not represented here; for routing-node - * use cases, query `list_peers()` directly. - */ - var `connectedChannelPeers`: List, - /** - * Unspent on-chain outputs owned by the node's wallet. Excludes - * spent outputs; includes confirmed, unconfirmed, immature, and - * reserved UTXOs (callers can filter by `status` and `reserved`). - */ - var `utxos`: List, - /** - * All non-pending on-chain balance buckets summed: - * `onchain_balance_msat + unconfirmed_onchain_balance_msat + immature_onchain_balance_msat`. - * Excludes funds locked in closing channels (`pending_onchain_balance_msat`) - * since those are not yet on-chain UTXOs. - */ - var `totalOnchainMsat`: kotlin.ULong, - /** - * Everything the user owns, summed: channel balance (including - * protocol reserves) + all on-chain buckets + funds locked in - * closing channels. The "total holdings" number a wallet home - * screen typically shows. - */ - var `totalBalanceMsat`: kotlin.ULong, - /** - * What the user can spend *right now*: - * `max_payable_msat + onchain_balance_msat`. Excludes reserves, - * unconfirmed, immature, and pending amounts. The number a - * send-money screen should gate against. - */ - var `spendableBalanceMsat`: kotlin.ULong -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeNodeState: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): NodeState { - return NodeState( - FfiConverterString.read(buf), - FfiConverterUInt.read(buf), - FfiConverterString.read(buf), - FfiConverterString.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterString.read(buf), - FfiConverterUInt.read(buf), - FfiConverterUInt.read(buf), - FfiConverterUInt.read(buf), - FfiConverterULong.read(buf), - FfiConverterULong.read(buf), - FfiConverterULong.read(buf), - FfiConverterULong.read(buf), - FfiConverterULong.read(buf), - FfiConverterULong.read(buf), - FfiConverterULong.read(buf), - FfiConverterULong.read(buf), - FfiConverterULong.read(buf), - FfiConverterULong.read(buf), - FfiConverterSequenceString.read(buf), - FfiConverterSequenceTypeFundOutput.read(buf), - FfiConverterULong.read(buf), - FfiConverterULong.read(buf), - FfiConverterULong.read(buf), - ) - } - - override fun allocationSize(value: NodeState) = ( - FfiConverterString.allocationSize(value.`id`) + - FfiConverterUInt.allocationSize(value.`blockHeight`) + - FfiConverterString.allocationSize(value.`network`) + - FfiConverterString.allocationSize(value.`version`) + - FfiConverterOptionalString.allocationSize(value.`alias`) + - FfiConverterString.allocationSize(value.`color`) + - FfiConverterUInt.allocationSize(value.`numActiveChannels`) + - FfiConverterUInt.allocationSize(value.`numPendingChannels`) + - FfiConverterUInt.allocationSize(value.`numInactiveChannels`) + - FfiConverterULong.allocationSize(value.`channelsBalanceMsat`) + - FfiConverterULong.allocationSize(value.`maxPayableMsat`) + - FfiConverterULong.allocationSize(value.`totalChannelCapacityMsat`) + - FfiConverterULong.allocationSize(value.`maxChanReserveMsat`) + - FfiConverterULong.allocationSize(value.`onchainBalanceMsat`) + - FfiConverterULong.allocationSize(value.`unconfirmedOnchainBalanceMsat`) + - FfiConverterULong.allocationSize(value.`immatureOnchainBalanceMsat`) + - FfiConverterULong.allocationSize(value.`pendingOnchainBalanceMsat`) + - FfiConverterULong.allocationSize(value.`maxReceivableSinglePaymentMsat`) + - FfiConverterULong.allocationSize(value.`totalInboundLiquidityMsat`) + - FfiConverterSequenceString.allocationSize(value.`connectedChannelPeers`) + - FfiConverterSequenceTypeFundOutput.allocationSize(value.`utxos`) + - FfiConverterULong.allocationSize(value.`totalOnchainMsat`) + - FfiConverterULong.allocationSize(value.`totalBalanceMsat`) + - FfiConverterULong.allocationSize(value.`spendableBalanceMsat`) - ) - - override fun write(value: NodeState, buf: ByteBuffer) { - FfiConverterString.write(value.`id`, buf) - FfiConverterUInt.write(value.`blockHeight`, buf) - FfiConverterString.write(value.`network`, buf) - FfiConverterString.write(value.`version`, buf) - FfiConverterOptionalString.write(value.`alias`, buf) - FfiConverterString.write(value.`color`, buf) - FfiConverterUInt.write(value.`numActiveChannels`, buf) - FfiConverterUInt.write(value.`numPendingChannels`, buf) - FfiConverterUInt.write(value.`numInactiveChannels`, buf) - FfiConverterULong.write(value.`channelsBalanceMsat`, buf) - FfiConverterULong.write(value.`maxPayableMsat`, buf) - FfiConverterULong.write(value.`totalChannelCapacityMsat`, buf) - FfiConverterULong.write(value.`maxChanReserveMsat`, buf) - FfiConverterULong.write(value.`onchainBalanceMsat`, buf) - FfiConverterULong.write(value.`unconfirmedOnchainBalanceMsat`, buf) - FfiConverterULong.write(value.`immatureOnchainBalanceMsat`, buf) - FfiConverterULong.write(value.`pendingOnchainBalanceMsat`, buf) - FfiConverterULong.write(value.`maxReceivableSinglePaymentMsat`, buf) - FfiConverterULong.write(value.`totalInboundLiquidityMsat`, buf) - FfiConverterSequenceString.write(value.`connectedChannelPeers`, buf) - FfiConverterSequenceTypeFundOutput.write(value.`utxos`, buf) - FfiConverterULong.write(value.`totalOnchainMsat`, buf) - FfiConverterULong.write(value.`totalBalanceMsat`, buf) - FfiConverterULong.write(value.`spendableBalanceMsat`, buf) - } -} - - - -/** - * On-chain fee rates in sats per virtual byte at various - * confirmation targets, derived from the connected node's view of - * network mempool conditions. Use as the basis for a fee-picker UI. - */ -data class OnchainFeeRates ( - /** - * Target the next block (~10 min). - */ - var `nextBlockSatPerVbyte`: kotlin.ULong, - /** - * ~30 minute confirmation target (3 blocks). - */ - var `halfHourSatPerVbyte`: kotlin.ULong, - /** - * ~1 hour confirmation target (6 blocks). - */ - var `hourSatPerVbyte`: kotlin.ULong, - /** - * ~1 day confirmation target (144 blocks). Suitable for - * non-urgent sweeps. - */ - var `daySatPerVbyte`: kotlin.ULong, - /** - * Network minimum relay fee. Anything below this will be - * rejected by mempool policy at broadcast time. Use as the - * lower bound of any user-facing fee slider. - */ - var `minimumRelaySatPerVbyte`: kotlin.ULong -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeOnchainFeeRates: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): OnchainFeeRates { - return OnchainFeeRates( - FfiConverterULong.read(buf), - FfiConverterULong.read(buf), - FfiConverterULong.read(buf), - FfiConverterULong.read(buf), - FfiConverterULong.read(buf), - ) - } - - override fun allocationSize(value: OnchainFeeRates) = ( - FfiConverterULong.allocationSize(value.`nextBlockSatPerVbyte`) + - FfiConverterULong.allocationSize(value.`halfHourSatPerVbyte`) + - FfiConverterULong.allocationSize(value.`hourSatPerVbyte`) + - FfiConverterULong.allocationSize(value.`daySatPerVbyte`) + - FfiConverterULong.allocationSize(value.`minimumRelaySatPerVbyte`) - ) - - override fun write(value: OnchainFeeRates, buf: ByteBuffer) { - FfiConverterULong.write(value.`nextBlockSatPerVbyte`, buf) - FfiConverterULong.write(value.`halfHourSatPerVbyte`, buf) - FfiConverterULong.write(value.`hourSatPerVbyte`, buf) - FfiConverterULong.write(value.`daySatPerVbyte`, buf) - FfiConverterULong.write(value.`minimumRelaySatPerVbyte`, buf) - } -} - - - -/** - * A pair of on-chain addresses for receiving funds. - */ -data class OnchainReceiveResponse ( - /** - * SegWit v0 (bech32) address — starts with `bc1q` on mainnet. - */ - var `bech32`: kotlin.String, - /** - * Taproot (bech32m) address — starts with `bc1p` on mainnet. - */ - var `p2tr`: kotlin.String -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeOnchainReceiveResponse: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): OnchainReceiveResponse { - return OnchainReceiveResponse( - FfiConverterString.read(buf), - FfiConverterString.read(buf), - ) - } - - override fun allocationSize(value: OnchainReceiveResponse) = ( - FfiConverterString.allocationSize(value.`bech32`) + - FfiConverterString.allocationSize(value.`p2tr`) - ) - - override fun write(value: OnchainReceiveResponse, buf: ByteBuffer) { - FfiConverterString.write(value.`bech32`, buf) - FfiConverterString.write(value.`p2tr`, buf) - } -} - - - -/** - * Result of an on-chain send. The transaction has already been broadcast. - */ -data class OnchainSendResponse ( - /** - * The raw signed transaction bytes. - */ - var `tx`: kotlin.ByteArray, - /** - * The transaction id as lowercase hex (64 chars). - */ - var `txid`: kotlin.String, - /** - * The transaction as a Partially Signed Bitcoin Transaction string. - */ - var `psbt`: kotlin.String -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeOnchainSendResponse: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): OnchainSendResponse { - return OnchainSendResponse( - FfiConverterByteArray.read(buf), - FfiConverterString.read(buf), - FfiConverterString.read(buf), - ) - } - - override fun allocationSize(value: OnchainSendResponse) = ( - FfiConverterByteArray.allocationSize(value.`tx`) + - FfiConverterString.allocationSize(value.`txid`) + - FfiConverterString.allocationSize(value.`psbt`) - ) - - override fun write(value: OnchainSendResponse, buf: ByteBuffer) { - FfiConverterByteArray.write(value.`tx`, buf) - FfiConverterString.write(value.`txid`, buf) - FfiConverterString.write(value.`psbt`, buf) - } -} - - - -/** - * A specific on-chain output, identified by its outpoint. - */ -data class Outpoint ( - /** - * Transaction id as lowercase hex (64 chars). - */ - var `txid`: kotlin.String, - /** - * Output index within that transaction. - */ - var `vout`: kotlin.UInt -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeOutpoint: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): Outpoint { - return Outpoint( - FfiConverterString.read(buf), - FfiConverterUInt.read(buf), - ) - } - - override fun allocationSize(value: Outpoint) = ( - FfiConverterString.allocationSize(value.`txid`) + - FfiConverterUInt.allocationSize(value.`vout`) - ) - - override fun write(value: Outpoint, buf: ByteBuffer) { - FfiConverterString.write(value.`txid`, buf) - FfiConverterUInt.write(value.`vout`, buf) - } -} - - - -/** - * Parsed BOLT11 invoice with extracted fields. - */ -data class ParsedInvoice ( - /** - * The original invoice string. - */ - var `bolt11`: kotlin.String, - /** - * Recipient public key as lowercase hex (66 chars), recovered from the invoice signature. - */ - var `payeePubkey`: kotlin.String?, - /** - * Payment hash as lowercase hex (64 chars) identifying this payment. - */ - var `paymentHash`: kotlin.String, - /** - * Invoice description. None if the invoice uses a description hash. - */ - var `description`: kotlin.String?, - /** - * Requested amount in millisatoshis. None for "any amount" invoices. - */ - var `amountMsat`: kotlin.ULong?, - /** - * Seconds from creation until the invoice expires. - */ - var `expiry`: kotlin.ULong, - /** - * Unix timestamp (seconds) when the invoice was created. - */ - var `timestamp`: kotlin.ULong -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeParsedInvoice: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): ParsedInvoice { - return ParsedInvoice( - FfiConverterString.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterString.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterOptionalULong.read(buf), - FfiConverterULong.read(buf), - FfiConverterULong.read(buf), - ) - } - - override fun allocationSize(value: ParsedInvoice) = ( - FfiConverterString.allocationSize(value.`bolt11`) + - FfiConverterOptionalString.allocationSize(value.`payeePubkey`) + - FfiConverterString.allocationSize(value.`paymentHash`) + - FfiConverterOptionalString.allocationSize(value.`description`) + - FfiConverterOptionalULong.allocationSize(value.`amountMsat`) + - FfiConverterULong.allocationSize(value.`expiry`) + - FfiConverterULong.allocationSize(value.`timestamp`) - ) - - override fun write(value: ParsedInvoice, buf: ByteBuffer) { - FfiConverterString.write(value.`bolt11`, buf) - FfiConverterOptionalString.write(value.`payeePubkey`, buf) - FfiConverterString.write(value.`paymentHash`, buf) - FfiConverterOptionalString.write(value.`description`, buf) - FfiConverterOptionalULong.write(value.`amountMsat`, buf) - FfiConverterULong.write(value.`expiry`, buf) - FfiConverterULong.write(value.`timestamp`, buf) - } -} - - - -data class Pay ( - /** - * Payment hash as lowercase hex (64 chars). - */ - var `paymentHash`: kotlin.String, - var `status`: PayStatus, - /** - * Recipient node pubkey as lowercase hex (66 chars), if known. - */ - var `destinationPubkey`: kotlin.String?, - var `amountMsat`: kotlin.ULong?, - var `amountSentMsat`: kotlin.ULong?, - var `label`: kotlin.String?, - var `bolt11`: kotlin.String?, - var `description`: kotlin.String?, - var `bolt12`: kotlin.String?, - /** - * Payment preimage as lowercase hex (64 chars), if the payment completed. - */ - var `preimage`: kotlin.String?, - var `createdAt`: kotlin.ULong, - var `completedAt`: kotlin.ULong?, - var `numberOfParts`: kotlin.ULong? -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypePay: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): Pay { - return Pay( - FfiConverterString.read(buf), - FfiConverterTypePayStatus.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterOptionalULong.read(buf), - FfiConverterOptionalULong.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterULong.read(buf), - FfiConverterOptionalULong.read(buf), - FfiConverterOptionalULong.read(buf), - ) - } - - override fun allocationSize(value: Pay) = ( - FfiConverterString.allocationSize(value.`paymentHash`) + - FfiConverterTypePayStatus.allocationSize(value.`status`) + - FfiConverterOptionalString.allocationSize(value.`destinationPubkey`) + - FfiConverterOptionalULong.allocationSize(value.`amountMsat`) + - FfiConverterOptionalULong.allocationSize(value.`amountSentMsat`) + - FfiConverterOptionalString.allocationSize(value.`label`) + - FfiConverterOptionalString.allocationSize(value.`bolt11`) + - FfiConverterOptionalString.allocationSize(value.`description`) + - FfiConverterOptionalString.allocationSize(value.`bolt12`) + - FfiConverterOptionalString.allocationSize(value.`preimage`) + - FfiConverterULong.allocationSize(value.`createdAt`) + - FfiConverterOptionalULong.allocationSize(value.`completedAt`) + - FfiConverterOptionalULong.allocationSize(value.`numberOfParts`) - ) - - override fun write(value: Pay, buf: ByteBuffer) { - FfiConverterString.write(value.`paymentHash`, buf) - FfiConverterTypePayStatus.write(value.`status`, buf) - FfiConverterOptionalString.write(value.`destinationPubkey`, buf) - FfiConverterOptionalULong.write(value.`amountMsat`, buf) - FfiConverterOptionalULong.write(value.`amountSentMsat`, buf) - FfiConverterOptionalString.write(value.`label`, buf) - FfiConverterOptionalString.write(value.`bolt11`, buf) - FfiConverterOptionalString.write(value.`description`, buf) - FfiConverterOptionalString.write(value.`bolt12`, buf) - FfiConverterOptionalString.write(value.`preimage`, buf) - FfiConverterULong.write(value.`createdAt`, buf) - FfiConverterOptionalULong.write(value.`completedAt`, buf) - FfiConverterOptionalULong.write(value.`numberOfParts`, buf) - } -} - - - -data class Payment ( - var `id`: kotlin.String, - var `paymentType`: PaymentType, - var `paymentTime`: kotlin.ULong, - var `amountMsat`: kotlin.ULong, - var `feeMsat`: kotlin.ULong, - var `status`: PaymentStatus, - var `description`: kotlin.String?, - var `bolt11`: kotlin.String?, - /** - * Payment preimage as lowercase hex (64 chars), when known. - */ - var `preimage`: kotlin.String?, - /** - * Pubkey of the counterparty in the payment, as lowercase hex - * (66 chars). - * - * For `PaymentType::Sent`: the recipient node we paid (when CLN - * reports it). - * - * For `PaymentType::Received`: always `None`. Lightning's privacy - * model does not reveal the sender's pubkey to the recipient — the - * HTLC arrives via one of our channel peers, but that peer is - * usually just a router, not the original payer. The only pubkey - * derivable from a paid invoice is the *payee* (i.e. our own - * node), which is uninteresting to display per-row. - */ - var `destination`: kotlin.String? -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypePayment: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): Payment { - return Payment( - FfiConverterString.read(buf), - FfiConverterTypePaymentType.read(buf), - FfiConverterULong.read(buf), - FfiConverterULong.read(buf), - FfiConverterULong.read(buf), - FfiConverterTypePaymentStatus.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterOptionalString.read(buf), - ) - } - - override fun allocationSize(value: Payment) = ( - FfiConverterString.allocationSize(value.`id`) + - FfiConverterTypePaymentType.allocationSize(value.`paymentType`) + - FfiConverterULong.allocationSize(value.`paymentTime`) + - FfiConverterULong.allocationSize(value.`amountMsat`) + - FfiConverterULong.allocationSize(value.`feeMsat`) + - FfiConverterTypePaymentStatus.allocationSize(value.`status`) + - FfiConverterOptionalString.allocationSize(value.`description`) + - FfiConverterOptionalString.allocationSize(value.`bolt11`) + - FfiConverterOptionalString.allocationSize(value.`preimage`) + - FfiConverterOptionalString.allocationSize(value.`destination`) - ) - - override fun write(value: Payment, buf: ByteBuffer) { - FfiConverterString.write(value.`id`, buf) - FfiConverterTypePaymentType.write(value.`paymentType`, buf) - FfiConverterULong.write(value.`paymentTime`, buf) - FfiConverterULong.write(value.`amountMsat`, buf) - FfiConverterULong.write(value.`feeMsat`, buf) - FfiConverterTypePaymentStatus.write(value.`status`, buf) - FfiConverterOptionalString.write(value.`description`, buf) - FfiConverterOptionalString.write(value.`bolt11`, buf) - FfiConverterOptionalString.write(value.`preimage`, buf) - FfiConverterOptionalString.write(value.`destination`, buf) - } -} - - - -data class Peer ( - /** - * Peer node public key as lowercase hex (66 chars). - */ - var `id`: kotlin.String, - var `connected`: kotlin.Boolean, - var `numChannels`: kotlin.UInt?, - var `netaddr`: List, - var `remoteAddr`: kotlin.String?, - var `features`: kotlin.ByteArray? -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypePeer: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): Peer { - return Peer( - FfiConverterString.read(buf), - FfiConverterBoolean.read(buf), - FfiConverterOptionalUInt.read(buf), - FfiConverterSequenceString.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterOptionalByteArray.read(buf), - ) - } - - override fun allocationSize(value: Peer) = ( - FfiConverterString.allocationSize(value.`id`) + - FfiConverterBoolean.allocationSize(value.`connected`) + - FfiConverterOptionalUInt.allocationSize(value.`numChannels`) + - FfiConverterSequenceString.allocationSize(value.`netaddr`) + - FfiConverterOptionalString.allocationSize(value.`remoteAddr`) + - FfiConverterOptionalByteArray.allocationSize(value.`features`) - ) - - override fun write(value: Peer, buf: ByteBuffer) { - FfiConverterString.write(value.`id`, buf) - FfiConverterBoolean.write(value.`connected`, buf) - FfiConverterOptionalUInt.write(value.`numChannels`, buf) - FfiConverterSequenceString.write(value.`netaddr`, buf) - FfiConverterOptionalString.write(value.`remoteAddr`, buf) - FfiConverterOptionalByteArray.write(value.`features`, buf) - } -} - - - -data class PeerChannel ( - /** - * Peer node public key as lowercase hex (66 chars). - */ - var `peerId`: kotlin.String, - var `peerConnected`: kotlin.Boolean, - var `state`: ChannelState, - var `shortChannelId`: kotlin.String?, - /** - * Channel id as lowercase hex (64 chars). - */ - var `channelId`: kotlin.String?, - /** - * Funding transaction id as lowercase hex (64 chars). - */ - var `fundingTxid`: kotlin.String?, - var `fundingOutnum`: kotlin.UInt?, - var `toUsMsat`: kotlin.ULong?, - var `totalMsat`: kotlin.ULong?, - var `spendableMsat`: kotlin.ULong?, - var `receivableMsat`: kotlin.ULong?, - /** - * Which side initiated the close, if the channel is closing or closed. - */ - var `closer`: ChannelSide?, - /** - * Human-readable status strings from CLN, ordered oldest to newest. - * For a channel in `Onchain` state, the last entry indicates whether - * our payout is still timelocked (`DELAYED_OUTPUT_TO_US`) or already - * available in the on-chain balance. - */ - var `status`: List -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypePeerChannel: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): PeerChannel { - return PeerChannel( - FfiConverterString.read(buf), - FfiConverterBoolean.read(buf), - FfiConverterTypeChannelState.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterOptionalUInt.read(buf), - FfiConverterOptionalULong.read(buf), - FfiConverterOptionalULong.read(buf), - FfiConverterOptionalULong.read(buf), - FfiConverterOptionalULong.read(buf), - FfiConverterOptionalTypeChannelSide.read(buf), - FfiConverterSequenceString.read(buf), - ) - } - - override fun allocationSize(value: PeerChannel) = ( - FfiConverterString.allocationSize(value.`peerId`) + - FfiConverterBoolean.allocationSize(value.`peerConnected`) + - FfiConverterTypeChannelState.allocationSize(value.`state`) + - FfiConverterOptionalString.allocationSize(value.`shortChannelId`) + - FfiConverterOptionalString.allocationSize(value.`channelId`) + - FfiConverterOptionalString.allocationSize(value.`fundingTxid`) + - FfiConverterOptionalUInt.allocationSize(value.`fundingOutnum`) + - FfiConverterOptionalULong.allocationSize(value.`toUsMsat`) + - FfiConverterOptionalULong.allocationSize(value.`totalMsat`) + - FfiConverterOptionalULong.allocationSize(value.`spendableMsat`) + - FfiConverterOptionalULong.allocationSize(value.`receivableMsat`) + - FfiConverterOptionalTypeChannelSide.allocationSize(value.`closer`) + - FfiConverterSequenceString.allocationSize(value.`status`) - ) - - override fun write(value: PeerChannel, buf: ByteBuffer) { - FfiConverterString.write(value.`peerId`, buf) - FfiConverterBoolean.write(value.`peerConnected`, buf) - FfiConverterTypeChannelState.write(value.`state`, buf) - FfiConverterOptionalString.write(value.`shortChannelId`, buf) - FfiConverterOptionalString.write(value.`channelId`, buf) - FfiConverterOptionalString.write(value.`fundingTxid`, buf) - FfiConverterOptionalUInt.write(value.`fundingOutnum`, buf) - FfiConverterOptionalULong.write(value.`toUsMsat`, buf) - FfiConverterOptionalULong.write(value.`totalMsat`, buf) - FfiConverterOptionalULong.write(value.`spendableMsat`, buf) - FfiConverterOptionalULong.write(value.`receivableMsat`, buf) - FfiConverterOptionalTypeChannelSide.write(value.`closer`, buf) - FfiConverterSequenceString.write(value.`status`, buf) - } -} - - - -/** - * Preview of an on-chain send: the inputs CLN would select at the - * given fee rate, the resulting fee, and the amount the recipient - * would receive. Inputs are NOT reserved — the wallet is free to - * spend them via other paths until `onchain_send` actually broadcasts. - * - * Pass `utxos` and `sat_per_vbyte` back to `onchain_send` to broadcast - * with identical inputs and fee. - * - * Amounts are in satoshis: on-chain transactions cannot carry sub-sat - * precision, so msat denomination would be misleading here. - */ -data class PreparedOnchainSend ( - /** - * UTXOs that would be spent, in selection order. - */ - var `utxos`: List, - /** - * Sum of all input UTXO values, in satoshis. - */ - var `totalInputSat`: kotlin.ULong, - /** - * Fee that would be paid, in satoshis. - */ - var `feeSat`: kotlin.ULong, - /** - * Amount the recipient would receive, in satoshis. - * For a sweep ("all") this equals `total_input_sat - fee_sat`. - * For a fixed amount this equals the requested amount. - */ - var `recipientSat`: kotlin.ULong, - /** - * Effective fee rate (sat per virtual byte) the node used to - * compute this preview. Equal to the caller's `sat_per_vbyte` if - * one was supplied; otherwise the rate the node picked at - * "normal" priority. Pass this back to `onchain_send` to - * reproduce the previewed fee. - */ - var `satPerVbyte`: kotlin.UInt -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypePreparedOnchainSend: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): PreparedOnchainSend { - return PreparedOnchainSend( - FfiConverterSequenceTypeOutpoint.read(buf), - FfiConverterULong.read(buf), - FfiConverterULong.read(buf), - FfiConverterULong.read(buf), - FfiConverterUInt.read(buf), - ) - } - - override fun allocationSize(value: PreparedOnchainSend) = ( - FfiConverterSequenceTypeOutpoint.allocationSize(value.`utxos`) + - FfiConverterULong.allocationSize(value.`totalInputSat`) + - FfiConverterULong.allocationSize(value.`feeSat`) + - FfiConverterULong.allocationSize(value.`recipientSat`) + - FfiConverterUInt.allocationSize(value.`satPerVbyte`) - ) - - override fun write(value: PreparedOnchainSend, buf: ByteBuffer) { - FfiConverterSequenceTypeOutpoint.write(value.`utxos`, buf) - FfiConverterULong.write(value.`totalInputSat`, buf) - FfiConverterULong.write(value.`feeSat`, buf) - FfiConverterULong.write(value.`recipientSat`, buf) - FfiConverterUInt.write(value.`satPerVbyte`, buf) - } -} - - - -data class ReceiveResponse ( - var `bolt11`: kotlin.String, - /** - * The fee charged by the LSP for opening a JIT channel, in - * millisatoshi. This is 0 if no JIT channel was needed. - */ - var `openingFeeMsat`: kotlin.ULong -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeReceiveResponse: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): ReceiveResponse { - return ReceiveResponse( - FfiConverterString.read(buf), - FfiConverterULong.read(buf), - ) - } - - override fun allocationSize(value: ReceiveResponse) = ( - FfiConverterString.allocationSize(value.`bolt11`) + - FfiConverterULong.allocationSize(value.`openingFeeMsat`) - ) - - override fun write(value: ReceiveResponse, buf: ByteBuffer) { - FfiConverterString.write(value.`bolt11`, buf) - FfiConverterULong.write(value.`openingFeeMsat`, buf) - } -} - - - -data class SendResponse ( - var `status`: PayStatus, - /** - * Payment preimage (proof of payment) as lowercase hex (64 chars). - */ - var `preimage`: kotlin.String, - /** - * Payment hash as lowercase hex (64 chars). - */ - var `paymentHash`: kotlin.String, - /** - * Recipient node pubkey as lowercase hex (66 chars), if known. - */ - var `destinationPubkey`: kotlin.String?, - var `amountMsat`: kotlin.ULong, - var `amountSentMsat`: kotlin.ULong, - var `parts`: kotlin.UInt -) { - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeSendResponse: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): SendResponse { - return SendResponse( - FfiConverterTypePayStatus.read(buf), - FfiConverterString.read(buf), - FfiConverterString.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterULong.read(buf), - FfiConverterULong.read(buf), - FfiConverterUInt.read(buf), - ) - } - - override fun allocationSize(value: SendResponse) = ( - FfiConverterTypePayStatus.allocationSize(value.`status`) + - FfiConverterString.allocationSize(value.`preimage`) + - FfiConverterString.allocationSize(value.`paymentHash`) + - FfiConverterOptionalString.allocationSize(value.`destinationPubkey`) + - FfiConverterULong.allocationSize(value.`amountMsat`) + - FfiConverterULong.allocationSize(value.`amountSentMsat`) + - FfiConverterUInt.allocationSize(value.`parts`) - ) - - override fun write(value: SendResponse, buf: ByteBuffer) { - FfiConverterTypePayStatus.write(value.`status`, buf) - FfiConverterString.write(value.`preimage`, buf) - FfiConverterString.write(value.`paymentHash`, buf) - FfiConverterOptionalString.write(value.`destinationPubkey`, buf) - FfiConverterULong.write(value.`amountMsat`, buf) - FfiConverterULong.write(value.`amountSentMsat`, buf) - FfiConverterUInt.write(value.`parts`, buf) - } -} - - - -/** - * Which side of a channel performed a given action (e.g. initiated close). - */ - -enum class ChannelSide { - - LOCAL, - REMOTE; - companion object -} - - -/** - * @suppress - */ -public object FfiConverterTypeChannelSide: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer) = try { - ChannelSide.values()[buf.getInt() - 1] - } catch (e: IndexOutOfBoundsException) { - throw RuntimeException("invalid enum value, something is very wrong!!", e) - } - - override fun allocationSize(value: ChannelSide) = 4UL - - override fun write(value: ChannelSide, buf: ByteBuffer) { - buf.putInt(value.ordinal + 1) - } -} - - - - - - -enum class ChannelState { - - OPENINGD, - CHANNELD_AWAITING_LOCKIN, - CHANNELD_NORMAL, - CHANNELD_SHUTTING_DOWN, - CLOSINGD_SIGEXCHANGE, - CLOSINGD_COMPLETE, - AWAITING_UNILATERAL, - FUNDING_SPEND_SEEN, - ONCHAIN, - DUALOPEND_OPEN_INIT, - DUALOPEND_AWAITING_LOCKIN, - DUALOPEND_OPEN_COMMITTED, - DUALOPEND_OPEN_COMMIT_READY, - /** - * A state reported by the node that this SDK doesn't recognize. - * Returned when CLN introduces a new channel state after this SDK - * was built. Treated as neither open nor closing by balance math. - */ - UNKNOWN; - companion object -} - - -/** - * @suppress - */ -public object FfiConverterTypeChannelState: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer) = try { - ChannelState.values()[buf.getInt() - 1] - } catch (e: IndexOutOfBoundsException) { - throw RuntimeException("invalid enum value, something is very wrong!!", e) - } - - override fun allocationSize(value: ChannelState) = 4UL - - override fun write(value: ChannelState, buf: ByteBuffer) { - buf.putInt(value.ordinal + 1) - } -} - - - - - - - -sealed class Exception: kotlin.Exception() { - - class DuplicateNode( - - val `code`: kotlin.Int, - - val `msg`: kotlin.String, - - val `values`: Map - ) : Exception() { - override val message - get() = "code=${ `code` }, msg=${ `msg` }, values=${ `values` }" - } - - class NoSuchNode( - - val `code`: kotlin.Int, - - val `msg`: kotlin.String, - - val `values`: Map - ) : Exception() { - override val message - get() = "code=${ `code` }, msg=${ `msg` }, values=${ `values` }" - } - - class UnparseableCreds( - - val `code`: kotlin.Int, - - val `msg`: kotlin.String, - - val `values`: Map - ) : Exception() { - override val message - get() = "code=${ `code` }, msg=${ `msg` }, values=${ `values` }" - } - - class PhraseCorrupted( - - val `code`: kotlin.Int, - - val `msg`: kotlin.String, - - val `values`: Map - ) : Exception() { - override val message - get() = "code=${ `code` }, msg=${ `msg` }, values=${ `values` }" - } - - class Rpc( - - val `code`: kotlin.Int, - - val `msg`: kotlin.String, - - val `values`: Map - ) : Exception() { - override val message - get() = "code=${ `code` }, msg=${ `msg` }, values=${ `values` }" - } - - class Argument( - - val `code`: kotlin.Int, - - val `msg`: kotlin.String, - - val `values`: Map - ) : Exception() { - override val message - get() = "code=${ `code` }, msg=${ `msg` }, values=${ `values` }" - } - - class Other( - - val `code`: kotlin.Int, - - val `msg`: kotlin.String, - - val `values`: Map - ) : Exception() { - override val message - get() = "code=${ `code` }, msg=${ `msg` }, values=${ `values` }" - } - - - companion object ErrorHandler : UniffiRustCallStatusErrorHandler { - override fun lift(error_buf: RustBuffer.ByValue): Exception = FfiConverterTypeError.lift(error_buf) - } - - -} - -/** - * @suppress - */ -public object FfiConverterTypeError : FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): Exception { - - - return when(buf.getInt()) { - 1 -> Exception.DuplicateNode( - FfiConverterInt.read(buf), - FfiConverterString.read(buf), - FfiConverterMapStringString.read(buf), - ) - 2 -> Exception.NoSuchNode( - FfiConverterInt.read(buf), - FfiConverterString.read(buf), - FfiConverterMapStringString.read(buf), - ) - 3 -> Exception.UnparseableCreds( - FfiConverterInt.read(buf), - FfiConverterString.read(buf), - FfiConverterMapStringString.read(buf), - ) - 4 -> Exception.PhraseCorrupted( - FfiConverterInt.read(buf), - FfiConverterString.read(buf), - FfiConverterMapStringString.read(buf), - ) - 5 -> Exception.Rpc( - FfiConverterInt.read(buf), - FfiConverterString.read(buf), - FfiConverterMapStringString.read(buf), - ) - 6 -> Exception.Argument( - FfiConverterInt.read(buf), - FfiConverterString.read(buf), - FfiConverterMapStringString.read(buf), - ) - 7 -> Exception.Other( - FfiConverterInt.read(buf), - FfiConverterString.read(buf), - FfiConverterMapStringString.read(buf), - ) - else -> throw RuntimeException("invalid error enum value, something is very wrong!!") - } - } - - override fun allocationSize(value: Exception): ULong { - return when(value) { - is Exception.DuplicateNode -> ( - // Add the size for the Int that specifies the variant plus the size needed for all fields - 4UL - + FfiConverterInt.allocationSize(value.`code`) - + FfiConverterString.allocationSize(value.`msg`) - + FfiConverterMapStringString.allocationSize(value.`values`) - ) - is Exception.NoSuchNode -> ( - // Add the size for the Int that specifies the variant plus the size needed for all fields - 4UL - + FfiConverterInt.allocationSize(value.`code`) - + FfiConverterString.allocationSize(value.`msg`) - + FfiConverterMapStringString.allocationSize(value.`values`) - ) - is Exception.UnparseableCreds -> ( - // Add the size for the Int that specifies the variant plus the size needed for all fields - 4UL - + FfiConverterInt.allocationSize(value.`code`) - + FfiConverterString.allocationSize(value.`msg`) - + FfiConverterMapStringString.allocationSize(value.`values`) - ) - is Exception.PhraseCorrupted -> ( - // Add the size for the Int that specifies the variant plus the size needed for all fields - 4UL - + FfiConverterInt.allocationSize(value.`code`) - + FfiConverterString.allocationSize(value.`msg`) - + FfiConverterMapStringString.allocationSize(value.`values`) - ) - is Exception.Rpc -> ( - // Add the size for the Int that specifies the variant plus the size needed for all fields - 4UL - + FfiConverterInt.allocationSize(value.`code`) - + FfiConverterString.allocationSize(value.`msg`) - + FfiConverterMapStringString.allocationSize(value.`values`) - ) - is Exception.Argument -> ( - // Add the size for the Int that specifies the variant plus the size needed for all fields - 4UL - + FfiConverterInt.allocationSize(value.`code`) - + FfiConverterString.allocationSize(value.`msg`) - + FfiConverterMapStringString.allocationSize(value.`values`) - ) - is Exception.Other -> ( - // Add the size for the Int that specifies the variant plus the size needed for all fields - 4UL - + FfiConverterInt.allocationSize(value.`code`) - + FfiConverterString.allocationSize(value.`msg`) - + FfiConverterMapStringString.allocationSize(value.`values`) - ) - } - } - - override fun write(value: Exception, buf: ByteBuffer) { - when(value) { - is Exception.DuplicateNode -> { - buf.putInt(1) - FfiConverterInt.write(value.`code`, buf) - FfiConverterString.write(value.`msg`, buf) - FfiConverterMapStringString.write(value.`values`, buf) - Unit - } - is Exception.NoSuchNode -> { - buf.putInt(2) - FfiConverterInt.write(value.`code`, buf) - FfiConverterString.write(value.`msg`, buf) - FfiConverterMapStringString.write(value.`values`, buf) - Unit - } - is Exception.UnparseableCreds -> { - buf.putInt(3) - FfiConverterInt.write(value.`code`, buf) - FfiConverterString.write(value.`msg`, buf) - FfiConverterMapStringString.write(value.`values`, buf) - Unit - } - is Exception.PhraseCorrupted -> { - buf.putInt(4) - FfiConverterInt.write(value.`code`, buf) - FfiConverterString.write(value.`msg`, buf) - FfiConverterMapStringString.write(value.`values`, buf) - Unit - } - is Exception.Rpc -> { - buf.putInt(5) - FfiConverterInt.write(value.`code`, buf) - FfiConverterString.write(value.`msg`, buf) - FfiConverterMapStringString.write(value.`values`, buf) - Unit - } - is Exception.Argument -> { - buf.putInt(6) - FfiConverterInt.write(value.`code`, buf) - FfiConverterString.write(value.`msg`, buf) - FfiConverterMapStringString.write(value.`values`, buf) - Unit - } - is Exception.Other -> { - buf.putInt(7) - FfiConverterInt.write(value.`code`, buf) - FfiConverterString.write(value.`msg`, buf) - FfiConverterMapStringString.write(value.`values`, buf) - Unit - } - }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } - } - -} - - - - -enum class InvoiceStatus { - - UNPAID, - PAID, - EXPIRED; - companion object -} - - -/** - * @suppress - */ -public object FfiConverterTypeInvoiceStatus: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer) = try { - InvoiceStatus.values()[buf.getInt() - 1] - } catch (e: IndexOutOfBoundsException) { - throw RuntimeException("invalid enum value, something is very wrong!!", e) - } - - override fun allocationSize(value: InvoiceStatus) = 4UL - - override fun write(value: InvoiceStatus, buf: ByteBuffer) { - buf.putInt(value.ordinal + 1) - } -} - - - - - -/** - * Index field used by CLN's paginated list RPCs. - */ - -enum class ListIndex { - - CREATED, - UPDATED; - companion object -} - - -/** - * @suppress - */ -public object FfiConverterTypeListIndex: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer) = try { - ListIndex.values()[buf.getInt() - 1] - } catch (e: IndexOutOfBoundsException) { - throw RuntimeException("invalid enum value, something is very wrong!!", e) - } - - override fun allocationSize(value: ListIndex) = 4UL - - override fun write(value: ListIndex, buf: ByteBuffer) { - buf.putInt(value.ordinal + 1) - } -} - - - - - -/** - * Result of an LNURL-pay operation. - */ -sealed class LnUrlPayResult { - - /** - * Payment succeeded. - */ - data class EndpointSuccess( - val `data`: LnUrlPaySuccessData) : LnUrlPayResult() { - companion object - } - - /** - * The LNURL service returned an error before the invoice was paid. - */ - data class EndpointError( - val `data`: LnUrlErrorData) : LnUrlPayResult() { - companion object - } - - /** - * The invoice was fetched successfully but paying it failed. - */ - data class PayError( - val `data`: LnUrlPayErrorData) : LnUrlPayResult() { - companion object - } - - - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeLnUrlPayResult : FfiConverterRustBuffer{ - override fun read(buf: ByteBuffer): LnUrlPayResult { - return when(buf.getInt()) { - 1 -> LnUrlPayResult.EndpointSuccess( - FfiConverterTypeLnUrlPaySuccessData.read(buf), - ) - 2 -> LnUrlPayResult.EndpointError( - FfiConverterTypeLnUrlErrorData.read(buf), - ) - 3 -> LnUrlPayResult.PayError( - FfiConverterTypeLnUrlPayErrorData.read(buf), - ) - else -> throw RuntimeException("invalid enum value, something is very wrong!!") - } - } - - override fun allocationSize(value: LnUrlPayResult) = when(value) { - is LnUrlPayResult.EndpointSuccess -> { - // Add the size for the Int that specifies the variant plus the size needed for all fields - ( - 4UL - + FfiConverterTypeLnUrlPaySuccessData.allocationSize(value.`data`) - ) - } - is LnUrlPayResult.EndpointError -> { - // Add the size for the Int that specifies the variant plus the size needed for all fields - ( - 4UL - + FfiConverterTypeLnUrlErrorData.allocationSize(value.`data`) - ) - } - is LnUrlPayResult.PayError -> { - // Add the size for the Int that specifies the variant plus the size needed for all fields - ( - 4UL - + FfiConverterTypeLnUrlPayErrorData.allocationSize(value.`data`) - ) - } - } - - override fun write(value: LnUrlPayResult, buf: ByteBuffer) { - when(value) { - is LnUrlPayResult.EndpointSuccess -> { - buf.putInt(1) - FfiConverterTypeLnUrlPaySuccessData.write(value.`data`, buf) - Unit - } - is LnUrlPayResult.EndpointError -> { - buf.putInt(2) - FfiConverterTypeLnUrlErrorData.write(value.`data`, buf) - Unit - } - is LnUrlPayResult.PayError -> { - buf.putInt(3) - FfiConverterTypeLnUrlPayErrorData.write(value.`data`, buf) - Unit - } - }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } - } -} - - - - - -/** - * Result of an LNURL-withdraw operation. - */ -sealed class LnUrlWithdrawResult { - - /** - * The service accepted our invoice and will pay it. - */ - data class Ok( - val `data`: LnUrlWithdrawSuccessData) : LnUrlWithdrawResult() { - companion object - } - - /** - * The LNURL service returned an error. - */ - data class ErrorStatus( - val `data`: LnUrlErrorData) : LnUrlWithdrawResult() { - companion object - } - - - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeLnUrlWithdrawResult : FfiConverterRustBuffer{ - override fun read(buf: ByteBuffer): LnUrlWithdrawResult { - return when(buf.getInt()) { - 1 -> LnUrlWithdrawResult.Ok( - FfiConverterTypeLnUrlWithdrawSuccessData.read(buf), - ) - 2 -> LnUrlWithdrawResult.ErrorStatus( - FfiConverterTypeLnUrlErrorData.read(buf), - ) - else -> throw RuntimeException("invalid enum value, something is very wrong!!") - } - } - - override fun allocationSize(value: LnUrlWithdrawResult) = when(value) { - is LnUrlWithdrawResult.Ok -> { - // Add the size for the Int that specifies the variant plus the size needed for all fields - ( - 4UL - + FfiConverterTypeLnUrlWithdrawSuccessData.allocationSize(value.`data`) - ) - } - is LnUrlWithdrawResult.ErrorStatus -> { - // Add the size for the Int that specifies the variant plus the size needed for all fields - ( - 4UL - + FfiConverterTypeLnUrlErrorData.allocationSize(value.`data`) - ) - } - } - - override fun write(value: LnUrlWithdrawResult, buf: ByteBuffer) { - when(value) { - is LnUrlWithdrawResult.Ok -> { - buf.putInt(1) - FfiConverterTypeLnUrlWithdrawSuccessData.write(value.`data`, buf) - Unit - } - is LnUrlWithdrawResult.ErrorStatus -> { - buf.putInt(2) - FfiConverterTypeLnUrlErrorData.write(value.`data`, buf) - Unit - } - }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } - } -} - - - - - -/** - * Log level for filtering messages. - */ - -enum class LogLevel { - - ERROR, - WARN, - INFO, - DEBUG, - TRACE; - companion object -} - - -/** - * @suppress - */ -public object FfiConverterTypeLogLevel: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer) = try { - LogLevel.values()[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) - } -} - - - - - - -enum class Network { - - BITCOIN, - REGTEST; - companion object -} - - -/** - * @suppress - */ -public object FfiConverterTypeNetwork: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer) = try { - Network.values()[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) - } -} - - - - - -/** - * A real-time event from the node. - */ -sealed class NodeEvent { - - /** - * An invoice was paid. - */ - data class InvoicePaid( - val `details`: InvoicePaidEvent) : NodeEvent() { - companion object - } - - - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeNodeEvent : FfiConverterRustBuffer{ - override fun read(buf: ByteBuffer): NodeEvent { - return when(buf.getInt()) { - 1 -> NodeEvent.InvoicePaid( - FfiConverterTypeInvoicePaidEvent.read(buf), - ) - else -> throw RuntimeException("invalid enum value, something is very wrong!!") - } - } - - override fun allocationSize(value: NodeEvent) = when(value) { - is NodeEvent.InvoicePaid -> { - // Add the size for the Int that specifies the variant plus the size needed for all fields - ( - 4UL - + FfiConverterTypeInvoicePaidEvent.allocationSize(value.`details`) - ) - } - } - - override fun write(value: NodeEvent, buf: ByteBuffer) { - when(value) { - is NodeEvent.InvoicePaid -> { - buf.putInt(1) - FfiConverterTypeInvoicePaidEvent.write(value.`details`, buf) - Unit - } - }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } - } -} - - - - - -/** - * Classifies the on-chain wallet into discrete cases that a wallet - * UI can switch on to render the correct entry-point for the - * withdraw flow. Derived purely from `NodeState` — no RPC. - */ -sealed class OnchainBalanceState { - - /** - * No funds on-chain in any form (confirmed, unconfirmed, - * immature, or pending channel-close payouts are all zero). - * Don't render a withdraw entry point. - */ - object Unavailable : OnchainBalanceState() - - - /** - * Funds are spendable now. Render the withdraw entry point - * enabled with `withdrawable_sat` as the headline. - */ - data class Available( - /** - * `onchain_balance_sat - emergency_reserve_sat`. Use as - * the displayed amount on the entry point. - */ - val `withdrawableSat`: kotlin.ULong, - /** - * Held back by CLN for anchor-channel safety; cannot be - * withdrawn without closing channels first. - */ - val `emergencyReserveSat`: kotlin.ULong, - /** - * Inbound on-chain funds not yet confirmed. Informational - * only — not part of `withdrawable_sat`. - */ - val `unconfirmedSat`: kotlin.ULong) : OnchainBalanceState() { - companion object - } - - /** - * On-chain funds exist but are entirely locked as the - * anchor-channel emergency reserve. Render the entry point - * disabled with an explainer (e.g. "close channels to free - * these funds"). - */ - data class ReserveOnly( - val `reserveSat`: kotlin.ULong) : OnchainBalanceState() { - companion object - } - - /** - * Inbound on-chain funds are awaiting confirmation. Render a - * "pending" indicator instead of an enabled withdraw button. - */ - data class PendingConfirmation( - val `unconfirmedSat`: kotlin.ULong) : OnchainBalanceState() { - companion object - } - - /** - * Funds exist as CSV-timelocked outputs from a recent channel - * close and can't be spent until the relative locktime - * expires. Render the entry point disabled with a - * "channel closing" explainer. - */ - data class Immature( - val `immatureSat`: kotlin.ULong) : OnchainBalanceState() { - companion object - } - - - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeOnchainBalanceState : FfiConverterRustBuffer{ - override fun read(buf: ByteBuffer): OnchainBalanceState { - return when(buf.getInt()) { - 1 -> OnchainBalanceState.Unavailable - 2 -> OnchainBalanceState.Available( - FfiConverterULong.read(buf), - FfiConverterULong.read(buf), - FfiConverterULong.read(buf), - ) - 3 -> OnchainBalanceState.ReserveOnly( - FfiConverterULong.read(buf), - ) - 4 -> OnchainBalanceState.PendingConfirmation( - FfiConverterULong.read(buf), - ) - 5 -> OnchainBalanceState.Immature( - FfiConverterULong.read(buf), - ) - else -> throw RuntimeException("invalid enum value, something is very wrong!!") - } - } - - override fun allocationSize(value: OnchainBalanceState) = when(value) { - is OnchainBalanceState.Unavailable -> { - // Add the size for the Int that specifies the variant plus the size needed for all fields - ( - 4UL - ) - } - is OnchainBalanceState.Available -> { - // Add the size for the Int that specifies the variant plus the size needed for all fields - ( - 4UL - + FfiConverterULong.allocationSize(value.`withdrawableSat`) - + FfiConverterULong.allocationSize(value.`emergencyReserveSat`) - + FfiConverterULong.allocationSize(value.`unconfirmedSat`) - ) - } - is OnchainBalanceState.ReserveOnly -> { - // Add the size for the Int that specifies the variant plus the size needed for all fields - ( - 4UL - + FfiConverterULong.allocationSize(value.`reserveSat`) - ) - } - is OnchainBalanceState.PendingConfirmation -> { - // Add the size for the Int that specifies the variant plus the size needed for all fields - ( - 4UL - + FfiConverterULong.allocationSize(value.`unconfirmedSat`) - ) - } - is OnchainBalanceState.Immature -> { - // Add the size for the Int that specifies the variant plus the size needed for all fields - ( - 4UL - + FfiConverterULong.allocationSize(value.`immatureSat`) - ) - } - } - - override fun write(value: OnchainBalanceState, buf: ByteBuffer) { - when(value) { - is OnchainBalanceState.Unavailable -> { - buf.putInt(1) - Unit - } - is OnchainBalanceState.Available -> { - buf.putInt(2) - FfiConverterULong.write(value.`withdrawableSat`, buf) - FfiConverterULong.write(value.`emergencyReserveSat`, buf) - FfiConverterULong.write(value.`unconfirmedSat`, buf) - Unit - } - is OnchainBalanceState.ReserveOnly -> { - buf.putInt(3) - FfiConverterULong.write(value.`reserveSat`, buf) - Unit - } - is OnchainBalanceState.PendingConfirmation -> { - buf.putInt(4) - FfiConverterULong.write(value.`unconfirmedSat`, buf) - Unit - } - is OnchainBalanceState.Immature -> { - buf.putInt(5) - FfiConverterULong.write(value.`immatureSat`, buf) - Unit - } - }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } - } -} - - - - - - -enum class OutputStatus { - - UNCONFIRMED, - CONFIRMED, - SPENT, - IMMATURE; - companion object -} - - -/** - * @suppress - */ -public object FfiConverterTypeOutputStatus: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer) = try { - OutputStatus.values()[buf.getInt() - 1] - } catch (e: IndexOutOfBoundsException) { - throw RuntimeException("invalid enum value, something is very wrong!!", e) - } - - override fun allocationSize(value: OutputStatus) = 4UL - - override fun write(value: OutputStatus, buf: ByteBuffer) { - buf.putInt(value.ordinal + 1) - } -} - - - - - -/** - * The result of `parse_input`: an offline classification of the - * input. No HTTP, no I/O. LNURL bech32 strings are returned as their - * decoded URL; Lightning Addresses as the unparsed `user@host` form. - */ -sealed class ParsedInput { - - /** - * A BOLT11 Lightning invoice. - */ - data class Bolt11( - val `invoice`: ParsedInvoice) : ParsedInput() { - companion object - } - - /** - * A Lightning node public key. - */ - data class NodeId( - val `nodeId`: kotlin.String) : ParsedInput() { - companion object - } - - /** - * An LNURL bech32 string (LUD-01) decoded to its underlying URL. - * Pass to `resolve_input` (or fetch yourself) to determine - * whether it's a pay, withdraw, or auth endpoint. - */ - data class LnUrl( - val `url`: kotlin.String) : ParsedInput() { - companion object - } - - /** - * A Lightning Address (LUD-16) in the form `user@host`. The - * well-known URL is not constructed offline; call `resolve_input` - * to fetch and classify. - */ - data class LnUrlAddress( - val `address`: kotlin.String) : ParsedInput() { - companion object - } - - - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeParsedInput : FfiConverterRustBuffer{ - override fun read(buf: ByteBuffer): ParsedInput { - return when(buf.getInt()) { - 1 -> ParsedInput.Bolt11( - FfiConverterTypeParsedInvoice.read(buf), - ) - 2 -> ParsedInput.NodeId( - FfiConverterString.read(buf), - ) - 3 -> ParsedInput.LnUrl( - FfiConverterString.read(buf), - ) - 4 -> ParsedInput.LnUrlAddress( - FfiConverterString.read(buf), - ) - else -> throw RuntimeException("invalid enum value, something is very wrong!!") - } - } - - override fun allocationSize(value: ParsedInput) = when(value) { - is ParsedInput.Bolt11 -> { - // Add the size for the Int that specifies the variant plus the size needed for all fields - ( - 4UL - + FfiConverterTypeParsedInvoice.allocationSize(value.`invoice`) - ) - } - is ParsedInput.NodeId -> { - // Add the size for the Int that specifies the variant plus the size needed for all fields - ( - 4UL - + FfiConverterString.allocationSize(value.`nodeId`) - ) - } - is ParsedInput.LnUrl -> { - // Add the size for the Int that specifies the variant plus the size needed for all fields - ( - 4UL - + FfiConverterString.allocationSize(value.`url`) - ) - } - is ParsedInput.LnUrlAddress -> { - // Add the size for the Int that specifies the variant plus the size needed for all fields - ( - 4UL - + FfiConverterString.allocationSize(value.`address`) - ) - } - } - - override fun write(value: ParsedInput, buf: ByteBuffer) { - when(value) { - is ParsedInput.Bolt11 -> { - buf.putInt(1) - FfiConverterTypeParsedInvoice.write(value.`invoice`, buf) - Unit - } - is ParsedInput.NodeId -> { - buf.putInt(2) - FfiConverterString.write(value.`nodeId`, buf) - Unit - } - is ParsedInput.LnUrl -> { - buf.putInt(3) - FfiConverterString.write(value.`url`, buf) - Unit - } - is ParsedInput.LnUrlAddress -> { - buf.putInt(4) - FfiConverterString.write(value.`address`, buf) - Unit - } - }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } - } -} - - - - - - -enum class PayStatus { - - COMPLETE, - PENDING, - FAILED; - companion object -} - - -/** - * @suppress - */ -public object FfiConverterTypePayStatus: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer) = try { - PayStatus.values()[buf.getInt() - 1] - } catch (e: IndexOutOfBoundsException) { - throw RuntimeException("invalid enum value, something is very wrong!!", e) - } - - override fun allocationSize(value: PayStatus) = 4UL - - override fun write(value: PayStatus, buf: ByteBuffer) { - buf.putInt(value.ordinal + 1) - } -} - - - - - - -enum class PaymentStatus { - - PENDING, - COMPLETE, - FAILED; - companion object -} - - -/** - * @suppress - */ -public object FfiConverterTypePaymentStatus: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer) = try { - PaymentStatus.values()[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) - } -} - - - - - - -enum class PaymentType { - - SENT, - RECEIVED; - companion object -} - - -/** - * @suppress - */ -public object FfiConverterTypePaymentType: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer) = try { - PaymentType.values()[buf.getInt() - 1] - } catch (e: IndexOutOfBoundsException) { - throw RuntimeException("invalid enum value, something is very wrong!!", e) - } - - override fun allocationSize(value: PaymentType) = 4UL - - override fun write(value: PaymentType, buf: ByteBuffer) { - buf.putInt(value.ordinal + 1) - } -} - - - - - - -enum class PaymentTypeFilter { - - SENT, - RECEIVED; - companion object -} - - -/** - * @suppress - */ -public object FfiConverterTypePaymentTypeFilter: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer) = try { - PaymentTypeFilter.values()[buf.getInt() - 1] - } catch (e: IndexOutOfBoundsException) { - throw RuntimeException("invalid enum value, something is very wrong!!", e) - } - - override fun allocationSize(value: PaymentTypeFilter) = 4UL - - override fun write(value: PaymentTypeFilter, buf: ByteBuffer) { - buf.putInt(value.ordinal + 1) - } -} - - - - - -/** - * The result of `resolve_input`: a fully-resolved input ready for - * the caller's next action. LNURL bech32 strings and Lightning - * Addresses are resolved over HTTP into typed pay or withdraw - * request data; BOLT11 and node IDs pass through unchanged. - */ -sealed class ResolvedInput { - - /** - * A BOLT11 Lightning invoice. No HTTP was performed. - */ - data class Bolt11( - val `invoice`: ParsedInvoice) : ResolvedInput() { - companion object - } - - /** - * A Lightning node public key. No HTTP was performed. - */ - data class NodeId( - val `nodeId`: kotlin.String) : ResolvedInput() { - companion object - } - - /** - * An LNURL-pay endpoint with the service's parameters fetched. - */ - data class LnUrlPay( - val `data`: LnUrlPayRequestData) : ResolvedInput() { - companion object - } - - /** - * An LNURL-withdraw endpoint with the service's parameters fetched. - */ - data class LnUrlWithdraw( - val `data`: LnUrlWithdrawRequestData) : ResolvedInput() { - companion object - } - - - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeResolvedInput : FfiConverterRustBuffer{ - override fun read(buf: ByteBuffer): ResolvedInput { - return when(buf.getInt()) { - 1 -> ResolvedInput.Bolt11( - FfiConverterTypeParsedInvoice.read(buf), - ) - 2 -> ResolvedInput.NodeId( - FfiConverterString.read(buf), - ) - 3 -> ResolvedInput.LnUrlPay( - FfiConverterTypeLnUrlPayRequestData.read(buf), - ) - 4 -> ResolvedInput.LnUrlWithdraw( - FfiConverterTypeLnUrlWithdrawRequestData.read(buf), - ) - else -> throw RuntimeException("invalid enum value, something is very wrong!!") - } - } - - override fun allocationSize(value: ResolvedInput) = when(value) { - is ResolvedInput.Bolt11 -> { - // Add the size for the Int that specifies the variant plus the size needed for all fields - ( - 4UL - + FfiConverterTypeParsedInvoice.allocationSize(value.`invoice`) - ) - } - is ResolvedInput.NodeId -> { - // Add the size for the Int that specifies the variant plus the size needed for all fields - ( - 4UL - + FfiConverterString.allocationSize(value.`nodeId`) - ) - } - is ResolvedInput.LnUrlPay -> { - // Add the size for the Int that specifies the variant plus the size needed for all fields - ( - 4UL - + FfiConverterTypeLnUrlPayRequestData.allocationSize(value.`data`) - ) - } - is ResolvedInput.LnUrlWithdraw -> { - // Add the size for the Int that specifies the variant plus the size needed for all fields - ( - 4UL - + FfiConverterTypeLnUrlWithdrawRequestData.allocationSize(value.`data`) - ) - } - } - - override fun write(value: ResolvedInput, buf: ByteBuffer) { - when(value) { - is ResolvedInput.Bolt11 -> { - buf.putInt(1) - FfiConverterTypeParsedInvoice.write(value.`invoice`, buf) - Unit - } - is ResolvedInput.NodeId -> { - buf.putInt(2) - FfiConverterString.write(value.`nodeId`, buf) - Unit - } - is ResolvedInput.LnUrlPay -> { - buf.putInt(3) - FfiConverterTypeLnUrlPayRequestData.write(value.`data`, buf) - Unit - } - is ResolvedInput.LnUrlWithdraw -> { - buf.putInt(4) - FfiConverterTypeLnUrlWithdrawRequestData.write(value.`data`, buf) - Unit - } - }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } - } -} - - - - - -/** - * A processed success action from an LNURL-pay callback. - * - * For Message and Url this is passed through as-is. For Aes the - * ciphertext has been decrypted using the payment preimage. - */ -sealed class SuccessActionProcessed { - - /** - * Display a message to the user. - */ - data class Message( - val `message`: kotlin.String) : SuccessActionProcessed() { - companion object - } - - /** - * Display a URL to the user. - */ - data class Url( - val `description`: kotlin.String, - val `url`: kotlin.String) : SuccessActionProcessed() { - companion object - } - - /** - * Decrypted AES payload (LUD-10). - */ - data class Aes( - val `description`: kotlin.String, - val `plaintext`: kotlin.String) : SuccessActionProcessed() { - companion object - } - - - - companion object -} - -/** - * @suppress - */ -public object FfiConverterTypeSuccessActionProcessed : FfiConverterRustBuffer{ - override fun read(buf: ByteBuffer): SuccessActionProcessed { - return when(buf.getInt()) { - 1 -> SuccessActionProcessed.Message( - FfiConverterString.read(buf), - ) - 2 -> SuccessActionProcessed.Url( - FfiConverterString.read(buf), - FfiConverterString.read(buf), - ) - 3 -> SuccessActionProcessed.Aes( - FfiConverterString.read(buf), - FfiConverterString.read(buf), - ) - else -> throw RuntimeException("invalid enum value, something is very wrong!!") - } - } - - override fun allocationSize(value: SuccessActionProcessed) = when(value) { - is SuccessActionProcessed.Message -> { - // Add the size for the Int that specifies the variant plus the size needed for all fields - ( - 4UL - + FfiConverterString.allocationSize(value.`message`) - ) - } - is SuccessActionProcessed.Url -> { - // Add the size for the Int that specifies the variant plus the size needed for all fields - ( - 4UL - + FfiConverterString.allocationSize(value.`description`) - + FfiConverterString.allocationSize(value.`url`) - ) - } - is SuccessActionProcessed.Aes -> { - // Add the size for the Int that specifies the variant plus the size needed for all fields - ( - 4UL - + FfiConverterString.allocationSize(value.`description`) - + FfiConverterString.allocationSize(value.`plaintext`) - ) - } - } - - override fun write(value: SuccessActionProcessed, buf: ByteBuffer) { - when(value) { - is SuccessActionProcessed.Message -> { - buf.putInt(1) - FfiConverterString.write(value.`message`, buf) - Unit - } - is SuccessActionProcessed.Url -> { - buf.putInt(2) - FfiConverterString.write(value.`description`, buf) - FfiConverterString.write(value.`url`, buf) - Unit - } - is SuccessActionProcessed.Aes -> { - buf.putInt(3) - FfiConverterString.write(value.`description`, buf) - FfiConverterString.write(value.`plaintext`, buf) - Unit - } - }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } - } -} - - - - - - - -/** - * Callback interface for receiving log messages. - * - * `on_log` is invoked on the thread that emitted the log — which can - * be any tokio worker or background thread inside the SDK. Keep the - * implementation cheap and non-blocking; if you need UI updates, - * hand the entry off to your app's main thread. - */ -public interface LogListener { - - fun `onLog`(`entry`: LogEntry) - - companion object -} - - - -// Put the implementation in an object so we don't pollute the top-level namespace -internal object uniffiCallbackInterfaceLogListener { - internal object `onLog`: UniffiCallbackInterfaceLogListenerMethod0 { - override fun callback(`uniffiHandle`: Long,`entry`: RustBuffer.ByValue,`uniffiOutReturn`: Pointer,uniffiCallStatus: UniffiRustCallStatus,) { - val uniffiObj = FfiConverterTypeLogListener.handleMap.get(uniffiHandle) - val makeCall = { -> - uniffiObj.`onLog`( - FfiConverterTypeLogEntry.lift(`entry`), - ) - } - val writeReturn = { _: Unit -> Unit } - uniffiTraitInterfaceCall(uniffiCallStatus, makeCall, writeReturn) - } - } - - internal object uniffiFree: UniffiCallbackInterfaceFree { - override fun callback(handle: Long) { - FfiConverterTypeLogListener.handleMap.remove(handle) - } - } - - internal var vtable = UniffiVTableCallbackInterfaceLogListener.UniffiByValue( - `onLog`, - uniffiFree, - ) - - // Registers the foreign callback with the Rust side. - // This method is generated for each callback interface. - internal fun register(lib: UniffiLib) { - lib.uniffi_glsdk_fn_init_callback_vtable_loglistener(vtable) - } -} - -/** - * The ffiConverter which transforms the Callbacks in to handles to pass to Rust. - * - * @suppress - */ -public object FfiConverterTypeLogListener: FfiConverterCallbackInterface() - - - - - -/** - * Callback interface for receiving node events. - * - * `on_event` is invoked from the SDK's internal event-dispatch task. - * Implementations should be cheap and non-blocking; to update UI, - * dispatch to the main thread from inside the handler. - * - * Installed via `NodeBuilder::with_event_listener(...)` so events - * emitted during node bring-up are captured. The polling-style - * `Node::stream_node_events()` API is still available for callers - * that prefer to drive events themselves. - */ -public interface NodeEventListener { - - fun `onEvent`(`event`: NodeEvent) - - companion object -} - - - -// Put the implementation in an object so we don't pollute the top-level namespace -internal object uniffiCallbackInterfaceNodeEventListener { - internal object `onEvent`: UniffiCallbackInterfaceNodeEventListenerMethod0 { - override fun callback(`uniffiHandle`: Long,`event`: RustBuffer.ByValue,`uniffiOutReturn`: Pointer,uniffiCallStatus: UniffiRustCallStatus,) { - val uniffiObj = FfiConverterTypeNodeEventListener.handleMap.get(uniffiHandle) - val makeCall = { -> - uniffiObj.`onEvent`( - FfiConverterTypeNodeEvent.lift(`event`), - ) - } - val writeReturn = { _: Unit -> Unit } - uniffiTraitInterfaceCall(uniffiCallStatus, makeCall, writeReturn) - } - } - - internal object uniffiFree: UniffiCallbackInterfaceFree { - override fun callback(handle: Long) { - FfiConverterTypeNodeEventListener.handleMap.remove(handle) - } - } - - internal var vtable = UniffiVTableCallbackInterfaceNodeEventListener.UniffiByValue( - `onEvent`, - uniffiFree, - ) - - // Registers the foreign callback with the Rust side. - // This method is generated for each callback interface. - internal fun register(lib: UniffiLib) { - lib.uniffi_glsdk_fn_init_callback_vtable_nodeeventlistener(vtable) - } -} - -/** - * The ffiConverter which transforms the Callbacks in to handles to pass to Rust. - * - * @suppress - */ -public object FfiConverterTypeNodeEventListener: FfiConverterCallbackInterface() - - - - -/** - * @suppress - */ -public 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) - } - } -} - - - - -/** - * @suppress - */ -public 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) - } - } -} - - - - -/** - * @suppress - */ -public 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) - } - } -} - - - - -/** - * @suppress - */ -public 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) - } - } -} - - - - -/** - * @suppress - */ -public object FfiConverterOptionalByteArray: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): kotlin.ByteArray? { - if (buf.get().toInt() == 0) { - return null - } - return FfiConverterByteArray.read(buf) - } - - override fun allocationSize(value: kotlin.ByteArray?): ULong { - if (value == null) { - return 1UL - } else { - return 1UL + FfiConverterByteArray.allocationSize(value) - } - } - - override fun write(value: kotlin.ByteArray?, buf: ByteBuffer) { - if (value == null) { - buf.put(0) - } else { - buf.put(1) - FfiConverterByteArray.write(value, buf) - } - } -} - - - - -/** - * @suppress - */ -public object FfiConverterOptionalTypeChannelSide: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): ChannelSide? { - if (buf.get().toInt() == 0) { - return null - } - return FfiConverterTypeChannelSide.read(buf) - } - - override fun allocationSize(value: ChannelSide?): ULong { - if (value == null) { - return 1UL - } else { - return 1UL + FfiConverterTypeChannelSide.allocationSize(value) - } - } - - override fun write(value: ChannelSide?, buf: ByteBuffer) { - if (value == null) { - buf.put(0) - } else { - buf.put(1) - FfiConverterTypeChannelSide.write(value, buf) - } - } -} - - - - -/** - * @suppress - */ -public object FfiConverterOptionalTypeListIndex: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): ListIndex? { - if (buf.get().toInt() == 0) { - return null - } - return FfiConverterTypeListIndex.read(buf) - } - - override fun allocationSize(value: ListIndex?): ULong { - if (value == null) { - return 1UL - } else { - return 1UL + FfiConverterTypeListIndex.allocationSize(value) - } - } - - override fun write(value: ListIndex?, buf: ByteBuffer) { - if (value == null) { - buf.put(0) - } else { - buf.put(1) - FfiConverterTypeListIndex.write(value, buf) - } - } -} - - - - -/** - * @suppress - */ -public object FfiConverterOptionalTypeNodeEvent: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): NodeEvent? { - if (buf.get().toInt() == 0) { - return null - } - return FfiConverterTypeNodeEvent.read(buf) - } - - override fun allocationSize(value: NodeEvent?): ULong { - if (value == null) { - return 1UL - } else { - return 1UL + FfiConverterTypeNodeEvent.allocationSize(value) - } - } - - override fun write(value: NodeEvent?, buf: ByteBuffer) { - if (value == null) { - buf.put(0) - } else { - buf.put(1) - FfiConverterTypeNodeEvent.write(value, buf) - } - } -} - - - - -/** - * @suppress - */ -public object FfiConverterOptionalTypePayStatus: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): PayStatus? { - if (buf.get().toInt() == 0) { - return null - } - return FfiConverterTypePayStatus.read(buf) - } - - override fun allocationSize(value: PayStatus?): ULong { - if (value == null) { - return 1UL - } else { - return 1UL + FfiConverterTypePayStatus.allocationSize(value) - } - } - - override fun write(value: PayStatus?, buf: ByteBuffer) { - if (value == null) { - buf.put(0) - } else { - buf.put(1) - FfiConverterTypePayStatus.write(value, buf) - } - } -} - - - - -/** - * @suppress - */ -public object FfiConverterOptionalTypeSuccessActionProcessed: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): SuccessActionProcessed? { - if (buf.get().toInt() == 0) { - return null - } - return FfiConverterTypeSuccessActionProcessed.read(buf) - } - - override fun allocationSize(value: SuccessActionProcessed?): ULong { - if (value == null) { - return 1UL - } else { - return 1UL + FfiConverterTypeSuccessActionProcessed.allocationSize(value) - } - } - - override fun write(value: SuccessActionProcessed?, buf: ByteBuffer) { - if (value == null) { - buf.put(0) - } else { - buf.put(1) - FfiConverterTypeSuccessActionProcessed.write(value, buf) - } - } -} - - - - -/** - * @suppress - */ -public object FfiConverterOptionalSequenceTypeOutpoint: FfiConverterRustBuffer?> { - override fun read(buf: ByteBuffer): List? { - if (buf.get().toInt() == 0) { - return null - } - return FfiConverterSequenceTypeOutpoint.read(buf) - } - - override fun allocationSize(value: List?): ULong { - if (value == null) { - return 1UL - } else { - return 1UL + FfiConverterSequenceTypeOutpoint.allocationSize(value) - } - } - - override fun write(value: List?, buf: ByteBuffer) { - if (value == null) { - buf.put(0) - } else { - buf.put(1) - FfiConverterSequenceTypeOutpoint.write(value, buf) - } - } -} - - - - -/** - * @suppress - */ -public object FfiConverterOptionalSequenceTypePaymentTypeFilter: FfiConverterRustBuffer?> { - override fun read(buf: ByteBuffer): List? { - if (buf.get().toInt() == 0) { - return null - } - return FfiConverterSequenceTypePaymentTypeFilter.read(buf) - } - - override fun allocationSize(value: List?): ULong { - if (value == null) { - return 1UL - } else { - return 1UL + FfiConverterSequenceTypePaymentTypeFilter.allocationSize(value) - } - } - - override fun write(value: List?, buf: ByteBuffer) { - if (value == null) { - buf.put(0) - } else { - buf.put(1) - FfiConverterSequenceTypePaymentTypeFilter.write(value, buf) - } - } -} - - - - -/** - * @suppress - */ -public 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.map { FfiConverterString.allocationSize(it) }.sum() - return sizeForLength + sizeForItems - } - - override fun write(value: List, buf: ByteBuffer) { - buf.putInt(value.size) - value.iterator().forEach { - FfiConverterString.write(it, buf) - } - } -} - - - - -/** - * @suppress - */ -public object FfiConverterSequenceTypeFundChannel: FfiConverterRustBuffer> { - override fun read(buf: ByteBuffer): List { - val len = buf.getInt() - return List(len) { - FfiConverterTypeFundChannel.read(buf) - } - } - - override fun allocationSize(value: List): ULong { - val sizeForLength = 4UL - val sizeForItems = value.map { FfiConverterTypeFundChannel.allocationSize(it) }.sum() - return sizeForLength + sizeForItems - } - - override fun write(value: List, buf: ByteBuffer) { - buf.putInt(value.size) - value.iterator().forEach { - FfiConverterTypeFundChannel.write(it, buf) - } - } -} - - - - -/** - * @suppress - */ -public object FfiConverterSequenceTypeFundOutput: FfiConverterRustBuffer> { - override fun read(buf: ByteBuffer): List { - val len = buf.getInt() - return List(len) { - FfiConverterTypeFundOutput.read(buf) - } - } - - override fun allocationSize(value: List): ULong { - val sizeForLength = 4UL - val sizeForItems = value.map { FfiConverterTypeFundOutput.allocationSize(it) }.sum() - return sizeForLength + sizeForItems - } - - override fun write(value: List, buf: ByteBuffer) { - buf.putInt(value.size) - value.iterator().forEach { - FfiConverterTypeFundOutput.write(it, buf) - } - } -} - - - - -/** - * @suppress - */ -public object FfiConverterSequenceTypeInvoice: FfiConverterRustBuffer> { - override fun read(buf: ByteBuffer): List { - val len = buf.getInt() - return List(len) { - FfiConverterTypeInvoice.read(buf) - } - } - - override fun allocationSize(value: List): ULong { - val sizeForLength = 4UL - val sizeForItems = value.map { FfiConverterTypeInvoice.allocationSize(it) }.sum() - return sizeForLength + sizeForItems - } - - override fun write(value: List, buf: ByteBuffer) { - buf.putInt(value.size) - value.iterator().forEach { - FfiConverterTypeInvoice.write(it, buf) - } - } -} - - - - -/** - * @suppress - */ -public object FfiConverterSequenceTypeOutpoint: FfiConverterRustBuffer> { - override fun read(buf: ByteBuffer): List { - val len = buf.getInt() - return List(len) { - FfiConverterTypeOutpoint.read(buf) - } - } - - override fun allocationSize(value: List): ULong { - val sizeForLength = 4UL - val sizeForItems = value.map { FfiConverterTypeOutpoint.allocationSize(it) }.sum() - return sizeForLength + sizeForItems - } - - override fun write(value: List, buf: ByteBuffer) { - buf.putInt(value.size) - value.iterator().forEach { - FfiConverterTypeOutpoint.write(it, buf) - } - } -} - - - - -/** - * @suppress - */ -public object FfiConverterSequenceTypePay: FfiConverterRustBuffer> { - override fun read(buf: ByteBuffer): List { - val len = buf.getInt() - return List(len) { - FfiConverterTypePay.read(buf) - } - } - - override fun allocationSize(value: List): ULong { - val sizeForLength = 4UL - val sizeForItems = value.map { FfiConverterTypePay.allocationSize(it) }.sum() - return sizeForLength + sizeForItems - } - - override fun write(value: List, buf: ByteBuffer) { - buf.putInt(value.size) - value.iterator().forEach { - FfiConverterTypePay.write(it, buf) - } - } -} - - - - -/** - * @suppress - */ -public object FfiConverterSequenceTypePayment: FfiConverterRustBuffer> { - override fun read(buf: ByteBuffer): List { - val len = buf.getInt() - return List(len) { - FfiConverterTypePayment.read(buf) - } - } - - override fun allocationSize(value: List): ULong { - val sizeForLength = 4UL - val sizeForItems = value.map { FfiConverterTypePayment.allocationSize(it) }.sum() - return sizeForLength + sizeForItems - } - - override fun write(value: List, buf: ByteBuffer) { - buf.putInt(value.size) - value.iterator().forEach { - FfiConverterTypePayment.write(it, buf) - } - } -} - - - - -/** - * @suppress - */ -public object FfiConverterSequenceTypePeer: FfiConverterRustBuffer> { - override fun read(buf: ByteBuffer): List { - val len = buf.getInt() - return List(len) { - FfiConverterTypePeer.read(buf) - } - } - - override fun allocationSize(value: List): ULong { - val sizeForLength = 4UL - val sizeForItems = value.map { FfiConverterTypePeer.allocationSize(it) }.sum() - return sizeForLength + sizeForItems - } - - override fun write(value: List, buf: ByteBuffer) { - buf.putInt(value.size) - value.iterator().forEach { - FfiConverterTypePeer.write(it, buf) - } - } -} - - - - -/** - * @suppress - */ -public object FfiConverterSequenceTypePeerChannel: FfiConverterRustBuffer> { - override fun read(buf: ByteBuffer): List { - val len = buf.getInt() - return List(len) { - FfiConverterTypePeerChannel.read(buf) - } - } - - override fun allocationSize(value: List): ULong { - val sizeForLength = 4UL - val sizeForItems = value.map { FfiConverterTypePeerChannel.allocationSize(it) }.sum() - return sizeForLength + sizeForItems - } - - override fun write(value: List, buf: ByteBuffer) { - buf.putInt(value.size) - value.iterator().forEach { - FfiConverterTypePeerChannel.write(it, buf) - } - } -} - - - - -/** - * @suppress - */ -public object FfiConverterSequenceTypePaymentTypeFilter: FfiConverterRustBuffer> { - override fun read(buf: ByteBuffer): List { - val len = buf.getInt() - return List(len) { - FfiConverterTypePaymentTypeFilter.read(buf) - } - } - - override fun allocationSize(value: List): ULong { - val sizeForLength = 4UL - val sizeForItems = value.map { FfiConverterTypePaymentTypeFilter.allocationSize(it) }.sum() - return sizeForLength + sizeForItems - } - - override fun write(value: List, buf: ByteBuffer) { - buf.putInt(value.size) - value.iterator().forEach { - FfiConverterTypePaymentTypeFilter.write(it, buf) - } - } -} - - - - -/** - * @suppress - */ -public 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.map { (k, v) -> - FfiConverterString.allocationSize(k) + - FfiConverterString.allocationSize(v) - }.sum() - 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) - } - } -} - /** - * Synchronously classify the input. **No HTTP, no I/O.** - * - * Recognises BOLT11 invoices, node IDs, LNURL bech32 strings, and - * Lightning Addresses. Strips `lightning:` / `LIGHTNING:` prefixes - * automatically. LNURL inputs are decoded to their underlying URL - * but **not fetched** — the caller chooses whether to resolve - * further (via `resolve_input`) or to surface the URL to the user - * as-is. - * - * Use this for offline operations like clipboard validation or - * invoice sanity checks. Use `resolve_input` for the QR-scan flow - * where you want the resolved pay/withdraw data in one call. - */ - @Throws(Exception::class) fun `parseInput`(`input`: kotlin.String): ParsedInput { - return FfiConverterTypeParsedInput.lift( - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_func_parse_input( - FfiConverterString.lower(`input`),_status) -} - ) - } - - - /** - * Classify and resolve the input. - * - * Internally calls `parse_input` for offline classification, then - * for LNURL bech32 strings and Lightning Addresses performs the - * HTTP GET to the LNURL endpoint and returns typed pay or withdraw - * request data. For BOLT11 invoices and node IDs it returns - * immediately without I/O. - * - * Strips `lightning:` / `LIGHTNING:` prefixes automatically. - * - * # Blocking - * - * This function blocks the calling thread while any network I/O - * completes. The SDK exposes a **synchronous-only** public API so - * that every language binding (Python, Kotlin, Swift, Ruby, C++) - * works without requiring an async runtime on the caller side. - * Async work is executed internally on a shared Tokio runtime - * managed by the SDK. - */ - @Throws(Exception::class) fun `resolveInput`(`input`: kotlin.String): ResolvedInput { - return FfiConverterTypeResolvedInput.lift( - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_func_resolve_input( - FfiConverterString.lower(`input`),_status) -} - ) - } - - - /** - * Change the log filter at runtime without reinstalling the listener. - */ fun `setLogLevel`(`level`: LogLevel) - = - uniffiRustCall() { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_func_set_log_level( - FfiConverterTypeLogLevel.lower(`level`),_status) -} - - - - /** - * Set up SDK logging. Call once before any other SDK function. - * - * The listener receives all log messages from the SDK and the - * underlying Greenlight client library. Call once, as early as - * possible, so early logs are captured. Returns an error if a logger - * has already been installed in this process. To change the filter - * after installation, use `set_log_level`. - */ - @Throws(Exception::class) fun `setLogger`(`level`: LogLevel, `listener`: LogListener) - = - uniffiRustCallWithError(Exception) { _status -> - UniffiLib.INSTANCE.uniffi_glsdk_fn_func_set_logger( - FfiConverterTypeLogLevel.lower(`level`),FfiConverterTypeLogListener.lower(`listener`),_status) -} - - - -