Skip to content

Commit dedea29

Browse files
authored
Merge branch 'master' into chore/keychain-error-logs
2 parents 32a9101 + d7dcefa commit dedea29

30 files changed

Lines changed: 1251 additions & 72 deletions

File tree

.claude/install-plugins.sh

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#!/usr/bin/env bash
2+
set -u -o pipefail
3+
4+
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
5+
MARKETPLACE_DIR="$REPO_ROOT/.claude/plugins"
6+
MARKETPLACE_NAME="bitkit-android"
7+
8+
if ! command -v claude >/dev/null 2>&1; then
9+
echo "Error: 'claude' CLI not found on PATH. Install Claude Code first." >&2
10+
exit 1
11+
fi
12+
13+
if [ ! -f "$MARKETPLACE_DIR/.claude-plugin/marketplace.json" ]; then
14+
echo "Error: $MARKETPLACE_DIR/.claude-plugin/marketplace.json not found." >&2
15+
exit 1
16+
fi
17+
18+
if claude plugin marketplace list 2>/dev/null | grep -q "\b${MARKETPLACE_NAME}\b"; then
19+
echo "Updating marketplace '${MARKETPLACE_NAME}'..."
20+
claude plugin marketplace update "${MARKETPLACE_NAME}" || \
21+
echo " (warning: marketplace update failed; continuing)"
22+
else
23+
echo "Adding marketplace '${MARKETPLACE_NAME}'..."
24+
claude plugin marketplace add "${MARKETPLACE_DIR}" --scope user
25+
fi
26+
27+
failures=()
28+
for plugin_dir in "${MARKETPLACE_DIR}"/*/; do
29+
[ -f "${plugin_dir}.claude-plugin/plugin.json" ] || continue
30+
plugin_name="$(basename "${plugin_dir}")"
31+
full="${plugin_name}@${MARKETPLACE_NAME}"
32+
33+
if claude plugin list 2>/dev/null | grep -q "${full}"; then
34+
echo "Updating plugin '${full}'..."
35+
claude plugin update "${full}" || failures+=("${full} (update)")
36+
else
37+
echo "Installing plugin '${full}'..."
38+
claude plugin install "${full}" --scope user || failures+=("${full} (install)")
39+
fi
40+
done
41+
42+
echo ""
43+
if [ "${#failures[@]}" -gt 0 ]; then
44+
echo "Completed with failures: ${failures[*]}" >&2
45+
exit 1
46+
fi
47+
echo "Done. Restart Claude Code if it was running."
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "bitkit-android",
3+
"owner": {
4+
"name": "Synonym",
5+
"email": "dev@synonym.to"
6+
},
7+
"plugins": [
8+
{
9+
"name": "blocktank-api",
10+
"source": "./blocktank-api",
11+
"description": "Interact with the Blocktank LSP API for Lightning testing during bitkit development."
12+
}
13+
]
14+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"name": "blocktank-api",
3+
"description": "Interact with the Blocktank LSP API for Lightning testing during bitkit development."
4+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Blocktank API Plugin
2+
3+
A Claude Code plugin that gives Claude knowledge of the full Blocktank LSP API, enabling it to autonomously create channels, fund them, mine blocks, pay invoices, and close channels during Blocktank LSP testing.
4+
5+
## Setup
6+
7+
Run once from the repo root (re-run anytime to update):
8+
9+
```sh
10+
./.claude/install-plugins.sh
11+
```
12+
13+
Restart Claude Code once. The `blocktank-api:lsp` skill (invoked as `/lsp`) is then available.
14+
15+
## Usage
16+
17+
Once installed, the skill auto-triggers when you mention things like:
18+
- "mine blocks", "deposit sats", "pay invoice", "force close"
19+
- "channel order", "CJIT", "blocktank", "LSP"
20+
21+
Claude will use the `./lsp` wrapper at the repo root to make API calls directly.
22+
23+
## Configuration
24+
25+
The default API base URL is `https://api.stag0.blocktank.to/blocktank/api/v2` (staging).
26+
27+
To override (e.g., for a local instance):
28+
29+
```bash
30+
export BLOCKTANK_API_URL=http://localhost:9000/api
31+
```
32+
33+
## Cross-project reuse
34+
35+
To use this plugin from another repo (e.g. bitkit-ios), symlink it into that project's `.claude/plugins/`:
36+
37+
```bash
38+
ln -s /path/to/bitkit-android/.claude/plugins/blocktank-api /path/to/other-repo/.claude/plugins/blocktank-api
39+
```
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
---
2+
name: lsp
3+
description: >
4+
This skill should be used when the user asks to interact with the Blocktank LSP API,
5+
"mine blocks", "deposit sats", "pay invoice", "force close a channel", "create a channel order",
6+
"open a channel", "estimate fees", "create a CJIT channel", or mentions "blocktank", "regtest",
7+
"LSP", or Lightning channel testing workflows during bitkit development.
8+
version: 0.1.0
9+
---
10+
11+
# Blocktank LSP API
12+
13+
Blocktank is the Lightning Service Provider (LSP) used by Bitkit. This skill provides full knowledge of its REST API and a utility script to call any endpoint from the command line.
14+
15+
No authentication is required. All requests and responses use JSON.
16+
17+
## Configuration
18+
19+
**Default base URL:** `https://api.stag0.blocktank.to/blocktank/api/v2` (staging)
20+
21+
Override with the `BLOCKTANK_API_URL` environment variable:
22+
- Local instance: `http://localhost:9000/api`
23+
24+
## API Script
25+
26+
Call any endpoint using the `./lsp` wrapper at the repo root:
27+
28+
```bash
29+
./lsp <GET|POST> <path> [json_body]
30+
```
31+
32+
Examples:
33+
34+
```bash
35+
# Get service info
36+
./lsp GET /info
37+
38+
# Create a channel order
39+
./lsp POST /channels '{"lspBalanceSat":100000,"channelExpiryWeeks":12}'
40+
41+
# Mine 6 blocks
42+
./lsp POST /regtest/chain/mine '{"count":6}'
43+
44+
# Deposit to an address
45+
./lsp POST /regtest/chain/deposit '{"address":"bcrt1q...","amountSat":500000}'
46+
```
47+
48+
The script outputs raw JSON. Pipe to `jq` for formatting if needed.
49+
50+
On HTTP errors (4xx/5xx), the script prints the status code to stderr and the error response body to stdout, then exits with code 1.
51+
52+
## Endpoint Quick Reference
53+
54+
### Service Info
55+
56+
| Method | Path | Description |
57+
|--------|------|-------------|
58+
| GET | `/info` | Service info, LSP nodes, channel size limits, fee rates |
59+
60+
### Channel Orders
61+
62+
| Method | Path | Description |
63+
|--------|------|-------------|
64+
| POST | `/channels` | Create a channel order |
65+
| GET | `/channels/:id` | Get order by ID |
66+
| GET | `/channels?ids[]=` | Get multiple orders (1-50 IDs) |
67+
| POST | `/channels/:id/open` | Open a paid channel |
68+
| GET | `/channels/:id/min-0conf-tx-fee` | Get 0-conf fee window |
69+
| POST | `/channels/estimate-fee` | Estimate order fee |
70+
| POST | `/channels/estimate-fee-full` | Estimate fee with breakdown |
71+
72+
### CJIT (Just-In-Time Channels)
73+
74+
| Method | Path | Description |
75+
|--------|------|-------------|
76+
| POST | `/cjit` | Create a JIT channel entry |
77+
| GET | `/cjit/:id` | Get CJIT entry status |
78+
79+
### Gift
80+
81+
| Method | Path | Description |
82+
|--------|------|-------------|
83+
| POST | `/gift/pay` | Pay a gift invoice |
84+
| POST | `/gift/order` | Create a gift order |
85+
| GET | `/gift/:id` | Get gift info |
86+
87+
### Regtest Tools (regtest only)
88+
89+
| Method | Path | Description |
90+
|--------|------|-------------|
91+
| POST | `/regtest/chain/mine` | Mine blocks (default: 1) |
92+
| POST | `/regtest/chain/deposit` | Deposit sats to address (default: 100,000) |
93+
| POST | `/regtest/channel/pay` | Pay a Lightning invoice |
94+
| GET | `/regtest/channel/pay/:id` | Get payment status |
95+
| POST | `/regtest/channel/close` | Force close a channel |
96+
97+
## Common Workflows
98+
99+
### Workflow A: Purchase a Channel
100+
101+
1. **Get service info**`GET /info` to retrieve LSP node pubkeys and channel size limits
102+
2. **Create order**`POST /channels` with `lspBalanceSat`, `channelExpiryWeeks`, and optional `clientBalanceSat`
103+
3. **Extract payment info** — from response: `payment.onchain.address` (bitcoin address) and `feeSat` (amount to pay)
104+
4. **Fund the order**`POST /regtest/chain/deposit` with the payment address and fee amount
105+
5. **Confirm payment**`POST /regtest/chain/mine` with `count: 1` to mine a block
106+
6. **Poll order status**`GET /channels/:id` until `state2` becomes `paid`
107+
7. **Open channel**`POST /channels/:id/open` with the client's `connectionStringOrPubkey`
108+
8. **Confirm channel**`POST /regtest/chain/mine` with `count: 6` to fully confirm
109+
110+
### Workflow B: CJIT Channel (Just-In-Time)
111+
112+
1. **Get service info**`GET /info` for node pubkeys and limits
113+
2. **Create CJIT entry**`POST /cjit` with `channelSizeSat`, `invoiceSat`, `nodeId`, `channelExpiryWeeks`
114+
3. **Extract invoice** — from response: `invoice.request` (bolt11 invoice string)
115+
4. **Client pays invoice** — the mobile app pays the invoice, triggering automatic channel opening
116+
5. **Poll status**`GET /cjit/:id` until `state` becomes `completed`
117+
118+
### Workflow C: Force Close a Channel
119+
120+
1. **Get order info**`GET /channels/:id` to find `channel.fundingTx.id` and `channel.fundingTx.vout`
121+
2. **Close channel**`POST /regtest/channel/close` with `fundingTxId`, `vout`, and `forceCloseAfterSec: 0` for immediate close
122+
3. **Mine blocks**`POST /regtest/chain/mine` with `count: 6` to finalize the closure
123+
124+
### Workflow D: Automated Invoice Payments
125+
126+
Bulk-create and pay invoices to populate the app with payment activity.
127+
128+
**Prerequisites:** Dev debug build installed, wallet set up, LDK node running, open channel with inbound capacity, ADB connected.
129+
130+
**Run with defaults** (21 invoices of 1..21 sats, mine 150 blocks in batches of 10):
131+
132+
```bash
133+
"${CLAUDE_PLUGIN_ROOT}/skills/lsp/scripts/pay-invoices.sh"
134+
```
135+
136+
**Custom parameters** via env vars:
137+
138+
```bash
139+
INVOICE_COUNT=10 DESCRIPTION="test-ovi-{i}" MINE_TOTAL=60 MINE_BATCH=10 \
140+
"${CLAUDE_PLUGIN_ROOT}/skills/lsp/scripts/pay-invoices.sh"
141+
```
142+
143+
- `DESCRIPTION` — invoice description; `{i}` is replaced with the invoice index (default: `dev-payment-{i}`)
144+
145+
The script uses the `DevToolsProvider` ContentProvider (dev builds only) to create invoices on the app's LDK node via `adb shell content call`, then pays each via the LSP's `POST /regtest/channel/pay` endpoint.
146+
147+
**Create a single invoice manually:**
148+
149+
```bash
150+
adb shell "content call --uri content://to.bitkit.dev.devtools \
151+
--method createInvoice --arg '{\"amount\":1000,\"description\":\"test\"}'"
152+
```
153+
154+
## State Machines
155+
156+
### Order States (`state2`)
157+
158+
```
159+
created → paid → executed
160+
↘ expired
161+
```
162+
163+
- `created` — waiting for payment
164+
- `paid` — payment confirmed, ready to open channel
165+
- `executed` — channel opened successfully
166+
- `expired` — order timed out
167+
168+
### Payment States (`payment.state2`)
169+
170+
```
171+
created → paid → refundAvailable → refunded
172+
↘ canceled
173+
```
174+
175+
### Channel States (`channel.state`)
176+
177+
```
178+
opening → open → closed
179+
```
180+
181+
### CJIT States (`state`)
182+
183+
```
184+
created → completed
185+
↘ expired
186+
↘ failed
187+
```
188+
189+
## Detailed API Reference
190+
191+
For full request/response schemas, field constraints, and error codes for every endpoint, consult:
192+
193+
- **`references/api-reference.md`** — Complete API reference with all fields, types, defaults, and validation rules

0 commit comments

Comments
 (0)