add agent/readme docs

This commit is contained in:
Nick Pulido
2026-05-20 21:59:04 -07:00
parent a4310317a0
commit 4982ac8a35
3 changed files with 553 additions and 0 deletions
+184
View File
@@ -0,0 +1,184 @@
# Garnet Integration into Amethyst - Project Notes & Learnings
## Quick Reference
| Item | Value |
|------|-------|
| **Garnet repo** | https://github.com/retrnull/garnet |
| **Amethyst repo** | https://github.com/vitorpamplona/amethyst |
| **Garnet base amethyst commit** | `175b79b29` (April 2024) |
| **Garnet fork date** | ~July 10, 2024 |
| **Latest amethyst commit** | `c19f0be57` (May 2026) |
| **Commits since fork** | ~9,330 |
| **Garnet version** | v0.3.0 |
| **Monero source** | https://github.com/retrnull/monero (branch: `release-v0.18.3.3-garnet`) |
---
## What Garnet Adds to Amethyst
Garnet adds **Monero tipping/zapping** support, mirroring how Amethyst already handles Lightning (Zap) tips. Key features:
1. **Monero wallet generation** - Derives a Monero spend key from the Nostr private key
2. **Tip integration** - "monero" tags on posts (similar to NIP-57 zap tags)
3. **3 tip modes** - Private, Anonymous, Public
4. **Tip event (kind 1814)** - Records on-chain transactions
5. **Tip display** - Counter on tipped notes and user profile
6. **Wallet balance display & transfers** - Internal Monero wallet with send to external wallet
### Code Changes Summary (vs Amethyst base at fork time)
- **103 files changed**, 11,569 insertions, 537 deletions
- **~1,750 lines** of C++ (Monero JNI bridge: monerujo.cpp + monerujo.h)
- **~30 Kotlin source files** (model, service, UI, quartz events)
- **New resources** - monero.xml icon, monero-specific strings
---
## Build Findings
### 1. Base amethyst builds cleanly (verified)
```bash
cd ~/projects/amethyst && ./gradlew assembleFdroidDebug
# BUILD SUCCESSFUL - ~116 tasks in 2m44s
```
### 2. Monero native libraries can be extracted from prebuilt APK
Download garnet v0.3.0 APK, extract `.so` files:
- `libmonerujo.so` - Monero JNI bridge (contains all monero dependencies)
- `libsodium.so` - Cryptographic library
- `libsecp256k1-jni.so` - secp256k1
- `libc++_shared.so` - C++ runtime
Place in `jniLibs/`, no CMake needed for these prebuilt binaries.
### 3. Garnet build is blocked by dependency issues
- `compose-richtext:richtext-ui:077a2cde64` **cannot be resolved from jitpack.io** (even though it shows "ok" on jitpack status)
- Workaround version `e9e0869266` exists but pulls kotlin-stdlib 2.2.0 incompatible with garnet's Kotlin 1.9.23
### 4. Monero Kotlin code has 667+ compilation errors when copied to latest amethyst
The monero integration was written against amethyst v0.4.x (April 2024). Key breaking changes since then:
#### Quartz Event Model
- **Old structure**: Single `quartz/src/main/java/com/vitorpamplona/quartz/events/Event.kt`
- **New structure**: Split across modules, `commonMain/kotlin`, KMP targets
- `HexKey`, `EventInterface`, `AddressableEvent`, `NostrSigner` moved to new packages in `nip01Core/`
#### Material3 / Compose
- `rememberRipple(Boolean, Dp, Color)` is deprecated and removed (error, not warning)
- `autoCorrect` parameter renamed/removed in TextField
- `HeadingStyle` moved/renamed
#### Module Structure
- `quartz` is now Kotlin Multiplatform (`commonMain`, `androidMain`, `jvmMain`)
- `commons` is KMP
- `gem` module removed, `geode` module added
- Settings.gradle changed from `.gradle` to `.gradle.kts`, modules renamed
#### API Changes
- Kotlin 1.9.23 → 2.3.21 → various dependency incompatibilities
- Gradle 8.4 → 9.x
- Compose BOM 2024.04.00 → 2026.05.00
- Material3 ripple API changed
---
## Docker / Monero Build Findings
### The Docker build approach is fragile
The monero build Dockerfiles (`android64.Dockerfile`, etc.) have multiple issues:
1. **Old Debian base** - `debian:stable``debian:bookworm` required
2. **Hardcoded NDK r17c** - Old, needs upgrade for modern toolchain
3. **Hash mismatches** - boost, zlib, openssl hashes no longer match available versions
4. **Missing dependencies** - Docker build fails without fixes to apt packages
### Alternative: Use system NDK
System NDK available at `~/Android/Sdk/ndk/29.0.13846066/`
- Toolchains: `aarch64-linux-android21-clang`, `armv7a-linux-androideabi21-clang`, `x86_64-linux-android21-clang`, `i686-linux-android21-clang`
- Monero make targets: `release-static-android-armv8-wallet_api`, `release-static-android-armv7-wallet_api`, `release-static-android-x86_64-wallet_api`, `release-static-android-x86-wallet_api`
### The prebuilt APK approach works
Since the monero libs are fully self-contained in `libmonerujo.so`, we can skip rebuilding monero entirely and use the released APK's `.so` files as a temporary solution.
---
## File Structure Mapping
### Garnet → Amethyst file mapping
| Garnet file (old) | New location (amethyst) |
|---|---|
| `app/src/main/java/.../model/` | `amethyst/src/main/java/.../model/` |
| `app/src/main/java/.../service/` | `amethyst/src/main/java/.../service/` |
| `app/src/main/java/.../ui/` | `amethyst/src/main/java/.../ui/` |
| `app/src/main/java/.../ui/note/` | `amethyst/src/main/java/.../ui/note/` |
| `app/src/main/java/.../ui/screen/` | `amethyst/src/main/java/.../ui/screen/` |
| `app/src/main/java/.../ui/dal/` | `amethyst/src/main/java/.../ui/dal/` |
| `quartz/src/main/java/com/vitorpamplona/quartz/events/` | **Moved to KMP - see below** |
| `app/src/main/res/` | `amethyst/src/main/res/` |
| `app/src/main/cpp/` | `amethyst/src/main/cpp/` |
### Quartz event files - the biggest restructure
Garnet adds/modifies these quartz event files:
- `TipEvent.kt` (new) - **Must be adapted for KMP structure**
- `Event.kt` - Modified (adds Monero-specific handling)
- `EventInterface.kt` - Modified
- `CryptoUtils.kt` - Modified
- Various event subclasses modified
In latest amethyst, quartz events live in:
```
/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/events/
```
and reference types from:
```
/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/
```
---
## Key Learnings for Next Session
1. **Start from latest amethyst, NOT garnet** - 9,330 commits since fork makes reverse-merging impossible
2. **Diff garnet against amethyst base 175b79b29** - This gives exact changes to apply
3. **Follow existing event patterns** - Study TipEvent.kt, LnZapEvent.kt in latest amethyst for the new structure
4. **Material3 APIs have changed** - Replace `rememberRipple` calls, check TextField parameters
5. **KMP quartz module** - Quartz event classes need to be in `commonMain/kotlin` not `main/java`
6. **Dependencies may need updating** - richtext version, kotlin version, compose BOM
7. **Prebuilt .so files work** - Can skip monero build if needed; use garnet APK's libmonerujo.so
8. **Amethyst builds cleanly** - Use as baseline; verify after each change
9. **gradle/libs.versions.toml** is the single source of truth for all version updates
---
## Next Session Task Plan
See [GARNET_MERGE_PLAN.md](./GARNET_MERGE_PLAN.md) for the detailed step-by-step plan.
## Commands Used in This Session
```bash
# Find garnet repo
curl -s "https://api.github.com/search/repositories?q=garnet+nostr&sort=stars"
# Clone repos
git clone https://github.com/retrnull/garnet.git
git clone https://github.com/vitorpamplona/amethyst.git
# Get garnet diff against amethyst base
cd garnet; git diff 99614f07..bfaf92e5 --stat
# Extract monero APK libs
curl -L -o garnet.apk "https://github.com/retrnull/garnet/releases/download/v0.3.0/app-mainnet-fdroid-universal-release.apk"
unzip garnet.apk -d extracted-libs/
# libmonerujo.so was all we needed
# Verify amethyst builds
./gradlew assembleFdroidDebug 2>&1 | tail -3
# Build garnet (fail - richtext dependency)
./gradlew assembleMainnetFdroidDebug 2>&1 | tail -10
# Count monero compilation errors in amethyst
./gradlew compileFdroidDebugKotlin 2>&1 | grep "^e:" | wc -l # 667 errors
```
+303
View File
@@ -0,0 +1,303 @@
# Plan: Integrate Garnet (Monero Tipping) into Latest Amethyst
## Approach
Create a new branch in amethyst and port all 30+ Kotlin source files from garnet, adapting them for the current amethyst codebase. The C++ monero bridge (`monerujo.cpp/.h`) can be copied with minor changes. Prebuilt `.so` files from garnet APK will be used temporarily to avoid the broken monero build process.
---
## Phase 1: Investigation (No changes)
### Step 1.1: Identify all changes in garnet
Garnet's diff against amethyst base (`175b79b29`):
- 103 files changed, 11,569 insertions, 537 deletions
- See `~/projects/garnet` diff output for full list
### Step 1.2: Generate the exact diff
Command to run:
```bash
cd ~/projects/garnet
# The base amethyst commit that garnet was derived from is 175b79b29
# We need the full diff between garnet and amethyst at that commit
# First, find the exact amethyst code at fork point:
git diff bfaf92e5~1..HEAD --name-only # All changed files in garnet
```
### Step 1.3: Identify which files need porting vs which are already in latest amethyst
Some monero-related UI elements may already exist in amethyst (zap UI, lightning), so we should check if any garnet UI work overlaps with existing features.
### Step 1.4: Study the new amethyst event patterns
Study these files in latest amethyst to understand the new Quartz/KMP event structure:
```
/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/events/TipEvent.kt
/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/events/LnZapEvent.kt
/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/HexKey.kt
/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/AddressableEvent.kt
/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/NostrSigner.kt
```
---
## Phase 2: Native Library Setup
### Step 2.1: Extract and place prebuilt libmonerujo.so
Since the monero build Docker approach is broken and the prebuilt .so from garnet APK works:
```bash
# Download garnet APK and extract libmonerujo.so
curl -L -o /tmp/garnet.apk "https://github.com/retrnull/garnet/releases/download/v0.3.0/app-mainnet-fdroid-universal-release.apk"
mkdir -p /tmp/garnet-extract && unzip -o /tmp/garnet.apk -d /tmp/garnet-extract/
```
Place extracted `.so` files into `amethyst/amethyst/src/main/jniLibs/`:
```
jniLibs/arm64-v8a/libmonerujo.so
jniLibs/arm64-v8a/libsodium.so
jniLibs/arm64-v8a/libc++_shared.so
jniLibs/arm64-v8a/libsecp256k1-jni.so
jniLibs/armeabi-v7a/ (same)
jniLibs/x86_64/ (same)
```
### Step 2.2: Copy monero C++ source files
Copy from garnet to amethyst:
- `garnet/app/src/main/cpp/monerujo.cpp``amethyst/amethyst/src/main/cpp/monerujo.cpp`
- `garnet/app/src/main/cpp/monerujo.h``amethyst/amethyst/src/main/cpp/monerujo.h`
- `garnet/external-libs/monero/src/wallet/api/wallet2_api.h``amethyst/amethyst/src/main/cpp/wallet2_api.h`
### Step 2.3: Remove CMakeLists.txt or make it optional
If the amethyst build doesn't have a `CMakeLists.txt`, we need to either:
- Add a minimal one that doesn't try to compile anything
- Or ensure the build.gradle doesn't reference CMake at all
- Or make `amethyst/src/main/cpp/` only be used when the .so files are present
---
## Phase 3: Port Kotlin Source Files (Model Layer)
Copy these files from garnet to latest amethyst, adapting for the new structure:
### New files (create in amethyst):
| Garnet Source | Destination | Priority |
|---|---|---|
| `MoneroWalletListener.kt` | `amethyst/model/` | High |
| `Wallet.kt` | `amethyst/model/` | High |
| `WalletManager.kt` | `amethyst/model/` | High |
| `MoneroDataSource.kt` | `amethyst/service/` | High |
| `TipEventDataSource.kt` | `amethyst/service/` | High |
| `TipHandler.kt` | `amethyst/service/` | High |
| `WalletService.kt` | `amethyst/service/` | High |
| `PendingTransaction.kt` | `amethyst/model/` | Medium |
| `ProofInfo.kt` | `amethyst/model/` | Medium |
| `Subaddress.kt` | `amethyst/model/` | Medium |
| `Transaction.kt` | `amethyst/model/` | Medium |
| `TransactionHistory.kt` | `amethyst/model/` | Medium |
| `TransactionInfo.kt` | `amethyst/model/` | Medium |
| `Transfer.kt` | `amethyst/model/` | Medium |
### Existing files that need modification:
| File | Changes needed |
|---|---|
| `Account.kt` | Add monero address management (key derivation, address storage) |
| `LocalCache.kt` | Add monero preferences |
| `LocalPreferences.kt` | Add monero-specific preference keys |
| `Note.kt` | Add monero tag handling |
| `User.kt` | Add monero address from type-0 event |
| `ServiceManager.kt` | Add wallet service lifecycle |
| `NostrAccountDataSource.kt` | Add monero account methods |
---
## Phase 4: Port Quartz Event Files (KMP Module)
### New TipEvent.kt for KMP structure
Study the existing `TipEvent.kt` in amethyst and `TipEvent.kt` in garnet (kind 1814). Adapt garnet's Monero TipEvent to follow the new pattern:
```kotlin
// Pattern to follow (from LnZapEvent.kt):
package com.vitorpamplona.quartz.events
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner
import com.vitorpamplona.quartz.nip01Core.core.IEvent
class MoneroTipEvent(
id: HexKey,
pubKey: HexKey,
createdAt: Long,
tags: Array<Array<String>>,
content: String,
sig: HexKey,
) : Event(id, pubKey, createdAt, KIND, tags, content, sig) {
// ... monero-specific logic
companion object {
const val KIND = 1814
// factory methods, tip proof parsing, etc.
}
}
```
Place at: `/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/events/MoneroTipEvent.kt`
### Modify Event.kt and EventFactory.kt
Garnet adds Monero-specific event handling in:
- `Event.kt` - Add Monero tag extraction from type-0 metadata
- `EventFactory.kt` - Add Monero events to factory
---
## Phase 5: Port UI Components
### New UI files:
| Garnet Source | Destination | Priority |
|---|---|---|
| `MoneroScreen.kt` | `ui/screen/loggedIn/` | High |
| `Tip.kt` | `ui/components/` | Medium |
| `TipCustomDialog.kt` | `ui/note/` | Medium |
| `TipNoteCompose.kt` | `ui/note/` | Medium |
| `TipUserSetCompose.kt` | `ui/note/` | Medium |
| `UpdateTipAmountDialog.kt` | `ui/note/` | Medium |
| `DisplayTipSplits.kt` | `ui/note/elements/` | Medium |
| `TipFeedViewModel.kt` | `ui/screen/` | High |
| `TipFeedState.kt` | `ui/screen/` | High |
| `TipFeedView.kt` | `ui/screen/` | High |
| `UserProfileTipsFeedFilter.kt` | `ui/dal/` | Medium |
### Existing files that need modification:
| File | Changes needed |
|---|---|
| `Routes.kt` | Add monero route |
| `AppNavigation.kt` | Add monero navigation |
| `AppTopBar.kt` | Add monero icon/button |
| `MainScreen.kt` | Add monero screen |
| `NoteCompose.kt` | Integrate monero tips display |
| `ReactionsRow.kt` | Add monero tip reactions |
| `ProfileScreen.kt` | Add monero tips tab |
| `NewPostView.kt` / `NewPostViewModel.kt` | Add monero tag to new posts |
### Adapt UI for Material3 changes:
- Replace `rememberRipple(Boolean, Dp, Color)` → use `LocalRippleInfo.current`
- Replace `autoCorrect` → check TextField API
- Adapt to any Compose parameter changes
---
## Phase 6: Resources and Build Configuration
### Strings
Add Monero-specific strings to `amethyst/amethyst/src/main/res/values/strings.xml`:
(129 strings changed in garnet diff)
### Icons
Add `monero.xml` to `amethyst/amethyst/src/main/res/drawable/`
### Build Configuration
Update `amethyst/amethyst/build.gradle.kts`:
- Ensure JNA dependency for monero JNI
- Add libsodium dependency (or verify it's transitively included)
---
## Phase 7: Build and Verify
### Build without failures:
```bash
cd ~/projects/amethyst
./gradlew assembleFdroidDebug
```
### Expected issues to fix:
1. **Import paths** - Update all quartz imports to new KMP locations (`nip01Core.core.*`, etc.)
2. **API changes** - Fix `rememberRipple`, TextField parameters, etc.
3. **Kotlin type inference** - Add explicit type parameters where needed
4. **Missing companion objects** - Add `companion object { val KIND = ... }`
5. **Jackson serialization** - Ensure Jackson annotations match new patterns
---
## Risk Assessment
| Risk | Likelihood | Mitigation |
|---|---|---|
| Monero TipEvent conflicts with existing Zap TipEvent | Medium | Study existing implementation before starting |
| Quartz KMP structure causes issues | High | Study existing events first; use as template |
| Material3 API changes cause errors | Medium | Fix iteratively as they appear |
| Dependencies break build | Low | Start clean, add one file at a time |
| Monoro .so ABI mismatch with target SDK | Low | Use same ABI as garnet (arm64-v8a, armeabi-v7a, x86_64) |
---
## Execution Strategy
1. **Start with one file at a time** - Verify build after each addition
2. **Order: Model → Service → Quartz → UI → Navigation**
3. **Study first, copy second, adapt last** - Understand each pattern before applying
4. **Use git to track progress** - Small commits, easy to revert if needed
5. **Verify after each phase** - Ensure base amethyst still builds
---
## Files to Port (Complete List)
### New files to create:
- `amethyst/src/main/java/.../model/MoneroWalletListener.kt`
- `amethyst/src/main/java/.../model/Wallet.kt`
- `amethyst/src/main/java/.../model/WalletManager.kt`
- `amethyst/src/main/java/.../service/MoneroDataSource.kt`
- `amethyst/src/main/java/.../service/TipEventDataSource.kt`
- `amethyst/src/main/java/.../service/TipHandler.kt`
- `amethyst/src/main/java/.../service/WalletService.kt`
- `amethyst/src/main/java/.../ui/screen/loggedIn/MoneroScreen.kt`
- `amethyst/src/main/java/.../ui/screen/TipFeedState.kt`
- `amethyst/src/main/java/.../ui/screen/TipFeedView.kt`
- `amethyst/src/main/java/.../ui/screen/TipFeedViewModel.kt`
- `amethyst/src/main/java/.../ui/components/Tip.kt`
- `amethyst/src/main/java/.../ui/note/TipCustomDialog.kt`
- `amethyst/src/main/java/.../ui/note/TipNoteCompose.kt`
- `amethyst/src/main/java/.../ui/note/TipUserSetCompose.kt`
- `amethyst/src/main/java/.../ui/note/UpdateTipAmountDialog.kt`
- `amethyst/src/main/java/.../ui/note/elements/DisplayTipSplits.kt`
- `amethyst/src/main/java/.../ui/dal/UserProfileTipsFeedFilter.kt`
- `quartz/src/commonMain/kotlin/.../events/MoneroTipEvent.kt`
### Files to modify:
- `Account.kt` - Monero address management
- `LocalPreferences.kt` - Add monero prefs
- `LocalCache.kt` - Add monero cache keys
- `Note.kt` - Add monero tag extraction
- `User.kt` - Add monero address from metadata
- `ServiceManager.kt` - Add wallet service
- `Routes.kt` - Add monero route
- `AppNavigation.kt` - Add monero navigation
- `AppTopBar.kt` - Add monero icon
- `MainScreen.kt` - Add monero screen
- `NoteCompose.kt` - Display monero tips
- `ReactionsRow.kt` - Monero tip reactions
- `ProfileScreen.kt` - Monero tips tab
- `NewPostView.kt` / `NewPostViewModel.kt` - Add monero tags
- `strings.xml` - Add monero strings
- `Event.kt` - Add Monero metadata handling (quartz)
### Files to copy (native):
- `amethyst/src/main/cpp/monerujo.cpp`
- `amethyst/src/main/cpp/monerujo.h`
- `amethyst/src/main/cpp/wallet2_api.h`
- `amethyst/src/main/jniLibs/*/libmonerujo.so`
- `amethyst/src/main/jniLibs/*/libsodium.so`
- `amethyst/src/main/res/drawable/monero.xml`
+66
View File
@@ -0,0 +1,66 @@
# Garnet Merge Attempt — Status & Notes
## What is Garnet?
Garnet ([github.com/retrnull/garnet](https://github.com/retrnull/garnet)) is an Amethyst fork that adds **Monero tipping/zapping** support alongside Lightning (zap) tips. Key features:
- Monero wallet key derived from the user's Nostr private key
- Three tip modes: private, anonymous, public
- `monero` tags on posts (similar to NIP-57 zap tags)
- Tip counter on notes and profiles, like zaps
- Send received tips to an external wallet
## Summary of Merge Attempt (May 2026)
We attempted to merge Garnet's Monero integration into the latest Amethyst codebase. The effort produced the following artifacts (in `~/projects/amethyst/`):
| File | Purpose |
|---|---|
| `AGENTS.md` | Detailed build findings, API changes, file mappings, lesson learned |
| `GARNET_MERGE_PLAN.md` | 7-phase step-by-step plan for porting 30+ source files |
| `GARNET_README.md` | ← this file |
### Key Findings
| ✓ Success | ✗ Failed |
|---|---|
| Base Amethyst builds cleanly (~116 tasks in ~3 min) | Garnet's richtext dependency (`077a2cde64`) no longer resolves from jitpack.io |
| Prebuilt `libmonerujo.so` extracted from garnet releases works with Amethyst | Direct merge of monero Kotlin code → 667+ compilation errors |
| Amethyst v0.4.x → current version gap = 9,330 commits | Amethyst moved to KMP; quartz events are now in `commonMain/kotlin` |
### Why the merge is non-trivial
Garnet was forked from Amethyst at commit `175b79b29` (April 2024). Since then, Amethyst has:
1. **Moved to KMP**`quartz/` and `commons/` are now Kotlin Multiplatform modules (`commonMain/`, `androidMain/`)
2. **Restructured internals** — types like `HexKey`, `NostrSigner`, `EventInterface` moved into `nip01Core/` packages
3. **Upgraded Material3**`rememberRipple(Boolean, Dp, Color)` removed (was an error, not warning)
4. **Updated toolchain** — Kotlin 1.9.23 → 2.3.21, Gradle 8.4 → 9.x, Compose BOM 2024.04 → 2026.05
The monero code (~11,500 lines across 103 files) was written against 2024-era Amethyst APIs and needs adaptation for the current structure.
### Recommended path forward
1. Start from **latest Amethyst** (not Garnet) — the 9,330-commit merge would be painful
2. Copy ~30 source files from Garnet into Amethyst, adapting imports, package paths, and Material3 APIs
3. Use the prebuilt `libmonerujo.so` from garnet releases to skip rebuilding monero via Docker (the Docker build is broken in 2026)
4. Port one file at a time, verifying `./gradlew assembleFdroidDebug` after each phase
See `AGENTS.md` for the full investigation log and `GARNET_MERGE_PLAN.md` for the detailed step-by-step plan.
### Quick commands for a new session
```bash
# Verify baseline builds
cd ~/projects/amethyst && ./gradlew assembleFdroidDebug | tail -3
# Get the diff between Garnet and the fork point
cd ~/projects/garnet
git diff 99614f07..bfaf92e5 --stat # 103 files
git diff 99614f07..bfaf92e5 --name-status # file list with A/M/D status
# Extract native libs from garnet releases
curl -L -o /tmp/garnet.apk "https://github.com/retrnull/garnet/releases/download/v0.3.0/app-mainnet-fdroid-universal-release.apk"
unzip -o /tmp/garnet.apk -d /tmp/garnet/
# libmonerujo.so is in extracted-libs/lib/<abi>/
```