@clawlogic/sdk 0.0.2 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +26 -2
  2. package/dist/bridge.d.ts +84 -0
  3. package/dist/bridge.d.ts.map +1 -0
  4. package/dist/bridge.js +99 -0
  5. package/dist/bridge.js.map +1 -0
  6. package/dist/cli/args.d.ts +9 -0
  7. package/dist/cli/args.d.ts.map +1 -0
  8. package/dist/cli/args.js +47 -0
  9. package/dist/cli/args.js.map +1 -0
  10. package/dist/cli/constants.d.ts +12 -0
  11. package/dist/cli/constants.d.ts.map +1 -0
  12. package/dist/cli/constants.js +13 -0
  13. package/dist/cli/constants.js.map +1 -0
  14. package/dist/cli/index.d.ts +3 -0
  15. package/dist/cli/index.d.ts.map +1 -0
  16. package/dist/cli/index.js +531 -0
  17. package/dist/cli/index.js.map +1 -0
  18. package/dist/cli/output.d.ts +5 -0
  19. package/dist/cli/output.d.ts.map +1 -0
  20. package/dist/cli/output.js +23 -0
  21. package/dist/cli/output.js.map +1 -0
  22. package/dist/cli/runtime.d.ts +25 -0
  23. package/dist/cli/runtime.d.ts.map +1 -0
  24. package/dist/cli/runtime.js +104 -0
  25. package/dist/cli/runtime.js.map +1 -0
  26. package/dist/client.d.ts +19 -2
  27. package/dist/client.d.ts.map +1 -1
  28. package/dist/client.js +56 -2
  29. package/dist/client.js.map +1 -1
  30. package/dist/identity.d.ts +9 -1
  31. package/dist/identity.d.ts.map +1 -1
  32. package/dist/identity.js +60 -9
  33. package/dist/identity.js.map +1 -1
  34. package/dist/index.d.ts +2 -0
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +1 -0
  37. package/dist/index.js.map +1 -1
  38. package/package.json +6 -3
  39. package/src/abis/AgentRegistry.json +1 -1
  40. package/src/abis/ENSAgentHelper.json +1 -1
  41. package/src/abis/OutcomeToken.json +1 -1
  42. package/src/abis/PredictionMarketHook.json +1 -1
  43. package/src/bridge.ts +193 -0
  44. package/src/cli/args.ts +66 -0
  45. package/src/cli/constants.ts +19 -0
  46. package/src/cli/index.ts +620 -0
  47. package/src/cli/output.ts +26 -0
  48. package/src/cli/runtime.ts +157 -0
  49. package/src/client.ts +70 -1
  50. package/src/identity.ts +76 -9
  51. package/src/index.ts +14 -0
