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.
Files changed (94) hide show
  1. package/README.md +142 -0
  2. package/dist/api-proxy.d.ts +11 -0
  3. package/dist/api-proxy.d.ts.map +1 -0
  4. package/dist/api-proxy.js +98 -0
  5. package/dist/api-proxy.js.map +1 -0
  6. package/dist/buyer/discovery.d.ts +52 -0
  7. package/dist/buyer/discovery.d.ts.map +1 -0
  8. package/dist/buyer/discovery.js +121 -0
  9. package/dist/buyer/discovery.js.map +1 -0
  10. package/dist/buyer/index.d.ts +4 -0
  11. package/dist/buyer/index.d.ts.map +1 -0
  12. package/dist/buyer/index.js +4 -0
  13. package/dist/buyer/index.js.map +1 -0
  14. package/dist/buyer/mode.d.ts +60 -0
  15. package/dist/buyer/mode.d.ts.map +1 -0
  16. package/dist/buyer/mode.js +150 -0
  17. package/dist/buyer/mode.js.map +1 -0
  18. package/dist/buyer/relay.d.ts +27 -0
  19. package/dist/buyer/relay.d.ts.map +1 -0
  20. package/dist/buyer/relay.js +103 -0
  21. package/dist/buyer/relay.js.map +1 -0
  22. package/dist/cli.d.ts +11 -0
  23. package/dist/cli.d.ts.map +1 -0
  24. package/dist/cli.js +252 -0
  25. package/dist/cli.js.map +1 -0
  26. package/dist/config.d.ts +29 -0
  27. package/dist/config.d.ts.map +1 -0
  28. package/dist/config.js +37 -0
  29. package/dist/config.js.map +1 -0
  30. package/dist/crypto/e2ee.d.ts +45 -0
  31. package/dist/crypto/e2ee.d.ts.map +1 -0
  32. package/dist/crypto/e2ee.js +87 -0
  33. package/dist/crypto/e2ee.js.map +1 -0
  34. package/dist/crypto/index.d.ts +3 -0
  35. package/dist/crypto/index.d.ts.map +1 -0
  36. package/dist/crypto/index.js +3 -0
  37. package/dist/crypto/index.js.map +1 -0
  38. package/dist/crypto/ticket.d.ts +62 -0
  39. package/dist/crypto/ticket.d.ts.map +1 -0
  40. package/dist/crypto/ticket.js +123 -0
  41. package/dist/crypto/ticket.js.map +1 -0
  42. package/dist/index.d.ts +11 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +13 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/local-proxy.d.ts +12 -0
  47. package/dist/local-proxy.d.ts.map +1 -0
  48. package/dist/local-proxy.js +593 -0
  49. package/dist/local-proxy.js.map +1 -0
  50. package/dist/openclaw-adapter.d.ts +105 -0
  51. package/dist/openclaw-adapter.d.ts.map +1 -0
  52. package/dist/openclaw-adapter.js +125 -0
  53. package/dist/openclaw-adapter.js.map +1 -0
  54. package/dist/provider.d.ts +116 -0
  55. package/dist/provider.d.ts.map +1 -0
  56. package/dist/provider.js +328 -0
  57. package/dist/provider.js.map +1 -0
  58. package/dist/seller/index.d.ts +4 -0
  59. package/dist/seller/index.d.ts.map +1 -0
  60. package/dist/seller/index.js +4 -0
  61. package/dist/seller/index.js.map +1 -0
  62. package/dist/seller/mode.d.ts +62 -0
  63. package/dist/seller/mode.d.ts.map +1 -0
  64. package/dist/seller/mode.js +179 -0
  65. package/dist/seller/mode.js.map +1 -0
  66. package/dist/seller/registry.d.ts +27 -0
  67. package/dist/seller/registry.d.ts.map +1 -0
  68. package/dist/seller/registry.js +95 -0
  69. package/dist/seller/registry.js.map +1 -0
  70. package/dist/seller/relay.d.ts +64 -0
  71. package/dist/seller/relay.d.ts.map +1 -0
  72. package/dist/seller/relay.js +171 -0
  73. package/dist/seller/relay.js.map +1 -0
  74. package/dist/seller-cli.d.ts +26 -0
  75. package/dist/seller-cli.d.ts.map +1 -0
  76. package/dist/seller-cli.js +354 -0
  77. package/dist/seller-cli.js.map +1 -0
  78. package/dist/seller-daemon.d.ts +7 -0
  79. package/dist/seller-daemon.d.ts.map +1 -0
  80. package/dist/seller-daemon.js +349 -0
  81. package/dist/seller-daemon.js.map +1 -0
  82. package/dist/types/config.d.ts +529 -0
  83. package/dist/types/config.d.ts.map +1 -0
  84. package/dist/types/config.js +81 -0
  85. package/dist/types/config.js.map +1 -0
  86. package/dist/types/index.d.ts +3 -0
  87. package/dist/types/index.d.ts.map +1 -0
  88. package/dist/types/index.js +3 -0
  89. package/dist/types/index.js.map +1 -0
  90. package/dist/types/protocol.d.ts +131 -0
  91. package/dist/types/protocol.d.ts.map +1 -0
  92. package/dist/types/protocol.js +2 -0
  93. package/dist/types/protocol.js.map +1 -0
  94. 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"}
@@ -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