clawmarket 0.4.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 +142 -0
- package/dist/api-proxy.d.ts +11 -0
- package/dist/api-proxy.d.ts.map +1 -0
- package/dist/api-proxy.js +98 -0
- package/dist/api-proxy.js.map +1 -0
- package/dist/buyer/discovery.d.ts +52 -0
- package/dist/buyer/discovery.d.ts.map +1 -0
- package/dist/buyer/discovery.js +121 -0
- package/dist/buyer/discovery.js.map +1 -0
- package/dist/buyer/index.d.ts +4 -0
- package/dist/buyer/index.d.ts.map +1 -0
- package/dist/buyer/index.js +4 -0
- package/dist/buyer/index.js.map +1 -0
- package/dist/buyer/mode.d.ts +60 -0
- package/dist/buyer/mode.d.ts.map +1 -0
- package/dist/buyer/mode.js +150 -0
- package/dist/buyer/mode.js.map +1 -0
- package/dist/buyer/relay.d.ts +27 -0
- package/dist/buyer/relay.d.ts.map +1 -0
- package/dist/buyer/relay.js +103 -0
- package/dist/buyer/relay.js.map +1 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +252 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +29 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +37 -0
- package/dist/config.js.map +1 -0
- package/dist/crypto/e2ee.d.ts +45 -0
- package/dist/crypto/e2ee.d.ts.map +1 -0
- package/dist/crypto/e2ee.js +87 -0
- package/dist/crypto/e2ee.js.map +1 -0
- package/dist/crypto/index.d.ts +3 -0
- package/dist/crypto/index.d.ts.map +1 -0
- package/dist/crypto/index.js +3 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/crypto/ticket.d.ts +62 -0
- package/dist/crypto/ticket.d.ts.map +1 -0
- package/dist/crypto/ticket.js +123 -0
- package/dist/crypto/ticket.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/local-proxy.d.ts +12 -0
- package/dist/local-proxy.d.ts.map +1 -0
- package/dist/local-proxy.js +593 -0
- package/dist/local-proxy.js.map +1 -0
- package/dist/openclaw-adapter.d.ts +105 -0
- package/dist/openclaw-adapter.d.ts.map +1 -0
- package/dist/openclaw-adapter.js +125 -0
- package/dist/openclaw-adapter.js.map +1 -0
- package/dist/provider.d.ts +116 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +328 -0
- package/dist/provider.js.map +1 -0
- package/dist/seller/index.d.ts +4 -0
- package/dist/seller/index.d.ts.map +1 -0
- package/dist/seller/index.js +4 -0
- package/dist/seller/index.js.map +1 -0
- package/dist/seller/mode.d.ts +62 -0
- package/dist/seller/mode.d.ts.map +1 -0
- package/dist/seller/mode.js +179 -0
- package/dist/seller/mode.js.map +1 -0
- package/dist/seller/registry.d.ts +27 -0
- package/dist/seller/registry.d.ts.map +1 -0
- package/dist/seller/registry.js +95 -0
- package/dist/seller/registry.js.map +1 -0
- package/dist/seller/relay.d.ts +64 -0
- package/dist/seller/relay.d.ts.map +1 -0
- package/dist/seller/relay.js +171 -0
- package/dist/seller/relay.js.map +1 -0
- package/dist/seller-cli.d.ts +26 -0
- package/dist/seller-cli.d.ts.map +1 -0
- package/dist/seller-cli.js +354 -0
- package/dist/seller-cli.js.map +1 -0
- package/dist/seller-daemon.d.ts +7 -0
- package/dist/seller-daemon.d.ts.map +1 -0
- package/dist/seller-daemon.js +349 -0
- package/dist/seller-daemon.js.map +1 -0
- package/dist/types/config.d.ts +529 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +81 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/protocol.d.ts +131 -0
- package/dist/types/protocol.d.ts.map +1 -0
- package/dist/types/protocol.js +2 -0
- package/dist/types/protocol.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenClaw Provider 适配器
|
|
3
|
+
*
|
|
4
|
+
* 让 OpenClaw 可以直接使用 ClawMarket 作为 AI provider
|
|
5
|
+
*/
|
|
6
|
+
interface Message {
|
|
7
|
+
role: 'user' | 'assistant' | 'system';
|
|
8
|
+
content: string;
|
|
9
|
+
}
|
|
10
|
+
interface ChatCompletionRequest {
|
|
11
|
+
model: string;
|
|
12
|
+
messages: Message[];
|
|
13
|
+
stream?: boolean;
|
|
14
|
+
max_tokens?: number;
|
|
15
|
+
temperature?: number;
|
|
16
|
+
}
|
|
17
|
+
interface ChatCompletionResponse {
|
|
18
|
+
id: string;
|
|
19
|
+
object: 'chat.completion';
|
|
20
|
+
created: number;
|
|
21
|
+
model: string;
|
|
22
|
+
choices: Array<{
|
|
23
|
+
index: number;
|
|
24
|
+
message: Message;
|
|
25
|
+
finish_reason: 'stop' | 'length';
|
|
26
|
+
}>;
|
|
27
|
+
usage: {
|
|
28
|
+
prompt_tokens: number;
|
|
29
|
+
completion_tokens: number;
|
|
30
|
+
total_tokens: number;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* OpenClaw Provider 接口实现
|
|
35
|
+
*/
|
|
36
|
+
export declare class ClawMarketOpenClawProvider {
|
|
37
|
+
private provider;
|
|
38
|
+
private initialized;
|
|
39
|
+
constructor(config?: any);
|
|
40
|
+
/**
|
|
41
|
+
* 初始化 provider
|
|
42
|
+
*/
|
|
43
|
+
initialize(): Promise<{
|
|
44
|
+
ready: boolean;
|
|
45
|
+
address?: string;
|
|
46
|
+
balance?: string;
|
|
47
|
+
}>;
|
|
48
|
+
/**
|
|
49
|
+
* 获取可用模型列表
|
|
50
|
+
*/
|
|
51
|
+
listModels(): Promise<string[]>;
|
|
52
|
+
/**
|
|
53
|
+
* OpenAI 兼容的 chat completion 接口
|
|
54
|
+
*/
|
|
55
|
+
createChatCompletion(request: ChatCompletionRequest): Promise<ChatCompletionResponse>;
|
|
56
|
+
/**
|
|
57
|
+
* 获取状态
|
|
58
|
+
*/
|
|
59
|
+
getStatus(): {
|
|
60
|
+
address: string;
|
|
61
|
+
ready: boolean;
|
|
62
|
+
sellers: number;
|
|
63
|
+
channels: number;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* 等待余额充足
|
|
67
|
+
*/
|
|
68
|
+
waitForBalance(): Promise<void>;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* OpenClaw 插件入口点
|
|
72
|
+
*
|
|
73
|
+
* OpenClaw 会调用这个函数来创建 provider
|
|
74
|
+
*/
|
|
75
|
+
export declare function createProvider(config?: any): ClawMarketOpenClawProvider;
|
|
76
|
+
/**
|
|
77
|
+
* 插件元数据
|
|
78
|
+
*/
|
|
79
|
+
export declare const metadata: {
|
|
80
|
+
name: string;
|
|
81
|
+
version: string;
|
|
82
|
+
description: string;
|
|
83
|
+
author: string;
|
|
84
|
+
models: string[];
|
|
85
|
+
configSchema: {
|
|
86
|
+
type: string;
|
|
87
|
+
properties: {
|
|
88
|
+
registryUrl: {
|
|
89
|
+
type: string;
|
|
90
|
+
default: string;
|
|
91
|
+
};
|
|
92
|
+
relayUrl: {
|
|
93
|
+
type: string;
|
|
94
|
+
default: string;
|
|
95
|
+
};
|
|
96
|
+
strategy: {
|
|
97
|
+
type: string;
|
|
98
|
+
enum: string[];
|
|
99
|
+
default: string;
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
export {};
|
|
105
|
+
//# sourceMappingURL=openclaw-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openclaw-adapter.d.ts","sourceRoot":"","sources":["../src/openclaw-adapter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,UAAU,OAAO;IACf,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,qBAAqB;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,UAAU,sBAAsB;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,iBAAiB,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,KAAK,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,OAAO,CAAC;QACjB,aAAa,EAAE,MAAM,GAAG,QAAQ,CAAC;KAClC,CAAC,CAAC;IACH,KAAK,EAAE;QACL,aAAa,EAAE,MAAM,CAAC;QACtB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAED;;GAEG;AACH,qBAAa,0BAA0B;IACrC,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,WAAW,CAAS;gBAEhB,MAAM,CAAC,EAAE,GAAG;IAIxB;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAMnF;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAcrC;;OAEG;IACG,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAsC3F;;OAEG;IACH,SAAS;;;;;;IAIT;;OAEG;IACG,cAAc;CAGrB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,CAAC,EAAE,GAAG,8BAE1C;AAED;;GAEG;AACH,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;CA2BpB,CAAC"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenClaw Provider 适配器
|
|
3
|
+
*
|
|
4
|
+
* 让 OpenClaw 可以直接使用 ClawMarket 作为 AI provider
|
|
5
|
+
*/
|
|
6
|
+
import { ClawMarketProvider } from './provider.js';
|
|
7
|
+
/**
|
|
8
|
+
* OpenClaw Provider 接口实现
|
|
9
|
+
*/
|
|
10
|
+
export class ClawMarketOpenClawProvider {
|
|
11
|
+
provider;
|
|
12
|
+
initialized = false;
|
|
13
|
+
constructor(config) {
|
|
14
|
+
this.provider = new ClawMarketProvider(config);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 初始化 provider
|
|
18
|
+
*/
|
|
19
|
+
async initialize() {
|
|
20
|
+
const status = await this.provider.initialize();
|
|
21
|
+
this.initialized = status.ready;
|
|
22
|
+
return status;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 获取可用模型列表
|
|
26
|
+
*/
|
|
27
|
+
async listModels() {
|
|
28
|
+
await this.provider.refreshSellers();
|
|
29
|
+
const status = this.provider.getStatus();
|
|
30
|
+
// 从卖家列表收集所有可用模型
|
|
31
|
+
const models = new Set();
|
|
32
|
+
// 这里简化处理,实际应该从 sellers 获取
|
|
33
|
+
models.add('claude-opus-4');
|
|
34
|
+
models.add('claude-sonnet-4');
|
|
35
|
+
models.add('gpt-4');
|
|
36
|
+
return Array.from(models);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* OpenAI 兼容的 chat completion 接口
|
|
40
|
+
*/
|
|
41
|
+
async createChatCompletion(request) {
|
|
42
|
+
if (!this.initialized) {
|
|
43
|
+
const status = await this.initialize();
|
|
44
|
+
if (!status.ready) {
|
|
45
|
+
throw new Error(`ClawMarket 未就绪,请先充值 USDC 到: ${status.address}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const response = await this.provider.chat({
|
|
49
|
+
model: request.model,
|
|
50
|
+
messages: request.messages
|
|
51
|
+
});
|
|
52
|
+
// 估算 token 数
|
|
53
|
+
const promptTokens = request.messages.reduce((sum, m) => sum + Math.ceil(m.content.length / 4), 0);
|
|
54
|
+
const completionTokens = Math.ceil(response.length / 4);
|
|
55
|
+
return {
|
|
56
|
+
id: `clawmarket-${Date.now()}`,
|
|
57
|
+
object: 'chat.completion',
|
|
58
|
+
created: Math.floor(Date.now() / 1000),
|
|
59
|
+
model: request.model,
|
|
60
|
+
choices: [{
|
|
61
|
+
index: 0,
|
|
62
|
+
message: {
|
|
63
|
+
role: 'assistant',
|
|
64
|
+
content: response
|
|
65
|
+
},
|
|
66
|
+
finish_reason: 'stop'
|
|
67
|
+
}],
|
|
68
|
+
usage: {
|
|
69
|
+
prompt_tokens: promptTokens,
|
|
70
|
+
completion_tokens: completionTokens,
|
|
71
|
+
total_tokens: promptTokens + completionTokens
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* 获取状态
|
|
77
|
+
*/
|
|
78
|
+
getStatus() {
|
|
79
|
+
return this.provider.getStatus();
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* 等待余额充足
|
|
83
|
+
*/
|
|
84
|
+
async waitForBalance() {
|
|
85
|
+
return this.provider.waitForBalance();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* OpenClaw 插件入口点
|
|
90
|
+
*
|
|
91
|
+
* OpenClaw 会调用这个函数来创建 provider
|
|
92
|
+
*/
|
|
93
|
+
export function createProvider(config) {
|
|
94
|
+
return new ClawMarketOpenClawProvider(config);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* 插件元数据
|
|
98
|
+
*/
|
|
99
|
+
export const metadata = {
|
|
100
|
+
name: 'clawmarket',
|
|
101
|
+
version: '0.1.0',
|
|
102
|
+
description: 'ClawMarket - 去中心化 AI 算力市场',
|
|
103
|
+
author: 'ClawMarket Team',
|
|
104
|
+
// 支持的模型
|
|
105
|
+
models: [
|
|
106
|
+
'claude-opus-4',
|
|
107
|
+
'claude-sonnet-4',
|
|
108
|
+
'gpt-4',
|
|
109
|
+
'gpt-4-turbo'
|
|
110
|
+
],
|
|
111
|
+
// 配置 schema
|
|
112
|
+
configSchema: {
|
|
113
|
+
type: 'object',
|
|
114
|
+
properties: {
|
|
115
|
+
registryUrl: { type: 'string', default: 'http://shenjige.xyz:9080' },
|
|
116
|
+
relayUrl: { type: 'string', default: 'http://shenjige.xyz:9081' },
|
|
117
|
+
strategy: {
|
|
118
|
+
type: 'string',
|
|
119
|
+
enum: ['lowest_price', 'lowest_latency', 'highest_reputation'],
|
|
120
|
+
default: 'lowest_price'
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
//# sourceMappingURL=openclaw-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openclaw-adapter.js","sourceRoot":"","sources":["../src/openclaw-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ClawMarket OpenClaw Provider
|
|
3
|
+
*
|
|
4
|
+
* 自动化流程:
|
|
5
|
+
* 1. 首次启动自动生成钱包
|
|
6
|
+
* 2. 显示充值地址
|
|
7
|
+
* 3. 检测到 USDC 后自动激活
|
|
8
|
+
* 4. 自动发现卖家、开通道、签票据
|
|
9
|
+
*/
|
|
10
|
+
declare const DEFAULT_CONFIG: {
|
|
11
|
+
registryUrl: string;
|
|
12
|
+
relayUrl: string;
|
|
13
|
+
relayWs: string;
|
|
14
|
+
rpcUrl: string;
|
|
15
|
+
channelContract: `0x${string}`;
|
|
16
|
+
usdcContract: `0x${string}`;
|
|
17
|
+
chainId: number;
|
|
18
|
+
minBalance: bigint;
|
|
19
|
+
channelDeposit: bigint;
|
|
20
|
+
};
|
|
21
|
+
interface SellerInfo {
|
|
22
|
+
id: string;
|
|
23
|
+
public_key: string;
|
|
24
|
+
endpoint: string;
|
|
25
|
+
models: Array<{
|
|
26
|
+
model: string;
|
|
27
|
+
input_per_1m: number;
|
|
28
|
+
output_per_1m: number;
|
|
29
|
+
}>;
|
|
30
|
+
reputation: {
|
|
31
|
+
score: number;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
interface Channel {
|
|
35
|
+
id: `0x${string}`;
|
|
36
|
+
seller: string;
|
|
37
|
+
sellerAddress: `0x${string}`;
|
|
38
|
+
deposit: bigint;
|
|
39
|
+
spent: bigint;
|
|
40
|
+
nonce: bigint;
|
|
41
|
+
}
|
|
42
|
+
export declare class ClawMarketProvider {
|
|
43
|
+
private config;
|
|
44
|
+
private walletPath;
|
|
45
|
+
private wallet;
|
|
46
|
+
private publicClient;
|
|
47
|
+
private walletClient;
|
|
48
|
+
private channels;
|
|
49
|
+
private sellers;
|
|
50
|
+
private isReady;
|
|
51
|
+
private onStatusChange?;
|
|
52
|
+
constructor(config?: Partial<typeof DEFAULT_CONFIG>);
|
|
53
|
+
/**
|
|
54
|
+
* 初始化 Provider
|
|
55
|
+
*/
|
|
56
|
+
initialize(): Promise<{
|
|
57
|
+
address: string;
|
|
58
|
+
balance: string;
|
|
59
|
+
ready: boolean;
|
|
60
|
+
}>;
|
|
61
|
+
/**
|
|
62
|
+
* 加载或创建钱包
|
|
63
|
+
*/
|
|
64
|
+
private loadOrCreateWallet;
|
|
65
|
+
/**
|
|
66
|
+
* 获取 USDC 余额
|
|
67
|
+
*/
|
|
68
|
+
getBalance(): Promise<bigint>;
|
|
69
|
+
/**
|
|
70
|
+
* 刷新卖家列表
|
|
71
|
+
*/
|
|
72
|
+
refreshSellers(): Promise<void>;
|
|
73
|
+
/**
|
|
74
|
+
* 选择最优卖家
|
|
75
|
+
*/
|
|
76
|
+
selectSeller(model: string): SellerInfo | null;
|
|
77
|
+
/**
|
|
78
|
+
* 确保与卖家有通道
|
|
79
|
+
*/
|
|
80
|
+
ensureChannel(seller: SellerInfo): Promise<Channel>;
|
|
81
|
+
/**
|
|
82
|
+
* 签名票据
|
|
83
|
+
*/
|
|
84
|
+
signTicket(channel: Channel, amount: bigint): Promise<string>;
|
|
85
|
+
/**
|
|
86
|
+
* 发送聊天请求 (OpenClaw Provider 接口)
|
|
87
|
+
*/
|
|
88
|
+
chat(params: {
|
|
89
|
+
model: string;
|
|
90
|
+
messages: Array<{
|
|
91
|
+
role: string;
|
|
92
|
+
content: string;
|
|
93
|
+
}>;
|
|
94
|
+
}): Promise<string>;
|
|
95
|
+
/**
|
|
96
|
+
* 获取状态
|
|
97
|
+
*/
|
|
98
|
+
getStatus(): {
|
|
99
|
+
address: string;
|
|
100
|
+
ready: boolean;
|
|
101
|
+
sellers: number;
|
|
102
|
+
channels: number;
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* 等待余额充足
|
|
106
|
+
*/
|
|
107
|
+
waitForBalance(intervalMs?: number): Promise<void>;
|
|
108
|
+
}
|
|
109
|
+
export declare const clawmarket: ClawMarketProvider;
|
|
110
|
+
export declare function initClawMarket(config?: Partial<typeof DEFAULT_CONFIG>): Promise<{
|
|
111
|
+
address: string;
|
|
112
|
+
balance: string;
|
|
113
|
+
ready: boolean;
|
|
114
|
+
}>;
|
|
115
|
+
export {};
|
|
116
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAYH,QAAA,MAAM,cAAc;;;;;qBAK+C,KAAK,MAAM,EAAE;kBAChB,KAAK,MAAM,EAAE;;;;CAI5E,CAAC;AAwBF,UAAU,UAAU;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,KAAK,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,YAAY,EAAE,MAAM,CAAC;QACrB,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC,CAAC;IACH,UAAU,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/B;AAED,UAAU,OAAO;IACf,EAAE,EAAE,KAAK,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,KAAK,MAAM,EAAE,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,QAAQ,CAAmC;IACnD,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,cAAc,CAAC,CAA2B;gBAEtC,MAAM,CAAC,EAAE,OAAO,CAAC,OAAO,cAAc,CAAC;IAUnD;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;IAiDjF;;OAEG;YACW,kBAAkB;IA+BhC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IASnC;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAWrC;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAiB9C;;OAEG;IACG,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC;IA6CzD;;OAEG;IACG,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA6BnE;;OAEG;IACG,IAAI,CAAC,MAAM,EAAE;QACjB,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KACpD,GAAG,OAAO,CAAC,MAAM,CAAC;IA0DnB;;OAEG;IACH,SAAS,IAAI;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE;IASnF;;OAEG;IACG,cAAc,CAAC,UAAU,SAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;CAaxD;AAGD,eAAO,MAAM,UAAU,oBAA2B,CAAC;AAGnD,wBAAsB,cAAc,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,OAAO,cAAc,CAAC;aAnTnC,MAAM;aAAW,MAAM;WAAS,OAAO;GAsT/E"}
|
package/dist/provider.js
ADDED
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ClawMarket OpenClaw Provider
|
|
3
|
+
*
|
|
4
|
+
* 自动化流程:
|
|
5
|
+
* 1. 首次启动自动生成钱包
|
|
6
|
+
* 2. 显示充值地址
|
|
7
|
+
* 3. 检测到 USDC 后自动激活
|
|
8
|
+
* 4. 自动发现卖家、开通道、签票据
|
|
9
|
+
*/
|
|
10
|
+
import { createWalletClient, createPublicClient, http, formatUnits } from 'viem';
|
|
11
|
+
import { privateKeyToAccount, generatePrivateKey } from 'viem/accounts';
|
|
12
|
+
import { baseSepolia } from 'viem/chains';
|
|
13
|
+
import * as fs from 'fs';
|
|
14
|
+
import * as path from 'path';
|
|
15
|
+
import * as os from 'os';
|
|
16
|
+
import { generateKeyPair, encrypt, decrypt } from './crypto/e2ee.js';
|
|
17
|
+
// 默认配置
|
|
18
|
+
const DEFAULT_CONFIG = {
|
|
19
|
+
registryUrl: 'http://shenjige.xyz:9080',
|
|
20
|
+
relayUrl: 'http://shenjige.xyz:9081',
|
|
21
|
+
relayWs: 'ws://shenjige.xyz:9081',
|
|
22
|
+
rpcUrl: 'https://sepolia.base.org',
|
|
23
|
+
channelContract: '0x1577e78D8a446edF10244A80bEf990751e80E495',
|
|
24
|
+
usdcContract: '0xcF0819eb156D6c6c1c5d9A515E351D2D1aefff7D',
|
|
25
|
+
chainId: 84532,
|
|
26
|
+
minBalance: 1000000n, // 1 USDC minimum to start
|
|
27
|
+
channelDeposit: 10000000n, // 10 USDC per channel
|
|
28
|
+
};
|
|
29
|
+
// ABIs
|
|
30
|
+
const USDC_ABI = [
|
|
31
|
+
{ name: 'balanceOf', type: 'function', inputs: [{ name: 'account', type: 'address' }], outputs: [{ type: 'uint256' }], stateMutability: 'view' },
|
|
32
|
+
{ name: 'approve', type: 'function', inputs: [{ name: 'spender', type: 'address' }, { name: 'amount', type: 'uint256' }], outputs: [{ type: 'bool' }] },
|
|
33
|
+
];
|
|
34
|
+
const CHANNEL_ABI = [
|
|
35
|
+
{ name: 'openChannel', type: 'function', inputs: [{ name: 'seller', type: 'address' }, { name: 'amount', type: 'uint256' }, { name: 'duration', type: 'uint256' }], outputs: [{ type: 'bytes32' }] },
|
|
36
|
+
{ name: 'channels', type: 'function', inputs: [{ name: 'channelId', type: 'bytes32' }], outputs: [{ name: 'buyer', type: 'address' }, { name: 'seller', type: 'address' }, { name: 'deposit', type: 'uint256' }, { name: 'settledAmount', type: 'uint256' }, { name: 'expiresAt', type: 'uint256' }, { name: 'closingRequestedAt', type: 'uint256' }, { name: 'isActive', type: 'bool' }], stateMutability: 'view' },
|
|
37
|
+
{ name: 'sellers', type: 'function', inputs: [{ name: 'seller', type: 'address' }], outputs: [{ name: 'stakedAmount', type: 'uint256' }, { name: 'slashedAmount', type: 'uint256' }, { name: 'isActive', type: 'bool' }], stateMutability: 'view' },
|
|
38
|
+
];
|
|
39
|
+
export class ClawMarketProvider {
|
|
40
|
+
config;
|
|
41
|
+
walletPath;
|
|
42
|
+
wallet = null;
|
|
43
|
+
publicClient;
|
|
44
|
+
walletClient = null;
|
|
45
|
+
channels = new Map();
|
|
46
|
+
sellers = [];
|
|
47
|
+
isReady = false;
|
|
48
|
+
onStatusChange;
|
|
49
|
+
constructor(config) {
|
|
50
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
51
|
+
this.walletPath = path.join(os.homedir(), '.clawmarket', 'wallet.json');
|
|
52
|
+
this.publicClient = createPublicClient({
|
|
53
|
+
chain: baseSepolia,
|
|
54
|
+
transport: http(this.config.rpcUrl)
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* 初始化 Provider
|
|
59
|
+
*/
|
|
60
|
+
async initialize() {
|
|
61
|
+
// 1. 加载或创建钱包
|
|
62
|
+
await this.loadOrCreateWallet();
|
|
63
|
+
// 2. 检查余额
|
|
64
|
+
const balance = await this.getBalance();
|
|
65
|
+
const balanceNum = parseFloat(formatUnits(balance, 6));
|
|
66
|
+
// 3. 判断是否就绪
|
|
67
|
+
this.isReady = balance >= this.config.minBalance;
|
|
68
|
+
if (!this.isReady) {
|
|
69
|
+
console.log('\n╔════════════════════════════════════════════════════════════╗');
|
|
70
|
+
console.log('║ ClawMarket - 需要充值 ║');
|
|
71
|
+
console.log('╠════════════════════════════════════════════════════════════╣');
|
|
72
|
+
console.log(`║ 钱包地址: ${this.wallet.address} ║`);
|
|
73
|
+
console.log(`║ 当前余额: ${balanceNum.toFixed(2)} USDC ║`);
|
|
74
|
+
console.log(`║ 最低要求: ${formatUnits(this.config.minBalance, 6)} USDC ║`);
|
|
75
|
+
console.log('╠════════════════════════════════════════════════════════════╣');
|
|
76
|
+
console.log('║ 请充值 USDC (Base Sepolia) 到上述地址 ║');
|
|
77
|
+
console.log('║ 充值后插件将自动激活 ║');
|
|
78
|
+
console.log('╚════════════════════════════════════════════════════════════╝\n');
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
console.log('\n╔════════════════════════════════════════════════════════════╗');
|
|
82
|
+
console.log('║ ClawMarket - 已就绪 ║');
|
|
83
|
+
console.log('╠════════════════════════════════════════════════════════════╣');
|
|
84
|
+
console.log(`║ 钱包地址: ${this.wallet.address} ║`);
|
|
85
|
+
console.log(`║ 当前余额: ${balanceNum.toFixed(2)} USDC ║`);
|
|
86
|
+
console.log('╚════════════════════════════════════════════════════════════╝\n');
|
|
87
|
+
// 初始化钱包客户端
|
|
88
|
+
const account = privateKeyToAccount(this.wallet.privateKey);
|
|
89
|
+
this.walletClient = createWalletClient({
|
|
90
|
+
account,
|
|
91
|
+
chain: baseSepolia,
|
|
92
|
+
transport: http(this.config.rpcUrl)
|
|
93
|
+
});
|
|
94
|
+
// 加载卖家列表
|
|
95
|
+
await this.refreshSellers();
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
address: this.wallet.address,
|
|
99
|
+
balance: balanceNum.toFixed(2),
|
|
100
|
+
ready: this.isReady
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* 加载或创建钱包
|
|
105
|
+
*/
|
|
106
|
+
async loadOrCreateWallet() {
|
|
107
|
+
const dir = path.dirname(this.walletPath);
|
|
108
|
+
if (!fs.existsSync(dir)) {
|
|
109
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
110
|
+
}
|
|
111
|
+
if (fs.existsSync(this.walletPath)) {
|
|
112
|
+
const data = fs.readFileSync(this.walletPath, 'utf-8');
|
|
113
|
+
this.wallet = JSON.parse(data);
|
|
114
|
+
console.log('[ClawMarket] 已加载钱包:', this.wallet.address);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
// 生成新钱包
|
|
118
|
+
const privateKey = generatePrivateKey();
|
|
119
|
+
const account = privateKeyToAccount(privateKey);
|
|
120
|
+
const encKeys = generateKeyPair();
|
|
121
|
+
this.wallet = {
|
|
122
|
+
address: account.address,
|
|
123
|
+
privateKey: privateKey,
|
|
124
|
+
encryptionKeys: {
|
|
125
|
+
publicKey: Buffer.from(encKeys.publicKey).toString('hex'),
|
|
126
|
+
secretKey: Buffer.from(encKeys.secretKey).toString('hex')
|
|
127
|
+
},
|
|
128
|
+
createdAt: new Date().toISOString()
|
|
129
|
+
};
|
|
130
|
+
fs.writeFileSync(this.walletPath, JSON.stringify(this.wallet, null, 2), { mode: 0o600 });
|
|
131
|
+
console.log('[ClawMarket] 已创建新钱包:', this.wallet.address);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* 获取 USDC 余额
|
|
136
|
+
*/
|
|
137
|
+
async getBalance() {
|
|
138
|
+
return await this.publicClient.readContract({
|
|
139
|
+
address: this.config.usdcContract,
|
|
140
|
+
abi: USDC_ABI,
|
|
141
|
+
functionName: 'balanceOf',
|
|
142
|
+
args: [this.wallet.address]
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* 刷新卖家列表
|
|
147
|
+
*/
|
|
148
|
+
async refreshSellers() {
|
|
149
|
+
try {
|
|
150
|
+
const res = await fetch(`${this.config.registryUrl}/v1/sellers?status=active`);
|
|
151
|
+
const data = await res.json();
|
|
152
|
+
this.sellers = data.sellers || [];
|
|
153
|
+
console.log(`[ClawMarket] 发现 ${this.sellers.length} 个在线卖家`);
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
console.error('[ClawMarket] 获取卖家列表失败:', err);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* 选择最优卖家
|
|
161
|
+
*/
|
|
162
|
+
selectSeller(model) {
|
|
163
|
+
const candidates = this.sellers.filter(s => s.models.some(m => m.model === model));
|
|
164
|
+
if (candidates.length === 0)
|
|
165
|
+
return null;
|
|
166
|
+
// 按价格排序
|
|
167
|
+
candidates.sort((a, b) => {
|
|
168
|
+
const aModel = a.models.find(m => m.model === model);
|
|
169
|
+
const bModel = b.models.find(m => m.model === model);
|
|
170
|
+
return (aModel.input_per_1m + aModel.output_per_1m) - (bModel.input_per_1m + bModel.output_per_1m);
|
|
171
|
+
});
|
|
172
|
+
return candidates[0] || null;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* 确保与卖家有通道
|
|
176
|
+
*/
|
|
177
|
+
async ensureChannel(seller) {
|
|
178
|
+
const existing = this.channels.get(seller.id);
|
|
179
|
+
if (existing)
|
|
180
|
+
return existing;
|
|
181
|
+
console.log('[ClawMarket] 开通道到卖家:', seller.id.slice(0, 8) + '...');
|
|
182
|
+
// 获取卖家链上地址 (简化:用公钥前20字节)
|
|
183
|
+
const sellerAddress = ('0x' + seller.public_key.slice(2, 42));
|
|
184
|
+
// Approve USDC
|
|
185
|
+
const approveHash = await this.walletClient.writeContract({
|
|
186
|
+
address: this.config.usdcContract,
|
|
187
|
+
abi: USDC_ABI,
|
|
188
|
+
functionName: 'approve',
|
|
189
|
+
args: [this.config.channelContract, this.config.channelDeposit]
|
|
190
|
+
});
|
|
191
|
+
await this.publicClient.waitForTransactionReceipt({ hash: approveHash });
|
|
192
|
+
// Open channel
|
|
193
|
+
const duration = BigInt(7 * 24 * 60 * 60); // 7 days
|
|
194
|
+
const openHash = await this.walletClient.writeContract({
|
|
195
|
+
address: this.config.channelContract,
|
|
196
|
+
abi: CHANNEL_ABI,
|
|
197
|
+
functionName: 'openChannel',
|
|
198
|
+
args: [sellerAddress, this.config.channelDeposit, duration]
|
|
199
|
+
});
|
|
200
|
+
const receipt = await this.publicClient.waitForTransactionReceipt({ hash: openHash });
|
|
201
|
+
const channelId = receipt.logs[1]?.topics[1];
|
|
202
|
+
const channel = {
|
|
203
|
+
id: channelId,
|
|
204
|
+
seller: seller.id,
|
|
205
|
+
sellerAddress,
|
|
206
|
+
deposit: this.config.channelDeposit,
|
|
207
|
+
spent: 0n,
|
|
208
|
+
nonce: 0n
|
|
209
|
+
};
|
|
210
|
+
this.channels.set(seller.id, channel);
|
|
211
|
+
console.log('[ClawMarket] 通道已开启:', channelId.slice(0, 16) + '...');
|
|
212
|
+
return channel;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* 签名票据
|
|
216
|
+
*/
|
|
217
|
+
async signTicket(channel, amount) {
|
|
218
|
+
channel.nonce += 1n;
|
|
219
|
+
channel.spent += amount;
|
|
220
|
+
const signature = await this.walletClient.signTypedData({
|
|
221
|
+
domain: {
|
|
222
|
+
name: 'ClawChannel',
|
|
223
|
+
version: '1',
|
|
224
|
+
chainId: this.config.chainId,
|
|
225
|
+
verifyingContract: this.config.channelContract
|
|
226
|
+
},
|
|
227
|
+
types: {
|
|
228
|
+
Ticket: [
|
|
229
|
+
{ name: 'channelId', type: 'bytes32' },
|
|
230
|
+
{ name: 'amount', type: 'uint256' },
|
|
231
|
+
{ name: 'nonce', type: 'uint256' }
|
|
232
|
+
]
|
|
233
|
+
},
|
|
234
|
+
primaryType: 'Ticket',
|
|
235
|
+
message: {
|
|
236
|
+
channelId: channel.id,
|
|
237
|
+
amount: channel.spent,
|
|
238
|
+
nonce: channel.nonce
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
return signature;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* 发送聊天请求 (OpenClaw Provider 接口)
|
|
245
|
+
*/
|
|
246
|
+
async chat(params) {
|
|
247
|
+
if (!this.isReady) {
|
|
248
|
+
throw new Error('ClawMarket 未就绪,请先充值 USDC');
|
|
249
|
+
}
|
|
250
|
+
// 1. 选择卖家
|
|
251
|
+
const seller = this.selectSeller(params.model);
|
|
252
|
+
if (!seller) {
|
|
253
|
+
throw new Error(`没有找到提供 ${params.model} 的卖家`);
|
|
254
|
+
}
|
|
255
|
+
// 2. 确保通道
|
|
256
|
+
const channel = await this.ensureChannel(seller);
|
|
257
|
+
// 3. 估算费用并签票据
|
|
258
|
+
const estimatedTokens = params.messages.reduce((sum, m) => sum + m.content.length / 4, 0);
|
|
259
|
+
const modelPricing = seller.models.find(m => m.model === params.model);
|
|
260
|
+
const estimatedCost = BigInt(Math.ceil(estimatedTokens * (modelPricing.input_per_1m + modelPricing.output_per_1m) / 1000));
|
|
261
|
+
const ticket = await this.signTicket(channel, estimatedCost);
|
|
262
|
+
// 4. 加密请求
|
|
263
|
+
const sellerPubKey = new Uint8Array(Buffer.from(seller.public_key, 'hex'));
|
|
264
|
+
const mySecretKey = new Uint8Array(Buffer.from(this.wallet.encryptionKeys.secretKey, 'hex'));
|
|
265
|
+
const payload = JSON.stringify({
|
|
266
|
+
model: params.model,
|
|
267
|
+
messages: params.messages,
|
|
268
|
+
ticket: {
|
|
269
|
+
channelId: channel.id,
|
|
270
|
+
amount: channel.spent.toString(),
|
|
271
|
+
nonce: channel.nonce.toString(),
|
|
272
|
+
signature: ticket
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
const encrypted = await encrypt(payload, mySecretKey, sellerPubKey);
|
|
276
|
+
// 5. 发送到 Relay
|
|
277
|
+
const res = await fetch(`${this.config.relayUrl}/relay/forward`, {
|
|
278
|
+
method: 'POST',
|
|
279
|
+
headers: { 'Content-Type': 'application/json' },
|
|
280
|
+
body: JSON.stringify({
|
|
281
|
+
seller_id: seller.id,
|
|
282
|
+
payload: encrypted,
|
|
283
|
+
buyer_public_key: this.wallet.encryptionKeys.publicKey
|
|
284
|
+
})
|
|
285
|
+
});
|
|
286
|
+
const result = await res.json();
|
|
287
|
+
if (!result.success) {
|
|
288
|
+
throw new Error('请求失败: ' + result.error);
|
|
289
|
+
}
|
|
290
|
+
// 6. 解密响应
|
|
291
|
+
const decrypted = await decrypt(result.payload, mySecretKey, sellerPubKey);
|
|
292
|
+
return decrypted;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* 获取状态
|
|
296
|
+
*/
|
|
297
|
+
getStatus() {
|
|
298
|
+
return {
|
|
299
|
+
address: this.wallet?.address || '',
|
|
300
|
+
ready: this.isReady,
|
|
301
|
+
sellers: this.sellers.length,
|
|
302
|
+
channels: this.channels.size
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* 等待余额充足
|
|
307
|
+
*/
|
|
308
|
+
async waitForBalance(intervalMs = 10000) {
|
|
309
|
+
console.log('[ClawMarket] 等待充值...');
|
|
310
|
+
while (true) {
|
|
311
|
+
const balance = await this.getBalance();
|
|
312
|
+
if (balance >= this.config.minBalance) {
|
|
313
|
+
console.log('[ClawMarket] 检测到充值,余额:', formatUnits(balance, 6), 'USDC');
|
|
314
|
+
await this.initialize();
|
|
315
|
+
break;
|
|
316
|
+
}
|
|
317
|
+
await new Promise(r => setTimeout(r, intervalMs));
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
// 导出默认实例
|
|
322
|
+
export const clawmarket = new ClawMarketProvider();
|
|
323
|
+
// 导出便捷函数
|
|
324
|
+
export async function initClawMarket(config) {
|
|
325
|
+
const provider = new ClawMarketProvider(config);
|
|
326
|
+
return await provider.initialize();
|
|
327
|
+
}
|
|
328
|
+
//# sourceMappingURL=provider.js.map
|