├── .cargo └── audit.toml ├── .config └── nextest.toml ├── .envrc ├── .github └── workflows │ ├── bindings.yml │ ├── cont_integration.yml │ ├── kotlin.yml │ └── wheels.yml ├── .gitignore ├── .gitlab-ci.yml ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── context ├── Dockerfile ├── download_bins.sh ├── env.sh ├── get-docker.sh └── jade-emulator │ ├── Dockerfile.suffix │ ├── Readme.md │ └── start.sh ├── docs ├── demo.md ├── dep-tree.svg ├── issue.gif ├── logos │ ├── emblem │ │ ├── LWK_emblem_dark_on_transparent_rgb.png │ │ ├── LWK_emblem_dark_on_transparent_rgb.svg │ │ ├── LWK_emblem_dark_on_white_rgb.png │ │ ├── LWK_emblem_on_dark_rgb.png │ │ ├── LWK_emblem_on_transparent_rgb.png │ │ └── LWK_emblem_on_transparent_rgb.svg │ ├── monotone │ │ ├── LWK_monotone_dark_on_transparent.png │ │ ├── LWK_monotone_dark_on_transparent.svg │ │ ├── LWK_monotone_white_on_transparent.png │ │ └── LWK_monotone_white_on_transparent.svg │ ├── print │ │ ├── LWK_logo_dark_on_transparent_cmyk.png │ │ ├── LWK_logo_dark_on_transparent_cmyk.svg │ │ ├── LWK_logo_dark_on_white_cmyk.png │ │ ├── LWK_logo_white_on_dark_cmyk.png │ │ ├── LWK_logo_white_on_transparent_cmyk.png │ │ └── LWK_logo_white_on_transparent_cmyk.svg │ └── web │ │ ├── LWK_logo_dark_on_transparent_rgb.png │ │ ├── LWK_logo_dark_on_transparent_rgb.svg │ │ ├── LWK_logo_dark_on_white_rgb.png │ │ ├── LWK_logo_white_on_dark_rgb.png │ │ ├── LWK_logo_white_on_transparent_rgb.png │ │ └── LWK_logo_white_on_transparent_rgb.svg ├── logos_no_padding │ ├── LWK_dark.svg │ ├── LWK_dark_emblem.svg │ ├── LWK_light.svg │ └── LWK_light_emblem.svg ├── multi.gif └── unblinded.png ├── flake.lock ├── flake.nix ├── justfile ├── lwk_app ├── Cargo.toml ├── schema.json └── src │ ├── client.rs │ ├── config.rs │ ├── consts.rs │ ├── error.rs │ ├── lib.rs │ ├── method.rs │ ├── reqwest_transport.rs │ └── state.rs ├── lwk_bindings ├── Cargo.toml ├── README-wheel.md ├── README.md ├── android_bindings │ ├── .gitignore │ ├── build.gradle.kts │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── lib │ │ ├── .gitignore │ │ ├── build.gradle.kts │ │ ├── consumer-rules.pro │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── androidTest │ │ │ └── kotlin │ │ │ │ └── com │ │ │ │ └── blockstream │ │ │ │ └── lwk_bindings │ │ │ │ └── InstrumentedTest.kt │ │ │ └── main │ │ │ └── AndroidManifest.xml │ └── settings.gradle.kts ├── csharp │ ├── LICENSE │ ├── LiquidWalletKit.csproj │ └── README.md ├── lwk │ └── __init__.py ├── pyproject.toml ├── src │ ├── amp2.rs │ ├── blockdata │ │ ├── address.rs │ │ ├── address_result.rs │ │ ├── mod.rs │ │ ├── out_point.rs │ │ ├── script.rs │ │ ├── transaction.rs │ │ ├── tx_in.rs │ │ ├── tx_out.rs │ │ ├── tx_out_secrets.rs │ │ ├── txid.rs │ │ ├── wallet_tx.rs │ │ └── wallet_tx_out.rs │ ├── chain.rs │ ├── contract.rs │ ├── desc.rs │ ├── electrum_client.rs │ ├── error.rs │ ├── esplora_client.rs │ ├── lib.rs │ ├── liquidex.rs │ ├── mnemonic.rs │ ├── network.rs │ ├── persister.rs │ ├── precision.rs │ ├── pset.rs │ ├── pset_details.rs │ ├── signer.rs │ ├── test_env.rs │ ├── tx_builder.rs │ ├── types │ │ ├── asset_id.rs │ │ ├── hex.rs │ │ ├── mod.rs │ │ └── secret_key.rs │ ├── update.rs │ └── wollet.rs ├── test_data │ └── pset_details │ │ ├── desc │ │ ├── pset.base64 │ │ └── readme.md ├── tests │ ├── bindings.rs │ ├── bindings │ │ ├── amp2.py │ │ ├── custom_persister.py │ │ ├── external_unblind.py │ │ ├── issue_asset.py │ │ ├── liquidex.py │ │ ├── list_transactions.cs │ │ ├── list_transactions.kts │ │ ├── list_transactions.py │ │ ├── list_transactions.swift │ │ ├── manual_coin_selection.py │ │ ├── multisig.py │ │ ├── pset_details.py │ │ ├── send_asset.py │ │ ├── send_transaction.py │ │ └── test_env.py │ ├── lwk_flow.rs │ └── test_data │ │ ├── test-dotnet.csproj │ │ └── tx.hex └── uniffi.toml ├── lwk_cli ├── CHANGELOG.md ├── Cargo.toml ├── README.md ├── src │ ├── args.rs │ ├── lib.rs │ ├── main.rs │ └── schema.rs └── tests │ ├── cli.rs │ └── test_data │ └── state.json ├── lwk_common ├── Cargo.toml ├── src │ ├── descriptor.rs │ ├── error.rs │ ├── keyorigin_xpub.rs │ ├── lib.rs │ ├── model.rs │ ├── network.rs │ ├── precision.rs │ ├── qr.rs │ ├── segwit.rs │ └── signer.rs └── test_data │ ├── pset_debug.txt │ ├── pset_details │ ├── descriptor │ ├── pset.base64 │ ├── pset2.base64 │ └── readme.md │ └── pset_outputs │ ├── descriptor │ └── pset.base64 ├── lwk_containers ├── Cargo.toml ├── README.md └── src │ ├── jade.rs │ ├── ledger │ ├── apps │ │ ├── app.elf │ │ ├── app.elf.old │ │ ├── btc.elf │ │ ├── nanos#btc#2.1#1c8db8da.elf │ │ └── speculos-automation.json │ └── mod.rs │ ├── lib.rs │ └── pin_server.rs ├── lwk_hwi ├── Cargo.toml ├── README.md └── src │ └── lib.rs ├── lwk_jade ├── Cargo.toml ├── README.md ├── src │ ├── asyncr │ │ ├── mod.rs │ │ └── sign_pset.rs │ ├── consts.rs │ ├── error.rs │ ├── get_receive_address.rs │ ├── jade_emulator.rs │ ├── lib.rs │ ├── protocol.rs │ ├── register_multisig.rs │ ├── sign_liquid_tx.rs │ └── sync │ │ ├── connection.rs │ │ ├── mod.rs │ │ └── sign_pset.rs ├── test_data │ ├── pset_to_be_signed.base64 │ ├── pset_to_be_signed_transaction.hex │ ├── register_multisig.json │ └── sign_liquid_tx_request.json └── tests │ ├── e2e.rs │ ├── emulator.rs │ └── serial.rs ├── lwk_ledger ├── Cargo.toml ├── README.md ├── src │ ├── apdu.rs │ ├── asyncr │ │ ├── client.rs │ │ ├── mod.rs │ │ └── transport_tcp.rs │ ├── client.rs │ ├── command.rs │ ├── error.rs │ ├── interpreter.rs │ ├── ledger_emulator.rs │ ├── lib.rs │ ├── merkle.rs │ ├── psbt │ │ ├── global.rs │ │ ├── input.rs │ │ ├── macros.rs │ │ ├── mod.rs │ │ └── output.rs │ ├── transport_hid.rs │ ├── transport_tcp.rs │ └── wallet.rs └── tests │ ├── data │ ├── pset_ledger.base64 │ ├── pset_ledger_regtest_issuance.base64 │ └── pset_ledger_regtest_issuance.txt │ └── e2e.rs ├── lwk_rpc_model ├── Cargo.toml └── src │ ├── lib.rs │ ├── request.rs │ └── response.rs ├── lwk_signer ├── Cargo.toml └── src │ ├── lib.rs │ └── software.rs ├── lwk_test_util ├── Cargo.toml ├── src │ └── lib.rs ├── test_data │ ├── afafbbdfc52a45e51a3b634f391f952f6bdfd14ef74b34925954b4e20d0ad639.raw │ ├── block_header_2_963_520.hex │ ├── pset_combine │ │ ├── desc │ │ ├── readme.md │ │ ├── s1_pset.base64 │ │ ├── s2_pset.base64 │ │ ├── s3_pset.base64 │ │ ├── s4_pset.base64 │ │ └── s5_pset.base64 │ ├── tx_out_secrets_test_vector.hex │ ├── update_many_txs.bin │ ├── update_test_vector.bin │ ├── update_test_vector.hex │ ├── update_test_vector │ │ ├── 000000000000 │ │ ├── desc │ │ ├── desc2 │ │ ├── readme.md │ │ └── update.base64 │ ├── update_test_vector_encrypted.hex │ ├── update_test_vector_v1.hex │ └── update_v2_after_many_txs.bin └── wasm_test_env.sh ├── lwk_tiny_jrpc ├── Cargo.toml ├── README.md ├── src │ ├── config.rs │ ├── error.rs │ └── lib.rs └── test │ └── data │ ├── README.md │ ├── file.css │ ├── file.ico │ ├── file.jpg │ ├── file.js │ ├── file.png │ └── file.svg ├── lwk_wasm ├── .envrc ├── Cargo.toml ├── README.md ├── flake.lock ├── flake.nix ├── src │ ├── amp2.rs │ ├── bip.rs │ ├── blockdata │ │ ├── address.rs │ │ ├── asset_id.rs │ │ ├── mod.rs │ │ ├── out_point.rs │ │ ├── script.rs │ │ ├── transaction.rs │ │ ├── tx_out_secrets.rs │ │ ├── wallet_tx.rs │ │ └── wallet_tx_out.rs │ ├── contract.rs │ ├── descriptor.rs │ ├── error.rs │ ├── esplora.rs │ ├── jade.rs │ ├── ledger.rs │ ├── lib.rs │ ├── liquidex.rs │ ├── mnemonic.rs │ ├── network.rs │ ├── precision.rs │ ├── pset.rs │ ├── pset_details.rs │ ├── registry.rs │ ├── serial.rs │ ├── signer.rs │ ├── tx_builder.rs │ ├── update.rs │ ├── wollet.rs │ └── xpub.rs └── test_data │ ├── desc │ ├── pset_details │ ├── desc │ ├── pset.base64 │ └── readme.md │ ├── update.base64 │ ├── update_test_balance_and_transactions.hex │ ├── update_test_vector.hex │ └── update_with_mnemonic │ ├── descriptor.txt │ ├── descriptor2.txt │ ├── mnemonic.txt │ ├── mnemonic2.txt │ ├── update_serialized_encrypted.txt │ └── update_serialized_encrypted2.txt ├── lwk_wollet ├── Cargo.toml ├── benches │ └── benches.rs ├── examples │ └── list_transactions.rs ├── src │ ├── amp2.rs │ ├── clients │ │ ├── asyncr │ │ │ ├── esplora.rs │ │ │ └── mod.rs │ │ ├── blocking │ │ │ ├── electrum_client.rs │ │ │ ├── elements_rpc_client.rs │ │ │ ├── esplora.rs │ │ │ └── mod.rs │ │ └── mod.rs │ ├── config.rs │ ├── descriptor.rs │ ├── domain.rs │ ├── error.rs │ ├── lib.rs │ ├── liquidex.rs │ ├── model.rs │ ├── pegin.rs │ ├── persister.rs │ ├── pset_create.rs │ ├── registry.rs │ ├── store.rs │ ├── tx_builder.rs │ ├── update.rs │ ├── util.rs │ └── wollet.rs └── tests │ ├── data │ ├── 62ea5d0aa7c9f4339b16a6d8e6ff4437ffb244de658222841c74d335324e4219 │ ├── usdt-issuance-tx.hex │ └── wallet_tx.json │ ├── e2e.rs │ ├── test_jade │ └── mod.rs │ ├── test_ledger │ └── mod.rs │ └── test_wollet.rs └── rust-toolchain.toml /.cargo/audit.toml: -------------------------------------------------------------------------------- 1 | [advisories] 2 | ignore = ["RUSTSEC-2020-0168"] # mach is unmaintained, still required by serialport-rs: https://github.com/serialport/serialport-rs/issues/112 3 | -------------------------------------------------------------------------------- /.config/nextest.toml: -------------------------------------------------------------------------------- 1 | 2 | [profile.ci] 3 | retries = 3 4 | test-threads = 6 5 | failure-output = "immediate-final" # Print out output for failing tests as soon as they fail, and also at the end of the run (for easy scrollability). 6 | fail-fast = false # Do not cancel the test run on the first failure. 7 | slow-timeout = { period = "60s", terminate-after = 3 } # test tagged as slow after X seconds, hard-terminated after 3 periods 8 | leak-timeout = "5s" # test is leaky if after termination, test still has stdout or stderr open (subprocess probably still running) 9 | 10 | [profile.ci.junit] 11 | path = "junit.xml" 12 | 13 | [profile.unit] 14 | slow-timeout = { period = "1s", terminate-after = 1 } 15 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # taken from https://fasterthanli.me/series/building-a-rust-service-with-nix/part-10 and updated the version 4 | 5 | if ! has nix_direnv_version || ! nix_direnv_version 3.0.4; then 6 | source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.0.4/direnvrc" "sha256-DzlYZ33mWF/Gs8DDeyjr8mnVmQGx7ASYqA5WlxwvBG4=" 7 | fi 8 | 9 | watch_file rust-toolchain.toml 10 | use flake 11 | -------------------------------------------------------------------------------- /.github/workflows/cont_integration.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - master 5 | pull_request: {} 6 | 7 | name: CI 8 | 9 | env: 10 | RUSTFLAGS: "--cfg=web_sys_unstable_apis" 11 | 12 | jobs: 13 | build: 14 | strategy: 15 | matrix: 16 | os: ["macos-14", "ubuntu-22.04", "windows-2022"] 17 | runs-on: ${{ matrix.os }} 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@v4 21 | - uses: dtolnay/rust-toolchain@stable 22 | - run: sudo apt-get update && sudo apt-get install -y libudev-dev 23 | if: ${{ matrix.os == 'ubuntu-22.04' }} 24 | - run: cargo build 25 | - run: cargo build --features serial 26 | 27 | nix: 28 | runs-on: ubuntu-22.04 29 | steps: 30 | - uses: actions/checkout@v4 31 | - uses: cachix/install-nix-action@v25 32 | with: 33 | extra_nix_config: | 34 | trusted-public-keys = nix.casatta.it:HseKZh7436/vKXfZDBHbhr7wwAkzjLwY5BIq+OOrITg= cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= 35 | substituters = https://nix.casatta.it https://cache.nixos.org/ 36 | - run: nix build . 37 | 38 | just-swift: # swift framework is built in the lwk-swift repo, here we care `just swift` doesn't brake 39 | runs-on: macos-14 40 | steps: 41 | - uses: actions/checkout@v4 42 | - uses: dtolnay/rust-toolchain@1.81.0 43 | with: 44 | targets: x86_64-apple-ios,aarch64-apple-ios,aarch64-apple-ios-sim 45 | - uses: extractions/setup-just@v2 46 | with: 47 | just-version: 1.5.0 # optional semver specification, otherwise latest 48 | - run: just swift 49 | 50 | csharp: 51 | runs-on: windows-2022 52 | steps: 53 | - name: Checkout 54 | uses: actions/checkout@v4 55 | - uses: dtolnay/rust-toolchain@stable 56 | - uses: extractions/setup-just@v2 57 | - run: just csharp-windows 58 | - run: ls target/release/csharp 59 | - uses: actions/setup-dotnet@v4 60 | with: 61 | dotnet-version: '6.0.x' 62 | - run: cd target/release/csharp && dotnet run && cd - 63 | - uses: actions/upload-artifact@v4 64 | with: 65 | name: csharp-windows 66 | path: target/release/csharp 67 | 68 | -------------------------------------------------------------------------------- /.github/workflows/kotlin.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - master 5 | tags: 6 | - 'bindings_*' 7 | pull_request: {} 8 | 9 | name: Build & Publish framework for Kotlin library 10 | 11 | jobs: 12 | 13 | build: 14 | runs-on: ubuntu-22.04 15 | steps: 16 | - name: "Show default version of NDK" 17 | run: echo $ANDROID_NDK_ROOT 18 | 19 | - name: "Check out PR branch" 20 | uses: actions/checkout@v4 21 | 22 | - name: "Set up JDK" 23 | uses: actions/setup-java@v4 24 | with: 25 | distribution: temurin 26 | java-version: 17 27 | 28 | - uses: dtolnay/rust-toolchain@1.81.0 29 | with: 30 | targets: x86_64-linux-android, aarch64-linux-android, armv7-linux-androideabi, i686-linux-android 31 | 32 | - uses: extractions/setup-just@v2 33 | with: 34 | just-version: 1.5.0 # optional semver specification, otherwise latest 35 | 36 | - name: "Install NDK" 37 | run: | 38 | cargo install cargo-ndk 39 | 40 | - name: "Build Android bindings" 41 | run: | 42 | just kotlin-android 43 | 44 | - name: "Build Android library" 45 | working-directory: lwk_bindings/android_bindings 46 | run: | 47 | ./gradlew build --console=plain 48 | 49 | - name: Temporarily save artifact 50 | uses: actions/upload-artifact@v4 51 | with: 52 | name: lwk-artifact 53 | path: lwk_bindings/android_bindings 54 | retention-days: 1 55 | 56 | publish: 57 | runs-on: ubuntu-22.04 58 | needs: build 59 | if: startsWith(github.ref, 'refs/tags/bindings_') 60 | steps: 61 | 62 | - name: Retrieve saved artifact 63 | uses: actions/download-artifact@v4 64 | with: 65 | name: lwk-artifact 66 | 67 | - name: "Set up JDK" 68 | uses: actions/setup-java@v4 69 | with: 70 | distribution: temurin 71 | java-version: 17 72 | 73 | - name: Set RELEASE_REF 74 | run: echo "RELEASE_REF=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV 75 | 76 | - name: Set RELEASE_VERSION 77 | run: echo "RELEASE_VERSION=$(echo ${{ env.RELEASE_REF }} | sed 's/bindings_//')" >> $GITHUB_ENV 78 | 79 | - name: set permissions 80 | run: chmod +x ./gradlew 81 | 82 | - name: Publish artifacts 83 | env: 84 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 85 | run: ./gradlew publish -PlibraryVersion=${{ env.RELEASE_VERSION }} 86 | -------------------------------------------------------------------------------- /.github/workflows/wheels.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - master 5 | pull_request: {} 6 | 7 | name: Build python wheels on mac and windows 8 | 9 | jobs: 10 | 11 | 12 | linux-wheels: 13 | runs-on: ubuntu-22.04 14 | steps: 15 | - uses: actions/checkout@v4 16 | - name: Build wheels 17 | uses: docker://ghcr.io/pyo3/maturin:latest 18 | with: 19 | entrypoint: bash 20 | args: -c "python3 -m pip install uniffi-bindgen==0.28.0 && maturin build --compatibility manylinux2014 --release -m lwk_bindings/Cargo.toml -b uniffi" 21 | - uses: actions/upload-artifact@v4 22 | with: 23 | name: linux-wheels 24 | path: target/wheels 25 | 26 | 27 | osx-wheels: 28 | strategy: 29 | matrix: 30 | os: ["macos-13", "macos-14"] # 13 -> x86_64, 14 -> arm64 # https://github.com/actions/runner-images?tab=readme-ov-file#available-images 31 | runs-on: ${{ matrix.os }} 32 | steps: 33 | - uses: actions/checkout@v4 34 | - uses: dtolnay/rust-toolchain@1.81.0 35 | with: 36 | components: "clippy,rust-src,rustfmt" # required by maturin build 37 | - uses: actions/setup-python@v5 38 | with: 39 | python-version: "3.12" 40 | - run: python3 -m pip install maturin 41 | - run: python3 -m pip install uniffi-bindgen==0.28.0 # must be the same version as the dep in lwk_bindings/Cargo.toml 42 | - run: maturin build --release -m lwk_bindings/Cargo.toml -b uniffi 43 | - uses: actions/upload-artifact@v4 44 | with: 45 | name: osx-wheel-${{ matrix.os }} 46 | path: target/wheels 47 | 48 | windows-wheels: 49 | runs-on: windows-latest 50 | steps: 51 | - uses: actions/checkout@v4 52 | - uses: dtolnay/rust-toolchain@1.81.0 53 | with: 54 | components: "clippy,rust-src,rustfmt" # required by maturin build 55 | - uses: actions/setup-python@v5 56 | with: 57 | python-version: "3.12" 58 | - run: python3 -m pip install maturin 59 | - run: python3 -m pip install uniffi-bindgen==0.28.0 # must be the same version as the dep in lwk_bindings/Cargo.toml 60 | - run: maturin build --release -m lwk_bindings/Cargo.toml -b uniffi 61 | - uses: actions/upload-artifact@v4 62 | with: 63 | name: windows-wheels 64 | path: target/wheels 65 | 66 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target* 2 | *swp 3 | bak* 4 | bin/ 5 | .vscode 6 | debug.log 7 | lwk_bindings.kt 8 | .idea 9 | flash_image.bin 10 | qemu_efuse.bin 11 | context/jade-emulator/Dockerfile 12 | .direnv 13 | result 14 | *__pycache__ 15 | venv/ 16 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | 3 | members = [ 4 | "lwk_app", 5 | "lwk_bindings", 6 | "lwk_cli", 7 | "lwk_hwi", 8 | "lwk_jade", 9 | "lwk_ledger", 10 | "lwk_signer", 11 | "lwk_tiny_jrpc", 12 | "lwk_wollet", 13 | "lwk_containers", 14 | "lwk_common", 15 | "lwk_rpc_model", 16 | "lwk_test_util", 17 | "lwk_wasm", 18 | ] 19 | resolver = "2" 20 | 21 | [patch.crates-io] 22 | lwk_app = { path = "lwk_app" } 23 | lwk_common = { path = "lwk_common" } 24 | lwk_containers = { path = "lwk_containers" } 25 | lwk_jade = { path = "lwk_jade" } 26 | lwk_ledger = { path = "lwk_ledger" } 27 | lwk_rpc_model = { path = "lwk_rpc_model" } 28 | lwk_signer = { path = "lwk_signer" } 29 | lwk_test_util = { path = "lwk_test_util" } 30 | lwk_tiny_jrpc = { path = "lwk_tiny_jrpc" } 31 | lwk_wollet = { path = "lwk_wollet" } 32 | 33 | [profile.release-smaller] 34 | inherits = "release" 35 | opt-level = 'z' # Optimize for size. 36 | lto = true # Enable Link Time Optimization 37 | codegen-units = 1 # Reduce number of codegen units to increase optimizations. 38 | panic = "abort" # Abort on panic 39 | strip = "debuginfo" # Partially strip symbols from binary 40 | 41 | [workspace.dependencies] 42 | log = "0.4.22" 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Except where noted in an individual source file, for sub-projects under the 2 | subprojects/ directory, and noted below, this code is covered by the following 3 | (BSD-MIT) license: 4 | 5 | Copyright (c) Blockstream, Inc 2024 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /context/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:1.81.0 2 | 3 | RUN apt update -qq 4 | RUN apt upgrade --no-install-recommends -yqq 5 | 6 | # libxml2-utils for xmllint 7 | # libudev-dev for jade serial 8 | # clang for wasm 9 | # libtinfo5 libncurses5 for swift 10 | # chromium-driver for wasm tests 11 | RUN apt install -y libudev-dev libxml2-utils clang libtinfo5 libncurses5 chromium-driver 12 | 13 | RUN rustup component add rustfmt 14 | RUN rustup component add clippy 15 | RUN rustup component add llvm-tools-preview 16 | RUN rustup target add wasm32-unknown-unknown 17 | RUN rustup install nightly # for docs building 18 | 19 | RUN cargo install cargo-audit 20 | RUN cargo install cargo-nextest 21 | RUN cargo install grcov 22 | RUN cargo install just 23 | 24 | # we don't need this, but it downloads and cache most of our dependency tree 25 | RUN cargo install lwk_cli 26 | 27 | COPY download_bins.sh /download_bins.sh 28 | RUN ./download_bins.sh 29 | 30 | # update the installation script with curl -fsSL https://get.docker.com -o get-docker.sh 31 | COPY get-docker.sh /get-docker.sh 32 | RUN sh ./get-docker.sh 33 | 34 | # move following layers up once upper layers needs modification 35 | 36 | RUN wget https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb -O packages-microsoft-prod.deb && dpkg -i packages-microsoft-prod.deb && rm packages-microsoft-prod.deb 37 | RUN apt update -qq && apt install -y dotnet-sdk-6.0 38 | 39 | RUN cargo install uniffi-bindgen-cs --git https://github.com/RCasatta/uniffi-bindgen-cs --rev fa87c381f88c8cacd26cf3e91e5c63af60162c3f 40 | -------------------------------------------------------------------------------- /context/download_bins.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | mkdir -p bin 5 | cd bin || exit 1 6 | 7 | # electrs 8 | FNAME=electrs_linux_esplora_a33e97e1a1fc63fa9c20a116bb92579bbf43b254_liquid && \ 9 | curl -Ls https://github.com/RCasatta/electrsd/releases/download/electrs_releases/${FNAME}.gz | gunzip > ${FNAME} && \ 10 | chmod +x $FNAME 11 | 12 | 13 | # elementsd 14 | curl -Ls https://github.com/ElementsProject/elements/releases/download/elements-23.2.4/elements-23.2.4-x86_64-linux-gnu.tar.gz | tar -xz 15 | 16 | # bitcoind 17 | curl -Ls https://bitcoincore.org/bin/bitcoin-core-26.0/bitcoin-26.0-x86_64-linux-gnu.tar.gz | tar -xz 18 | 19 | 20 | # Binaries for testing kotling bindings 21 | wget https://repo1.maven.org/maven2/net/java/dev/jna/jna/5.13.0/jna-5.13.0.jar 22 | 23 | FNAME=kotlin-compiler-1.8.20.zip && wget https://github.com/JetBrains/kotlin/releases/download/v1.8.20/${FNAME} && \ 24 | unzip ${FNAME} && rm $FNAME 25 | 26 | curl -Ls https://builds.openlogic.com/downloadJDK/openlogic-openjdk/11.0.21+9/openlogic-openjdk-11.0.21+9-linux-x64.tar.gz | tar -xz 27 | 28 | # swift 29 | curl -Ls https://download.swift.org/swift-5.5-release/ubuntu1804/swift-5.5-RELEASE/swift-5.5-RELEASE-ubuntu18.04.tar.gz | tar -xz 30 | 31 | # wasm 32 | curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh 33 | -------------------------------------------------------------------------------- /context/env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | export ELECTRS_LIQUID_EXEC="$PWD/bin/electrs_linux_esplora_a33e97e1a1fc63fa9c20a116bb92579bbf43b254_liquid" 3 | export ELEMENTSD_EXEC="$PWD/bin/elements-23.2.4/bin/elementsd" 4 | export BITCOIND_EXEC="$PWD/bin/bitcoin-26.0/bin/bitcoind" 5 | export JADE_EMULATOR_IMAGE_NAME=xenoky/local-jade-emulator 6 | export JADE_EMULATOR_IMAGE_VERSION="1.0.27" 7 | export PIN_SERVER_IMAGE_NAME=tulipan81/blind_pin_server 8 | export PIN_SERVER_IMAGE_VERSION=v0.0.7 9 | export ANDROID_NDK_HOME="$PWD/bin/android-ndk" 10 | export LIB_EXT=$([ $(uname) == "Darwin" ] && echo "dylib" || echo "so") 11 | export CLASSPATH="$CLASSPATH:$PWD/bin/jna-5.13.0.jar" 12 | export PATH="$PATH:$PWD/bin/kotlinc/bin:$PWD/bin/openlogic-openjdk-11.0.21+9-linux-x64/bin:$PWD/bin/swift-5.5-RELEASE-ubuntu18.04/usr/bin" 13 | export WASM_BINDGEN_TEST_TIMEOUT=60 14 | -------------------------------------------------------------------------------- /context/jade-emulator/Dockerfile.suffix: -------------------------------------------------------------------------------- 1 | 2 | RUN apt-get update && apt-get install -y tini 3 | 4 | COPY flash_image.bin / 5 | COPY qemu_efuse.bin / 6 | COPY start.sh / 7 | 8 | EXPOSE 30121 9 | 10 | CMD ["/start.sh"] 11 | 12 | -------------------------------------------------------------------------------- /context/jade-emulator/Readme.md: -------------------------------------------------------------------------------- 1 | # Jade emulator for LWK 2 | 3 | it's still a manual process 4 | 5 | ```shell 6 | $ export LWK= 7 | $ export JADE_EMULATOR_DIR=${LWK}/context/jade-emulator/ 8 | $ export VERSION=1.0.27 # update with recent tag 9 | $ cd /tmp 10 | $ git clone https://github.com/Blockstream/Jade 11 | $ cd Jade 12 | $ git checkout $VERSION 13 | $ git submodule update --init --recursive 14 | $ export BUILDER=$(cat .gitlab-ci.yml | grep sha256 | cut -d' ' -f2) # blockstream/verde@sha256:b95127cfd8c3df6031b6dcb8cdef163abd7da005d514f41d8ecefcfa21cc61d2 15 | $ docker run -v ${PWD}:/jade -p 30121:30121 -it $BUILDER bash 16 | # . $HOME/esp/esp-idf/export.sh 17 | # cd /jade 18 | # cp configs/sdkconfig_qemu_psram.defaults ./sdkconfig.defaults 19 | # idf.py all 20 | # virtualenv -p python3 ./venv3 21 | # source ./venv3/bin/activate 22 | # pip install -r requirements.txt 23 | # pip install click 24 | # ./tools/fwprep.py build/jade.bin build 25 | # ./main/qemu/make-flash-img.sh 26 | # mkdir firmware 27 | # cp /flash_image.bin firmware/ 28 | # cp /qemu_efuse.bin firmware/ 29 | # exit 30 | $ sudo chown -R $USER:$USER firmware/ 31 | $ mv firmware/* $JADE_EMULATOR_DIR 32 | $ cd $JADE_EMULATOR_DIR 33 | $ echo "FROM $BUILDER" > Dockerfile 34 | $ cat Dockerfile.suffix >> Dockerfile 35 | $ docker build . -t xenoky/local-jade-emulator:$VERSION 36 | $ docker push xenoky/local-jade-emulator:$VERSION # needs auth 37 | ``` 38 | -------------------------------------------------------------------------------- /context/jade-emulator/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | /usr/bin/tini -s -- /opt/bin/qemu-system-xtensa -nographic \ 4 | -machine esp32 \ 5 | -m 4M \ 6 | -drive file=/flash_image.bin,if=mtd,format=raw \ 7 | -nic user,model=open_eth,id=lo0,hostfwd=tcp:0.0.0.0:30121-:30121 \ 8 | -drive file=/qemu_efuse.bin,if=none,format=raw,id=efuse \ 9 | -global driver=nvram.esp32.efuse,property=drive,value=efuse \ 10 | -serial pty 11 | 12 | -------------------------------------------------------------------------------- /docs/demo.md: -------------------------------------------------------------------------------- 1 | # LWK Demo 2 | 3 | In this demo we will display some of the capabilities of **LWK**, 4 | using `lwk_cli`. 5 | 6 | ## Multisig wallet creation: 7 | * start a local LWK server 8 | * create a software signer 9 | * load a Jade signer 10 | * create a 2of2 multisig wallet with the software signer and Jade 11 | * get an address 12 | 13 | ![](multi.gif) 14 | 15 | ## Issuance using the multisig wallet: 16 | * receive some funds 17 | * create a PSET issuing an asset 18 | * sign it with the software signer 19 | * sign it with Jade 20 | * combine the PSETs 21 | * broadcast the transaction 22 | 23 | ![](issue.gif) 24 | 25 | This is the [unblinded issuance transaction](https://blockstream.info/liquidtestnet/tx/8ac20c80b115f202c03a3110f1b0a826c4ed9a91f0c09cd246e0bccdbfab914e#blinded=100000,144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49,eb72bab75085ab5861ac6e280977fdeb6c3c1c5f92af6a75bb6542c74d7c48fc,7804a46eb345dabbf136817e972cdacbbfe69f9641b09a3110d53e6b6f43ccf3,10,eeb2284be710e22b732416e9694e461c94da3208d4e1be7574295cd754dd766f,cf5840ee706fd12057479814ed68aa0607f1c0eb08ec2ab98640e3f806199705,df5b53c9ceff78595eaecbad828bdbc26296b08b59a7c49b86ee1ef75c28d4b5,1,fb6bd60cb0d5b91c1f41011d90f188cef9ecd61c306376b4fa61ba244874bf46,2bb129e283b713626942a6e0e2dec2c6b58d8e313ee1ebafa19964f5d55dd41b,cc94d5e59f7f1a57199d35659cbc4d91369c798eef9cb5b6c5d8ed0df9939262,99613,144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49,be5a56fcb0983c32f559e9ea2a5915fd0b42bbd1e234b825638a10124f254a36,59fbe4dead525c8ca428a6cad5048a78b9d260cb26f45bcb8b2505cbee5e4549): 26 | 27 | ![](unblinded.png) 28 | -------------------------------------------------------------------------------- /docs/issue.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blockstream/lwk/04838dd670c1e396648d4c3b0bb3505ffdfe5639/docs/issue.gif -------------------------------------------------------------------------------- /docs/logos/emblem/LWK_emblem_dark_on_transparent_rgb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blockstream/lwk/04838dd670c1e396648d4c3b0bb3505ffdfe5639/docs/logos/emblem/LWK_emblem_dark_on_transparent_rgb.png -------------------------------------------------------------------------------- /docs/logos/emblem/LWK_emblem_dark_on_transparent_rgb.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /docs/logos/emblem/LWK_emblem_dark_on_white_rgb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blockstream/lwk/04838dd670c1e396648d4c3b0bb3505ffdfe5639/docs/logos/emblem/LWK_emblem_dark_on_white_rgb.png -------------------------------------------------------------------------------- /docs/logos/emblem/LWK_emblem_on_dark_rgb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blockstream/lwk/04838dd670c1e396648d4c3b0bb3505ffdfe5639/docs/logos/emblem/LWK_emblem_on_dark_rgb.png -------------------------------------------------------------------------------- /docs/logos/emblem/LWK_emblem_on_transparent_rgb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blockstream/lwk/04838dd670c1e396648d4c3b0bb3505ffdfe5639/docs/logos/emblem/LWK_emblem_on_transparent_rgb.png -------------------------------------------------------------------------------- /docs/logos/emblem/LWK_emblem_on_transparent_rgb.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /docs/logos/monotone/LWK_monotone_dark_on_transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blockstream/lwk/04838dd670c1e396648d4c3b0bb3505ffdfe5639/docs/logos/monotone/LWK_monotone_dark_on_transparent.png -------------------------------------------------------------------------------- /docs/logos/monotone/LWK_monotone_dark_on_transparent.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /docs/logos/monotone/LWK_monotone_white_on_transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blockstream/lwk/04838dd670c1e396648d4c3b0bb3505ffdfe5639/docs/logos/monotone/LWK_monotone_white_on_transparent.png -------------------------------------------------------------------------------- /docs/logos/monotone/LWK_monotone_white_on_transparent.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /docs/logos/print/LWK_logo_dark_on_transparent_cmyk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blockstream/lwk/04838dd670c1e396648d4c3b0bb3505ffdfe5639/docs/logos/print/LWK_logo_dark_on_transparent_cmyk.png -------------------------------------------------------------------------------- /docs/logos/print/LWK_logo_dark_on_transparent_cmyk.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /docs/logos/print/LWK_logo_dark_on_white_cmyk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blockstream/lwk/04838dd670c1e396648d4c3b0bb3505ffdfe5639/docs/logos/print/LWK_logo_dark_on_white_cmyk.png -------------------------------------------------------------------------------- /docs/logos/print/LWK_logo_white_on_dark_cmyk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blockstream/lwk/04838dd670c1e396648d4c3b0bb3505ffdfe5639/docs/logos/print/LWK_logo_white_on_dark_cmyk.png -------------------------------------------------------------------------------- /docs/logos/print/LWK_logo_white_on_transparent_cmyk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blockstream/lwk/04838dd670c1e396648d4c3b0bb3505ffdfe5639/docs/logos/print/LWK_logo_white_on_transparent_cmyk.png -------------------------------------------------------------------------------- /docs/logos/print/LWK_logo_white_on_transparent_cmyk.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /docs/logos/web/LWK_logo_dark_on_transparent_rgb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blockstream/lwk/04838dd670c1e396648d4c3b0bb3505ffdfe5639/docs/logos/web/LWK_logo_dark_on_transparent_rgb.png -------------------------------------------------------------------------------- /docs/logos/web/LWK_logo_dark_on_transparent_rgb.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /docs/logos/web/LWK_logo_dark_on_white_rgb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blockstream/lwk/04838dd670c1e396648d4c3b0bb3505ffdfe5639/docs/logos/web/LWK_logo_dark_on_white_rgb.png -------------------------------------------------------------------------------- /docs/logos/web/LWK_logo_white_on_dark_rgb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blockstream/lwk/04838dd670c1e396648d4c3b0bb3505ffdfe5639/docs/logos/web/LWK_logo_white_on_dark_rgb.png -------------------------------------------------------------------------------- /docs/logos/web/LWK_logo_white_on_transparent_rgb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blockstream/lwk/04838dd670c1e396648d4c3b0bb3505ffdfe5639/docs/logos/web/LWK_logo_white_on_transparent_rgb.png -------------------------------------------------------------------------------- /docs/logos/web/LWK_logo_white_on_transparent_rgb.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /docs/logos_no_padding/LWK_dark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/logos_no_padding/LWK_dark_emblem.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/logos_no_padding/LWK_light.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/logos_no_padding/LWK_light_emblem.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/multi.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blockstream/lwk/04838dd670c1e396648d4c3b0bb3505ffdfe5639/docs/multi.gif -------------------------------------------------------------------------------- /docs/unblinded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blockstream/lwk/04838dd670c1e396648d4c3b0bb3505ffdfe5639/docs/unblinded.png -------------------------------------------------------------------------------- /lwk_app/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lwk_app" 3 | version = "0.9.0" 4 | edition = "2021" 5 | description = "Liquid Wallet Kit - RPC server App" 6 | license = "MIT OR BSD-2-Clause" 7 | documentation = "https://docs.rs/lwk_app" 8 | 9 | [dependencies] 10 | lwk_common = { version = "0.9.0" } 11 | lwk_jade = { version = "0.9.0" } 12 | lwk_signer = { version = "0.9.0" } 13 | lwk_wollet = { version = "0.9.0" } 14 | lwk_rpc_model = { version = "0.9.0" } 15 | lwk_tiny_jrpc = { version = "0.9.0" } 16 | 17 | jsonrpc = { version = "0.17.0" } 18 | serde = { version = "1.0", features = ["derive"] } 19 | serde_json = "1" 20 | secp256k1 = "0.27" 21 | thiserror = "1" 22 | log.workspace = true 23 | rand = "0.8.5" 24 | schemars = "0.8.16" 25 | home = "0.5.5" 26 | reqwest = { version = "0.12", default-features = false, features = [ 27 | "charset", 28 | "http2", 29 | "macos-system-configuration", 30 | "blocking", 31 | "json", 32 | "rustls-tls", 33 | ] } 34 | 35 | [features] 36 | serial = ["lwk_jade/serial"] 37 | 38 | [dev-dependencies] 39 | enum-iterator = "1.4.1" 40 | tempfile = "3.8.1" 41 | -------------------------------------------------------------------------------- /lwk_app/src/consts.rs: -------------------------------------------------------------------------------- 1 | use std::net::{Ipv4Addr, SocketAddrV4}; 2 | use std::time::Duration; 3 | 4 | pub const DEFAULT_ADDR: SocketAddrV4 = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 32_111); 5 | 6 | pub const APP_VERSION: &str = env!("CARGO_PKG_VERSION"); 7 | 8 | pub const SCANNING_INTERVAL: Duration = Duration::from_secs(10); 9 | -------------------------------------------------------------------------------- /lwk_app/src/reqwest_transport.rs: -------------------------------------------------------------------------------- 1 | use std::{fmt, time::Duration}; 2 | 3 | use jsonrpc::{Request, Response}; 4 | 5 | #[derive(Clone, Debug)] 6 | pub struct ReqwestHttpTransport { 7 | /// URL of the RPC server. 8 | url: String, 9 | /// timeout only supports second granularity. 10 | timeout: Duration, 11 | } 12 | 13 | impl ReqwestHttpTransport { 14 | pub fn new(url: String, timeout: Duration) -> Self { 15 | ReqwestHttpTransport { url, timeout } 16 | } 17 | fn request(&self, req: impl serde::Serialize) -> Result 18 | where 19 | R: for<'a> serde::de::Deserialize<'a>, 20 | { 21 | let client = reqwest::blocking::ClientBuilder::new() 22 | .timeout(self.timeout) 23 | .build()?; 24 | let response = client.post(&self.url).json(&req).send()?; 25 | Ok(response.json()?) 26 | } 27 | } 28 | 29 | impl From for jsonrpc::Error { 30 | fn from(value: crate::Error) -> Self { 31 | match value { 32 | crate::Error::JsonRpcClient(e) => e, 33 | e => jsonrpc::Error::Transport(Box::new(e)), 34 | } 35 | } 36 | } 37 | 38 | impl jsonrpc::Transport for ReqwestHttpTransport { 39 | fn send_request(&self, req: Request) -> Result { 40 | Ok(self.request(req)?) 41 | } 42 | 43 | fn send_batch(&self, reqs: &[Request]) -> Result, jsonrpc::Error> { 44 | Ok(self.request(reqs)?) 45 | } 46 | 47 | fn fmt_target(&self, f: &mut fmt::Formatter) -> fmt::Result { 48 | write!(f, "{}", self.url) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /lwk_bindings/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lwk_bindings" 3 | version = "0.9.1" 4 | edition = "2021" 5 | description = "Liquid Wallet Kit - Bindings for other languages" 6 | license = "MIT OR BSD-2-Clause" 7 | documentation = "https://docs.rs/lwk_bindings" 8 | 9 | [dependencies] 10 | lwk_common = { version = "0.9.0" } 11 | lwk_signer = { version = "0.9.0" } 12 | lwk_wollet = { version = "0.9.0" } 13 | lwk_test_util = { version = "0.9.0" } 14 | 15 | elements = "0.25.0" 16 | thiserror = "1.0.50" 17 | uniffi = { version = "0.28.2", features = ["bindgen-tests"] } 18 | serde_json = "1" 19 | 20 | [build-dependencies] 21 | uniffi = { version = "0.28.2", features = ["build"] } 22 | 23 | [lib] 24 | crate-type = ["staticlib", "cdylib", "rlib"] 25 | name = "lwk" 26 | 27 | [features] 28 | foreign_bindings = [] 29 | 30 | [package.metadata.docs.rs] 31 | all-features = true 32 | rustdoc-args = ["--cfg", "docsrs"] 33 | -------------------------------------------------------------------------------- /lwk_bindings/README-wheel.md: -------------------------------------------------------------------------------- 1 | # Liquid Wallet Kit 2 | 3 | A Python package to build on the [Liquid](https://blockstream.com/liquid/) network. 4 | 5 | ```python 6 | import lwk 7 | network = lwk.Network.mainnet() 8 | assert(str(network) == "Liquid") 9 | ``` 10 | 11 | ## Main Features 12 | 13 | * **Watch-Only** wallet support: using Liquid descriptors, better known as 14 | [CT descriptors](https://github.com/ElementsProject/ELIPs/blob/main/elip-0150.mediawiki). 15 | * **PSET** based: transactions are shared and processed using the 16 | [Partially Signed Elements Transaction](https://github.com/ElementsProject/elements/blob/1fcf0cf2323b7feaff5d1fc4c506fff5ec09132e/doc/pset.mediawiki) format. 17 | * **Electrum** and **Esplora** [backends](https://github.com/Blockstream/electrs): 18 | no need to run and sync a full Liquid node or rely on closed source servers. 19 | * **Asset issuance**, **reissuance** and **burn** support: manage the lifecycle 20 | of your Issued Assets with a lightweight client. 21 | * **Generic multisig** wallets: create a wallet controlled by 22 | any combination of hardware or software signers, with a user 23 | specified quorum. 24 | 25 | ## Examples 26 | 27 | * [List transactions](https://github.com/Blockstream/lwk/tree/master/lwk_bindings/tests/bindings/list_transactions.py) of a wpkh/slip77 wallet 28 | * [Send transaction](https://github.com/Blockstream/lwk/tree/master/lwk_bindings/tests/bindings/send_transaction.py) of a wpkh/slip77 wallet in a regtest environment 29 | * [Send asset](https://github.com/Blockstream/lwk/tree/master/lwk_bindings/tests/bindings/send_asset.py) of a wpkh/slip77 wallet in a regtest environment 30 | * [Custom persister](https://github.com/Blockstream/lwk/tree/master/lwk_bindings/tests/bindings/custom_persister.py), the caller code provide how the wallet updates are persisted 31 | 32 | 33 | -------------------------------------------------------------------------------- /lwk_bindings/android_bindings/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | *.so 17 | -------------------------------------------------------------------------------- /lwk_bindings/android_bindings/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | plugins { 3 | id("com.android.application") version "8.2.1" apply false 4 | id("org.jetbrains.kotlin.android") version "1.9.22" apply false 5 | id("com.android.library") version "8.2.1" apply false 6 | } -------------------------------------------------------------------------------- /lwk_bindings/android_bindings/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Kotlin code style for this project: "official" or "obsolete": 19 | kotlin.code.style=official 20 | # Enables namespacing of each library's R class so that its R class includes only the 21 | # resources declared in the library itself and none from the library's dependencies, 22 | # thereby reducing the size of the R class for that library 23 | android.nonTransitiveRClass=true 24 | 25 | libraryVersion= -------------------------------------------------------------------------------- /lwk_bindings/android_bindings/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blockstream/lwk/04838dd670c1e396648d4c3b0bb3505ffdfe5639/lwk_bindings/android_bindings/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /lwk_bindings/android_bindings/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jan 19 10:34:57 EET 2024 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /lwk_bindings/android_bindings/lib/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /lwk_bindings/android_bindings/lib/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blockstream/lwk/04838dd670c1e396648d4c3b0bb3505ffdfe5639/lwk_bindings/android_bindings/lib/consumer-rules.pro -------------------------------------------------------------------------------- /lwk_bindings/android_bindings/lib/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | 23 | # for JNA 24 | -dontwarn java.awt.* 25 | -keep class com.sun.jna.* { *; } 26 | -keep class lwk_bindings.** { *; } 27 | -keepclassmembers class * extends lwk_bindings.** { public *; } 28 | -keepclassmembers class * extends com.sun.jna.* { public *; } -------------------------------------------------------------------------------- /lwk_bindings/android_bindings/lib/src/androidTest/kotlin/com/blockstream/lwk_bindings/InstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.blockstream.lwk_bindings 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | import lwk_bindings.Mnemonic 6 | import lwk_bindings.NetworkBuilder 7 | import lwk_bindings.Signer 8 | import lwk_bindings.Wollet 9 | 10 | import org.junit.Test 11 | import org.junit.runner.RunWith 12 | 13 | import org.junit.Assert.* 14 | 15 | /** 16 | * Instrumented test, which will execute on an Android device. 17 | * 18 | * See [testing documentation](http://d.android.com/tools/testing). 19 | */ 20 | @RunWith(AndroidJUnit4::class) 21 | class InstrumentedTest { 22 | 23 | @Test 24 | fun test() { 25 | // MOVED to lwk_bindings/tests/bindings/list_transactions.kts cause there it's enforced in CI 26 | } 27 | } -------------------------------------------------------------------------------- /lwk_bindings/android_bindings/lib/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /lwk_bindings/android_bindings/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | gradlePluginPortal() 6 | } 7 | } 8 | dependencyResolutionManagement { 9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 10 | repositories { 11 | google() 12 | mavenCentral() 13 | } 14 | } 15 | 16 | rootProject.name = "lwk_bindings" 17 | include(":lib") -------------------------------------------------------------------------------- /lwk_bindings/csharp/LICENSE: -------------------------------------------------------------------------------- 1 | Except where noted in an individual source file, for sub-projects under the 2 | subprojects/ directory, and noted below, this code is covered by the following 3 | (BSD-MIT) license: 4 | 5 | Copyright (c) Blockstream, Inc 2024 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /lwk_bindings/csharp/LiquidWalletKit.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | LiquidWalletKit 4 | 0.8.2 5 | Blockstream 6 | C# Liquid Wallet Kit 7 | net6.0 8 | enable 9 | enable 10 | true 11 | true 12 | README.md 13 | LICENSE 14 | https://github.com/blockstream/lwk 15 | https://github.com/blockstream/lwk 16 | git 17 | bitcoin liquid blockstream sdk non-custodial 18 | 2024 Blockstream 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /lwk_bindings/csharp/README.md: -------------------------------------------------------------------------------- 1 | # C# Liquid Wallet Kit 2 | -------------------------------------------------------------------------------- /lwk_bindings/lwk/__init__.py: -------------------------------------------------------------------------------- 1 | from .lwk import * # NOQA 2 | 3 | __doc__ = lwk.__doc__ 4 | if hasattr(lwk, "__all__"): 5 | __all__ = lwk.__all__ 6 | 7 | # TODO: `help(lwk)` shows nested packages like `lwk.lwk.lwk.Address` even though 8 | # they are available with just `lwk.Address` 9 | 10 | -------------------------------------------------------------------------------- /lwk_bindings/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "lwk" 3 | version = "0.9.1" 4 | description = "Liquid Wallet Kit" 5 | keywords = ["liquid", "elements", "wallet"] 6 | readme = "README-wheel.md" 7 | 8 | [project.urls] 9 | homepage = "https://github.com/blockstream/lwk" 10 | documentation = "https://docs.rs/lwk_bindings/latest/lwk_bindings/" 11 | 12 | [build-system] 13 | requires = ["maturin>=1.0,<2.0"] 14 | build-backend = "maturin" 15 | 16 | [tool.maturin] 17 | bindings = "uniffi" 18 | -------------------------------------------------------------------------------- /lwk_bindings/src/blockdata/address_result.rs: -------------------------------------------------------------------------------- 1 | use crate::Address; 2 | use std::sync::Arc; 3 | 4 | #[derive(uniffi::Object)] 5 | pub struct AddressResult { 6 | inner: lwk_wollet::AddressResult, 7 | } 8 | 9 | impl From for AddressResult { 10 | fn from(inner: lwk_wollet::AddressResult) -> Self { 11 | Self { inner } 12 | } 13 | } 14 | 15 | #[uniffi::export] 16 | impl AddressResult { 17 | pub fn address(&self) -> Arc
{ 18 | Arc::new(self.inner.address().clone().into()) 19 | } 20 | 21 | pub fn index(&self) -> u32 { 22 | self.inner.index() 23 | } 24 | } 25 | 26 | #[cfg(test)] 27 | mod tests { 28 | 29 | use std::str::FromStr; 30 | 31 | use super::AddressResult; 32 | 33 | #[test] 34 | fn address_result() { 35 | let address_str = "tlq1qq2xvpcvfup5j8zscjq05u2wxxjcyewk7979f3mmz5l7uw5pqmx6xf5xy50hsn6vhkm5euwt72x878eq6zxx2z58hd7zrsg9qn"; 36 | let index = 0; 37 | let wollet_address_result = lwk_wollet::AddressResult::new( 38 | elements::Address::from_str(address_str).unwrap(), 39 | index, 40 | ); 41 | 42 | let address_result: AddressResult = wollet_address_result.into(); 43 | 44 | assert_eq!(address_result.address().to_string(), address_str); 45 | 46 | assert_eq!(address_result.index(), index); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lwk_bindings/src/blockdata/mod.rs: -------------------------------------------------------------------------------- 1 | //! Elements block data. 2 | //! 3 | //! This module defines structures contained in the Elements Blockchain 4 | //! 5 | 6 | pub mod address; 7 | pub mod address_result; 8 | pub mod out_point; 9 | pub mod script; 10 | pub mod transaction; 11 | pub mod tx_in; 12 | pub mod tx_out; 13 | pub mod tx_out_secrets; 14 | pub mod txid; 15 | pub mod wallet_tx; 16 | pub mod wallet_tx_out; 17 | -------------------------------------------------------------------------------- /lwk_bindings/src/blockdata/out_point.rs: -------------------------------------------------------------------------------- 1 | use crate::{LwkError, Txid}; 2 | use std::{fmt::Display, sync::Arc}; 3 | 4 | #[derive(uniffi::Object)] 5 | #[uniffi::export(Display)] 6 | pub struct OutPoint { 7 | inner: elements::OutPoint, 8 | } 9 | 10 | impl From for OutPoint { 11 | fn from(inner: elements::OutPoint) -> Self { 12 | Self { inner } 13 | } 14 | } 15 | 16 | impl From for elements::OutPoint { 17 | fn from(o: OutPoint) -> Self { 18 | o.inner 19 | } 20 | } 21 | 22 | impl From<&OutPoint> for elements::OutPoint { 23 | fn from(o: &OutPoint) -> Self { 24 | o.inner 25 | } 26 | } 27 | 28 | impl Display for OutPoint { 29 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 30 | write!(f, "{}", self.inner) 31 | } 32 | } 33 | 34 | #[uniffi::export] 35 | impl OutPoint { 36 | /// Construct an OutPoint object 37 | #[uniffi::constructor] 38 | pub fn new(s: &str) -> Result, LwkError> { 39 | let inner: elements::OutPoint = s.parse()?; 40 | Ok(Arc::new(Self { inner })) 41 | } 42 | 43 | pub fn txid(&self) -> Arc { 44 | Arc::new(self.inner.txid.into()) 45 | } 46 | 47 | pub fn vout(&self) -> u32 { 48 | self.inner.vout 49 | } 50 | } 51 | 52 | #[cfg(test)] 53 | mod tests { 54 | use crate::OutPoint; 55 | use std::str::FromStr; 56 | 57 | #[test] 58 | fn out_point() { 59 | let expected_txid = "0000000000000000000000000000000000000000000000000000000000000001"; 60 | let expected_vout = 1; 61 | let expected = format!("[elements]{expected_txid}:{expected_vout}"); 62 | let out_point_elements = elements::OutPoint::new( 63 | elements::Txid::from_str(expected_txid).unwrap(), 64 | expected_vout, 65 | ); 66 | 67 | assert_eq!(expected, out_point_elements.to_string()); 68 | let out_point_bindings = OutPoint::new(&expected).unwrap(); 69 | assert_eq!(expected, out_point_bindings.to_string()); 70 | 71 | let out_point: OutPoint = out_point_elements.into(); 72 | assert_eq!(expected, out_point.to_string()); 73 | 74 | assert_eq!(expected_txid, out_point.txid().to_string()); 75 | 76 | assert_eq!(expected_vout, out_point.vout()); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /lwk_bindings/src/blockdata/script.rs: -------------------------------------------------------------------------------- 1 | use elements::{hex::ToHex, pset::serialize::Deserialize}; 2 | 3 | use crate::{types::Hex, LwkError}; 4 | use std::{fmt::Display, sync::Arc}; 5 | 6 | #[derive(uniffi::Object)] 7 | #[uniffi::export(Display)] 8 | pub struct Script { 9 | inner: elements::Script, 10 | } 11 | 12 | impl From for Script { 13 | fn from(inner: elements::Script) -> Self { 14 | Self { inner } 15 | } 16 | } 17 | 18 | impl From