@@ -0,0 +1,157 @@
1
+ import { chmod, mkdir, readFile, writeFile } from 'node:fs/promises';
2
+ import { dirname, resolve } from 'node:path';
3
+ import { homedir } from 'node:os';
4
+ import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts';
5
+ import type { ClawlogicConfig } from '../types.js';
6
+ import { createConfig } from '../config.js';
7
+ import { ClawlogicClient } from '../client.js';
8
+ import {
9
+ DEFAULT_CHAIN_ID,
10
+ DEFAULT_CONTRACTS,
11
+ DEFAULT_RPC_URL,
12
+ DEFAULT_STATE_PATH,
13
+ } from './constants.js';
14
+
15
+ interface PersistedState {
16
+ version: 1;
17
+ privateKey: `0x${string}`;
18
+ address: `0x${string}`;
19
+ createdAt: string;
20
+ rpcUrl?: string;
21
+ contracts?: Partial<ClawlogicConfig['contracts']>;
22
+ }
23
+
24
+ export interface RuntimeContext {
25
+ client: ClawlogicClient;
26
+ config: ClawlogicConfig;
27
+ address?: `0x${string}`;
28
+ statePath: string;
29
+ createdWallet: boolean;
30
+ state?: PersistedState;
31
+ }
32
+
33
+ export interface RuntimeOptions {
34
+ requireWallet?: boolean;
35
+ autoCreateWallet?: boolean;
36
+ }
37
+
38
+ export async function createRuntime(
39
+ options: RuntimeOptions = {},
40
+ ): Promise<RuntimeContext> {
41
+ const statePath = resolveStatePath(process.env.CLAWLOGIC_STATE_PATH ?? DEFAULT_STATE_PATH);
42
+ const state = await readState(statePath);
43
+ let privateKey = readPrivateKeyFromEnv();
44
+ let createdWallet = false;
45
+
46
+ if (!privateKey && state?.privateKey) {
47
+ privateKey = state.privateKey;
48
+ }
49
+
50
+ if (!privateKey && options.requireWallet && options.autoCreateWallet !== false) {
51
+ const generated = generatePrivateKey();
52
+ const address = privateKeyToAccount(generated).address;
53
+ const nextState: PersistedState = {
54
+ version: 1,
55
+ privateKey: generated,
56
+ address,
57
+ createdAt: new Date().toISOString(),
58
+ rpcUrl: state?.rpcUrl,
59
+ contracts: state?.contracts,
60
+ };
61
+ await writeState(statePath, nextState);
62
+ privateKey = generated;
63
+ createdWallet = true;
64
+ }
65
+
66
+ if (!privateKey && options.requireWallet) {
67
+ throw new Error(
68
+ 'No wallet available. Run `npx @clawlogic/sdk@latest clawlogic-agent init` first.',
69
+ );
70
+ }
71
+
72
+ const config = resolveConfig(state);
73
+ const client = new ClawlogicClient(config, privateKey);
74
+ const address = privateKey ? privateKeyToAccount(privateKey).address : state?.address;
75
+
76
+ return {
77
+ client,
78
+ config,
79
+ address,
80
+ statePath,
81
+ createdWallet,
82
+ state: state ?? undefined,
83
+ };
84
+ }
85
+
86
+ function resolveConfig(state: PersistedState | null): ClawlogicConfig {
87
+ const rpcUrl =
88
+ process.env.ARBITRUM_SEPOLIA_RPC_URL ??
89
+ process.env.CLAWLOGIC_RPC_URL ??
90
+ state?.rpcUrl ??
91
+ DEFAULT_RPC_URL;
92
+
93
+ const agentRegistry =
94
+ process.env.AGENT_REGISTRY ??
95
+ state?.contracts?.agentRegistry ??
96
+ DEFAULT_CONTRACTS.agentRegistry;
97
+ const predictionMarketHook =
98
+ process.env.PREDICTION_MARKET_HOOK ??
99
+ state?.contracts?.predictionMarketHook ??
100
+ DEFAULT_CONTRACTS.predictionMarketHook;
101
+ const poolManager =
102
+ process.env.V4_POOL_MANAGER ??
103
+ state?.contracts?.poolManager ??
104
+ DEFAULT_CONTRACTS.poolManager;
105
+ const optimisticOracleV3 =
106
+ process.env.UMA_OOV3 ??
107
+ state?.contracts?.optimisticOracleV3 ??
108
+ DEFAULT_CONTRACTS.optimisticOracleV3;
109
+
110
+ return createConfig(
111
+ {
112
+ agentRegistry: agentRegistry as `0x${string}`,
113
+ predictionMarketHook: predictionMarketHook as `0x${string}`,
114
+ poolManager: poolManager as `0x${string}`,
115
+ optimisticOracleV3: optimisticOracleV3 as `0x${string}`,
116
+ },
117
+ DEFAULT_CHAIN_ID,
118
+ rpcUrl,
119
+ );
120
+ }
121
+
122
+ function readPrivateKeyFromEnv(): `0x${string}` | undefined {
123
+ const candidate = process.env.AGENT_PRIVATE_KEY?.trim();
124
+ if (!candidate) {
125
+ return undefined;
126
+ }
127
+ if (!/^0x[0-9a-fA-F]{64}$/.test(candidate)) {
128
+ throw new Error('AGENT_PRIVATE_KEY must be a 32-byte hex string (0x + 64 hex chars).');
129
+ }
130
+ return candidate as `0x${string}`;
131
+ }
132
+
133
+ async function readState(path: string): Promise<PersistedState | null> {
134
+ try {
135
+ const raw = await readFile(path, 'utf-8');
136
+ const parsed = JSON.parse(raw) as PersistedState;
137
+ if (!parsed.privateKey || !parsed.address) {
138
+ return null;
139
+ }
140
+ return parsed;
141
+ } catch {
142
+ return null;
143
+ }
144
+ }
145
+
146
+ async function writeState(path: string, state: PersistedState): Promise<void> {
147
+ await mkdir(dirname(path), { recursive: true, mode: 0o700 });
148
+ await writeFile(path, JSON.stringify(state, null, 2), { mode: 0o600 });
149
+ await chmod(path, 0o600);
150
+ }
151
+
152
+ function resolveStatePath(path: string): string {
153
+ if (path.startsWith('~/')) {
154
+ return resolve(homedir(), path.slice(2));
155
+ }
156
+ return resolve(path);
157
+ }
package/src/client.ts CHANGED
@@ -13,6 +13,7 @@ import {
13
13
  type WatchContractEventReturnType,
14
14
  } from 'viem';
