@clawlogic/sdk 0.0.1
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 +227 -0
- package/dist/abis/agentIdentityRegistryAbi.d.ts +532 -0
- package/dist/abis/agentIdentityRegistryAbi.d.ts.map +1 -0
- package/dist/abis/agentIdentityRegistryAbi.js +2 -0
- package/dist/abis/agentIdentityRegistryAbi.js.map +1 -0
- package/dist/abis/agentRegistryAbi.d.ts +265 -0
- package/dist/abis/agentRegistryAbi.d.ts.map +1 -0
- package/dist/abis/agentRegistryAbi.js +151 -0
- package/dist/abis/agentRegistryAbi.js.map +1 -0
- package/dist/abis/agentReputationRegistryAbi.d.ts +224 -0
- package/dist/abis/agentReputationRegistryAbi.d.ts.map +1 -0
- package/dist/abis/agentReputationRegistryAbi.js +2 -0
- package/dist/abis/agentReputationRegistryAbi.js.map +1 -0
- package/dist/abis/agentValidationRegistryAbi.d.ts +281 -0
- package/dist/abis/agentValidationRegistryAbi.d.ts.map +1 -0
- package/dist/abis/agentValidationRegistryAbi.js +2 -0
- package/dist/abis/agentValidationRegistryAbi.js.map +1 -0
- package/dist/abis/outcomeTokenAbi.d.ts +255 -0
- package/dist/abis/outcomeTokenAbi.d.ts.map +1 -0
- package/dist/abis/outcomeTokenAbi.js +152 -0
- package/dist/abis/outcomeTokenAbi.js.map +1 -0
- package/dist/abis/predictionMarketHookAbi.d.ts +396 -0
- package/dist/abis/predictionMarketHookAbi.d.ts.map +1 -0
- package/dist/abis/predictionMarketHookAbi.js +212 -0
- package/dist/abis/predictionMarketHookAbi.js.map +1 -0
- package/dist/client.d.ts +241 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +569 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +84 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +134 -0
- package/dist/config.js.map +1 -0
- package/dist/identity.d.ts +133 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +314 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +191 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +11 -0
- package/dist/types.js.map +1 -0
- package/package.json +51 -0
- package/src/abis/.gitkeep +0 -0
- package/src/abis/AgentRegistry.json +1 -0
- package/src/abis/ENSAgentHelper.json +1 -0
- package/src/abis/OutcomeToken.json +1 -0
- package/src/abis/PredictionMarketHook.json +1 -0
- package/src/abis/agentIdentityRegistryAbi.ts +1 -0
- package/src/abis/agentRegistryAbi.ts +150 -0
- package/src/abis/agentReputationRegistryAbi.ts +1 -0
- package/src/abis/agentValidationRegistryAbi.ts +1 -0
- package/src/abis/outcomeTokenAbi.ts +153 -0
- package/src/abis/predictionMarketHookAbi.ts +214 -0
- package/src/client.ts +722 -0
- package/src/config.ts +161 -0
- package/src/identity.ts +395 -0
- package/src/index.ts +48 -0
- package/src/types.ts +207 -0
package/src/client.ts
ADDED
|
@@ -0,0 +1,722 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createPublicClient,
|
|
3
|
+
createWalletClient,
|
|
4
|
+
http,
|
|
5
|
+
getContract,
|
|
6
|
+
type PublicClient,
|
|
7
|
+
type WalletClient,
|
|
8
|
+
type Transport,
|
|
9
|
+
type Chain,
|
|
10
|
+
type Account,
|
|
11
|
+
type GetContractReturnType,
|
|
12
|
+
type Log,
|
|
13
|
+
type WatchContractEventReturnType,
|
|
14
|
+
} from 'viem';
|
|
15
|
+
import { privateKeyToAccount } from 'viem/accounts';
|
|
16
|
+
import type {
|
|
17
|
+
ClawlogicConfig,
|
|
18
|
+
MarketInfo,
|
|
19
|
+
AgentInfo,
|
|
20
|
+
MarketEvent,
|
|
21
|
+
MarketEventCallback,
|
|
22
|
+
} from './types.js';
|
|
23
|
+
import { agentRegistryAbi } from './abis/agentRegistryAbi.js';
|
|
24
|
+
import { predictionMarketHookAbi } from './abis/predictionMarketHookAbi.js';
|
|
25
|
+
import { outcomeTokenAbi } from './abis/outcomeTokenAbi.js';
|
|
26
|
+
|
|
27
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
28
|
+
// Chain definition for Arbitrum Sepolia (in case viem does not export it)
|
|
29
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
30
|
+
|
|
31
|
+
const arbitrumSepolia: Chain = {
|
|
32
|
+
id: 421614,
|
|
33
|
+
name: 'Arbitrum Sepolia',
|
|
34
|
+
nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
|
|
35
|
+
rpcUrls: {
|
|
36
|
+
default: { http: ['https://sepolia-rollup.arbitrum.io/rpc'] },
|
|
37
|
+
},
|
|
38
|
+
blockExplorers: {
|
|
39
|
+
default: { name: 'Arbiscan', url: 'https://sepolia.arbiscan.io' },
|
|
40
|
+
},
|
|
41
|
+
testnet: true,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
45
|
+
// Helper: build a viem Chain object from a config
|
|
46
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
47
|
+
|
|
48
|
+
function buildChain(config: ClawlogicConfig): Chain {
|
|
49
|
+
if (config.chainId === 421614) {
|
|
50
|
+
return {
|
|
51
|
+
...arbitrumSepolia,
|
|
52
|
+
rpcUrls: {
|
|
53
|
+
default: { http: [config.rpcUrl] },
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
id: config.chainId,
|
|
59
|
+
name: `Chain ${config.chainId}`,
|
|
60
|
+
nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
|
|
61
|
+
rpcUrls: {
|
|
62
|
+
default: { http: [config.rpcUrl] },
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
68
|
+
// ClawlogicClient
|
|
69
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Main client for interacting with the $CLAWLOGIC protocol.
|
|
73
|
+
*
|
|
74
|
+
* Provides methods for:
|
|
75
|
+
* - Agent registration & lookup (AgentRegistry)
|
|
76
|
+
* - Market creation, minting, assertion & settlement (PredictionMarketHook)
|
|
77
|
+
* - Outcome token balance queries (OutcomeToken ERC-20)
|
|
78
|
+
* - Event watching for real-time market activity
|
|
79
|
+
*
|
|
80
|
+
* Requires a private key for write operations. Read-only operations work
|
|
81
|
+
* without a private key (pass `undefined` and only use read methods).
|
|
82
|
+
*/
|
|
83
|
+
export class ClawlogicClient {
|
|
84
|
+
/** Protocol configuration (chain, RPC, contract addresses). */
|
|
85
|
+
readonly config: ClawlogicConfig;
|
|
86
|
+
|
|
87
|
+
/** viem public client for read operations. */
|
|
88
|
+
readonly publicClient: PublicClient<Transport, Chain>;
|
|
89
|
+
|
|
90
|
+
/** viem wallet client for write operations (undefined if read-only). */
|
|
91
|
+
readonly walletClient: WalletClient<Transport, Chain, Account> | undefined;
|
|
92
|
+
|
|
93
|
+
/** The account derived from the private key (undefined if read-only). */
|
|
94
|
+
readonly account: Account | undefined;
|
|
95
|
+
|
|
96
|
+
/** Typed contract handle for AgentRegistry (read-only). */
|
|
97
|
+
private readonly registryRead: GetContractReturnType<
|
|
98
|
+
typeof agentRegistryAbi,
|
|
99
|
+
PublicClient<Transport, Chain>
|
|
100
|
+
>;
|
|
101
|
+
|
|
102
|
+
/** Typed contract handle for PredictionMarketHook (read-only). */
|
|
103
|
+
private readonly hookRead: GetContractReturnType<
|
|
104
|
+
typeof predictionMarketHookAbi,
|
|
105
|
+
PublicClient<Transport, Chain>
|
|
106
|
+
>;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Create a new ClawlogicClient.
|
|
110
|
+
*
|
|
111
|
+
* @param config - Protocol configuration with chain info and contract addresses.
|
|
112
|
+
* @param privateKey - Hex-encoded private key for signing transactions.
|
|
113
|
+
* Pass `undefined` for a read-only client.
|
|
114
|
+
*/
|
|
115
|
+
constructor(config: ClawlogicConfig, privateKey?: `0x${string}`) {
|
|
116
|
+
this.config = config;
|
|
117
|
+
|
|
118
|
+
const chain = buildChain(config);
|
|
119
|
+
|
|
120
|
+
this.publicClient = createPublicClient({
|
|
121
|
+
chain,
|
|
122
|
+
transport: http(config.rpcUrl),
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
if (privateKey) {
|
|
126
|
+
this.account = privateKeyToAccount(privateKey);
|
|
127
|
+
this.walletClient = createWalletClient({
|
|
128
|
+
account: this.account,
|
|
129
|
+
chain,
|
|
130
|
+
transport: http(config.rpcUrl),
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
this.registryRead = getContract({
|
|
135
|
+
address: config.contracts.agentRegistry,
|
|
136
|
+
abi: agentRegistryAbi,
|
|
137
|
+
client: this.publicClient,
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
this.hookRead = getContract({
|
|
141
|
+
address: config.contracts.predictionMarketHook,
|
|
142
|
+
abi: predictionMarketHookAbi,
|
|
143
|
+
client: this.publicClient,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
148
|
+
// Private helpers
|
|
149
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Ensure a wallet client is available for write operations.
|
|
153
|
+
* Throws a descriptive error if the client was created in read-only mode.
|
|
154
|
+
*/
|
|
155
|
+
private requireWallet(): WalletClient<Transport, Chain, Account> {
|
|
156
|
+
if (!this.walletClient || !this.account) {
|
|
157
|
+
throw new Error(
|
|
158
|
+
'ClawlogicClient: No private key provided. ' +
|
|
159
|
+
'Write operations require a private key in the constructor.',
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
return this.walletClient;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Wait for a transaction receipt and return the transaction hash.
|
|
167
|
+
*/
|
|
168
|
+
private async waitForTx(hash: `0x${string}`): Promise<`0x${string}`> {
|
|
169
|
+
await this.publicClient.waitForTransactionReceipt({ hash });
|
|
170
|
+
return hash;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
174
|
+
// Agent Registry Methods
|
|
175
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Register the caller as an agent in the AgentRegistry.
|
|
179
|
+
*
|
|
180
|
+
* @param name - Human-readable agent name (e.g., "AlphaTrader"). Must be non-empty.
|
|
181
|
+
* @param attestation - TEE attestation bytes (hex-encoded). Defaults to "0x" (empty).
|
|
182
|
+
* @returns Transaction hash of the registration.
|
|
183
|
+
*/
|
|
184
|
+
async registerAgent(
|
|
185
|
+
name: string,
|
|
186
|
+
attestation: `0x${string}` = '0x',
|
|
187
|
+
): Promise<`0x${string}`> {
|
|
188
|
+
const wallet = this.requireWallet();
|
|
189
|
+
|
|
190
|
+
const hash = await wallet.writeContract({
|
|
191
|
+
address: this.config.contracts.agentRegistry,
|
|
192
|
+
abi: agentRegistryAbi,
|
|
193
|
+
functionName: 'registerAgent',
|
|
194
|
+
args: [name, attestation],
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
return this.waitForTx(hash);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Check whether an address is a registered agent.
|
|
202
|
+
*
|
|
203
|
+
* @param address - The address to check.
|
|
204
|
+
* @returns True if the address is registered as an agent.
|
|
205
|
+
*/
|
|
206
|
+
async isAgent(address: `0x${string}`): Promise<boolean> {
|
|
207
|
+
const result = await this.publicClient.readContract({
|
|
208
|
+
address: this.config.contracts.agentRegistry,
|
|
209
|
+
abi: agentRegistryAbi,
|
|
210
|
+
functionName: 'isAgent',
|
|
211
|
+
args: [address],
|
|
212
|
+
});
|
|
213
|
+
return result as boolean;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Get the full agent info for a registered address.
|
|
218
|
+
*
|
|
219
|
+
* @param address - The agent address to look up.
|
|
220
|
+
* @returns AgentInfo with name, attestation, registeredAt, and exists flag.
|
|
221
|
+
*/
|
|
222
|
+
async getAgent(address: `0x${string}`): Promise<AgentInfo> {
|
|
223
|
+
const result = await this.publicClient.readContract({
|
|
224
|
+
address: this.config.contracts.agentRegistry,
|
|
225
|
+
abi: agentRegistryAbi,
|
|
226
|
+
functionName: 'getAgent',
|
|
227
|
+
args: [address],
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// The result is a tuple struct: { name, attestation, registeredAt, exists }
|
|
231
|
+
const agent = result as {
|
|
232
|
+
name: string;
|
|
233
|
+
attestation: `0x${string}`;
|
|
234
|
+
registeredAt: bigint;
|
|
235
|
+
exists: boolean;
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
return {
|
|
239
|
+
address,
|
|
240
|
+
name: agent.name,
|
|
241
|
+
attestation: agent.attestation,
|
|
242
|
+
registeredAt: agent.registeredAt,
|
|
243
|
+
exists: agent.exists,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Get the total number of registered agents.
|
|
249
|
+
*
|
|
250
|
+
* @returns The agent count as a bigint.
|
|
251
|
+
*/
|
|
252
|
+
async getAgentCount(): Promise<bigint> {
|
|
253
|
+
const result = await this.publicClient.readContract({
|
|
254
|
+
address: this.config.contracts.agentRegistry,
|
|
255
|
+
abi: agentRegistryAbi,
|
|
256
|
+
functionName: 'getAgentCount',
|
|
257
|
+
});
|
|
258
|
+
return result as bigint;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Get all registered agent addresses.
|
|
263
|
+
*
|
|
264
|
+
* @returns Array of agent addresses.
|
|
265
|
+
*/
|
|
266
|
+
async getAgentAddresses(): Promise<`0x${string}`[]> {
|
|
267
|
+
const result = await this.publicClient.readContract({
|
|
268
|
+
address: this.config.contracts.agentRegistry,
|
|
269
|
+
abi: agentRegistryAbi,
|
|
270
|
+
functionName: 'getAgentAddresses',
|
|
271
|
+
});
|
|
272
|
+
return result as `0x${string}`[];
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
276
|
+
// Prediction Market Methods (Write)
|
|
277
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Create a new prediction market.
|
|
281
|
+
*
|
|
282
|
+
* The caller must be a registered agent. If `reward > 0`, the caller must
|
|
283
|
+
* have previously approved that amount of the bond currency (i_currency)
|
|
284
|
+
* to the PredictionMarketHook contract.
|
|
285
|
+
*
|
|
286
|
+
* @param outcome1 - Label for outcome 1 (e.g., "yes").
|
|
287
|
+
* @param outcome2 - Label for outcome 2 (e.g., "no").
|
|
288
|
+
* @param description - Human-readable market question.
|
|
289
|
+
* @param reward - Amount of bond currency offered as incentive to the asserter.
|
|
290
|
+
* @param requiredBond - Minimum bond required from an asserter.
|
|
291
|
+
* @returns Transaction hash of the market creation.
|
|
292
|
+
*/
|
|
293
|
+
async initializeMarket(
|
|
294
|
+
outcome1: string,
|
|
295
|
+
outcome2: string,
|
|
296
|
+
description: string,
|
|
297
|
+
reward: bigint,
|
|
298
|
+
requiredBond: bigint,
|
|
299
|
+
): Promise<`0x${string}`> {
|
|
300
|
+
const wallet = this.requireWallet();
|
|
301
|
+
|
|
302
|
+
const hash = await wallet.writeContract({
|
|
303
|
+
address: this.config.contracts.predictionMarketHook,
|
|
304
|
+
abi: predictionMarketHookAbi,
|
|
305
|
+
functionName: 'initializeMarket',
|
|
306
|
+
args: [outcome1, outcome2, description, reward, requiredBond],
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
return this.waitForTx(hash);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Deposit ETH collateral to mint equal amounts of both outcome tokens.
|
|
314
|
+
*
|
|
315
|
+
* The caller must be a registered agent. Sends `ethAmount` in wei as
|
|
316
|
+
* msg.value and receives that amount of outcome1Token AND outcome2Token.
|
|
317
|
+
*
|
|
318
|
+
* @param marketId - The market to mint tokens for (bytes32).
|
|
319
|
+
* @param ethAmount - Amount of ETH to deposit as collateral (in wei).
|
|
320
|
+
* @returns Transaction hash of the mint operation.
|
|
321
|
+
*/
|
|
322
|
+
async mintOutcomeTokens(
|
|
323
|
+
marketId: `0x${string}`,
|
|
324
|
+
ethAmount: bigint,
|
|
325
|
+
): Promise<`0x${string}`> {
|
|
326
|
+
const wallet = this.requireWallet();
|
|
327
|
+
|
|
328
|
+
const hash = await wallet.writeContract({
|
|
329
|
+
address: this.config.contracts.predictionMarketHook,
|
|
330
|
+
abi: predictionMarketHookAbi,
|
|
331
|
+
functionName: 'mintOutcomeTokens',
|
|
332
|
+
args: [marketId],
|
|
333
|
+
value: ethAmount,
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
return this.waitForTx(hash);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Assert the outcome of a market via UMA Optimistic Oracle V3.
|
|
341
|
+
*
|
|
342
|
+
* The caller must be a registered agent. The asserted outcome must exactly
|
|
343
|
+
* match `outcome1`, `outcome2`, or the literal string "Unresolvable".
|
|
344
|
+
* The caller must have approved the required bond amount of `i_currency`
|
|
345
|
+
* to the PredictionMarketHook contract.
|
|
346
|
+
*
|
|
347
|
+
* @param marketId - The market to assert (bytes32).
|
|
348
|
+
* @param assertedOutcome - The outcome string being asserted.
|
|
349
|
+
* @returns Transaction hash of the assertion.
|
|
350
|
+
*/
|
|
351
|
+
async assertMarket(
|
|
352
|
+
marketId: `0x${string}`,
|
|
353
|
+
assertedOutcome: string,
|
|
354
|
+
): Promise<`0x${string}`> {
|
|
355
|
+
const wallet = this.requireWallet();
|
|
356
|
+
|
|
357
|
+
const hash = await wallet.writeContract({
|
|
358
|
+
address: this.config.contracts.predictionMarketHook,
|
|
359
|
+
abi: predictionMarketHookAbi,
|
|
360
|
+
functionName: 'assertMarket',
|
|
361
|
+
args: [marketId, assertedOutcome],
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
return this.waitForTx(hash);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Redeem winning outcome tokens for proportional ETH collateral.
|
|
369
|
+
*
|
|
370
|
+
* The market must be resolved. The caller's winning tokens are burned and
|
|
371
|
+
* they receive a proportional share of the total collateral.
|
|
372
|
+
*
|
|
373
|
+
* @param marketId - The resolved market (bytes32).
|
|
374
|
+
* @returns Transaction hash of the settlement.
|
|
375
|
+
*/
|
|
376
|
+
async settleOutcomeTokens(marketId: `0x${string}`): Promise<`0x${string}`> {
|
|
377
|
+
const wallet = this.requireWallet();
|
|
378
|
+
|
|
379
|
+
const hash = await wallet.writeContract({
|
|
380
|
+
address: this.config.contracts.predictionMarketHook,
|
|
381
|
+
abi: predictionMarketHookAbi,
|
|
382
|
+
functionName: 'settleOutcomeTokens',
|
|
383
|
+
args: [marketId],
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
return this.waitForTx(hash);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
390
|
+
// Prediction Market Methods (Read)
|
|
391
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Get full market details for a given marketId.
|
|
395
|
+
*
|
|
396
|
+
* Parses the 11-value tuple returned by PredictionMarketHook.getMarket()
|
|
397
|
+
* into a structured MarketInfo object.
|
|
398
|
+
*
|
|
399
|
+
* @param marketId - The market identifier (bytes32).
|
|
400
|
+
* @returns MarketInfo with all market details.
|
|
401
|
+
*/
|
|
402
|
+
async getMarket(marketId: `0x${string}`): Promise<MarketInfo> {
|
|
403
|
+
const result = await this.publicClient.readContract({
|
|
404
|
+
address: this.config.contracts.predictionMarketHook,
|
|
405
|
+
abi: predictionMarketHookAbi,
|
|
406
|
+
functionName: 'getMarket',
|
|
407
|
+
args: [marketId],
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
// The result is a tuple of 11 values matching the getMarket return signature.
|
|
411
|
+
const [
|
|
412
|
+
description,
|
|
413
|
+
outcome1,
|
|
414
|
+
outcome2,
|
|
415
|
+
outcome1Token,
|
|
416
|
+
outcome2Token,
|
|
417
|
+
reward,
|
|
418
|
+
requiredBond,
|
|
419
|
+
resolved,
|
|
420
|
+
assertedOutcomeId,
|
|
421
|
+
poolId,
|
|
422
|
+
totalCollateral,
|
|
423
|
+
] = result as [
|
|
424
|
+
string,
|
|
425
|
+
string,
|
|
426
|
+
string,
|
|
427
|
+
`0x${string}`,
|
|
428
|
+
`0x${string}`,
|
|
429
|
+
bigint,
|
|
430
|
+
bigint,
|
|
431
|
+
boolean,
|
|
432
|
+
`0x${string}`,
|
|
433
|
+
`0x${string}`,
|
|
434
|
+
bigint,
|
|
435
|
+
];
|
|
436
|
+
|
|
437
|
+
return {
|
|
438
|
+
marketId,
|
|
439
|
+
description,
|
|
440
|
+
outcome1,
|
|
441
|
+
outcome2,
|
|
442
|
+
outcome1Token,
|
|
443
|
+
outcome2Token,
|
|
444
|
+
reward,
|
|
445
|
+
requiredBond,
|
|
446
|
+
resolved,
|
|
447
|
+
assertedOutcomeId,
|
|
448
|
+
poolId,
|
|
449
|
+
totalCollateral,
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Get all market IDs.
|
|
455
|
+
*
|
|
456
|
+
* @returns Array of all created market IDs (bytes32[]).
|
|
457
|
+
*/
|
|
458
|
+
async getMarketIds(): Promise<`0x${string}`[]> {
|
|
459
|
+
const result = await this.publicClient.readContract({
|
|
460
|
+
address: this.config.contracts.predictionMarketHook,
|
|
461
|
+
abi: predictionMarketHookAbi,
|
|
462
|
+
functionName: 'getMarketIds',
|
|
463
|
+
});
|
|
464
|
+
return result as `0x${string}`[];
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Get all markets with full details.
|
|
469
|
+
*
|
|
470
|
+
* Calls getMarketIds() then getMarket() for each.
|
|
471
|
+
* For large numbers of markets, consider using getMarketIds() + getMarket()
|
|
472
|
+
* individually with pagination.
|
|
473
|
+
*
|
|
474
|
+
* @returns Array of MarketInfo for all markets.
|
|
475
|
+
*/
|
|
476
|
+
async getAllMarkets(): Promise<MarketInfo[]> {
|
|
477
|
+
const ids = await this.getMarketIds();
|
|
478
|
+
const markets = await Promise.all(ids.map((id) => this.getMarket(id)));
|
|
479
|
+
return markets;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Get the total number of created markets.
|
|
484
|
+
*
|
|
485
|
+
* @returns The market count as a bigint.
|
|
486
|
+
*/
|
|
487
|
+
async getMarketCount(): Promise<bigint> {
|
|
488
|
+
const result = await this.publicClient.readContract({
|
|
489
|
+
address: this.config.contracts.predictionMarketHook,
|
|
490
|
+
abi: predictionMarketHookAbi,
|
|
491
|
+
functionName: 's_marketCount',
|
|
492
|
+
});
|
|
493
|
+
return result as bigint;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
497
|
+
// Outcome Token Methods (Read)
|
|
498
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Get the balance of an outcome token for a given owner.
|
|
502
|
+
*
|
|
503
|
+
* @param tokenAddress - The OutcomeToken contract address.
|
|
504
|
+
* @param ownerAddress - The address to check the balance of.
|
|
505
|
+
* @returns The token balance as a bigint.
|
|
506
|
+
*/
|
|
507
|
+
async getOutcomeTokenBalance(
|
|
508
|
+
tokenAddress: `0x${string}`,
|
|
509
|
+
ownerAddress: `0x${string}`,
|
|
510
|
+
): Promise<bigint> {
|
|
511
|
+
const result = await this.publicClient.readContract({
|
|
512
|
+
address: tokenAddress,
|
|
513
|
+
abi: outcomeTokenAbi,
|
|
514
|
+
functionName: 'balanceOf',
|
|
515
|
+
args: [ownerAddress],
|
|
516
|
+
});
|
|
517
|
+
return result as bigint;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Get the total supply of an outcome token.
|
|
522
|
+
*
|
|
523
|
+
* @param tokenAddress - The OutcomeToken contract address.
|
|
524
|
+
* @returns The total supply as a bigint.
|
|
525
|
+
*/
|
|
526
|
+
async getOutcomeTokenTotalSupply(tokenAddress: `0x${string}`): Promise<bigint> {
|
|
527
|
+
const result = await this.publicClient.readContract({
|
|
528
|
+
address: tokenAddress,
|
|
529
|
+
abi: outcomeTokenAbi,
|
|
530
|
+
functionName: 'totalSupply',
|
|
531
|
+
});
|
|
532
|
+
return result as bigint;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Get both outcome token balances for a given agent in a specific market.
|
|
537
|
+
*
|
|
538
|
+
* @param marketId - The market identifier.
|
|
539
|
+
* @param ownerAddress - The address to check balances for.
|
|
540
|
+
* @returns Object with outcome1Balance and outcome2Balance.
|
|
541
|
+
*/
|
|
542
|
+
async getPositions(
|
|
543
|
+
marketId: `0x${string}`,
|
|
544
|
+
ownerAddress: `0x${string}`,
|
|
545
|
+
): Promise<{ outcome1Balance: bigint; outcome2Balance: bigint }> {
|
|
546
|
+
const market = await this.getMarket(marketId);
|
|
547
|
+
|
|
548
|
+
const [outcome1Balance, outcome2Balance] = await Promise.all([
|
|
549
|
+
this.getOutcomeTokenBalance(market.outcome1Token, ownerAddress),
|
|
550
|
+
this.getOutcomeTokenBalance(market.outcome2Token, ownerAddress),
|
|
551
|
+
]);
|
|
552
|
+
|
|
553
|
+
return { outcome1Balance, outcome2Balance };
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
557
|
+
// Protocol Info Methods
|
|
558
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* Get the bond currency address used by the PredictionMarketHook.
|
|
562
|
+
*
|
|
563
|
+
* @returns The ERC-20 bond currency contract address.
|
|
564
|
+
*/
|
|
565
|
+
async getBondCurrency(): Promise<`0x${string}`> {
|
|
566
|
+
const result = await this.publicClient.readContract({
|
|
567
|
+
address: this.config.contracts.predictionMarketHook,
|
|
568
|
+
abi: predictionMarketHookAbi,
|
|
569
|
+
functionName: 'i_currency',
|
|
570
|
+
});
|
|
571
|
+
return result as `0x${string}`;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* Get the default liveness window for UMA assertions (in seconds).
|
|
576
|
+
*
|
|
577
|
+
* @returns The liveness window as a bigint (seconds).
|
|
578
|
+
*/
|
|
579
|
+
async getDefaultLiveness(): Promise<bigint> {
|
|
580
|
+
const result = await this.publicClient.readContract({
|
|
581
|
+
address: this.config.contracts.predictionMarketHook,
|
|
582
|
+
abi: predictionMarketHookAbi,
|
|
583
|
+
functionName: 'i_defaultLiveness',
|
|
584
|
+
});
|
|
585
|
+
return result as bigint;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* Get the UMA Optimistic Oracle V3 address used by the hook.
|
|
590
|
+
*
|
|
591
|
+
* @returns The OOV3 contract address.
|
|
592
|
+
*/
|
|
593
|
+
async getOracleAddress(): Promise<`0x${string}`> {
|
|
594
|
+
const result = await this.publicClient.readContract({
|
|
595
|
+
address: this.config.contracts.predictionMarketHook,
|
|
596
|
+
abi: predictionMarketHookAbi,
|
|
597
|
+
functionName: 'i_oo',
|
|
598
|
+
});
|
|
599
|
+
return result as `0x${string}`;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
603
|
+
// Event Watching
|
|
604
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* Watch for all prediction market events in real time.
|
|
608
|
+
*
|
|
609
|
+
* Subscribes to: MarketInitialized, TokensMinted, MarketAsserted,
|
|
610
|
+
* MarketResolved, AssertionFailed, AssertionDisputed, TokensSettled.
|
|
611
|
+
*
|
|
612
|
+
* @param callback - Function called for each new event.
|
|
613
|
+
* @returns An unwatch function. Call it to stop watching.
|
|
614
|
+
*/
|
|
615
|
+
watchMarketEvents(callback: MarketEventCallback): () => void {
|
|
616
|
+
const hookAddress = this.config.contracts.predictionMarketHook;
|
|
617
|
+
const unwatchers: WatchContractEventReturnType[] = [];
|
|
618
|
+
|
|
619
|
+
// Helper to create a watcher for a specific event
|
|
620
|
+
const watchEvent = (
|
|
621
|
+
eventName: MarketEvent['type'],
|
|
622
|
+
) => {
|
|
623
|
+
const unwatch = this.publicClient.watchContractEvent({
|
|
624
|
+
address: hookAddress,
|
|
625
|
+
abi: predictionMarketHookAbi,
|
|
626
|
+
eventName,
|
|
627
|
+
onLogs: (logs: Log[]) => {
|
|
628
|
+
for (const log of logs) {
|
|
629
|
+
const typedLog = log as Log & { args?: Record<string, unknown> };
|
|
630
|
+
const marketId =
|
|
631
|
+
(typedLog.args?.['marketId'] as `0x${string}`) ??
|
|
632
|
+
'0x0000000000000000000000000000000000000000000000000000000000000000';
|
|
633
|
+
|
|
634
|
+
callback({
|
|
635
|
+
type: eventName,
|
|
636
|
+
marketId,
|
|
637
|
+
blockNumber: log.blockNumber ?? 0n,
|
|
638
|
+
transactionHash: log.transactionHash ?? ('0x' as `0x${string}`),
|
|
639
|
+
args: (typedLog.args ?? {}) as Record<string, unknown>,
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
},
|
|
643
|
+
});
|
|
644
|
+
unwatchers.push(unwatch);
|
|
645
|
+
};
|
|
646
|
+
|
|
647
|
+
watchEvent('MarketInitialized');
|
|
648
|
+
watchEvent('TokensMinted');
|
|
649
|
+
watchEvent('MarketAsserted');
|
|
650
|
+
watchEvent('MarketResolved');
|
|
651
|
+
watchEvent('AssertionFailed');
|
|
652
|
+
watchEvent('AssertionDisputed');
|
|
653
|
+
watchEvent('TokensSettled');
|
|
654
|
+
|
|
655
|
+
// Return a single unwatch function that stops all watchers
|
|
656
|
+
return () => {
|
|
657
|
+
for (const unwatch of unwatchers) {
|
|
658
|
+
unwatch();
|
|
659
|
+
}
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/**
|
|
664
|
+
* Watch for AgentRegistered events from the AgentRegistry.
|
|
665
|
+
*
|
|
666
|
+
* @param callback - Function called with (agent address, name) for each registration.
|
|
667
|
+
* @returns An unwatch function. Call it to stop watching.
|
|
668
|
+
*/
|
|
669
|
+
watchAgentRegistrations(
|
|
670
|
+
callback: (agent: `0x${string}`, name: string) => void,
|
|
671
|
+
): () => void {
|
|
672
|
+
return this.publicClient.watchContractEvent({
|
|
673
|
+
address: this.config.contracts.agentRegistry,
|
|
674
|
+
abi: agentRegistryAbi,
|
|
675
|
+
eventName: 'AgentRegistered',
|
|
676
|
+
onLogs: (logs: Log[]) => {
|
|
677
|
+
for (const log of logs) {
|
|
678
|
+
const typedLog = log as Log & { args?: Record<string, unknown> };
|
|
679
|
+
const agent = (typedLog.args?.['agent'] as `0x${string}`) ?? '0x';
|
|
680
|
+
const name = (typedLog.args?.['name'] as string) ?? '';
|
|
681
|
+
callback(agent, name);
|
|
682
|
+
}
|
|
683
|
+
},
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
688
|
+
// Utility Methods
|
|
689
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
690
|
+
|
|
691
|
+
/**
|
|
692
|
+
* Get the address of the account associated with this client.
|
|
693
|
+
*
|
|
694
|
+
* @returns The account address, or undefined if read-only.
|
|
695
|
+
*/
|
|
696
|
+
getAddress(): `0x${string}` | undefined {
|
|
697
|
+
return this.account?.address;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
/**
|
|
701
|
+
* Get the ETH balance of the connected account.
|
|
702
|
+
*
|
|
703
|
+
* @returns The balance in wei.
|
|
704
|
+
*/
|
|
705
|
+
async getBalance(): Promise<bigint> {
|
|
706
|
+
const address = this.getAddress();
|
|
707
|
+
if (!address) {
|
|
708
|
+
throw new Error('ClawlogicClient: No account available (read-only client).');
|
|
709
|
+
}
|
|
710
|
+
return this.publicClient.getBalance({ address });
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
/**
|
|
714
|
+
* Get the ETH balance of any address.
|
|
715
|
+
*
|
|
716
|
+
* @param address - The address to check.
|
|
717
|
+
* @returns The balance in wei.
|
|
718
|
+
*/
|
|
719
|
+
async getBalanceOf(address: `0x${string}`): Promise<bigint> {
|
|
720
|
+
return this.publicClient.getBalance({ address });
|
|
721
|
+
}
|
|
722
|
+
}
|