imm-cli 0.1.0
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 +315 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +112 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/config.d.ts +3 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +251 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/immbook.d.ts +16 -0
- package/dist/commands/immbook.d.ts.map +1 -0
- package/dist/commands/immbook.js +795 -0
- package/dist/commands/immbook.js.map +1 -0
- package/dist/commands/jaine.d.ts +3 -0
- package/dist/commands/jaine.d.ts.map +1 -0
- package/dist/commands/jaine.js +1397 -0
- package/dist/commands/jaine.js.map +1 -0
- package/dist/commands/send.d.ts +3 -0
- package/dist/commands/send.d.ts.map +1 -0
- package/dist/commands/send.js +229 -0
- package/dist/commands/send.js.map +1 -0
- package/dist/commands/setup.d.ts +3 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +83 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/slop-app.d.ts +9 -0
- package/dist/commands/slop-app.d.ts.map +1 -0
- package/dist/commands/slop-app.js +793 -0
- package/dist/commands/slop-app.js.map +1 -0
- package/dist/commands/slop.d.ts +3 -0
- package/dist/commands/slop.d.ts.map +1 -0
- package/dist/commands/slop.js +1053 -0
- package/dist/commands/slop.js.map +1 -0
- package/dist/commands/wallet.d.ts +3 -0
- package/dist/commands/wallet.d.ts.map +1 -0
- package/dist/commands/wallet.js +298 -0
- package/dist/commands/wallet.js.map +1 -0
- package/dist/config/paths.d.ts +6 -0
- package/dist/config/paths.d.ts.map +1 -0
- package/dist/config/paths.js +24 -0
- package/dist/config/paths.js.map +1 -0
- package/dist/config/store.d.ts +44 -0
- package/dist/config/store.d.ts.map +1 -0
- package/dist/config/store.js +109 -0
- package/dist/config/store.js.map +1 -0
- package/dist/constants/chain.d.ts +56 -0
- package/dist/constants/chain.d.ts.map +1 -0
- package/dist/constants/chain.js +50 -0
- package/dist/constants/chain.js.map +1 -0
- package/dist/errors.d.ts +86 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +100 -0
- package/dist/errors.js.map +1 -0
- package/dist/immbook/api.d.ts +38 -0
- package/dist/immbook/api.d.ts.map +1 -0
- package/dist/immbook/api.js +86 -0
- package/dist/immbook/api.js.map +1 -0
- package/dist/immbook/auth.d.ts +31 -0
- package/dist/immbook/auth.d.ts.map +1 -0
- package/dist/immbook/auth.js +93 -0
- package/dist/immbook/auth.js.map +1 -0
- package/dist/immbook/comments.d.ts +26 -0
- package/dist/immbook/comments.d.ts.map +1 -0
- package/dist/immbook/comments.js +20 -0
- package/dist/immbook/comments.js.map +1 -0
- package/dist/immbook/follows.d.ts +19 -0
- package/dist/immbook/follows.d.ts.map +1 -0
- package/dist/immbook/follows.js +21 -0
- package/dist/immbook/follows.js.map +1 -0
- package/dist/immbook/jwtCache.d.ts +15 -0
- package/dist/immbook/jwtCache.d.ts.map +1 -0
- package/dist/immbook/jwtCache.js +63 -0
- package/dist/immbook/jwtCache.js.map +1 -0
- package/dist/immbook/points.d.ts +35 -0
- package/dist/immbook/points.d.ts.map +1 -0
- package/dist/immbook/points.js +20 -0
- package/dist/immbook/points.js.map +1 -0
- package/dist/immbook/posts.d.ts +46 -0
- package/dist/immbook/posts.d.ts.map +1 -0
- package/dist/immbook/posts.js +43 -0
- package/dist/immbook/posts.js.map +1 -0
- package/dist/immbook/profile.d.ts +29 -0
- package/dist/immbook/profile.d.ts.map +1 -0
- package/dist/immbook/profile.js +14 -0
- package/dist/immbook/profile.js.map +1 -0
- package/dist/immbook/submolts.d.ts +22 -0
- package/dist/immbook/submolts.d.ts.map +1 -0
- package/dist/immbook/submolts.js +24 -0
- package/dist/immbook/submolts.js.map +1 -0
- package/dist/immbook/tradeProof.d.ts +21 -0
- package/dist/immbook/tradeProof.d.ts.map +1 -0
- package/dist/immbook/tradeProof.js +14 -0
- package/dist/immbook/tradeProof.js.map +1 -0
- package/dist/immbook/votes.d.ts +17 -0
- package/dist/immbook/votes.d.ts.map +1 -0
- package/dist/immbook/votes.js +20 -0
- package/dist/immbook/votes.js.map +1 -0
- package/dist/intents/store.d.ts +22 -0
- package/dist/intents/store.d.ts.map +1 -0
- package/dist/intents/store.js +76 -0
- package/dist/intents/store.js.map +1 -0
- package/dist/intents/types.d.ts +21 -0
- package/dist/intents/types.d.ts.map +1 -0
- package/dist/intents/types.js +2 -0
- package/dist/intents/types.js.map +1 -0
- package/dist/jaine/abi/erc20.d.ts +90 -0
- package/dist/jaine/abi/erc20.d.ts.map +1 -0
- package/dist/jaine/abi/erc20.js +65 -0
- package/dist/jaine/abi/erc20.js.map +1 -0
- package/dist/jaine/abi/factory.d.ts +38 -0
- package/dist/jaine/abi/factory.d.ts.map +1 -0
- package/dist/jaine/abi/factory.js +26 -0
- package/dist/jaine/abi/factory.js.map +1 -0
- package/dist/jaine/abi/index.d.ts +11 -0
- package/dist/jaine/abi/index.d.ts.map +1 -0
- package/dist/jaine/abi/index.js +11 -0
- package/dist/jaine/abi/index.js.map +1 -0
- package/dist/jaine/abi/nftManager.d.ts +282 -0
- package/dist/jaine/abi/nftManager.d.ts.map +1 -0
- package/dist/jaine/abi/nftManager.js +182 -0
- package/dist/jaine/abi/nftManager.js.map +1 -0
- package/dist/jaine/abi/pool.d.ts +77 -0
- package/dist/jaine/abi/pool.d.ts.map +1 -0
- package/dist/jaine/abi/pool.js +56 -0
- package/dist/jaine/abi/pool.js.map +1 -0
- package/dist/jaine/abi/quoter.d.ts +84 -0
- package/dist/jaine/abi/quoter.d.ts.map +1 -0
- package/dist/jaine/abi/quoter.js +53 -0
- package/dist/jaine/abi/quoter.js.map +1 -0
- package/dist/jaine/abi/router.d.ts +135 -0
- package/dist/jaine/abi/router.d.ts.map +1 -0
- package/dist/jaine/abi/router.js +88 -0
- package/dist/jaine/abi/router.js.map +1 -0
- package/dist/jaine/abi/w0g.d.ts +41 -0
- package/dist/jaine/abi/w0g.d.ts.map +1 -0
- package/dist/jaine/abi/w0g.js +34 -0
- package/dist/jaine/abi/w0g.js.map +1 -0
- package/dist/jaine/allowance.d.ts +48 -0
- package/dist/jaine/allowance.d.ts.map +1 -0
- package/dist/jaine/allowance.js +192 -0
- package/dist/jaine/allowance.js.map +1 -0
- package/dist/jaine/coreTokens.d.ts +32 -0
- package/dist/jaine/coreTokens.d.ts.map +1 -0
- package/dist/jaine/coreTokens.js +91 -0
- package/dist/jaine/coreTokens.js.map +1 -0
- package/dist/jaine/pathEncoding.d.ts +39 -0
- package/dist/jaine/pathEncoding.d.ts.map +1 -0
- package/dist/jaine/pathEncoding.js +98 -0
- package/dist/jaine/pathEncoding.js.map +1 -0
- package/dist/jaine/paths.d.ts +11 -0
- package/dist/jaine/paths.d.ts.map +1 -0
- package/dist/jaine/paths.js +20 -0
- package/dist/jaine/paths.js.map +1 -0
- package/dist/jaine/poolCache.d.ts +42 -0
- package/dist/jaine/poolCache.d.ts.map +1 -0
- package/dist/jaine/poolCache.js +164 -0
- package/dist/jaine/poolCache.js.map +1 -0
- package/dist/jaine/routing.d.ts +41 -0
- package/dist/jaine/routing.d.ts.map +1 -0
- package/dist/jaine/routing.js +247 -0
- package/dist/jaine/routing.js.map +1 -0
- package/dist/jaine/userTokens.d.ts +27 -0
- package/dist/jaine/userTokens.d.ts.map +1 -0
- package/dist/jaine/userTokens.js +89 -0
- package/dist/jaine/userTokens.js.map +1 -0
- package/dist/slop/abi/factory.d.ts +128 -0
- package/dist/slop/abi/factory.d.ts.map +1 -0
- package/dist/slop/abi/factory.js +70 -0
- package/dist/slop/abi/factory.js.map +1 -0
- package/dist/slop/abi/feeCollector.d.ts +95 -0
- package/dist/slop/abi/feeCollector.d.ts.map +1 -0
- package/dist/slop/abi/feeCollector.js +71 -0
- package/dist/slop/abi/feeCollector.js.map +1 -0
- package/dist/slop/abi/index.d.ts +5 -0
- package/dist/slop/abi/index.d.ts.map +1 -0
- package/dist/slop/abi/index.js +5 -0
- package/dist/slop/abi/index.js.map +1 -0
- package/dist/slop/abi/registry.d.ts +135 -0
- package/dist/slop/abi/registry.d.ts.map +1 -0
- package/dist/slop/abi/registry.js +90 -0
- package/dist/slop/abi/registry.js.map +1 -0
- package/dist/slop/abi/token.d.ts +320 -0
- package/dist/slop/abi/token.d.ts.map +1 -0
- package/dist/slop/abi/token.js +251 -0
- package/dist/slop/abi/token.js.map +1 -0
- package/dist/slop/quote.d.ts +80 -0
- package/dist/slop/quote.d.ts.map +1 -0
- package/dist/slop/quote.js +174 -0
- package/dist/slop/quote.js.map +1 -0
- package/dist/utils/canonicalJson.d.ts +8 -0
- package/dist/utils/canonicalJson.d.ts.map +1 -0
- package/dist/utils/canonicalJson.js +20 -0
- package/dist/utils/canonicalJson.js.map +1 -0
- package/dist/utils/env.d.ts +11 -0
- package/dist/utils/env.d.ts.map +1 -0
- package/dist/utils/env.js +20 -0
- package/dist/utils/env.js.map +1 -0
- package/dist/utils/http.d.ts +19 -0
- package/dist/utils/http.d.ts.map +1 -0
- package/dist/utils/http.js +61 -0
- package/dist/utils/http.js.map +1 -0
- package/dist/utils/logger.d.ts +4 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +21 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/output.d.ts +19 -0
- package/dist/utils/output.d.ts.map +1 -0
- package/dist/utils/output.js +37 -0
- package/dist/utils/output.js.map +1 -0
- package/dist/utils/respond.d.ts +19 -0
- package/dist/utils/respond.d.ts.map +1 -0
- package/dist/utils/respond.js +25 -0
- package/dist/utils/respond.js.map +1 -0
- package/dist/utils/ui.d.ts +38 -0
- package/dist/utils/ui.d.ts.map +1 -0
- package/dist/utils/ui.js +126 -0
- package/dist/utils/ui.js.map +1 -0
- package/dist/wallet/client.d.ts +4 -0
- package/dist/wallet/client.d.ts.map +1 -0
- package/dist/wallet/client.js +53 -0
- package/dist/wallet/client.js.map +1 -0
- package/dist/wallet/keystore.d.ts +21 -0
- package/dist/wallet/keystore.d.ts.map +1 -0
- package/dist/wallet/keystore.js +111 -0
- package/dist/wallet/keystore.js.map +1 -0
- package/package.json +56 -0
- package/skills/imm/SKILL.md +617 -0
package/README.md
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
# IMM CLI
|
|
2
|
+
|
|
3
|
+
Intelligent Money Market CLI for 0G Network.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g imm-cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or run locally:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install
|
|
15
|
+
npm run build
|
|
16
|
+
npm link
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Initialize config
|
|
23
|
+
imm config init
|
|
24
|
+
|
|
25
|
+
# Generate new wallet (automation-first)
|
|
26
|
+
export IMM_KEYSTORE_PASSWORD="your-secure-password"
|
|
27
|
+
imm wallet create --json
|
|
28
|
+
|
|
29
|
+
# Or import existing key (interactive)
|
|
30
|
+
imm config set-key
|
|
31
|
+
|
|
32
|
+
# Check wallet address
|
|
33
|
+
imm wallet address
|
|
34
|
+
|
|
35
|
+
# Check balance
|
|
36
|
+
imm wallet balance
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Automation / Headless Mode
|
|
40
|
+
|
|
41
|
+
IMM CLI supports automation-first operation for agents like Moltbot/OpenClaw.
|
|
42
|
+
|
|
43
|
+
### JSON Output
|
|
44
|
+
|
|
45
|
+
Add `--json` flag to any command for machine-readable output:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
imm wallet create --json
|
|
49
|
+
# {"success":true,"address":"0x...","chainId":16661}
|
|
50
|
+
|
|
51
|
+
imm wallet balance --json
|
|
52
|
+
# {"success":true,"address":"0x...","chainId":16661,"native":{"symbol":"0G","balanceWei":"...","balance":"1.5"}}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Environment Variables
|
|
56
|
+
|
|
57
|
+
| Variable | Description |
|
|
58
|
+
|----------|-------------|
|
|
59
|
+
| `IMM_KEYSTORE_PASSWORD` | Password for encrypting/decrypting keystore (required for `wallet create` and `send confirm`) |
|
|
60
|
+
|
|
61
|
+
### Headless Detection
|
|
62
|
+
|
|
63
|
+
CLI automatically detects non-TTY environments (pipes, scripts) and suppresses interactive UI elements.
|
|
64
|
+
|
|
65
|
+
### Agent Flow (2-Step Transfers)
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
# 1. Check if wallet exists
|
|
69
|
+
imm wallet address
|
|
70
|
+
|
|
71
|
+
# 2. Create wallet if needed
|
|
72
|
+
imm wallet create --json
|
|
73
|
+
|
|
74
|
+
# 3. Check balance
|
|
75
|
+
imm wallet balance --json
|
|
76
|
+
|
|
77
|
+
# 4. Prepare transfer (creates intent valid for 10 min)
|
|
78
|
+
imm send prepare --to 0x... --amount 1.5 --json
|
|
79
|
+
# {"success":true,"intentId":"<uuid>","from":"0x...","to":"0x...","value":"1.5","expiresAt":"..."}
|
|
80
|
+
|
|
81
|
+
# 5. Confirm and broadcast
|
|
82
|
+
imm send confirm <intentId> --yes --json
|
|
83
|
+
# {"success":true,"txHash":"0x...","status":"pending",...}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Error Handling
|
|
87
|
+
|
|
88
|
+
All errors return structured JSON:
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
{
|
|
92
|
+
"success": false,
|
|
93
|
+
"error": {
|
|
94
|
+
"code": "KEYSTORE_PASSWORD_NOT_SET",
|
|
95
|
+
"message": "IMM_KEYSTORE_PASSWORD environment variable is required.",
|
|
96
|
+
"hint": "Set it in OpenClaw config: skills.entries.imm.env.IMM_KEYSTORE_PASSWORD"
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Error codes: `KEYSTORE_PASSWORD_NOT_SET`, `WALLET_NOT_CONFIGURED`, `KEYSTORE_NOT_FOUND`, `KEYSTORE_ALREADY_EXISTS`, `KEYSTORE_DECRYPT_FAILED`, `INSUFFICIENT_BALANCE`, `INTENT_NOT_FOUND`, `INTENT_EXPIRED`, `CONFIRMATION_REQUIRED`, `INVALID_ADDRESS`, `INVALID_AMOUNT`, `CHAIN_MISMATCH`, `RPC_ERROR`, `SIGNER_MISMATCH`.
|
|
102
|
+
|
|
103
|
+
## Configuration
|
|
104
|
+
|
|
105
|
+
Config files are stored in:
|
|
106
|
+
- **Windows**: `%APPDATA%/imm/`
|
|
107
|
+
- **macOS**: `~/Library/Application Support/imm/`
|
|
108
|
+
- **Linux**: `~/.config/imm/`
|
|
109
|
+
|
|
110
|
+
Files:
|
|
111
|
+
- `config.json` - Main configuration
|
|
112
|
+
- `keystore.json` - Encrypted private key
|
|
113
|
+
- `intents/` - Pending transfer intents
|
|
114
|
+
|
|
115
|
+
### Services URLs
|
|
116
|
+
|
|
117
|
+
`config.json` contains a `services` block with API endpoints:
|
|
118
|
+
|
|
119
|
+
| Key | Default | Description |
|
|
120
|
+
|-----|---------|-------------|
|
|
121
|
+
| `services.backendApiUrl` | `https://be.slop.money/api` | Backend API for profiles, tokens |
|
|
122
|
+
| `services.proxyApiUrl` | `https://ai.slop.money/api` | Proxy API for image upload/generation |
|
|
123
|
+
| `services.chatWsUrl` | `https://ai.slop.money` | WebSocket endpoint for chat |
|
|
124
|
+
|
|
125
|
+
These can be manually edited in `config.json` to point to a staging or local environment.
|
|
126
|
+
|
|
127
|
+
## Commands
|
|
128
|
+
|
|
129
|
+
### Config
|
|
130
|
+
|
|
131
|
+
- `imm config init` - Initialize configuration with defaults
|
|
132
|
+
- `imm config set-key` - Set wallet private key (interactive, encrypted)
|
|
133
|
+
- `imm config set-rpc <url>` - Change RPC endpoint
|
|
134
|
+
- `imm config show` - Show current configuration
|
|
135
|
+
|
|
136
|
+
### Wallet
|
|
137
|
+
|
|
138
|
+
- `imm wallet create [--force] [--json]` - Generate new wallet and save encrypted keystore
|
|
139
|
+
- `imm wallet address` - Display configured address
|
|
140
|
+
- `imm wallet balance [--tokens] [--json]` - Show native and token balances
|
|
141
|
+
- `imm wallet tokens add <address>` - Add token to watchlist
|
|
142
|
+
- `imm wallet tokens remove <address>` - Remove token from watchlist
|
|
143
|
+
- `imm wallet tokens list` - List watchlist tokens
|
|
144
|
+
|
|
145
|
+
### Send
|
|
146
|
+
|
|
147
|
+
- `imm send prepare --to <addr> --amount <0G> [--note <text>] [--json]` - Prepare transfer intent (valid 10 min)
|
|
148
|
+
- `imm send confirm <intentId> --yes [--json]` - Confirm and broadcast transfer
|
|
149
|
+
|
|
150
|
+
### Jaine DEX
|
|
151
|
+
|
|
152
|
+
Jaine is a Uniswap V3-compatible DEX on 0G Network.
|
|
153
|
+
|
|
154
|
+
**Tokens:**
|
|
155
|
+
- `imm jaine tokens list` - List known tokens
|
|
156
|
+
- `imm jaine tokens add-alias <symbol> <address>` - Add token alias
|
|
157
|
+
- `imm jaine tokens remove-alias <symbol>` - Remove alias
|
|
158
|
+
|
|
159
|
+
**Pools:**
|
|
160
|
+
- `imm jaine pools scan-core` - Scan and cache core token pools
|
|
161
|
+
- `imm jaine pools for-token <token>` - Find pools for a token
|
|
162
|
+
- `imm jaine pools find <tokenIn> <tokenOut>` - Find pools between tokens
|
|
163
|
+
|
|
164
|
+
**Wrapped 0G:**
|
|
165
|
+
- `imm jaine w0g balance` - Show 0G and w0G balances
|
|
166
|
+
- `imm jaine w0g wrap --amount <0G> --yes` - Wrap native 0G
|
|
167
|
+
- `imm jaine w0g unwrap --amount <w0G> --yes` - Unwrap w0G
|
|
168
|
+
|
|
169
|
+
**Allowances:**
|
|
170
|
+
- `imm jaine allowance show <token>` - Show approvals
|
|
171
|
+
- `imm jaine allowance revoke <token> --yes` - Revoke approval
|
|
172
|
+
|
|
173
|
+
**Swaps:**
|
|
174
|
+
- `imm jaine swap sell <in> <out> --amount-in <amt> [--dry-run] --yes` - Sell exact input
|
|
175
|
+
- `imm jaine swap buy <in> <out> --amount-out <amt> [--dry-run] --yes` - Buy exact output
|
|
176
|
+
|
|
177
|
+
**Liquidity:**
|
|
178
|
+
- `imm jaine lp list` - List LP positions
|
|
179
|
+
- `imm jaine lp show <id>` - Show position details
|
|
180
|
+
- `imm jaine lp add --token0 <t> --token1 <t> --fee <f> --amount0 <a> --amount1 <a> --yes` - Create position
|
|
181
|
+
- `imm jaine lp increase <id> --amount0 <a> --amount1 <a> --yes` - Add liquidity
|
|
182
|
+
- `imm jaine lp collect <id> --yes` - Collect fees
|
|
183
|
+
- `imm jaine lp remove <id> --percent <n> [--burn] --yes` - Remove liquidity
|
|
184
|
+
|
|
185
|
+
### Slop Money
|
|
186
|
+
|
|
187
|
+
Slop.money is a bonding curve token launcher on 0G Network. Tokens trade on the bonding curve until 80% of the curve supply is sold, then automatically graduate to Jaine DEX. All slop tokens use 18 decimals.
|
|
188
|
+
|
|
189
|
+
**Token Management:**
|
|
190
|
+
- `imm slop token create --name <n> --symbol <s> [--description <d>] [--image-url <u>] --yes` - Create new token
|
|
191
|
+
- `imm slop token info <token>` - Show token info (price, reserves, graduation progress)
|
|
192
|
+
- `imm slop tokens mine [--creator <addr>]` - List tokens created by address
|
|
193
|
+
|
|
194
|
+
**Trading (pre-graduation only):**
|
|
195
|
+
- `imm slop trade buy <token> --amount-og <0G> [--slippage-bps <bps>] [--dry-run] --yes` - Buy tokens with 0G
|
|
196
|
+
- `imm slop trade sell <token> --amount-tokens <amt> [--slippage-bps <bps>] [--dry-run] --yes` - Sell tokens for 0G
|
|
197
|
+
|
|
198
|
+
**Helpers:**
|
|
199
|
+
- `imm slop price <token>` - Current price (bonding or pool)
|
|
200
|
+
- `imm slop curve <token>` - Reserves and graduation progress
|
|
201
|
+
|
|
202
|
+
**Fees:**
|
|
203
|
+
- `imm slop fees stats <token>` - Fee statistics
|
|
204
|
+
- `imm slop fees claim-creator <token> --yes` - Withdraw creator fees
|
|
205
|
+
- `imm slop fees lp pending <token>` - Pending LP fees (post-graduation)
|
|
206
|
+
- `imm slop fees lp collect <token> --yes` - Collect LP fees
|
|
207
|
+
|
|
208
|
+
**Creator Reward:**
|
|
209
|
+
- `imm slop reward pending <token>` - Pending graduation reward
|
|
210
|
+
- `imm slop reward claim <token> --yes` - Claim graduation reward
|
|
211
|
+
|
|
212
|
+
**Error codes:** `SLOP_TOKEN_NOT_OFFICIAL`, `SLOP_TOKEN_GRADUATED`, `SLOP_TRADE_DISABLED`, `SLOP_QUOTE_FAILED`, `SLOP_TX_FAILED`, `SLOP_INSUFFICIENT_BALANCE`, `SLOP_CREATE_FAILED`.
|
|
213
|
+
|
|
214
|
+
### Slop App
|
|
215
|
+
|
|
216
|
+
Interact with the slop.money platform — manage user profiles, upload/generate images, and post to global chat (including triggering the `@mr.slop` AI agent).
|
|
217
|
+
|
|
218
|
+
**Profile:**
|
|
219
|
+
- `imm slop-app profile nonce --json` - Request authentication nonce
|
|
220
|
+
- `imm slop-app profile register --username <name> [--twitter <url>] [--avatar-cid <cid>] [--avatar-gateway <url>] --yes --json` - Register profile with IMM bot badge
|
|
221
|
+
- `imm slop-app profile show [address] --json` - Show profile by address (default: configured wallet)
|
|
222
|
+
|
|
223
|
+
**Image:**
|
|
224
|
+
- `imm slop-app image upload --file <path> --json` - Upload image to IPFS via proxy
|
|
225
|
+
- `imm slop-app image generate --prompt <text> [--upload] --json` - Generate AI image from prompt (optionally upload to IPFS)
|
|
226
|
+
|
|
227
|
+
**Chat:**
|
|
228
|
+
- `imm slop-app chat post --message <text> [--gif <url>] --json` - Post a message to global chat
|
|
229
|
+
- `imm slop-app chat read [--limit <n>] --json` - Read recent chat messages (no auth required, limit 1-250, default 25)
|
|
230
|
+
|
|
231
|
+
Starting a message with `@mr.slop` triggers the AI agent (rate limited).
|
|
232
|
+
|
|
233
|
+
**Image → Avatar/Token flow:**
|
|
234
|
+
1. Upload image: `imm slop-app image upload --file ./avatar.png --json` → returns `ipfsHash` and `gatewayUrl`
|
|
235
|
+
2. Use in profile: `imm slop-app profile register --username bot --avatar-cid <ipfsHash> --avatar-gateway <gatewayUrl> --yes --json`
|
|
236
|
+
3. Or use in token: `imm slop token create --name "X" --symbol "X" --image-url <gatewayUrl> --yes --json`
|
|
237
|
+
|
|
238
|
+
### Agent Query (Signed DSL)
|
|
239
|
+
|
|
240
|
+
Query slop.money token data via signed Agent API. Requires a registered profile.
|
|
241
|
+
|
|
242
|
+
**Shortcuts:**
|
|
243
|
+
- `imm slop-app agents trending [--limit <n>] --json` - Top tokens by 24h volume
|
|
244
|
+
- `imm slop-app agents newest [--limit <n>] --json` - Newest tokens by creation time
|
|
245
|
+
- `imm slop-app agents search --name <pattern> [--limit <n>] --json` - Search tokens by name (ILIKE)
|
|
246
|
+
|
|
247
|
+
**Full query:**
|
|
248
|
+
- `imm slop-app agents query --source tokens [--filter <json>]... [--order-by <field>] [--order-dir asc|desc] [--limit <n>] [--offset <n>] --json` - Custom DSL query
|
|
249
|
+
|
|
250
|
+
`--filter` is repeatable. Each value is a JSON object: `{"field":"status","op":"=","value":"active"}`
|
|
251
|
+
|
|
252
|
+
**Allowed filter fields:** `address`, `symbol`, `name`, `status`, `is_official`, `created_at_ms`, `market_cap`, `actual_price`, `price_change_24h`, `volume_24h`, `holders_count`, `bonding_progress`, `trade_count`, `unique_traders`, `dex_pool_address`
|
|
253
|
+
|
|
254
|
+
**Allowed operators:** `=`, `!=`, `>`, `>=`, `<`, `<=`, `in`, `like`
|
|
255
|
+
- `like` only for `name`/`symbol` (ILIKE, backend wraps with `%`)
|
|
256
|
+
- `in` max 20 elements
|
|
257
|
+
|
|
258
|
+
**Allowed orderBy fields:** `created_at_ms`, `market_cap`, `volume_24h`, `price_change_24h`, `holders_count`
|
|
259
|
+
|
|
260
|
+
**Limits:** max 10 filters, limit 1-200 (default 50), string values max 100 chars. Rate limits: 10 nonce/min per IP, 30 queries/min per wallet.
|
|
261
|
+
|
|
262
|
+
**Error codes:** `AGENT_QUERY_FAILED`, `AGENT_QUERY_TIMEOUT`, `AGENT_QUERY_INVALID`
|
|
263
|
+
|
|
264
|
+
**Error codes:**
|
|
265
|
+
|
|
266
|
+
*Profile:* `PROFILE_NOT_FOUND`, `PROFILE_ALREADY_EXISTS`, `USERNAME_TAKEN`, `INVALID_USERNAME`, `NONCE_EXPIRED`, `SIGNATURE_FAILED`, `REGISTRATION_FAILED`
|
|
267
|
+
|
|
268
|
+
*Image:* `IMAGE_UPLOAD_FAILED`, `IMAGE_TOO_LARGE`, `IMAGE_INVALID_FORMAT`, `IMAGE_GENERATION_FAILED`
|
|
269
|
+
|
|
270
|
+
*Chat:* `CHAT_NOT_AUTHENTICATED`, `CHAT_SESSION_EXPIRED`, `CHAT_RATE_LIMITED`, `CHAT_MESSAGE_EMPTY`, `CHAT_MESSAGE_TOO_LONG`, `CHAT_SEND_FAILED`
|
|
271
|
+
|
|
272
|
+
*HTTP:* `HTTP_REQUEST_FAILED`, `HTTP_TIMEOUT`
|
|
273
|
+
|
|
274
|
+
**Smoke test:**
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
imm config init
|
|
278
|
+
export IMM_KEYSTORE_PASSWORD="..."
|
|
279
|
+
imm wallet create --json
|
|
280
|
+
imm slop-app profile register --username testbot --yes --json
|
|
281
|
+
imm slop-app profile show --json
|
|
282
|
+
imm slop-app image generate --prompt "a happy slop" --upload --json
|
|
283
|
+
imm slop-app chat post --message "@mr.slop hello" --json
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Security
|
|
287
|
+
|
|
288
|
+
Private keys are encrypted using:
|
|
289
|
+
- **KDF**: scrypt (N=16384, r=8, p=1)
|
|
290
|
+
- **Cipher**: AES-256-GCM
|
|
291
|
+
|
|
292
|
+
**Security features:**
|
|
293
|
+
- Private keys never printed to stdout/stderr
|
|
294
|
+
- 2-step send flow prevents accidental transfers
|
|
295
|
+
- Intents expire after 10 minutes
|
|
296
|
+
- Signer verification before broadcast
|
|
297
|
+
|
|
298
|
+
Never share your `keystore.json` or password.
|
|
299
|
+
|
|
300
|
+
## OpenClaw Integration
|
|
301
|
+
|
|
302
|
+
IMM CLI ships an OpenClaw skill. After installing, link it:
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
imm setup openclaw
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
This creates a symlink at `~/.openclaw/skills/imm/` pointing to the packaged skill.
|
|
309
|
+
Use `--force` to overwrite an existing skill. Use `--json` for automation output.
|
|
310
|
+
|
|
311
|
+
For the full skill reference, see [skills/imm/SKILL.md](skills/imm/SKILL.md).
|
|
312
|
+
|
|
313
|
+
## License
|
|
314
|
+
|
|
315
|
+
MIT
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAyBA;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,KAAK,CA+B/C"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { Command, CommanderError } from "commander";
|
|
6
|
+
import { createConfigCommand } from "./commands/config.js";
|
|
7
|
+
import { createWalletCommand } from "./commands/wallet.js";
|
|
8
|
+
import { createSendCommand } from "./commands/send.js";
|
|
9
|
+
import { createJaineCommand } from "./commands/jaine.js";
|
|
10
|
+
import { createSlopCommand } from "./commands/slop.js";
|
|
11
|
+
import { createSlopAppCommand } from "./commands/slop-app.js";
|
|
12
|
+
import { createImmBookCommand } from "./commands/immbook.js";
|
|
13
|
+
import { createSetupCommand } from "./commands/setup.js";
|
|
14
|
+
import { printLogo, errorBox } from "./utils/ui.js";
|
|
15
|
+
import { setJsonMode, isHeadless, writeJsonError } from "./utils/output.js";
|
|
16
|
+
import { ImmError } from "./errors.js";
|
|
17
|
+
// Early --json detection BEFORE program.parse()
|
|
18
|
+
// This ensures isHeadless() returns true even for Commander parsing errors
|
|
19
|
+
const isJsonRequested = process.argv.includes("--json");
|
|
20
|
+
if (isJsonRequested) {
|
|
21
|
+
setJsonMode(true);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Global error handler for consistent error output.
|
|
25
|
+
* Outputs JSON error in headless mode, UI box otherwise.
|
|
26
|
+
*/
|
|
27
|
+
export function handleError(err) {
|
|
28
|
+
// Handle Commander errors (unknown option, missing required, etc.)
|
|
29
|
+
if (err instanceof CommanderError) {
|
|
30
|
+
// Skip help/version exits (exitCode 0)
|
|
31
|
+
if (err.exitCode === 0) {
|
|
32
|
+
process.exit(0);
|
|
33
|
+
}
|
|
34
|
+
if (isHeadless()) {
|
|
35
|
+
writeJsonError("CLI_ERROR", err.message);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
errorBox("CLI Error", err.message);
|
|
39
|
+
}
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
if (err instanceof ImmError) {
|
|
43
|
+
if (isHeadless()) {
|
|
44
|
+
writeJsonError(err.code, err.message, err.hint);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
const content = err.hint ? `${err.message}\n\nHint: ${err.hint}` : err.message;
|
|
48
|
+
errorBox(err.code, content);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
53
|
+
if (isHeadless()) {
|
|
54
|
+
writeJsonError("UNKNOWN_ERROR", message);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
errorBox("Error", message);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
63
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, "../package.json"), "utf-8"));
|
|
64
|
+
const program = new Command();
|
|
65
|
+
program
|
|
66
|
+
.name("imm")
|
|
67
|
+
.description("Intelligent Money Market CLI for 0G Network")
|
|
68
|
+
.version(pkg.version)
|
|
69
|
+
.option("--json", "Output in JSON format (implies headless mode)")
|
|
70
|
+
.hook("preAction", () => {
|
|
71
|
+
// Double-check --json flag (also set early above for parsing errors)
|
|
72
|
+
const opts = program.opts();
|
|
73
|
+
if (opts.json) {
|
|
74
|
+
setJsonMode(true);
|
|
75
|
+
}
|
|
76
|
+
// Print logo only for --help or when no args (and not in JSON mode)
|
|
77
|
+
if (!opts.json && (process.argv.includes("--help") || process.argv.includes("-h") || process.argv.length <= 2)) {
|
|
78
|
+
printLogo();
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
// Configure output: in headless mode, route Commander's stdout to stderr
|
|
82
|
+
// This keeps stdout clean for JSON data only
|
|
83
|
+
program.configureOutput({
|
|
84
|
+
writeOut: (str) => {
|
|
85
|
+
if (isHeadless()) {
|
|
86
|
+
process.stderr.write(str);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
process.stdout.write(str);
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
writeErr: (str) => process.stderr.write(str),
|
|
93
|
+
});
|
|
94
|
+
// Exit override: throw CommanderError instead of process.exit()
|
|
95
|
+
// This allows handleError to produce JSON output for CLI errors
|
|
96
|
+
program.exitOverride();
|
|
97
|
+
// Register commands
|
|
98
|
+
program.addCommand(createConfigCommand());
|
|
99
|
+
program.addCommand(createWalletCommand());
|
|
100
|
+
program.addCommand(createSendCommand());
|
|
101
|
+
program.addCommand(createJaineCommand());
|
|
102
|
+
program.addCommand(createSlopCommand());
|
|
103
|
+
program.addCommand(createSlopAppCommand());
|
|
104
|
+
program.addCommand(createImmBookCommand());
|
|
105
|
+
program.addCommand(createSetupCommand());
|
|
106
|
+
// Global unhandled rejection handler for async command errors
|
|
107
|
+
process.on("unhandledRejection", (err) => {
|
|
108
|
+
handleError(err);
|
|
109
|
+
});
|
|
110
|
+
// Parse and run - use parseAsync + catch for CommanderError handling
|
|
111
|
+
program.parseAsync().catch(handleError);
|
|
112
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC5E,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,gDAAgD;AAChD,2EAA2E;AAC3E,MAAM,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AACxD,IAAI,eAAe,EAAE,CAAC;IACpB,WAAW,CAAC,IAAI,CAAC,CAAC;AACpB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,GAAY;IACtC,mEAAmE;IACnE,IAAI,GAAG,YAAY,cAAc,EAAE,CAAC;QAClC,uCAAuC;QACvC,IAAI,GAAG,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,IAAI,UAAU,EAAE,EAAE,CAAC;YACjB,cAAc,CAAC,WAAW,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;QAC3C,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,WAAW,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;QACrC,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,GAAG,YAAY,QAAQ,EAAE,CAAC;QAC5B,IAAI,UAAU,EAAE,EAAE,CAAC;YACjB,cAAc,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QAClD,CAAC;aAAM,CAAC;YACN,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,OAAO,aAAa,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC;YAC/E,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;SAAM,CAAC;QACN,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,IAAI,UAAU,EAAE,EAAE,CAAC;YACjB,cAAc,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;QAC3C,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1D,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;AAElF,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,KAAK,CAAC;KACX,WAAW,CAAC,6CAA6C,CAAC;KAC1D,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;KACpB,MAAM,CAAC,QAAQ,EAAE,+CAA+C,CAAC;KACjE,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE;IACtB,qEAAqE;IACrE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,WAAW,CAAC,IAAI,CAAC,CAAC;IACpB,CAAC;IACD,oEAAoE;IACpE,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,EAAE,CAAC;QAC/G,SAAS,EAAE,CAAC;IACd,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,yEAAyE;AACzE,6CAA6C;AAC7C,OAAO,CAAC,eAAe,CAAC;IACtB,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE;QAChB,IAAI,UAAU,EAAE,EAAE,CAAC;YACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC5B,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC;CAC7C,CAAC,CAAC;AAEH,gEAAgE;AAChE,gEAAgE;AAChE,OAAO,CAAC,YAAY,EAAE,CAAC;AAEvB,oBAAoB;AACpB,OAAO,CAAC,UAAU,CAAC,mBAAmB,EAAE,CAAC,CAAC;AAC1C,OAAO,CAAC,UAAU,CAAC,mBAAmB,EAAE,CAAC,CAAC;AAC1C,OAAO,CAAC,UAAU,CAAC,iBAAiB,EAAE,CAAC,CAAC;AACxC,OAAO,CAAC,UAAU,CAAC,kBAAkB,EAAE,CAAC,CAAC;AACzC,OAAO,CAAC,UAAU,CAAC,iBAAiB,EAAE,CAAC,CAAC;AACxC,OAAO,CAAC,UAAU,CAAC,oBAAoB,EAAE,CAAC,CAAC;AAC3C,OAAO,CAAC,UAAU,CAAC,oBAAoB,EAAE,CAAC,CAAC;AAC3C,OAAO,CAAC,UAAU,CAAC,kBAAkB,EAAE,CAAC,CAAC;AAEzC,8DAA8D;AAC9D,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,GAAG,EAAE,EAAE;IACvC,WAAW,CAAC,GAAG,CAAC,CAAC;AACnB,CAAC,CAAC,CAAC;AAEH,qEAAqE;AACrE,OAAO,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAyBpC,wBAAgB,mBAAmB,IAAI,OAAO,CAuR7C"}
|