15
15
  import { privateKeyToAccount } from 'viem/accounts';
16
+ import { namehash } from 'viem/ens';
16
17
  import type {
17
18
  ClawlogicConfig,
18
19
  MarketInfo,
@@ -43,6 +44,22 @@ const arbitrumSepolia: Chain = {
43
44
  testnet: true,
44
45
  };
45
46
 
47
+ const ZERO_BYTES32 =
48
+ '0x0000000000000000000000000000000000000000000000000000000000000000' as const;
49
+ const ZERO_ADDRESS =
50
+ '0x0000000000000000000000000000000000000000' as const;
51
+
52
+ function isBytes32Hex(value: string): value is `0x${string}` {
53
+ return /^0x[0-9a-fA-F]{64}$/.test(value);
54
+ }
55
+
56
+ function resolveEnsNode(ensNodeOrName: `0x${string}` | string): `0x${string}` {
57
+ if (isBytes32Hex(ensNodeOrName)) {
58
+ return ensNodeOrName;
59
+ }
60
+ return namehash(ensNodeOrName) as `0x${string}`;
61
+ }
62
+
46
63
  // ─────────────────────────────────────────────────────────────────────────────
47
64
  // Helper: build a viem Chain object from a config
48
65
  // ─────────────────────────────────────────────────────────────────────────────
@@ -71,7 +88,7 @@ function buildChain(config: ClawlogicConfig): Chain {
71
88
  // ─────────────────────────────────────────────────────────────────────────────
72
89
 
73
90
  /**
74
- * Main client for interacting with the $CLAWLOGIC protocol.
91
+ * Main client for interacting with the CLAWLOGIC protocol.
75
92
  *
76
93
  * Provides methods for:
77
94
  * - Agent registration & lookup (AgentRegistry)
@@ -199,6 +216,32 @@ export class ClawlogicClient {
199
216
  return this.waitForTx(hash);
200
217
  }
201
218
 
219
+ /**
220
+ * Register the caller as an agent and link an ENS node.
221
+ *
222
+ * @param name - Human-readable agent name.
223
+ * @param ensNodeOrName - ENS namehash (`0x...`) or ENS name (`alpha.clawlogic.eth`).
224
+ * @param attestation - TEE attestation bytes (hex-encoded). Defaults to "0x".
225
+ * @returns Transaction hash of the registration.
226
+ */
227
+ async registerAgentWithENS(
228
+ name: string,
229
+ ensNodeOrName: `0x${string}` | string,
230
+ attestation: `0x${string}` = '0x',
231
+ ): Promise<`0x${string}`> {
232
+ const wallet = this.requireWallet();
233
+ const ensNode = resolveEnsNode(ensNodeOrName);
234
+
235
+ const hash = await wallet.writeContract({
236
+ address: this.config.contracts.agentRegistry,
237
+ abi: agentRegistryAbi,
238
+ functionName: 'registerAgentWithENS',
239
+ args: [name, attestation, ensNode],
240
+ });
241
+
242
+ return this.waitForTx(hash);
243
+ }
244
+
202
245
  /**
203
246
  * Check whether an address is a registered agent.
204
247
  *
@@ -235,6 +278,7 @@ export class ClawlogicClient {
235
278
  attestation: `0x${string}`;
236
279
  registeredAt: bigint;
237
280
  exists: boolean;
281
+ ensNode?: `0x${string}`;
238
282
  };
239
283
 
240
284
  return {
@@ -243,9 +287,31 @@ export class ClawlogicClient {
243
287
  attestation: agent.attestation,
244
288
  registeredAt: agent.registeredAt,
245
289
  exists: agent.exists,
290
+ ensNode: agent.ensNode && agent.ensNode !== ZERO_BYTES32 ? agent.ensNode : undefined,
246
291
  };
247
292
  }
248
293
 
294
+ /**
295
+ * Resolve an ENS-linked agent address from ENS namehash or name.
296
+ *
297
+ * @param ensNodeOrName - ENS namehash (`0x...`) or ENS name (`alpha.clawlogic.eth`).
298
+ * @returns The registered agent address linked to the ENS node.
299
+ */
300
+ async getAgentByENS(ensNodeOrName: `0x${string}` | string): Promise<`0x${string}`> {
301
+ const ensNode = resolveEnsNode(ensNodeOrName);
302
+ const result = await this.publicClient.readContract({
303
+ address: this.config.contracts.agentRegistry,
304
+ abi: agentRegistryAbi,
305
+ functionName: 'getAgentByENS',
306
+ args: [ensNode],
307
+ });
308
+ const agent = result as `0x${string}`;
309
+ if (agent.toLowerCase() === ZERO_ADDRESS) {
310
+ throw new Error(`No agent linked to ENS node ${ensNode}`);
311
+ }
312
+ return agent;
313
+ }
314
+
249
315
  /**
250
316
  * Get the total number of registered agents.
251
317
  *
@@ -290,6 +356,7 @@ export class ClawlogicClient {
290
356
  * @param description - Human-readable market question.
291
357
  * @param reward - Amount of bond currency offered as incentive to the asserter.
292
358
  * @param requiredBond - Minimum bond required from an asserter.
359
+ * @param initialLiquidityEth - Optional ETH value to seed CPMM reserves at market creation.
293
360
  * @returns Transaction hash of the market creation.
294
361
  */
295
362
  async initializeMarket(
@@ -298,6 +365,7 @@ export class ClawlogicClient {
298
365
  description: string,
299
366
  reward: bigint,
300
367
  requiredBond: bigint,
368
+ initialLiquidityEth: bigint = 0n,
301
369
  ): Promise<`0x${string}`> {
302
370
  const wallet = this.requireWallet();
303
371
 
@@ -306,6 +374,7 @@ export class ClawlogicClient {
306
374
  abi: predictionMarketHookAbi,
307
375
  functionName: 'initializeMarket',
308
376
  args: [outcome1, outcome2, description, reward, requiredBond],
377
+ value: initialLiquidityEth,
309
378
  });
310
379
 
311
380
  return this.waitForTx(hash);
package/src/identity.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @file identity.ts
3
3
  *
4
- * Phase 1 Identity & Trust infrastructure for $CLAWLOGIC.
4
+ * Phase 1 Identity & Trust infrastructure for CLAWLOGIC.
5
5
  *
6
6
  * Provides SDK methods for:
7
7
  * - ENS agent identity resolution
@@ -30,17 +30,24 @@ import { ValidationType } from './types.js';
30
30
  import { agentIdentityRegistryAbi } from './abis/agentIdentityRegistryAbi.js';
31
31
  import { agentReputationRegistryAbi } from './abis/agentReputationRegistryAbi.js';
32
32
  import { agentValidationRegistryAbi } from './abis/agentValidationRegistryAbi.js';
33
+ import { agentRegistryAbi } from './abis/agentRegistryAbi.js';
33
34
 
34
35
  /**
35
36
  * Extended contract addresses for Phase 1 identity infrastructure.
36
37
  */
37
38
  export interface IdentityContracts {
39
+ agentRegistry?: `0x${string}`;
38
40
  agentIdentityRegistry: `0x${string}`;
39
41
  agentReputationRegistry: `0x${string}`;
40
42
  agentValidationRegistry: `0x${string}`;
41
43
  ensRegistry?: `0x${string}`; // Optional: 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e on most chains
42
44
  }
43
45
 
46
+ const ZERO_BYTES32 =
47
+ '0x0000000000000000000000000000000000000000000000000000000000000000' as const;
48
+ const ZERO_ADDRESS =
49
+ '0x0000000000000000000000000000000000000000' as const;
50
+
44
51
  /**
45
52
  * Identity client for Phase 1 ENS + ERC-8004 + TEE functionality.
46
53
  *
@@ -65,12 +72,23 @@ export class IdentityClient {
65
72
  * @returns Agent address, or null if not found
66
73
  */
67
74
  async resolveAgentENS(ensName: string): Promise<`0x${string}` | null> {
68
- try {
69
- // ENS resolution is handled by AgentRegistry.getAgentByENS(), not the
70
- // identity registry. Use the main ClawlogicClient for ENS resolution.
71
- // This method is a no-op placeholder; callers should use
72
- // ClawlogicClient.getAgentByENS() directly.
75
+ const registry = this.contracts.agentRegistry;
76
+ if (!registry) {
73
77
  return null;
78
+ }
79
+
80
+ try {
81
+ const ensNode = namehash(ensName) as `0x${string}`;
82
+ const agent = await this.publicClient.readContract({
83
+ address: registry,
84
+ abi: agentRegistryAbi,
85
+ functionName: 'getAgentByENS',
86
+ args: [ensNode],
87
+ }) as `0x${string}`;
88
+ if (agent.toLowerCase() === ZERO_ADDRESS) {
89
+ return null;
90
+ }
91
+ return agent;
74
92
  } catch {
75
93
  return null;
76
94
  }
@@ -83,10 +101,58 @@ export class IdentityClient {
83
101
  * @returns ENS name, or null if not linked
84
102
  */
85
103
  async getAgentENSName(address: `0x${string}`): Promise<string | null> {
104
+ const ensCapableClient = this.publicClient as PublicClient<Transport, Chain> & {
105
+ getEnsName?: (args: { address: `0x${string}` }) => Promise<string | null>;
106
+ };
107
+
86
108
  try {
87
- // This will be implemented once AgentRegistry includes ENS reverse mapping
88
- // For now, return null (requires contract support)
109
+ if (typeof ensCapableClient.getEnsName === 'function') {
110
+ const ensName = await ensCapableClient.getEnsName({ address });
111
+ if (ensName) {
112
+ return ensName;
113
+ }
114
+ }
115
+ } catch {
116
+ // Fall through to registry-based fallback.
117
+ }
118
+
119
+ const ensNode = await this.getAgentENSNode(address);
120
+ if (!ensNode) {
121
+ return null;
122
+ }
123
+ return `ens-node:${ensNode}`;
124
+ }
125
+
126
+ /**
127
+ * Get the ENS node linked to a given agent address.
128
+ *
129
+ * @param address - Agent address
130
+ * @returns ENS node (bytes32) if linked, otherwise null
131
+ */
132
+ async getAgentENSNode(address: `0x${string}`): Promise<`0x${string}` | null> {
133
+ const registry = this.contracts.agentRegistry;
134
+ if (!registry) {
89
135
  return null;
136
+ }
137
+
138
+ try {
139
+ const result = await this.publicClient.readContract({
140
+ address: registry,
141
+ abi: agentRegistryAbi,
142
+ functionName: 'getAgent',
143
+ args: [address],
144
+ });
145
+
146
+ const agent = result as {
147
+ exists: boolean;
148
+ ensNode?: `0x${string}`;
149
+ };
150
+
151
+ if (!agent.exists || !agent.ensNode || agent.ensNode === ZERO_BYTES32) {
152
+ return null;
153
+ }
154
+
155
+ return agent.ensNode;
90
156
  } catch {
91
157
  return null;
92
158
  }
@@ -362,6 +428,7 @@ export class IdentityClient {
362
428
 
363
429
  // Get ENS name
364
430
  const ensName = await this.getAgentENSName(address);
431
+ const ensNode = await this.getAgentENSNode(address);
365
432
 
366
433
  // Get identity token
367
434
  const identityToken = await this.getAgentIdentityToken(address);
@@ -384,7 +451,7 @@ export class IdentityClient {
384
451
  attestation: '0x', // Will be filled by caller
385
452
  registeredAt: 0n, // Will be filled by caller
386
453
  exists: true,
387
- ensNode: ensName ? namehash(ensName) : undefined,
454
+ ensNode: ensNode ?? (ensName && !ensName.startsWith('ens-node:') ? namehash(ensName) : undefined),
388
455
  agentId: identityToken?.tokenId,
389
456
  reputationScore,
390
457
  ensName,
package/src/index.ts CHANGED
@@ -4,6 +4,20 @@
4
4
 
5
5
  // Main client
6
6
  export { ClawlogicClient } from './client.js';
7
+ export {
8
+ bridge,
9
+ bridgeQuote,
10
+ bridgeStatus,
11
+ bridgeExecute,
12
+ } from './bridge.js';
13
+ export type {
14
+ LiFiQuoteRequest,
15
+ LiFiQuoteResponse,
16
+ LiFiStatusRequest,
17
+ LiFiStatusResponse,
18
+ LiFiExecuteRequest,
19
+ LiFiExecuteResult,
20
+ } from './bridge.js';
7
21
 
8
22
  // Phase 1: Identity & Trust infrastructure
9
23
  export { IdentityClient } from './identity.js';