@token2chat/t2c 0.2.0-beta.1 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +117 -144
- package/dist/cashu-store.d.ts +1 -1
- package/dist/cashu-store.js +4 -4
- package/dist/commands/audit.d.ts +65 -0
- package/dist/commands/audit.js +12 -12
- package/dist/commands/balance.js +2 -2
- package/dist/commands/doctor.js +2 -2
- package/dist/commands/init.js +2 -2
- package/dist/commands/mint.js +14 -14
- package/dist/commands/monitor.d.ts +51 -0
- package/dist/commands/monitor.js +353 -0
- package/dist/commands/recover.js +4 -4
- package/dist/commands/setup.js +2 -2
- package/dist/commands/status.js +2 -3
- package/dist/config.d.ts +5 -0
- package/dist/config.js +17 -0
- package/dist/connectors/cursor.js +44 -15
- package/dist/connectors/openclaw.js +32 -24
- package/dist/index.js +8 -1
- package/dist/proxy/auth.d.ts +20 -0
- package/dist/proxy/auth.js +28 -0
- package/dist/proxy/errors.d.ts +58 -0
- package/dist/proxy/errors.js +95 -0
- package/dist/proxy/gate-client.d.ts +34 -0
- package/dist/proxy/gate-client.js +81 -0
- package/dist/proxy/index.d.ts +10 -0
- package/dist/proxy/index.js +17 -0
- package/dist/proxy/payment-service.d.ts +65 -0
- package/dist/proxy/payment-service.js +101 -0
- package/dist/proxy/pricing.d.ts +37 -0
- package/dist/proxy/pricing.js +90 -0
- package/dist/proxy/response.d.ts +24 -0
- package/dist/proxy/response.js +48 -0
- package/dist/proxy/sse-parser.d.ts +19 -0
- package/dist/proxy/sse-parser.js +80 -0
- package/dist/proxy/types.d.ts +113 -0
- package/dist/proxy/types.js +74 -0
- package/dist/proxy.d.ts +2 -9
- package/dist/proxy.js +74 -186
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -1,188 +1,161 @@
|
|
|
1
|
-
# t2c
|
|
1
|
+
# t2c — Pay for AI with Ecash
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> CLI + local proxy that makes any AI tool work with token2chat. No accounts, no API keys.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
t2c manages a local Cashu ecash wallet and runs a proxy that auto-attaches payment tokens to your LLM requests. Point your AI tool at `localhost:10402` and it just works.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
npm install -g @token2chat/cli
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Quick Start
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
# 1. Run setup wizard
|
|
15
|
-
t2c setup
|
|
16
|
-
|
|
17
|
-
# 2. Start the proxy service
|
|
18
|
-
t2c service start
|
|
19
|
-
|
|
20
|
-
# 3. Add funds to your wallet
|
|
21
|
-
t2c mint
|
|
22
|
-
|
|
23
|
-
# 4. Configure your AI tool
|
|
24
|
-
t2c config openclaw --apply # For OpenClaw (auto-merge)
|
|
25
|
-
t2c config cursor # For Cursor
|
|
26
|
-
t2c config env # For other tools
|
|
27
|
-
|
|
28
|
-
# 5. (Optional) Install as system service for auto-start
|
|
29
|
-
t2c service install
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## Commands
|
|
7
|
+
Built by an autonomous AI agent.
|
|
33
8
|
|
|
34
|
-
|
|
35
|
-
Interactive setup wizard. Configures Gate URL, Mint URL, proxy port, and wallet path.
|
|
36
|
-
|
|
37
|
-
### `t2c status`
|
|
38
|
-
Show service status and wallet balance.
|
|
9
|
+
## Install
|
|
39
10
|
|
|
40
11
|
```bash
|
|
41
|
-
|
|
42
|
-
t2c status --json # JSON output
|
|
12
|
+
npm install -g @token2chat/t2c
|
|
43
13
|
```
|
|
44
14
|
|
|
45
|
-
|
|
46
|
-
Manage the local proxy service.
|
|
15
|
+
## Quick Start
|
|
47
16
|
|
|
48
17
|
```bash
|
|
49
|
-
|
|
50
|
-
t2c
|
|
51
|
-
t2c service stop # Stop the service
|
|
52
|
-
t2c service restart # Restart the service
|
|
53
|
-
t2c service status # Show detailed service status
|
|
54
|
-
t2c service logs # Show logs
|
|
55
|
-
t2c service logs -f # Follow logs
|
|
56
|
-
|
|
57
|
-
# System service management (auto-start on login)
|
|
58
|
-
t2c service install # Install as launchd (macOS) or systemd (Linux)
|
|
59
|
-
t2c service uninstall # Uninstall system service
|
|
60
|
-
```
|
|
18
|
+
# 1. Initialize wallet and config
|
|
19
|
+
t2c init
|
|
61
20
|
|
|
62
|
-
|
|
63
|
-
|
|
21
|
+
# 2. Fund your wallet via Lightning
|
|
22
|
+
t2c mint 5000 # creates invoice for 5000 sats
|
|
23
|
+
t2c mint --check <quote> # check payment & mint ecash
|
|
64
24
|
|
|
65
|
-
|
|
66
|
-
t2c
|
|
67
|
-
t2c
|
|
68
|
-
t2c mint 1000 # Create Lightning invoice for 1000 sat
|
|
69
|
-
```
|
|
25
|
+
# 3. Connect your AI tool
|
|
26
|
+
t2c connect cursor # or: openclaw, cline, aider, continue, env
|
|
27
|
+
t2c service start # start the local proxy
|
|
70
28
|
|
|
71
|
-
|
|
72
|
-
Generate configuration for AI tools.
|
|
73
|
-
|
|
74
|
-
```bash
|
|
75
|
-
t2c config list # List supported tools
|
|
76
|
-
t2c config openclaw # Show OpenClaw config
|
|
77
|
-
t2c config openclaw --apply # Apply to openclaw.json (creates backup)
|
|
78
|
-
t2c config openclaw --json # Output raw JSON
|
|
79
|
-
t2c config cursor # Show Cursor config
|
|
80
|
-
t2c config env # Show environment variables
|
|
29
|
+
# 4. Use AI as normal — t2c handles payment automatically
|
|
81
30
|
```
|
|
82
31
|
|
|
83
|
-
##
|
|
32
|
+
## How It Works
|
|
84
33
|
|
|
85
34
|
```
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
│
|
|
89
|
-
│
|
|
90
|
-
|
|
91
|
-
|
|
35
|
+
Your AI Tool (Cursor, Cline, OpenClaw, etc.)
|
|
36
|
+
│
|
|
37
|
+
│ POST http://127.0.0.1:10402/v1/chat/completions
|
|
38
|
+
│ Authorization: Bearer <proxy-secret>
|
|
39
|
+
▼
|
|
40
|
+
t2c proxy (local)
|
|
41
|
+
│ 1. Estimate price from request
|
|
42
|
+
│ 2. Select ecash proofs from wallet
|
|
43
|
+
│ 3. Encode as Cashu V4 token
|
|
44
|
+
│ 4. Attach X-Cashu header
|
|
45
|
+
│ 5. Forward to Gate
|
|
46
|
+
▼
|
|
47
|
+
Gate (gate.token2chat.com)
|
|
48
|
+
│ 6. Verify ecash, proxy to LLM
|
|
49
|
+
│ 7. Return response + change token
|
|
50
|
+
▼
|
|
51
|
+
Response flows back to your AI tool
|
|
52
|
+
(t2c reclaims change into wallet)
|
|
92
53
|
```
|
|
93
54
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
55
|
+
## CLI Reference
|
|
56
|
+
|
|
57
|
+
### Wallet
|
|
58
|
+
|
|
59
|
+
| Command | Description |
|
|
60
|
+
|---------|-------------|
|
|
61
|
+
| `t2c init` | Initialize config + wallet |
|
|
62
|
+
| `t2c balance` | Show wallet balance (in USD) |
|
|
63
|
+
| `t2c mint [amount]` | Fund wallet via Lightning invoice |
|
|
64
|
+
| `t2c mint --check <quote>` | Check payment and mint ecash |
|
|
65
|
+
| `t2c recover` | Recover failed change/refund tokens |
|
|
66
|
+
| `t2c audit` | Full fund audit (wallet + mint + gate + anomalies) |
|
|
67
|
+
|
|
68
|
+
### Proxy Service
|
|
69
|
+
|
|
70
|
+
| Command | Description |
|
|
71
|
+
|---------|-------------|
|
|
72
|
+
| `t2c service start` | Start local proxy (foreground) |
|
|
73
|
+
| `t2c service stop` | Stop proxy |
|
|
74
|
+
| `t2c service restart` | Restart proxy |
|
|
75
|
+
| `t2c service status` | Show proxy status |
|
|
76
|
+
| `t2c service logs` | View proxy logs |
|
|
77
|
+
| `t2c service install` | Install as system service (launchd/systemd) |
|
|
78
|
+
| `t2c service uninstall` | Remove system service |
|
|
79
|
+
|
|
80
|
+
### Integration
|
|
81
|
+
|
|
82
|
+
| Command | Description |
|
|
83
|
+
|---------|-------------|
|
|
84
|
+
| `t2c connect <app>` | Auto-configure an AI tool |
|
|
85
|
+
| `t2c config <tool>` | Print config snippet for a specific tool |
|
|
86
|
+
| `t2c status` | Service status + balance overview |
|
|
87
|
+
| `t2c monitor` | Live TUI dashboard |
|
|
88
|
+
| `t2c doctor` | Self-diagnostic |
|
|
89
|
+
|
|
90
|
+
### Supported AI Tools
|
|
91
|
+
|
|
92
|
+
| Tool | Command | What it does |
|
|
93
|
+
|------|---------|-------------|
|
|
94
|
+
| **Cursor** | `t2c connect cursor` | Writes proxy URL + key to Cursor config |
|
|
95
|
+
| **OpenClaw** | `t2c connect openclaw` | Adds provider to OpenClaw config |
|
|
96
|
+
| **Cline** | `t2c connect cline` | Configures VS Code extension |
|
|
97
|
+
| **Continue** | `t2c connect continue` | Configures Continue extension |
|
|
98
|
+
| **Aider** | `t2c connect aider` | Sets environment variables |
|
|
99
|
+
| **Any tool** | `t2c connect env` | Prints env vars to export manually |
|
|
100
100
|
|
|
101
101
|
## Configuration
|
|
102
102
|
|
|
103
|
-
Config is stored
|
|
103
|
+
Config is stored at `~/.t2c/config.json`.
|
|
104
104
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
```
|
|
105
|
+
| Field | Default | Description |
|
|
106
|
+
|-------|---------|-------------|
|
|
107
|
+
| `gate` | `https://gate.token2chat.com` | Gate URL |
|
|
108
|
+
| `mint` | `https://mint.token2chat.com` | Mint URL |
|
|
109
|
+
| `proxy.port` | `10402` | Local proxy port |
|
|
110
|
+
| `proxy.secret` | (auto-generated) | Bearer token for proxy auth |
|
|
111
|
+
| `wallet` | `~/.t2c/wallet.json` | Wallet file path |
|
|
114
112
|
|
|
115
|
-
|
|
113
|
+
### Gate Discovery
|
|
116
114
|
|
|
117
|
-
|
|
115
|
+
t2c automatically discovers available gates from [token2.cash/gates.json](https://token2.cash/gates.json). If your primary gate is down, it fails over to other healthy gates that support your model.
|
|
118
116
|
|
|
119
|
-
|
|
120
|
-
# Install
|
|
121
|
-
t2c service install
|
|
117
|
+
## Security
|
|
122
118
|
|
|
123
|
-
|
|
124
|
-
|
|
119
|
+
- **Local proxy auth** — Bearer token with timing-safe comparison
|
|
120
|
+
- **Wallet file** — 0o600 permissions, only readable by owner
|
|
121
|
+
- **Config directory** — 0o700 permissions
|
|
122
|
+
- **Mutex-protected wallet** — no concurrent double-spend from overlapping requests
|
|
123
|
+
- **Failed token persistence** — tokens that fail to process are saved for recovery
|
|
124
|
+
- **No tracking** — ecash is bearer money; the gate never knows who you are
|
|
125
125
|
|
|
126
|
-
|
|
127
|
-
t2c service uninstall
|
|
128
|
-
```
|
|
126
|
+
## Wallet
|
|
129
127
|
|
|
130
|
-
|
|
128
|
+
The wallet stores Cashu ecash proofs locally at `~/.t2c/wallet.json`.
|
|
131
129
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
130
|
+
- **Unit**: USD (1 unit = $0.00001, displayed as dollars)
|
|
131
|
+
- **Proof selection**: largest-first greedy (minimizes number of proofs per payment)
|
|
132
|
+
- **Change handling**: automatically reclaimed from gate responses (header or SSE event)
|
|
133
|
+
- **Funding**: Lightning invoices via `t2c mint`
|
|
135
134
|
|
|
136
|
-
|
|
137
|
-
systemctl --user daemon-reload
|
|
138
|
-
systemctl --user enable t2c-proxy.service
|
|
139
|
-
systemctl --user start t2c-proxy.service
|
|
135
|
+
### Balance Display
|
|
140
136
|
|
|
141
|
-
|
|
142
|
-
t2c
|
|
137
|
+
```bash
|
|
138
|
+
$ t2c balance
|
|
139
|
+
Wallet: $4.52 (452,000 units, 23 proofs)
|
|
140
|
+
Mint: https://mint.token2chat.com
|
|
143
141
|
```
|
|
144
142
|
|
|
145
|
-
##
|
|
146
|
-
|
|
147
|
-
| Tool | Command | Notes |
|
|
148
|
-
|------|---------|-------|
|
|
149
|
-
| OpenClaw | `t2c config openclaw --apply` | Auto-merges token2chat provider |
|
|
150
|
-
| Cursor | `t2c config cursor` | OpenAI base URL config |
|
|
151
|
-
| Generic | `t2c config env` | OPENAI_API_KEY + OPENAI_BASE_URL |
|
|
152
|
-
|
|
153
|
-
Any tool that supports OpenAI-compatible APIs can use Token2Chat.
|
|
154
|
-
|
|
155
|
-
## Error Handling
|
|
156
|
-
|
|
157
|
-
The CLI handles various error conditions gracefully:
|
|
158
|
-
|
|
159
|
-
- **No config**: Prompts to run `t2c setup`
|
|
160
|
-
- **No wallet**: Creates one automatically
|
|
161
|
-
- **Corrupted config**: Auto-recovers with backup
|
|
162
|
-
- **Network timeout**: Retries with exponential backoff
|
|
163
|
-
- **Insufficient balance**: Clear error message with balance info
|
|
143
|
+
## System Service
|
|
164
144
|
|
|
165
|
-
|
|
145
|
+
Install t2c as a background service that starts on boot:
|
|
166
146
|
|
|
167
147
|
```bash
|
|
168
|
-
#
|
|
169
|
-
|
|
170
|
-
cd cli
|
|
171
|
-
npm install
|
|
172
|
-
|
|
173
|
-
# Build
|
|
174
|
-
npm run build
|
|
175
|
-
|
|
176
|
-
# Run tests
|
|
177
|
-
npm test
|
|
148
|
+
# macOS (launchd)
|
|
149
|
+
t2c service install
|
|
178
150
|
|
|
179
|
-
#
|
|
180
|
-
|
|
151
|
+
# Linux (systemd)
|
|
152
|
+
t2c service install
|
|
181
153
|
|
|
182
|
-
#
|
|
183
|
-
npm link
|
|
154
|
+
# Both auto-detect the platform
|
|
184
155
|
```
|
|
185
156
|
|
|
157
|
+
The proxy runs in the background, automatically paying for LLM requests from any connected AI tool.
|
|
158
|
+
|
|
186
159
|
## License
|
|
187
160
|
|
|
188
161
|
MIT
|
package/dist/cashu-store.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ export declare class CashuStore {
|
|
|
22
22
|
/** Returns true if balance is below threshold */
|
|
23
23
|
needsFunding(threshold: number): boolean;
|
|
24
24
|
/**
|
|
25
|
-
* Select proofs totalling at least `amount`
|
|
25
|
+
* Select proofs totalling at least `amount` units,
|
|
26
26
|
* encode as a Cashu V4 token, and remove them from the store.
|
|
27
27
|
*/
|
|
28
28
|
selectAndEncode(amount: number): Promise<string>;
|
package/dist/cashu-store.js
CHANGED
|
@@ -73,7 +73,7 @@ export class CashuStore {
|
|
|
73
73
|
catch {
|
|
74
74
|
const data = {
|
|
75
75
|
mint: mint ?? "https://mint.token2chat.com",
|
|
76
|
-
unit: "
|
|
76
|
+
unit: "usd",
|
|
77
77
|
proofs: [],
|
|
78
78
|
};
|
|
79
79
|
const store = new CashuStore(path, data);
|
|
@@ -102,13 +102,13 @@ export class CashuStore {
|
|
|
102
102
|
}
|
|
103
103
|
// ── Proof selection ────────────────────────────────────────
|
|
104
104
|
/**
|
|
105
|
-
* Select proofs totalling at least `amount`
|
|
105
|
+
* Select proofs totalling at least `amount` units,
|
|
106
106
|
* encode as a Cashu V4 token, and remove them from the store.
|
|
107
107
|
*/
|
|
108
108
|
async selectAndEncode(amount) {
|
|
109
109
|
return this.mutex.lock(async () => {
|
|
110
110
|
if (this.balance < amount) {
|
|
111
|
-
throw new Error(`Insufficient balance: need ${amount}
|
|
111
|
+
throw new Error(`Insufficient balance: need ${amount}, have ${this.balance}`);
|
|
112
112
|
}
|
|
113
113
|
const sorted = [...this.data.proofs].sort((a, b) => b.amount - a.amount);
|
|
114
114
|
const selected = [];
|
|
@@ -120,7 +120,7 @@ export class CashuStore {
|
|
|
120
120
|
total += p.amount;
|
|
121
121
|
}
|
|
122
122
|
if (total < amount) {
|
|
123
|
-
throw new Error(`Could not select enough proofs for ${amount}
|
|
123
|
+
throw new Error(`Could not select enough proofs for ${amount}`);
|
|
124
124
|
}
|
|
125
125
|
// Remove selected proofs
|
|
126
126
|
const selectedSecrets = new Set(selected.map((p) => typeof p.secret === "string" ? p.secret : JSON.stringify(p.secret)));
|
package/dist/commands/audit.d.ts
CHANGED
|
@@ -1,6 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* t2c audit — Full-chain fund visualization
|
|
3
|
+
*
|
|
4
|
+
* Unified view: local wallet + Mint + Gate + transaction log.
|
|
5
|
+
* Cross-references data and highlights anomalies.
|
|
6
|
+
*/
|
|
7
|
+
import { type TransactionRecord, type FailedToken } from "../config.js";
|
|
1
8
|
interface AuditOptions {
|
|
2
9
|
json?: boolean;
|
|
3
10
|
lines?: string;
|
|
4
11
|
}
|
|
12
|
+
interface MintInfo {
|
|
13
|
+
reachable: boolean;
|
|
14
|
+
name?: string;
|
|
15
|
+
version?: string;
|
|
16
|
+
nuts?: Record<string, unknown>;
|
|
17
|
+
keysetIds?: string[];
|
|
18
|
+
error?: string;
|
|
19
|
+
}
|
|
20
|
+
interface GateInfo {
|
|
21
|
+
reachable: boolean;
|
|
22
|
+
mints?: string[];
|
|
23
|
+
models?: string[];
|
|
24
|
+
pricing?: Record<string, {
|
|
25
|
+
input_per_million?: number;
|
|
26
|
+
output_per_million?: number;
|
|
27
|
+
per_request?: number;
|
|
28
|
+
}>;
|
|
29
|
+
error?: string;
|
|
30
|
+
}
|
|
31
|
+
interface ProofBreakdown {
|
|
32
|
+
[denomination: number]: number;
|
|
33
|
+
}
|
|
34
|
+
export interface Anomaly {
|
|
35
|
+
severity: "error" | "warn" | "info";
|
|
36
|
+
message: string;
|
|
37
|
+
}
|
|
38
|
+
interface DiscoveredGate {
|
|
39
|
+
name: string;
|
|
40
|
+
url: string;
|
|
41
|
+
mint: string;
|
|
42
|
+
models: string[];
|
|
43
|
+
healthy: boolean;
|
|
44
|
+
}
|
|
45
|
+
export interface AuditReport {
|
|
46
|
+
timestamp: number;
|
|
47
|
+
wallet: {
|
|
48
|
+
balance: number;
|
|
49
|
+
proofCount: number;
|
|
50
|
+
proofBreakdown: ProofBreakdown;
|
|
51
|
+
mint: string;
|
|
52
|
+
} | null;
|
|
53
|
+
mint: MintInfo;
|
|
54
|
+
gate: GateInfo;
|
|
55
|
+
discoveredGates: DiscoveredGate[];
|
|
56
|
+
transactions: {
|
|
57
|
+
total: number;
|
|
58
|
+
shown: number;
|
|
59
|
+
totalSpent: number;
|
|
60
|
+
totalChange: number;
|
|
61
|
+
totalRefund: number;
|
|
62
|
+
netCost: number;
|
|
63
|
+
errorCount: number;
|
|
64
|
+
recent: TransactionRecord[];
|
|
65
|
+
};
|
|
66
|
+
failedTokens: FailedToken[];
|
|
67
|
+
anomalies: Anomaly[];
|
|
68
|
+
}
|
|
69
|
+
export declare function detectAnomalies(report: AuditReport): Anomaly[];
|
|
5
70
|
export declare function auditCommand(opts: AuditOptions): Promise<void>;
|
|
6
71
|
export {};
|
package/dist/commands/audit.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Unified view: local wallet + Mint + Gate + transaction log.
|
|
5
5
|
* Cross-references data and highlights anomalies.
|
|
6
6
|
*/
|
|
7
|
-
import { loadConfig, resolveHome, loadFailedTokens, loadTransactions, } from "../config.js";
|
|
7
|
+
import { loadConfig, resolveHome, loadFailedTokens, loadTransactions, formatUnits, } from "../config.js";
|
|
8
8
|
import { CashuStore } from "../cashu-store.js";
|
|
9
9
|
import { GateRegistry } from "../gate-discovery.js";
|
|
10
10
|
async function fetchMintInfo(mintUrl) {
|
|
@@ -52,7 +52,7 @@ async function fetchGateInfo(gateUrl) {
|
|
|
52
52
|
return { reachable: false, error: e instanceof Error ? e.message : String(e) };
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
|
-
function detectAnomalies(report) {
|
|
55
|
+
export function detectAnomalies(report) {
|
|
56
56
|
const anomalies = [];
|
|
57
57
|
// Wallet anomalies
|
|
58
58
|
if (report.wallet) {
|
|
@@ -60,7 +60,7 @@ function detectAnomalies(report) {
|
|
|
60
60
|
anomalies.push({ severity: "error", message: "Wallet balance is 0 — cannot make requests" });
|
|
61
61
|
}
|
|
62
62
|
else if (report.wallet.balance < 500) {
|
|
63
|
-
anomalies.push({ severity: "warn", message: `Low wallet balance: ${report.wallet.balance}
|
|
63
|
+
anomalies.push({ severity: "warn", message: `Low wallet balance: ${formatUnits(report.wallet.balance)}` });
|
|
64
64
|
}
|
|
65
65
|
if (report.wallet.proofCount > 100) {
|
|
66
66
|
anomalies.push({ severity: "warn", message: `High proof count (${report.wallet.proofCount}) — consider consolidating via swap` });
|
|
@@ -101,7 +101,7 @@ function detectAnomalies(report) {
|
|
|
101
101
|
if (report.transactions.totalSpent > 0 && lossRate > 50) {
|
|
102
102
|
anomalies.push({
|
|
103
103
|
severity: "warn",
|
|
104
|
-
message: `High fund loss rate: ${lossRate.toFixed(1)}% of spent
|
|
104
|
+
message: `High fund loss rate: ${lossRate.toFixed(1)}% of spent funds not returned as change/refund`,
|
|
105
105
|
});
|
|
106
106
|
}
|
|
107
107
|
// Failed token anomalies
|
|
@@ -118,7 +118,7 @@ function detectAnomalies(report) {
|
|
|
118
118
|
if (last.balanceAfter !== report.wallet.balance) {
|
|
119
119
|
anomalies.push({
|
|
120
120
|
severity: "info",
|
|
121
|
-
message: `Balance drift: last tx recorded ${last.balanceAfter}
|
|
121
|
+
message: `Balance drift: last tx recorded ${formatUnits(last.balanceAfter)}, wallet now ${formatUnits(report.wallet.balance)} (may indicate manual changes)`,
|
|
122
122
|
});
|
|
123
123
|
}
|
|
124
124
|
}
|
|
@@ -141,7 +141,7 @@ function printReport(report) {
|
|
|
141
141
|
// ── Wallet ──
|
|
142
142
|
console.log("--- Wallet ---");
|
|
143
143
|
if (report.wallet) {
|
|
144
|
-
console.log(` Balance: ${report.wallet.balance
|
|
144
|
+
console.log(` Balance: ${formatUnits(report.wallet.balance)}`);
|
|
145
145
|
console.log(` Proofs: ${report.wallet.proofCount}`);
|
|
146
146
|
console.log(` Mint: ${report.wallet.mint}`);
|
|
147
147
|
const denominations = Object.entries(report.wallet.proofBreakdown)
|
|
@@ -149,7 +149,7 @@ function printReport(report) {
|
|
|
149
149
|
if (denominations.length > 0) {
|
|
150
150
|
console.log(" Breakdown:");
|
|
151
151
|
for (const [denom, count] of denominations) {
|
|
152
|
-
console.log(` ${denom}
|
|
152
|
+
console.log(` ${formatUnits(Number(denom))} x ${count} = ${formatUnits(Number(denom) * count)}`);
|
|
153
153
|
}
|
|
154
154
|
}
|
|
155
155
|
}
|
|
@@ -188,7 +188,7 @@ function printReport(report) {
|
|
|
188
188
|
parts.push(`out:${rule.output_per_million}/M`);
|
|
189
189
|
if (rule.per_request)
|
|
190
190
|
parts.push(`req:${rule.per_request}`);
|
|
191
|
-
console.log(` ${model}: ${parts.join(", ")}
|
|
191
|
+
console.log(` ${model}: ${parts.join(", ")}`);
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
194
|
// ── Discovered Gates ──
|
|
@@ -210,10 +210,10 @@ function printReport(report) {
|
|
|
210
210
|
}
|
|
211
211
|
else {
|
|
212
212
|
console.log(` Total: ${report.transactions.total} requests`);
|
|
213
|
-
console.log(` Spent: ${report.transactions.totalSpent
|
|
214
|
-
console.log(` Change: +${report.transactions.totalChange
|
|
215
|
-
console.log(` Refund: +${report.transactions.totalRefund
|
|
216
|
-
console.log(` Net cost: ${report.transactions.netCost
|
|
213
|
+
console.log(` Spent: ${formatUnits(report.transactions.totalSpent)}`);
|
|
214
|
+
console.log(` Change: +${formatUnits(report.transactions.totalChange)}`);
|
|
215
|
+
console.log(` Refund: +${formatUnits(report.transactions.totalRefund)}`);
|
|
216
|
+
console.log(` Net cost: ${formatUnits(report.transactions.netCost)}`);
|
|
217
217
|
console.log(` Errors: ${report.transactions.errorCount}`);
|
|
218
218
|
if (report.transactions.recent.length > 0) {
|
|
219
219
|
console.log("\n Recent transactions:");
|
package/dist/commands/balance.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* t2c balance - Simple balance display
|
|
3
3
|
*/
|
|
4
|
-
import { loadConfig, WALLET_PATH } from "../config.js";
|
|
4
|
+
import { loadConfig, WALLET_PATH, formatUnits } from "../config.js";
|
|
5
5
|
import { CashuStore } from "../cashu-store.js";
|
|
6
6
|
export async function balanceCommand(opts) {
|
|
7
7
|
const config = await loadConfig();
|
|
@@ -14,7 +14,7 @@ export async function balanceCommand(opts) {
|
|
|
14
14
|
}));
|
|
15
15
|
}
|
|
16
16
|
else {
|
|
17
|
-
console.log(
|
|
17
|
+
console.log(formatUnits(wallet.balance));
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
catch (e) {
|
package/dist/commands/doctor.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import fs from "node:fs/promises";
|
|
5
5
|
import os from "node:os";
|
|
6
6
|
import path from "node:path";
|
|
7
|
-
import { loadConfig, configExists, checkGateHealth, checkMintHealth, CONFIG_PATH, WALLET_PATH, } from "../config.js";
|
|
7
|
+
import { loadConfig, configExists, checkGateHealth, checkMintHealth, CONFIG_PATH, WALLET_PATH, formatUnits, } from "../config.js";
|
|
8
8
|
import { CashuStore } from "../cashu-store.js";
|
|
9
9
|
// Platform-specific service paths
|
|
10
10
|
const LAUNCHD_PLIST_PATH = path.join(os.homedir(), "Library", "LaunchAgents", "com.token2chat.proxy.plist");
|
|
@@ -31,7 +31,7 @@ async function checkWallet(config) {
|
|
|
31
31
|
return {
|
|
32
32
|
name: "Wallet",
|
|
33
33
|
ok: true,
|
|
34
|
-
detail: `${WALLET_PATH} (${wallet.balance}
|
|
34
|
+
detail: `${WALLET_PATH} (${formatUnits(wallet.balance)})`,
|
|
35
35
|
};
|
|
36
36
|
}
|
|
37
37
|
catch (e) {
|
package/dist/commands/init.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Uses sensible defaults for gate/mint/port/wallet.
|
|
5
5
|
* No interactive prompts — just validate connectivity and create wallet.
|
|
6
6
|
*/
|
|
7
|
-
import { saveConfig, configExists, resolveHome, loadConfig, checkGateHealth, checkMintHealth, DEFAULT_CONFIG, } from "../config.js";
|
|
7
|
+
import { saveConfig, configExists, resolveHome, loadConfig, checkGateHealth, checkMintHealth, DEFAULT_CONFIG, formatUnits, } from "../config.js";
|
|
8
8
|
import { CashuStore } from "../cashu-store.js";
|
|
9
9
|
export async function initCommand(opts) {
|
|
10
10
|
console.log("\n🎟️ Token2Chat Init\n");
|
|
@@ -35,7 +35,7 @@ export async function initCommand(opts) {
|
|
|
35
35
|
try {
|
|
36
36
|
const resolvedPath = resolveHome(config.walletPath);
|
|
37
37
|
const wallet = await CashuStore.load(resolvedPath, config.mintUrl);
|
|
38
|
-
console.log(` Wallet initialized (balance: ${wallet.balance}
|
|
38
|
+
console.log(` Wallet initialized (balance: ${formatUnits(wallet.balance)})`);
|
|
39
39
|
}
|
|
40
40
|
catch (e) {
|
|
41
41
|
console.log(` ⚠️ Wallet init failed: ${e}`);
|
package/dist/commands/mint.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import fs from "node:fs/promises";
|
|
5
5
|
import path from "node:path";
|
|
6
|
-
import { loadConfig, resolveHome, CONFIG_DIR } from "../config.js";
|
|
6
|
+
import { loadConfig, resolveHome, CONFIG_DIR, formatUnits } from "../config.js";
|
|
7
7
|
import { CashuStore } from "../cashu-store.js";
|
|
8
8
|
// Fallback deposit address (Mint's EVM address for USDC/USDT)
|
|
9
9
|
// This is used if /v1/info endpoint doesn't provide a deposit address
|
|
@@ -61,7 +61,7 @@ export async function mintCommand(amount, opts) {
|
|
|
61
61
|
}
|
|
62
62
|
const currentBalance = wallet.balance;
|
|
63
63
|
console.log("\n🎟️ Token2Chat Funding\n");
|
|
64
|
-
console.log(`Current balance: ${currentBalance
|
|
64
|
+
console.log(`Current balance: ${formatUnits(currentBalance)}\n`);
|
|
65
65
|
if (opts.check) {
|
|
66
66
|
// Check for pending Lightning quotes and mint paid ones
|
|
67
67
|
console.log("Checking pending Lightning quotes...\n");
|
|
@@ -84,7 +84,7 @@ export async function mintCommand(amount, opts) {
|
|
|
84
84
|
}
|
|
85
85
|
try {
|
|
86
86
|
const minted = await wallet.mintFromQuote(pq.quote, pq.amount);
|
|
87
|
-
console.log(`✅ Minted ${minted
|
|
87
|
+
console.log(`✅ Minted ${formatUnits(minted)} from quote ${pq.quote.slice(0, 8)}...`);
|
|
88
88
|
mintedTotal += minted;
|
|
89
89
|
}
|
|
90
90
|
catch (e) {
|
|
@@ -105,8 +105,8 @@ export async function mintCommand(amount, opts) {
|
|
|
105
105
|
// Update pending quotes file
|
|
106
106
|
await savePendingQuotes({ quotes: stillPending });
|
|
107
107
|
if (mintedTotal > 0) {
|
|
108
|
-
console.log(`\n🎉 Total minted: ${mintedTotal
|
|
109
|
-
console.log(`New balance: ${wallet.balance
|
|
108
|
+
console.log(`\n🎉 Total minted: ${formatUnits(mintedTotal)}`);
|
|
109
|
+
console.log(`New balance: ${formatUnits(wallet.balance)}\n`);
|
|
110
110
|
}
|
|
111
111
|
else if (stillPending.length > 0) {
|
|
112
112
|
console.log(`\n${stillPending.length} quote(s) still awaiting payment.`);
|
|
@@ -122,19 +122,19 @@ export async function mintCommand(amount, opts) {
|
|
|
122
122
|
}
|
|
123
123
|
// Lightning funding (if amount specified)
|
|
124
124
|
if (amount) {
|
|
125
|
-
const
|
|
126
|
-
if (isNaN(
|
|
127
|
-
console.error("Invalid amount. Specify
|
|
125
|
+
const units = parseInt(amount, 10);
|
|
126
|
+
if (isNaN(units) || units <= 0) {
|
|
127
|
+
console.error("Invalid amount. Specify units to fund via Lightning.");
|
|
128
128
|
process.exit(1);
|
|
129
129
|
}
|
|
130
|
-
console.log(`⚡ Creating Lightning invoice for ${
|
|
130
|
+
console.log(`⚡ Creating Lightning invoice for ${formatUnits(units)}...\n`);
|
|
131
131
|
try {
|
|
132
|
-
const quote = await wallet.createMintQuote(
|
|
132
|
+
const quote = await wallet.createMintQuote(units);
|
|
133
133
|
// Save to pending quotes
|
|
134
134
|
const pendingData = await loadPendingQuotes();
|
|
135
135
|
pendingData.quotes.push({
|
|
136
136
|
quote: quote.quote,
|
|
137
|
-
amount:
|
|
137
|
+
amount: units,
|
|
138
138
|
request: quote.request,
|
|
139
139
|
createdAt: Date.now(),
|
|
140
140
|
});
|
|
@@ -153,7 +153,7 @@ export async function mintCommand(amount, opts) {
|
|
|
153
153
|
// Show deposit instructions (EVM stablecoins)
|
|
154
154
|
const depositAddress = await fetchDepositAddress(config.mintUrl);
|
|
155
155
|
console.log("Option 1: Lightning (recommended)\n");
|
|
156
|
-
console.log(" t2c mint <
|
|
156
|
+
console.log(" t2c mint <amount> Create a Lightning invoice\n");
|
|
157
157
|
console.log("Option 2: EVM Stablecoins\n");
|
|
158
158
|
console.log(" Send USDC or USDT to:\n");
|
|
159
159
|
console.log(` ${depositAddress}\n`);
|
|
@@ -163,6 +163,6 @@ export async function mintCommand(amount, opts) {
|
|
|
163
163
|
}
|
|
164
164
|
console.log("\n💡 Tips:");
|
|
165
165
|
console.log(" • Lightning deposits are instant");
|
|
166
|
-
console.log(" • EVM deposits:
|
|
167
|
-
console.log(" • Minimum deposit: $1 USD
|
|
166
|
+
console.log(" • EVM deposits: 100,000 units = $1.00 USD");
|
|
167
|
+
console.log(" • Minimum deposit: $1.00 USD\n");
|
|
168
168
|
}
|