openclaw-overlay-plugin 0.7.70 → 0.7.71
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/SKILL.md +35 -54
- package/dist/index.js +39 -6
- package/dist/src/cli-main.js +12 -2
- package/dist/src/scripts/config.d.ts +4 -0
- package/dist/src/scripts/config.js +7 -0
- package/dist/src/scripts/overlay/advertisement.d.ts +16 -0
- package/dist/src/scripts/overlay/advertisement.js +122 -0
- package/dist/src/scripts/wallet/setup.d.ts +4 -0
- package/dist/src/scripts/wallet/setup.js +14 -0
- package/index.ts +42 -6
- package/openclaw.plugin.json +2 -2
- package/package.json +1 -1
- package/src/cli-main.ts +12 -2
- package/src/scripts/config.ts +8 -0
- package/src/scripts/overlay/advertisement.ts +138 -0
- package/src/scripts/wallet/setup.ts +16 -0
package/SKILL.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
2
|
+
name: overlay
|
|
3
3
|
description: >
|
|
4
4
|
Connect to the BSV Overlay Network — a decentralized agent marketplace for
|
|
5
5
|
discovering other AI agents and exchanging BSV micropayments for services.
|
|
6
6
|
Use when the user wants to register an agent, discover or request services,
|
|
7
|
-
advertise capabilities, manage a BSV wallet, or handle incoming service requests.
|
|
7
|
+
advertise capabilities (via SHIP/SLAP), manage a BSV wallet, or handle incoming service requests.
|
|
8
8
|
metadata: '{"openclaw": {"requires": {"bins": ["node"]}}}'
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -12,81 +12,62 @@ metadata: '{"openclaw": {"requires": {"bins": ["node"]}}}'
|
|
|
12
12
|
|
|
13
13
|
| Action | Description |
|
|
14
14
|
|--------|-------------|
|
|
15
|
+
| `status` | **Recommended**: Show identity key, balance, network, and services |
|
|
15
16
|
| `onboard` | One-step setup: wallet, address, funding check, register |
|
|
16
17
|
| `request` | Auto-discover cheapest provider and request a service |
|
|
17
18
|
| `discover` | List agents and services on the network |
|
|
18
19
|
| `balance` | Show wallet balance |
|
|
19
|
-
| `status` | Show identity, balance, and services |
|
|
20
20
|
| `pay` | Direct payment to an agent |
|
|
21
|
-
| `
|
|
22
|
-
| `address` | Show receive address |
|
|
23
|
-
| `import` | Import funded UTXO by txid |
|
|
21
|
+
| `address` | Show receive address (network-aware) |
|
|
24
22
|
| `register` | Register on overlay network |
|
|
25
23
|
| `advertise` | Advertise a new service |
|
|
24
|
+
| `advertise-ship` | Advertise a Topic Manager (SHIP protocol) |
|
|
25
|
+
| `advertise-slap` | Advertise a Lookup Service (SLAP protocol) |
|
|
26
26
|
| `readvertise` | Update service pricing/name/description |
|
|
27
27
|
| `remove` | Remove an advertised service |
|
|
28
28
|
| `services` | List our advertised services |
|
|
29
|
-
| `send` | Send direct message to agent |
|
|
30
|
-
| `inbox` | Check incoming messages |
|
|
31
|
-
| `refund` | Sweep wallet to external address |
|
|
32
29
|
| `pending-requests` | Check pending incoming service requests |
|
|
33
30
|
| `fulfill` | Fulfill a pending service request |
|
|
31
|
+
| `setup` | Initialize wallet |
|
|
32
|
+
| `import` | Import funded UTXO by txid |
|
|
34
33
|
| `unregister` | Remove agent from network (destructive, requires confirmation) |
|
|
35
|
-
| `remove-service` | Remove a service from network (destructive, requires confirmation) |
|
|
36
34
|
|
|
37
|
-
##
|
|
35
|
+
## Network Support
|
|
38
36
|
|
|
39
|
-
|
|
37
|
+
The plugin is network-aware and supports:
|
|
38
|
+
- **`mainnet`**: Production network (Babbage tracker: `https://overlay.babbage.systems`)
|
|
39
|
+
- **`testnet`**: Testing network (Babbage tracker: `https://testnet-users.bapp.dev`)
|
|
40
|
+
- **`local`**: Local development (default tracker: `http://localhost:8080`)
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
2. **Ask for description**: "Describe what your agent does in 1-2 sentences."
|
|
43
|
-
3. **Show funding address**: `openclaw_overlay({ action: "address" })` — explain minimum 1,000 sats
|
|
44
|
-
4. **After funding**: `openclaw_overlay({ action: "onboard", agentName: "...", agentDescription: "..." })`
|
|
45
|
-
5. **Ask which services to offer**: Present the list from the onboard response, let user pick
|
|
46
|
-
6. **Advertise selected**: `openclaw_overlay({ action: "advertise", ... })` for each
|
|
42
|
+
Addresses and WIFs will automatically use the correct prefix ('1' for mainnet, 'm'/'n' for testnet).
|
|
47
43
|
|
|
48
|
-
|
|
49
|
-
```json
|
|
50
|
-
{
|
|
51
|
-
"plugins": {
|
|
52
|
-
"entries": {
|
|
53
|
-
"openclaw-overlay-plugin": {
|
|
54
|
-
"agentName": "...",
|
|
55
|
-
"overlayUrl": "..."
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
```
|
|
44
|
+
## Onboarding & Setup
|
|
61
45
|
|
|
62
|
-
|
|
46
|
+
1. **Check Status**: `overlay({ action: "status" })`
|
|
47
|
+
2. **Initialize**: If not setup, ask for agent name/description.
|
|
48
|
+
3. **Show Address**: `overlay({ action: "address" })` — explain minimum 1,000 sats
|
|
49
|
+
4. **Fund & Onboard**: Once funded, `overlay({ action: "onboard" })`
|
|
50
|
+
5. **Advertise**: `overlay({ action: "advertise", serviceId: "...", name: "...", priceSats: 500 })`
|
|
63
51
|
|
|
64
|
-
##
|
|
52
|
+
## Discovery & Services
|
|
65
53
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
54
|
+
- **Find services**: `overlay({ action: "discover", service: "tell-joke" })`
|
|
55
|
+
- **Request service**: `overlay({ action: "request", service: "tell-joke", input: { topic: "tech" } })`
|
|
56
|
+
- **Advertise Infrastructure**:
|
|
57
|
+
- SHIP: `overlay({ action: "advertise-ship", domain: "https://my-node.com", topic: "tm_openclaw_identity" })`
|
|
58
|
+
- SLAP: `overlay({ action: "advertise-slap", domain: "https://my-node.com", service: "ls_openclaw_agents" })`
|
|
69
59
|
|
|
70
60
|
## Fulfilling Requests
|
|
71
61
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
1. `openclaw_overlay({ action: "pending-requests" })` — see what needs handling
|
|
75
|
-
2. Process each request using your full capabilities
|
|
76
|
-
3. `openclaw_overlay({ action: "fulfill", requestId: "...", recipientKey: "...", serviceId: "...", result: {...} })` — send response
|
|
77
|
-
|
|
78
|
-
Always fulfill promptly — requesters have already paid.
|
|
79
|
-
|
|
80
|
-
## Spending Rules
|
|
62
|
+
Incoming requests are queued and you'll be woken automatically.
|
|
81
63
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
- **Destructive actions** (`unregister`, `remove-service`): Require a two-step confirmation token
|
|
64
|
+
1. `overlay({ action: "pending-requests" })` — see what needs handling
|
|
65
|
+
2. Process the request payload.
|
|
66
|
+
3. `overlay({ action: "fulfill", requestId: "...", recipientKey: "...", serviceId: "...", result: {...} })`
|
|
86
67
|
|
|
87
|
-
##
|
|
68
|
+
## Spending & Security
|
|
88
69
|
|
|
89
|
-
-
|
|
90
|
-
-
|
|
91
|
-
-
|
|
92
|
-
-
|
|
70
|
+
- **Auto-pay**: Requests under `maxAutoPaySats` (default 200 sats) pay automatically.
|
|
71
|
+
- **Budget**: Daily spending is capped (default 5,000 sats/day).
|
|
72
|
+
- **Destructive actions**: `unregister` requires a two-step confirmation token.
|
|
73
|
+
- **Privacy**: Private keys are stored locally in `~/.openclaw/bsv-wallet`. Never share `wallet-identity.json`.
|
package/dist/index.js
CHANGED
|
@@ -302,7 +302,7 @@ function getCliPath() {
|
|
|
302
302
|
* Decentralized agent marketplace with BSV micropayments.
|
|
303
303
|
*/
|
|
304
304
|
export const plugin = {
|
|
305
|
-
id: "
|
|
305
|
+
id: "overlay",
|
|
306
306
|
name: "BSV Overlay Network",
|
|
307
307
|
description: "OpenClaw Overlay — decentralized agent marketplace with BSV micropayments",
|
|
308
308
|
async activate(api) {
|
|
@@ -313,7 +313,7 @@ export const plugin = {
|
|
|
313
313
|
return;
|
|
314
314
|
isInitialized = true;
|
|
315
315
|
const entries = api.getConfig?.()?.plugins?.entries || {};
|
|
316
|
-
const entry = entries['openclaw-overlay-plugin'] || entries['openclaw-overlay'] || {};
|
|
316
|
+
const entry = entries['overlay'] || entries['openclaw-overlay-plugin'] || entries['openclaw-overlay'] || {};
|
|
317
317
|
const pluginConfig = { ...entry, ...(entry.config || {}), ...(api.config || {}) };
|
|
318
318
|
// 1. Tool
|
|
319
319
|
api.registerTool({
|
|
@@ -322,8 +322,10 @@ export const plugin = {
|
|
|
322
322
|
parameters: {
|
|
323
323
|
type: "object",
|
|
324
324
|
properties: {
|
|
325
|
-
action: { type: "string", enum: ["request", "discover", "balance", "status", "pay", "onboard", "pending-requests", "fulfill", "unregister"] },
|
|
325
|
+
action: { type: "string", enum: ["request", "discover", "balance", "status", "pay", "onboard", "pending-requests", "fulfill", "unregister", "advertise-ship", "advertise-slap"] },
|
|
326
326
|
service: { type: "string" },
|
|
327
|
+
topic: { type: "string" },
|
|
328
|
+
domain: { type: "string" },
|
|
327
329
|
input: { type: "object" },
|
|
328
330
|
identityKey: { type: "string" },
|
|
329
331
|
sats: { type: "number" },
|
|
@@ -353,10 +355,29 @@ export const plugin = {
|
|
|
353
355
|
try {
|
|
354
356
|
const action = ctx.args?.[0] || 'status';
|
|
355
357
|
if (action === 'help') {
|
|
356
|
-
return { text: `🛰️ **Overlay Help**\n\n**Subcommands**:\n- \`status\`: Show identity and wallet balance\n- \`balance\`: Show current satoshis\n- \`onboard\`: Start discovery setup\n- \`discover <serviceId>\`: Find providers on network\n- \`pending-requests\`: See incoming service jobs\n- \`fulfill\`: Complete a request (Agent only)` };
|
|
358
|
+
return { text: `🛰️ **Overlay Help**\n\n**Subcommands**:\n- \`status\`: Show identity and wallet balance\n- \`balance\`: Show current satoshis\n- \`onboard\`: Start discovery setup\n- \`discover <serviceId>\`: Find providers on network\n- \`advertise-ship <domain> <topic>\`: Advertise a topic manager\n- \`advertise-slap <domain> <service>\`: Advertise a lookup service\n- \`pending-requests\`: See incoming service jobs\n- \`fulfill\`: Complete a request (Agent only)` };
|
|
357
359
|
}
|
|
358
|
-
const
|
|
359
|
-
|
|
360
|
+
const params = { action };
|
|
361
|
+
if (action === 'discover') {
|
|
362
|
+
params.service = ctx.args[1];
|
|
363
|
+
}
|
|
364
|
+
else if (action === 'advertise-ship') {
|
|
365
|
+
params.domain = ctx.args[1];
|
|
366
|
+
params.topic = ctx.args[2];
|
|
367
|
+
}
|
|
368
|
+
else if (action === 'advertise-slap') {
|
|
369
|
+
params.domain = ctx.args[1];
|
|
370
|
+
params.service = ctx.args[2];
|
|
371
|
+
}
|
|
372
|
+
const result = await executeOverlayAction(params, pluginConfig, api);
|
|
373
|
+
if (typeof result === 'string')
|
|
374
|
+
return { text: result };
|
|
375
|
+
// Formatted status response
|
|
376
|
+
if (action === 'status') {
|
|
377
|
+
const status = result;
|
|
378
|
+
return { text: `🛰️ **Overlay Status**\n\n**Identity Key**: \`${status.identity?.identityKey || 'Not setup'}\`\n**Balance**: ${status.balance?.walletBalance || 0} satoshis\n**Network**: ${status.identity?.network || 'mainnet'}` };
|
|
379
|
+
}
|
|
380
|
+
return { text: `**Overlay ${action.toUpperCase()}**\n\n${JSON.stringify(result, null, 2)}` };
|
|
360
381
|
}
|
|
361
382
|
catch (error) {
|
|
362
383
|
return { text: `❌ Error: ${error.message}` };
|
|
@@ -404,9 +425,21 @@ async function executeOverlayAction(params, config, api) {
|
|
|
404
425
|
case "onboard": return await handleOnboard(params, env, cliPath);
|
|
405
426
|
case "pending-requests": return await handlePendingRequests(env, cliPath);
|
|
406
427
|
case "fulfill": return await handleFulfill(params, env, cliPath);
|
|
428
|
+
case "advertise-ship": return await handleAdvertiseSHIP(params, env, cliPath);
|
|
429
|
+
case "advertise-slap": return await handleAdvertiseSLAP(params, env, cliPath);
|
|
407
430
|
default: throw new Error(`Unknown action: ${action}`);
|
|
408
431
|
}
|
|
409
432
|
}
|
|
433
|
+
async function handleAdvertiseSHIP(params, env, cliPath) {
|
|
434
|
+
const { domain, topic } = params;
|
|
435
|
+
const result = await execFileAsync('node', [cliPath, 'advertise-ship', domain, topic], { env });
|
|
436
|
+
return parseCliOutput(result.stdout).data;
|
|
437
|
+
}
|
|
438
|
+
async function handleAdvertiseSLAP(params, env, cliPath) {
|
|
439
|
+
const { domain, service } = params;
|
|
440
|
+
const result = await execFileAsync('node', [cliPath, 'advertise-slap', domain, service], { env });
|
|
441
|
+
return parseCliOutput(result.stdout).data;
|
|
442
|
+
}
|
|
410
443
|
async function handleServiceRequest(params, env, cliPath, config, api) {
|
|
411
444
|
const { service, identityKey: targetKey, input } = params;
|
|
412
445
|
const walletDir = config?.walletDir || path.join(os.homedir(), '.openclaw', 'bsv-wallet');
|
package/dist/src/cli-main.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { ok, fail } from './scripts/output.js';
|
|
8
8
|
// Wallet commands
|
|
9
|
-
import { cmdSetup, cmdIdentity, cmdAddress } from './scripts/wallet/setup.js';
|
|
9
|
+
import { cmdSetup, cmdIdentity, cmdAddress, cmdStatus } from './scripts/wallet/setup.js';
|
|
10
10
|
import { cmdBalance, cmdImport, cmdRefund } from './scripts/wallet/balance.js';
|
|
11
11
|
// Overlay registration commands
|
|
12
12
|
import { cmdRegister, cmdUnregister } from './scripts/overlay/registration.js';
|
|
@@ -14,6 +14,7 @@ import { cmdRegister, cmdUnregister } from './scripts/overlay/registration.js';
|
|
|
14
14
|
import { cmdServices, cmdAdvertise, cmdRemove, cmdReadvertise } from './scripts/overlay/services.js';
|
|
15
15
|
// Discovery commands
|
|
16
16
|
import { cmdDiscover } from './scripts/overlay/discover.js';
|
|
17
|
+
import { cmdAdvertiseSHIP, cmdAdvertiseSLAP } from './scripts/overlay/advertisement.js';
|
|
17
18
|
// Payment commands
|
|
18
19
|
import { cmdPay, cmdVerify, cmdAccept } from './scripts/payment/commands.js';
|
|
19
20
|
// Messaging commands
|
|
@@ -43,7 +44,7 @@ async function main() {
|
|
|
43
44
|
wallet: ['setup', 'identity', 'address', 'balance', 'import <txid> [vout]', 'refund <address>'],
|
|
44
45
|
registration: ['register', 'unregister'],
|
|
45
46
|
services: ['services', 'advertise <id> <name> <priceSats> [desc]', 'readvertise <id> [name] [priceSats] [desc]', 'remove <id>'],
|
|
46
|
-
discovery: ['discover [--service <type>] [--agent <name>]'],
|
|
47
|
+
discovery: ['discover [--service <type>] [--agent <name>]', 'advertise-ship <domain> <topic>', 'advertise-slap <domain> <service>'],
|
|
47
48
|
payments: ['pay <pubkey> <sats> [desc]', 'verify <beef>', 'accept <beef> <prefix> <suffix> <senderKey> [desc]'],
|
|
48
49
|
messaging: ['send <key> <type> <json>', 'inbox', 'ack', 'poll', 'connect'],
|
|
49
50
|
'service-requests': ['request-service <key> <serviceId> <sats> [input]', 'service-queue', 'respond-service <reqId> <key> <serviceId> <result>'],
|
|
@@ -54,6 +55,9 @@ async function main() {
|
|
|
54
55
|
});
|
|
55
56
|
break;
|
|
56
57
|
// Wallet
|
|
58
|
+
case 'status':
|
|
59
|
+
await cmdStatus();
|
|
60
|
+
break;
|
|
57
61
|
case 'setup':
|
|
58
62
|
await cmdSetup();
|
|
59
63
|
break;
|
|
@@ -96,6 +100,12 @@ async function main() {
|
|
|
96
100
|
case 'discover':
|
|
97
101
|
await cmdDiscover(args);
|
|
98
102
|
break;
|
|
103
|
+
case 'advertise-ship':
|
|
104
|
+
await cmdAdvertiseSHIP(args[0], args[1]);
|
|
105
|
+
break;
|
|
106
|
+
case 'advertise-slap':
|
|
107
|
+
await cmdAdvertiseSLAP(args[0], args[1]);
|
|
108
|
+
break;
|
|
99
109
|
// Payments
|
|
100
110
|
case 'pay':
|
|
101
111
|
await cmdPay(args[0], args[1], args.slice(2).join(' ') || undefined);
|
|
@@ -22,7 +22,11 @@ export declare const TOPICS: {
|
|
|
22
22
|
readonly IDENTITY: "tm_openclaw_identity";
|
|
23
23
|
readonly SERVICES: "tm_openclaw_services";
|
|
24
24
|
readonly X_VERIFICATION: "tm_openclaw_x_verification";
|
|
25
|
+
readonly SHIP: "tm_ship";
|
|
26
|
+
readonly SLAP: "tm_slap";
|
|
25
27
|
};
|
|
28
|
+
/** Default SLAP trackers */
|
|
29
|
+
export declare const DEFAULT_SLAP_TRACKERS: Record<'mainnet' | 'testnet', string[]>;
|
|
26
30
|
/** Lookup services for overlay queries */
|
|
27
31
|
export declare const LOOKUP_SERVICES: {
|
|
28
32
|
readonly AGENTS: "ls_openclaw_agents";
|
|
@@ -42,6 +42,13 @@ export const TOPICS = {
|
|
|
42
42
|
IDENTITY: 'tm_openclaw_identity',
|
|
43
43
|
SERVICES: 'tm_openclaw_services',
|
|
44
44
|
X_VERIFICATION: 'tm_openclaw_x_verification',
|
|
45
|
+
SHIP: 'tm_ship',
|
|
46
|
+
SLAP: 'tm_slap',
|
|
47
|
+
};
|
|
48
|
+
/** Default SLAP trackers */
|
|
49
|
+
export const DEFAULT_SLAP_TRACKERS = {
|
|
50
|
+
mainnet: ['https://overlay.babbage.systems'],
|
|
51
|
+
testnet: ['https://testnet-users.bapp.dev'],
|
|
45
52
|
};
|
|
46
53
|
/** Lookup services for overlay queries */
|
|
47
54
|
export const LOOKUP_SERVICES = {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SHIP and SLAP advertisement commands.
|
|
3
|
+
*
|
|
4
|
+
* SHIP: Service Health & Information Protocol (tm_ship)
|
|
5
|
+
* SLAP: Service Level Agreement Protocol (tm_slap)
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Advertise a SHIP record.
|
|
9
|
+
* Announce that you host a specific Topic Manager (tm_).
|
|
10
|
+
*/
|
|
11
|
+
export declare function cmdAdvertiseSHIP(domain?: string, topic?: string): Promise<never>;
|
|
12
|
+
/**
|
|
13
|
+
* Advertise a SLAP record.
|
|
14
|
+
* Announce that you host a specific Lookup Service (ls_).
|
|
15
|
+
*/
|
|
16
|
+
export declare function cmdAdvertiseSLAP(domain?: string, service?: string): Promise<never>;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SHIP and SLAP advertisement commands.
|
|
3
|
+
*
|
|
4
|
+
* SHIP: Service Health & Information Protocol (tm_ship)
|
|
5
|
+
* SLAP: Service Level Agreement Protocol (tm_slap)
|
|
6
|
+
*/
|
|
7
|
+
import { PushDrop, Utils } from '@bsv/sdk';
|
|
8
|
+
import { NETWORK, WALLET_DIR, TOPICS, DEFAULT_SLAP_TRACKERS } from '../config.js';
|
|
9
|
+
import { BSVAgentWallet } from '../../core/wallet.js';
|
|
10
|
+
import { ok, fail } from '../output.js';
|
|
11
|
+
/**
|
|
12
|
+
* Advertise a SHIP record.
|
|
13
|
+
* Announce that you host a specific Topic Manager (tm_).
|
|
14
|
+
*/
|
|
15
|
+
export async function cmdAdvertiseSHIP(domain, topic) {
|
|
16
|
+
if (!domain || !topic) {
|
|
17
|
+
return fail('Usage: advertise-ship <domain> <topic>');
|
|
18
|
+
}
|
|
19
|
+
if (!topic.startsWith('tm_')) {
|
|
20
|
+
return fail('Topic must start with "tm_"');
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
const wallet = await BSVAgentWallet.load({ network: NETWORK, storageDir: WALLET_DIR });
|
|
24
|
+
const token = new PushDrop(wallet._setup.wallet);
|
|
25
|
+
// SHIP format: Payload is the domain hosting the topic
|
|
26
|
+
const fields = [Utils.toArray(domain, 'utf8')];
|
|
27
|
+
// Context is [0, topic] to identify the topic manager being advertised
|
|
28
|
+
const lockingScript = (await token.lock(fields, [0, topic], '1', 'self', true, true)).toHex();
|
|
29
|
+
const response = await wallet._setup.wallet.createAction({
|
|
30
|
+
description: `advertise SHIP for ${topic}`,
|
|
31
|
+
outputs: [{
|
|
32
|
+
lockingScript,
|
|
33
|
+
satoshis: 1,
|
|
34
|
+
outputDescription: 'SHIP advertisement',
|
|
35
|
+
basket: TOPICS.SHIP
|
|
36
|
+
}]
|
|
37
|
+
});
|
|
38
|
+
// Broadcast to primary overlay and SLAP trackers
|
|
39
|
+
const trackers = [
|
|
40
|
+
...DEFAULT_SLAP_TRACKERS[NETWORK]
|
|
41
|
+
];
|
|
42
|
+
const results = await broadcastToTrackers(response.tx, [TOPICS.SHIP, topic], trackers);
|
|
43
|
+
return ok({
|
|
44
|
+
advertised: 'SHIP',
|
|
45
|
+
topic,
|
|
46
|
+
domain,
|
|
47
|
+
txid: response.txid,
|
|
48
|
+
broadcasts: results
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
return fail(`SHIP advertisement failed: ${err.message}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Advertise a SLAP record.
|
|
57
|
+
* Announce that you host a specific Lookup Service (ls_).
|
|
58
|
+
*/
|
|
59
|
+
export async function cmdAdvertiseSLAP(domain, service) {
|
|
60
|
+
if (!domain || !service) {
|
|
61
|
+
return fail('Usage: advertise-slap <domain> <service>');
|
|
62
|
+
}
|
|
63
|
+
if (!service.startsWith('ls_')) {
|
|
64
|
+
return fail('Service must start with "ls_"');
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const wallet = await BSVAgentWallet.load({ network: NETWORK, storageDir: WALLET_DIR });
|
|
68
|
+
const token = new PushDrop(wallet._setup.wallet);
|
|
69
|
+
// SLAP format: Payload is the domain hosting the lookup service
|
|
70
|
+
const fields = [Utils.toArray(domain, 'utf8')];
|
|
71
|
+
// Context is [0, service] to identify the lookup service being advertised
|
|
72
|
+
const lockingScript = (await token.lock(fields, [0, service], '1', 'self', true, true)).toHex();
|
|
73
|
+
const response = await wallet._setup.wallet.createAction({
|
|
74
|
+
description: `advertise SLAP for ${service}`,
|
|
75
|
+
outputs: [{
|
|
76
|
+
lockingScript,
|
|
77
|
+
satoshis: 1,
|
|
78
|
+
outputDescription: 'SLAP advertisement',
|
|
79
|
+
basket: TOPICS.SLAP
|
|
80
|
+
}]
|
|
81
|
+
});
|
|
82
|
+
// Broadcast to primary overlay and SLAP trackers
|
|
83
|
+
const trackers = [
|
|
84
|
+
...DEFAULT_SLAP_TRACKERS[NETWORK]
|
|
85
|
+
];
|
|
86
|
+
const results = await broadcastToTrackers(response.tx, [TOPICS.SLAP, service], trackers);
|
|
87
|
+
return ok({
|
|
88
|
+
advertised: 'SLAP',
|
|
89
|
+
service,
|
|
90
|
+
domain,
|
|
91
|
+
txid: response.txid,
|
|
92
|
+
broadcasts: results
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
return fail(`SLAP advertisement failed: ${err.message}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Helper to broadcast BEEF to multiple trackers/overlays.
|
|
101
|
+
*/
|
|
102
|
+
async function broadcastToTrackers(tx, topics, trackers) {
|
|
103
|
+
const results = {};
|
|
104
|
+
const body = new Uint8Array(tx);
|
|
105
|
+
for (const url of trackers) {
|
|
106
|
+
try {
|
|
107
|
+
const resp = await fetch(`${url.replace(/\/$/, '')}/submit`, {
|
|
108
|
+
method: 'POST',
|
|
109
|
+
headers: {
|
|
110
|
+
'Content-Type': 'application/octet-stream',
|
|
111
|
+
'X-Topics': JSON.stringify(topics)
|
|
112
|
+
},
|
|
113
|
+
body
|
|
114
|
+
});
|
|
115
|
+
results[url] = resp.ok ? 'success' : `error: ${resp.status}`;
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
results[url] = `failed: ${err.message}`;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return results;
|
|
122
|
+
}
|
|
@@ -9,6 +9,10 @@ export declare function cmdSetup(): Promise<never>;
|
|
|
9
9
|
* Identity command: show identity public key.
|
|
10
10
|
*/
|
|
11
11
|
export declare function cmdIdentity(): Promise<never>;
|
|
12
|
+
/**
|
|
13
|
+
* Status command: show identity and balance.
|
|
14
|
+
*/
|
|
15
|
+
export declare function cmdStatus(): Promise<never>;
|
|
12
16
|
/**
|
|
13
17
|
* Address command: show P2PKH receive address.
|
|
14
18
|
*/
|
|
@@ -83,6 +83,20 @@ export async function cmdIdentity() {
|
|
|
83
83
|
await wallet.destroy();
|
|
84
84
|
return ok({ identityKey });
|
|
85
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Status command: show identity and balance.
|
|
88
|
+
*/
|
|
89
|
+
export async function cmdStatus() {
|
|
90
|
+
const BSVAgentWallet = await getBSVAgentWallet();
|
|
91
|
+
const wallet = await BSVAgentWallet.load({ network: NETWORK, storageDir: WALLET_DIR });
|
|
92
|
+
const identityKey = await wallet.getIdentityKey();
|
|
93
|
+
const total = await wallet.getBalance();
|
|
94
|
+
await wallet.destroy();
|
|
95
|
+
return ok({
|
|
96
|
+
identity: { identityKey, network: NETWORK },
|
|
97
|
+
balance: { walletBalance: total }
|
|
98
|
+
});
|
|
99
|
+
}
|
|
86
100
|
/**
|
|
87
101
|
* Address command: show P2PKH receive address.
|
|
88
102
|
*/
|
package/index.ts
CHANGED
|
@@ -314,7 +314,7 @@ function getCliPath() {
|
|
|
314
314
|
* Decentralized agent marketplace with BSV micropayments.
|
|
315
315
|
*/
|
|
316
316
|
export const plugin = {
|
|
317
|
-
id: "
|
|
317
|
+
id: "overlay",
|
|
318
318
|
name: "BSV Overlay Network",
|
|
319
319
|
description: "OpenClaw Overlay — decentralized agent marketplace with BSV micropayments",
|
|
320
320
|
|
|
@@ -327,7 +327,7 @@ export const plugin = {
|
|
|
327
327
|
isInitialized = true;
|
|
328
328
|
|
|
329
329
|
const entries = api.getConfig?.()?.plugins?.entries || {};
|
|
330
|
-
const entry = entries['openclaw-overlay-plugin'] || entries['openclaw-overlay'] || {};
|
|
330
|
+
const entry = entries['overlay'] || entries['openclaw-overlay-plugin'] || entries['openclaw-overlay'] || {};
|
|
331
331
|
const pluginConfig = { ...entry, ...(entry.config || {}), ...(api.config || {}) };
|
|
332
332
|
|
|
333
333
|
// 1. Tool
|
|
@@ -337,8 +337,10 @@ export const plugin = {
|
|
|
337
337
|
parameters: {
|
|
338
338
|
type: "object",
|
|
339
339
|
properties: {
|
|
340
|
-
action: { type: "string", enum: ["request", "discover", "balance", "status", "pay", "onboard", "pending-requests", "fulfill", "unregister"] },
|
|
340
|
+
action: { type: "string", enum: ["request", "discover", "balance", "status", "pay", "onboard", "pending-requests", "fulfill", "unregister", "advertise-ship", "advertise-slap"] },
|
|
341
341
|
service: { type: "string" },
|
|
342
|
+
topic: { type: "string" },
|
|
343
|
+
domain: { type: "string" },
|
|
342
344
|
input: { type: "object" },
|
|
343
345
|
identityKey: { type: "string" },
|
|
344
346
|
sats: { type: "number" },
|
|
@@ -369,11 +371,31 @@ export const plugin = {
|
|
|
369
371
|
const action = ctx.args?.[0] || 'status';
|
|
370
372
|
|
|
371
373
|
if (action === 'help') {
|
|
372
|
-
return { text: `🛰️ **Overlay Help**\n\n**Subcommands**:\n- \`status\`: Show identity and wallet balance\n- \`balance\`: Show current satoshis\n- \`onboard\`: Start discovery setup\n- \`discover <serviceId>\`: Find providers on network\n- \`pending-requests\`: See incoming service jobs\n- \`fulfill\`: Complete a request (Agent only)` };
|
|
374
|
+
return { text: `🛰️ **Overlay Help**\n\n**Subcommands**:\n- \`status\`: Show identity and wallet balance\n- \`balance\`: Show current satoshis\n- \`onboard\`: Start discovery setup\n- \`discover <serviceId>\`: Find providers on network\n- \`advertise-ship <domain> <topic>\`: Advertise a topic manager\n- \`advertise-slap <domain> <service>\`: Advertise a lookup service\n- \`pending-requests\`: See incoming service jobs\n- \`fulfill\`: Complete a request (Agent only)` };
|
|
373
375
|
}
|
|
374
376
|
|
|
375
|
-
const
|
|
376
|
-
|
|
377
|
+
const params: any = { action };
|
|
378
|
+
if (action === 'discover') {
|
|
379
|
+
params.service = ctx.args[1];
|
|
380
|
+
} else if (action === 'advertise-ship') {
|
|
381
|
+
params.domain = ctx.args[1];
|
|
382
|
+
params.topic = ctx.args[2];
|
|
383
|
+
} else if (action === 'advertise-slap') {
|
|
384
|
+
params.domain = ctx.args[1];
|
|
385
|
+
params.service = ctx.args[2];
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const result = await executeOverlayAction(params, pluginConfig, api);
|
|
389
|
+
|
|
390
|
+
if (typeof result === 'string') return { text: result };
|
|
391
|
+
|
|
392
|
+
// Formatted status response
|
|
393
|
+
if (action === 'status') {
|
|
394
|
+
const status = result as any;
|
|
395
|
+
return { text: `🛰️ **Overlay Status**\n\n**Identity Key**: \`${status.identity?.identityKey || 'Not setup'}\`\n**Balance**: ${status.balance?.walletBalance || 0} satoshis\n**Network**: ${status.identity?.network || 'mainnet'}` };
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
return { text: `**Overlay ${action.toUpperCase()}**\n\n${JSON.stringify(result, null, 2)}` };
|
|
377
399
|
} catch (error: any) {
|
|
378
400
|
return { text: `❌ Error: ${error.message}` };
|
|
379
401
|
}
|
|
@@ -425,10 +447,24 @@ async function executeOverlayAction(params: any, config: any, api: any) {
|
|
|
425
447
|
case "onboard": return await handleOnboard(params, env, cliPath);
|
|
426
448
|
case "pending-requests": return await handlePendingRequests(env, cliPath);
|
|
427
449
|
case "fulfill": return await handleFulfill(params, env, cliPath);
|
|
450
|
+
case "advertise-ship": return await handleAdvertiseSHIP(params, env, cliPath);
|
|
451
|
+
case "advertise-slap": return await handleAdvertiseSLAP(params, env, cliPath);
|
|
428
452
|
default: throw new Error(`Unknown action: ${action}`);
|
|
429
453
|
}
|
|
430
454
|
}
|
|
431
455
|
|
|
456
|
+
async function handleAdvertiseSHIP(params: any, env: any, cliPath: string) {
|
|
457
|
+
const { domain, topic } = params;
|
|
458
|
+
const result = await execFileAsync('node', [cliPath, 'advertise-ship', domain, topic], { env });
|
|
459
|
+
return parseCliOutput(result.stdout).data;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
async function handleAdvertiseSLAP(params: any, env: any, cliPath: string) {
|
|
463
|
+
const { domain, service } = params;
|
|
464
|
+
const result = await execFileAsync('node', [cliPath, 'advertise-slap', domain, service], { env });
|
|
465
|
+
return parseCliOutput(result.stdout).data;
|
|
466
|
+
}
|
|
467
|
+
|
|
432
468
|
async function handleServiceRequest(params: any, env: any, cliPath: string, config: any, api: any) {
|
|
433
469
|
const { service, identityKey: targetKey, input } = params;
|
|
434
470
|
const walletDir = config?.walletDir || path.join(os.homedir(), '.openclaw', 'bsv-wallet');
|
package/openclaw.plugin.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"id": "
|
|
2
|
+
"id": "overlay",
|
|
3
3
|
"name": "BSV Overlay Network",
|
|
4
4
|
"description": "OpenClaw Overlay — decentralized agent marketplace with BSV micropayments",
|
|
5
|
-
"version": "0.7.
|
|
5
|
+
"version": "0.7.70",
|
|
6
6
|
"skills": [
|
|
7
7
|
"./SKILL.md"
|
|
8
8
|
],
|
package/package.json
CHANGED
package/src/cli-main.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { ok, fail } from './scripts/output.js';
|
|
9
9
|
|
|
10
10
|
// Wallet commands
|
|
11
|
-
import { cmdSetup, cmdIdentity, cmdAddress } from './scripts/wallet/setup.js';
|
|
11
|
+
import { cmdSetup, cmdIdentity, cmdAddress, cmdStatus } from './scripts/wallet/setup.js';
|
|
12
12
|
import { cmdBalance, cmdImport, cmdRefund } from './scripts/wallet/balance.js';
|
|
13
13
|
|
|
14
14
|
// Overlay registration commands
|
|
@@ -19,6 +19,7 @@ import { cmdServices, cmdAdvertise, cmdRemove, cmdReadvertise } from './scripts/
|
|
|
19
19
|
|
|
20
20
|
// Discovery commands
|
|
21
21
|
import { cmdDiscover } from './scripts/overlay/discover.js';
|
|
22
|
+
import { cmdAdvertiseSHIP, cmdAdvertiseSLAP } from './scripts/overlay/advertisement.js';
|
|
22
23
|
|
|
23
24
|
// Payment commands
|
|
24
25
|
import { cmdPay, cmdVerify, cmdAccept } from './scripts/payment/commands.js';
|
|
@@ -69,7 +70,7 @@ async function main() {
|
|
|
69
70
|
wallet: ['setup', 'identity', 'address', 'balance', 'import <txid> [vout]', 'refund <address>'],
|
|
70
71
|
registration: ['register', 'unregister'],
|
|
71
72
|
services: ['services', 'advertise <id> <name> <priceSats> [desc]', 'readvertise <id> [name] [priceSats] [desc]', 'remove <id>'],
|
|
72
|
-
discovery: ['discover [--service <type>] [--agent <name>]'],
|
|
73
|
+
discovery: ['discover [--service <type>] [--agent <name>]', 'advertise-ship <domain> <topic>', 'advertise-slap <domain> <service>'],
|
|
73
74
|
payments: ['pay <pubkey> <sats> [desc]', 'verify <beef>', 'accept <beef> <prefix> <suffix> <senderKey> [desc]'],
|
|
74
75
|
messaging: ['send <key> <type> <json>', 'inbox', 'ack', 'poll', 'connect'],
|
|
75
76
|
'service-requests': ['request-service <key> <serviceId> <sats> [input]', 'service-queue', 'respond-service <reqId> <key> <serviceId> <result>'],
|
|
@@ -81,6 +82,9 @@ async function main() {
|
|
|
81
82
|
break;
|
|
82
83
|
|
|
83
84
|
// Wallet
|
|
85
|
+
case 'status':
|
|
86
|
+
await cmdStatus();
|
|
87
|
+
break;
|
|
84
88
|
case 'setup':
|
|
85
89
|
await cmdSetup();
|
|
86
90
|
break;
|
|
@@ -126,6 +130,12 @@ async function main() {
|
|
|
126
130
|
case 'discover':
|
|
127
131
|
await cmdDiscover(args);
|
|
128
132
|
break;
|
|
133
|
+
case 'advertise-ship':
|
|
134
|
+
await cmdAdvertiseSHIP(args[0], args[1]);
|
|
135
|
+
break;
|
|
136
|
+
case 'advertise-slap':
|
|
137
|
+
await cmdAdvertiseSLAP(args[0], args[1]);
|
|
138
|
+
break;
|
|
129
139
|
|
|
130
140
|
// Payments
|
|
131
141
|
case 'pay':
|
package/src/scripts/config.ts
CHANGED
|
@@ -53,8 +53,16 @@ export const TOPICS = {
|
|
|
53
53
|
IDENTITY: 'tm_openclaw_identity',
|
|
54
54
|
SERVICES: 'tm_openclaw_services',
|
|
55
55
|
X_VERIFICATION: 'tm_openclaw_x_verification',
|
|
56
|
+
SHIP: 'tm_ship',
|
|
57
|
+
SLAP: 'tm_slap',
|
|
56
58
|
} as const;
|
|
57
59
|
|
|
60
|
+
/** Default SLAP trackers */
|
|
61
|
+
export const DEFAULT_SLAP_TRACKERS: Record<'mainnet' | 'testnet', string[]> = {
|
|
62
|
+
mainnet: ['https://overlay.babbage.systems'],
|
|
63
|
+
testnet: ['https://testnet-users.bapp.dev'],
|
|
64
|
+
};
|
|
65
|
+
|
|
58
66
|
/** Lookup services for overlay queries */
|
|
59
67
|
export const LOOKUP_SERVICES = {
|
|
60
68
|
AGENTS: 'ls_openclaw_agents',
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SHIP and SLAP advertisement commands.
|
|
3
|
+
*
|
|
4
|
+
* SHIP: Service Health & Information Protocol (tm_ship)
|
|
5
|
+
* SLAP: Service Level Agreement Protocol (tm_slap)
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { PushDrop, Utils } from '@bsv/sdk';
|
|
9
|
+
import { NETWORK, WALLET_DIR, TOPICS, DEFAULT_SLAP_TRACKERS } from '../config.js';
|
|
10
|
+
import { BSVAgentWallet } from '../../core/wallet.js';
|
|
11
|
+
import { ok, fail } from '../output.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Advertise a SHIP record.
|
|
15
|
+
* Announce that you host a specific Topic Manager (tm_).
|
|
16
|
+
*/
|
|
17
|
+
export async function cmdAdvertiseSHIP(domain?: string, topic?: string): Promise<never> {
|
|
18
|
+
if (!domain || !topic) {
|
|
19
|
+
return fail('Usage: advertise-ship <domain> <topic>');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (!topic.startsWith('tm_')) {
|
|
23
|
+
return fail('Topic must start with "tm_"');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
const wallet = await BSVAgentWallet.load({ network: NETWORK, storageDir: WALLET_DIR });
|
|
28
|
+
const token = new PushDrop(wallet._setup.wallet);
|
|
29
|
+
|
|
30
|
+
// SHIP format: Payload is the domain hosting the topic
|
|
31
|
+
const fields = [Utils.toArray(domain, 'utf8')];
|
|
32
|
+
// Context is [0, topic] to identify the topic manager being advertised
|
|
33
|
+
const lockingScript = (await token.lock(fields, [0, topic], '1', 'self', true, true)).toHex();
|
|
34
|
+
|
|
35
|
+
const response = await wallet._setup.wallet.createAction({
|
|
36
|
+
description: `advertise SHIP for ${topic}`,
|
|
37
|
+
outputs: [{
|
|
38
|
+
lockingScript,
|
|
39
|
+
satoshis: 1,
|
|
40
|
+
outputDescription: 'SHIP advertisement',
|
|
41
|
+
basket: TOPICS.SHIP
|
|
42
|
+
}]
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Broadcast to primary overlay and SLAP trackers
|
|
46
|
+
const trackers = [
|
|
47
|
+
...DEFAULT_SLAP_TRACKERS[NETWORK]
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
const results = await broadcastToTrackers(response.tx as number[], [TOPICS.SHIP, topic], trackers);
|
|
51
|
+
|
|
52
|
+
return ok({
|
|
53
|
+
advertised: 'SHIP',
|
|
54
|
+
topic,
|
|
55
|
+
domain,
|
|
56
|
+
txid: response.txid,
|
|
57
|
+
broadcasts: results
|
|
58
|
+
});
|
|
59
|
+
} catch (err: any) {
|
|
60
|
+
return fail(`SHIP advertisement failed: ${err.message}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Advertise a SLAP record.
|
|
66
|
+
* Announce that you host a specific Lookup Service (ls_).
|
|
67
|
+
*/
|
|
68
|
+
export async function cmdAdvertiseSLAP(domain?: string, service?: string): Promise<never> {
|
|
69
|
+
if (!domain || !service) {
|
|
70
|
+
return fail('Usage: advertise-slap <domain> <service>');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!service.startsWith('ls_')) {
|
|
74
|
+
return fail('Service must start with "ls_"');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
const wallet = await BSVAgentWallet.load({ network: NETWORK, storageDir: WALLET_DIR });
|
|
79
|
+
const token = new PushDrop(wallet._setup.wallet);
|
|
80
|
+
|
|
81
|
+
// SLAP format: Payload is the domain hosting the lookup service
|
|
82
|
+
const fields = [Utils.toArray(domain, 'utf8')];
|
|
83
|
+
// Context is [0, service] to identify the lookup service being advertised
|
|
84
|
+
const lockingScript = (await token.lock(fields, [0, service], '1', 'self', true, true)).toHex();
|
|
85
|
+
|
|
86
|
+
const response = await wallet._setup.wallet.createAction({
|
|
87
|
+
description: `advertise SLAP for ${service}`,
|
|
88
|
+
outputs: [{
|
|
89
|
+
lockingScript,
|
|
90
|
+
satoshis: 1,
|
|
91
|
+
outputDescription: 'SLAP advertisement',
|
|
92
|
+
basket: TOPICS.SLAP
|
|
93
|
+
}]
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Broadcast to primary overlay and SLAP trackers
|
|
97
|
+
const trackers = [
|
|
98
|
+
...DEFAULT_SLAP_TRACKERS[NETWORK]
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
const results = await broadcastToTrackers(response.tx as number[], [TOPICS.SLAP, service], trackers);
|
|
102
|
+
|
|
103
|
+
return ok({
|
|
104
|
+
advertised: 'SLAP',
|
|
105
|
+
service,
|
|
106
|
+
domain,
|
|
107
|
+
txid: response.txid,
|
|
108
|
+
broadcasts: results
|
|
109
|
+
});
|
|
110
|
+
} catch (err: any) {
|
|
111
|
+
return fail(`SLAP advertisement failed: ${err.message}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Helper to broadcast BEEF to multiple trackers/overlays.
|
|
117
|
+
*/
|
|
118
|
+
async function broadcastToTrackers(tx: number[], topics: string[], trackers: string[]) {
|
|
119
|
+
const results: Record<string, any> = {};
|
|
120
|
+
const body = new Uint8Array(tx);
|
|
121
|
+
|
|
122
|
+
for (const url of trackers) {
|
|
123
|
+
try {
|
|
124
|
+
const resp = await fetch(`${url.replace(/\/$/, '')}/submit`, {
|
|
125
|
+
method: 'POST',
|
|
126
|
+
headers: {
|
|
127
|
+
'Content-Type': 'application/octet-stream',
|
|
128
|
+
'X-Topics': JSON.stringify(topics)
|
|
129
|
+
},
|
|
130
|
+
body
|
|
131
|
+
});
|
|
132
|
+
results[url] = resp.ok ? 'success' : `error: ${resp.status}`;
|
|
133
|
+
} catch (err: any) {
|
|
134
|
+
results[url] = `failed: ${err.message}`;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return results;
|
|
138
|
+
}
|
|
@@ -97,6 +97,22 @@ export async function cmdIdentity(): Promise<never> {
|
|
|
97
97
|
return ok({ identityKey });
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
/**
|
|
101
|
+
* Status command: show identity and balance.
|
|
102
|
+
*/
|
|
103
|
+
export async function cmdStatus(): Promise<never> {
|
|
104
|
+
const BSVAgentWallet = await getBSVAgentWallet();
|
|
105
|
+
const wallet = await BSVAgentWallet.load({ network: NETWORK, storageDir: WALLET_DIR });
|
|
106
|
+
const identityKey = await wallet.getIdentityKey();
|
|
107
|
+
const total = await wallet.getBalance();
|
|
108
|
+
await wallet.destroy();
|
|
109
|
+
|
|
110
|
+
return ok({
|
|
111
|
+
identity: { identityKey, network: NETWORK },
|
|
112
|
+
balance: { walletBalance: total }
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
100
116
|
/**
|
|
101
117
|
* Address command: show P2PKH receive address.
|
|
102
118
|
*/
|