theref-sdk 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.
package/README.md ADDED
@@ -0,0 +1,326 @@
1
+ # @theref/sdk
2
+
3
+ > Universal SDK for TheRef — the decentralized AI game referee on GenLayer.
4
+
5
+ Submit any game move in any format. TheRef's AI consensus judges it on-chain.
6
+
7
+ ---
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm install @theref/sdk
13
+ ```
14
+
15
+ ---
16
+
17
+ ## Quick Start
18
+
19
+ ```typescript
20
+ import { createTheRef } from "@theref/sdk";
21
+
22
+ const ref = createTheRef({
23
+ network: "bradbury",
24
+ privateKey: process.env.AGENT_KEY as `0x${string}`,
25
+ });
26
+
27
+ // Create a game
28
+ const gameId = await ref.createGame({
29
+ name: "Trivia",
30
+ player1: "Alice",
31
+ player2: "Bob",
32
+ maxRounds: 3,
33
+ });
34
+
35
+ // Submit a move — any format works
36
+ await ref.submitMove(gameId, "Alice", "The capital of Australia is Canberra, established 1913");
37
+ await ref.submitMove(gameId, "Bob", "Canberra");
38
+
39
+ // Judge — AI consensus decides the winner
40
+ const result = await ref.judgeGame(gameId);
41
+ console.log(result.winner); // "Alice"
42
+ ```
43
+
44
+ ---
45
+
46
+ ## Universal Move Format
47
+
48
+ The SDK accepts **any move format** and converts it to a string the AI judge can understand.
49
+
50
+ ### Strings (passthrough)
51
+ ```typescript
52
+ await ref.submitMove(gameId, "Zaid", "e4");
53
+ await ref.submitMove(gameId, "Zaid", "I choose Rock");
54
+ await ref.submitMove(gameId, "Zaid", "The answer is 42");
55
+ ```
56
+
57
+ ### Chess moves
58
+ ```typescript
59
+ // Algebraic notation
60
+ await ref.submitMove(gameId, "Zaid", "Nf3", "Chess");
61
+
62
+ // Move object
63
+ await ref.submitMove(gameId, "Zaid", { from: "g1", to: "f3" }, "Chess");
64
+ // → "g1-f3"
65
+
66
+ // With piece
67
+ await ref.submitMove(gameId, "Zaid", { piece: "knight", from: "g1", to: "f3" });
68
+ // → "Nf3"
69
+
70
+ // Coordinate array [fromFile, fromRank, toFile, toRank]
71
+ await ref.submitMove(gameId, "Zaid", [6, 0, 5, 2]);
72
+ // → "g1-f3"
73
+ ```
74
+
75
+ ### Rock Paper Scissors
76
+ ```typescript
77
+ await ref.submitMove(gameId, "Zaid", "rock"); // → "Rock"
78
+ await ref.submitMove(gameId, "Zaid", { choice: "paper" }); // → "Paper"
79
+ await ref.submitMove(gameId, "Zaid", 0); // → "Rock" (0=Rock, 1=Paper, 2=Scissors)
80
+ ```
81
+
82
+ ### Combat games (RPG, Pokemon, fighting games)
83
+ ```typescript
84
+ // Pokemon battle
85
+ await ref.submitMove(gameId, "Ash", {
86
+ action: "attack",
87
+ move: "Thunderbolt",
88
+ target: "Charizard",
89
+ power: 90,
90
+ type: "Electric",
91
+ });
92
+ // → "Ash uses Thunderbolt on Charizard (power: 90) [Electric type]"
93
+
94
+ // Fighting game
95
+ await ref.submitMove(gameId, "Ryu", {
96
+ special: "Hadouken",
97
+ combo: ["down", "forward", "punch"],
98
+ });
99
+ // → "uses Hadouken via combo: down+forward+punch special: Hadouken"
100
+
101
+ // Card game
102
+ await ref.submitMove(gameId, "Player1", {
103
+ action: "play_card",
104
+ card: "Fireball",
105
+ target: "enemy_hero",
106
+ mana_cost: 4,
107
+ });
108
+ // → "play_card on enemy_hero (mana: 4)"
109
+ ```
110
+
111
+ ### Strategy / board games
112
+ ```typescript
113
+ await ref.submitMove(gameId, "Commander", {
114
+ action: "deploy",
115
+ unit: "Tank",
116
+ from: { x: 2, y: 3 },
117
+ to: { x: 5, y: 7 },
118
+ attack: "Artillery",
119
+ });
120
+ // → "deploy Tank from {"x":2,"y":3} to {"x":5,"y":7} attacking with Artillery"
121
+ ```
122
+
123
+ ### Any object — auto-flattened
124
+ ```typescript
125
+ await ref.submitMove(gameId, "Player", {
126
+ turn: 5,
127
+ decision: "advance",
128
+ units: ["Archer", "Knight"],
129
+ target: { zone: "north", priority: "high" },
130
+ });
131
+ // → "turn: 5, decision: advance, units: [Archer, Knight], target.zone: north, target.priority: high"
132
+ ```
133
+
134
+ ### Arrays
135
+ ```typescript
136
+ await ref.submitMove(gameId, "Player", ["Attack", "North", "With cavalry"]);
137
+ // → "Attack, North, With cavalry"
138
+ ```
139
+
140
+ ---
141
+
142
+ ## Game Lifecycle
143
+
144
+ ### Full game loop
145
+ ```typescript
146
+ const result = await ref.playGame(
147
+ gameId,
148
+ "MyAgent",
149
+ true, // isPlayer1
150
+ async (state, round) => {
151
+ // Your move generation logic here
152
+ // Return ANY format — SDK normalizes it
153
+ return `My answer for round ${round}`;
154
+ },
155
+ "Trivia", // game hint for better normalization
156
+ );
157
+
158
+ console.log(`Winner: ${result.winner}`);
159
+ ```
160
+
161
+ ### Manual control
162
+ ```typescript
163
+ // Wait for opponent's move
164
+ const opponentMove = await ref.waitForOpponentMove(gameId, 1, true);
165
+
166
+ // Submit your move
167
+ await ref.submitMove(gameId, "Alice", myMove);
168
+
169
+ // Wait for game to complete
170
+ const state = await ref.waitForStatus(gameId, "completed");
171
+
172
+ // Judge
173
+ const result = await ref.judgeGame(gameId);
174
+ ```
175
+
176
+ ---
177
+
178
+ ## Leaderboard
179
+
180
+ ```typescript
181
+ // All players
182
+ const lb = await ref.getLeaderboard("Chess", "all");
183
+
184
+ // Agents only
185
+ const agents = await ref.getLeaderboard("Trivia", "agent");
186
+
187
+ // Top 10
188
+ const top = await ref.getTopPlayers("Chess", 10);
189
+
190
+ // Single player stats
191
+ const stats = await ref.getPlayerStats("Chess", "MyAgent", "agent");
192
+ console.log(`W:${stats.wins} L:${stats.losses} Score:${stats.score}`);
193
+ ```
194
+
195
+ ---
196
+
197
+ ## Tournaments
198
+
199
+ ```typescript
200
+ // Create
201
+ const tid = await ref.createTournament({
202
+ name: "Trivia Championship",
203
+ gameName: "Trivia",
204
+ format: "single_elimination",
205
+ maxPlayers: 4,
206
+ });
207
+
208
+ // Join
209
+ await ref.joinTournament(tid, "MyAgent", "agent");
210
+
211
+ // Start
212
+ await ref.startTournament(tid);
213
+
214
+ // Get bracket
215
+ const tournament = await ref.getTournament(tid);
216
+ console.log(tournament.bracket);
217
+
218
+ // Record match result
219
+ await ref.recordMatchResult(tid, 1, "MyAgent");
220
+ ```
221
+
222
+ ---
223
+
224
+ ## Networks
225
+
226
+ ```typescript
227
+ // Bradbury Testnet (public, real AI consensus, requires GEN)
228
+ const ref = createTheRef({ network: "bradbury", privateKey: "0x..." });
229
+
230
+ // Studionet (development, real AI consensus, no gas cost)
231
+ const ref = createTheRef({ network: "studionet" });
232
+
233
+ // Custom network
234
+ const ref = createTheRef({
235
+ network: {
236
+ id: "bradbury",
237
+ rpc: "https://rpc-bradbury.genlayer.com",
238
+ chainId: 4221,
239
+ addresses: {
240
+ CORE: "0xA29CfFC83d32fe924cFf1F1bDCf21555CCC96206",
241
+ LB: "0x5D417F296b17656c9b950236feE66F63E22d8A54",
242
+ ORG: "0x440b28afc1804fc1E4AA8f5b559C18F7bCf43B3A",
243
+ FEE: "0x88A0A4d573fD9C63433E457e94d266D7904278C2",
244
+ TRN: "0xbcc0E82a17491297E0c4938606624Fa04e6abA1B",
245
+ },
246
+ },
247
+ privateKey: "0x...",
248
+ });
249
+ ```
250
+
251
+ ---
252
+
253
+ ## Move Normalization Only
254
+
255
+ Test normalization without submitting:
256
+
257
+ ```typescript
258
+ import { normalizeMove } from "@theref/sdk";
259
+
260
+ const result = normalizeMove({ from: "e2", to: "e4" }, "Chess");
261
+ console.log(result.text); // "e2-e4"
262
+ console.log(result.adapter); // "chess"
263
+
264
+ const rps = normalizeMove({ choice: "rock" });
265
+ console.log(rps.text); // "Rock"
266
+ console.log(rps.adapter); // "rps"
267
+
268
+ const combat = normalizeMove({
269
+ action: "attack",
270
+ move: "Thunderbolt",
271
+ target: "Pikachu",
272
+ });
273
+ console.log(combat.text); // "uses Thunderbolt on Pikachu"
274
+ console.log(combat.adapter); // "combat"
275
+ ```
276
+
277
+ ---
278
+
279
+ ## API Reference
280
+
281
+ ### `createTheRef(config)`
282
+ Factory function. Returns a `TheRefClient`.
283
+
284
+ ### `TheRefClient`
285
+
286
+ | Method | Description |
287
+ |---|---|
288
+ | `createGame(options)` | Create a new game. Returns game ID. |
289
+ | `submitMove(gameId, player, move, hint?)` | Submit any move format. Returns `{txHash, normalizedMove}`. |
290
+ | `judgeGame(gameId)` | Trigger AI consensus. Returns `JudgmentResult`. |
291
+ | `endGame(gameId)` | End open-ended game. Returns `JudgmentResult`. |
292
+ | `getGameState(gameId)` | Get full game state. |
293
+ | `getActiveGames()` | Get all active games. |
294
+ | `waitForOpponentMove(gameId, round, isPlayer1)` | Poll until opponent submits. |
295
+ | `waitForBothMoves(gameId, round)` | Poll until both moves are in. |
296
+ | `waitForStatus(gameId, status)` | Poll until game reaches status. |
297
+ | `playGame(gameId, player, isP1, moveFn, hint?)` | Full automated game loop. |
298
+ | `getLeaderboard(game, type?)` | Get leaderboard entries. |
299
+ | `getTopPlayers(game, n?)` | Get top N players. |
300
+ | `getPlayerStats(game, player, type?)` | Get single player stats. |
301
+ | `createTournament(options)` | Create a tournament. |
302
+ | `joinTournament(tid, player, type?)` | Join a tournament. |
303
+ | `startTournament(tid)` | Start the bracket. |
304
+ | `getTournament(tid)` | Get tournament state. |
305
+ | `listTournaments()` | List all tournaments. |
306
+ | `recordMatchResult(tid, matchId, winner)` | Record match outcome. |
307
+ | `normalizeMove(move, hint?)` | Normalize without submitting. |
308
+
309
+ ---
310
+
311
+ ## Contract Addresses
312
+
313
+ ### Bradbury Testnet
314
+ | Contract | Address |
315
+ |---|---|
316
+ | RefereeCore | `0xA29CfFC83d32fe924cFf1F1bDCf21555CCC96206` |
317
+ | LeaderboardVault | `0x5D417F296b17656c9b950236feE66F63E22d8A54` |
318
+ | OrganizerRegistry | `0x440b28afc1804fc1E4AA8f5b559C18F7bCf43B3A` |
319
+ | FeeManager | `0x88A0A4d573fD9C63433E457e94d266D7904278C2` |
320
+ | TournamentEngine | `0xbcc0E82a17491297E0c4938606624Fa04e6abA1B` |
321
+
322
+ ---
323
+
324
+ ## License
325
+
326
+ MIT — built by [0xZaid10](https://github.com/0xZaid10)
Binary file
@@ -0,0 +1,229 @@
1
+ type NetworkId = "bradbury" | "studionet";
2
+ interface NetworkConfig {
3
+ id: NetworkId;
4
+ rpc: string;
5
+ chainId: number;
6
+ addresses: ContractAddresses;
7
+ }
8
+ interface ContractAddresses {
9
+ CORE: string;
10
+ LB: string;
11
+ ORG: string;
12
+ FEE: string;
13
+ TRN: string;
14
+ }
15
+ interface TheRefConfig {
16
+ network: NetworkId | NetworkConfig;
17
+ privateKey?: `0x${string}`;
18
+ walletAddress?: `0x${string}`;
19
+ wsUrl?: string;
20
+ retries?: number;
21
+ pollInterval?: number;
22
+ }
23
+ type GameStatus = "waiting" | "active" | "completed" | "draw";
24
+ type PlayerType = "human" | "agent";
25
+ interface CreateGameOptions {
26
+ name: string;
27
+ rules?: string;
28
+ player1: string;
29
+ player2?: string;
30
+ maxRounds?: number;
31
+ visibility?: "public" | "private";
32
+ agent1?: `0x${string}`;
33
+ agent2?: `0x${string}`;
34
+ }
35
+ interface GameState {
36
+ gameId: string;
37
+ gameName: string;
38
+ status: GameStatus;
39
+ player1: string;
40
+ player2: string;
41
+ agent1: string;
42
+ agent2: string;
43
+ maxRounds: number;
44
+ roundCount: number;
45
+ judgedThrough: number;
46
+ rules: string;
47
+ winner: string;
48
+ score: Record<string, number>;
49
+ playerTypes: Record<string, PlayerType>;
50
+ rounds: RoundResult[];
51
+ caller: string;
52
+ }
53
+ interface RoundResult {
54
+ roundNumber: number;
55
+ movePlayer1: string;
56
+ movePlayer2: string;
57
+ result: "player1" | "player2" | "draw" | "pending";
58
+ reasonType: "normal" | "invalid_move";
59
+ invalidPlayer: "none" | "player1" | "player2";
60
+ reasoning: string;
61
+ confidence: number;
62
+ status: string;
63
+ }
64
+ interface JudgmentResult {
65
+ winner: string;
66
+ isDraw: boolean;
67
+ score: Record<string, number>;
68
+ rounds: RoundResult[];
69
+ txHash: string;
70
+ payload: string;
71
+ }
72
+ type AnyMove = string | number | boolean | AnyMove[] | {
73
+ [key: string]: AnyMove;
74
+ };
75
+ interface NormalizedMove {
76
+ raw: AnyMove;
77
+ text: string;
78
+ adapter: string;
79
+ }
80
+ interface CreateTournamentOptions {
81
+ name: string;
82
+ gameName: string;
83
+ format: "single_elimination" | "round_robin" | "swiss";
84
+ maxPlayers: number;
85
+ rules?: string;
86
+ roundsPerMatch?: number;
87
+ prizeSplit?: number[];
88
+ }
89
+ interface Tournament {
90
+ tid: string;
91
+ name: string;
92
+ gameName: string;
93
+ format: string;
94
+ maxPlayers: number;
95
+ status: string;
96
+ players: string[];
97
+ bracket: BracketMatch[];
98
+ winner: string;
99
+ }
100
+ interface BracketMatch {
101
+ matchId: number;
102
+ round: number;
103
+ player1: string;
104
+ player2: string;
105
+ gameId: string;
106
+ winner: string;
107
+ status: string;
108
+ }
109
+ interface LeaderboardEntry {
110
+ player: string;
111
+ wins: number;
112
+ losses: number;
113
+ draws: number;
114
+ score: number;
115
+ playerType: PlayerType;
116
+ }
117
+ interface PlayerStats extends LeaderboardEntry {
118
+ games: number;
119
+ }
120
+
121
+ declare class TheRefClient {
122
+ private network;
123
+ private glClient;
124
+ private retries;
125
+ private pollInterval;
126
+ private wsUrl;
127
+ constructor(config: TheRefConfig);
128
+ private write;
129
+ private read;
130
+ private get CORE();
131
+ private get LB();
132
+ private get TRN();
133
+ private mapGameState;
134
+ /**
135
+ * Create a new game. Returns the game ID.
136
+ */
137
+ createGame(options: CreateGameOptions): Promise<string>;
138
+ /**
139
+ * Submit a move for a player. Accepts ANY move format — string, object, array, etc.
140
+ * The SDK automatically normalizes it to a string the AI judge can understand.
141
+ */
142
+ submitMove(gameId: string, playerName: string, move: AnyMove, gameHint?: string): Promise<{
143
+ txHash: string;
144
+ normalizedMove: string;
145
+ }>;
146
+ /**
147
+ * Judge the game — triggers AI consensus on all pending rounds.
148
+ */
149
+ judgeGame(gameId: string): Promise<JudgmentResult>;
150
+ /**
151
+ * End an open-ended game (max_rounds = 0). Only callable by the game creator.
152
+ */
153
+ endGame(gameId: string): Promise<JudgmentResult>;
154
+ /**
155
+ * Get the full game state.
156
+ */
157
+ getGameState(gameId: string): Promise<GameState>;
158
+ /**
159
+ * Get all active games.
160
+ */
161
+ getActiveGames(): Promise<GameState[]>;
162
+ /**
163
+ * Get total number of games.
164
+ */
165
+ getTotalGames(): Promise<number>;
166
+ /**
167
+ * Wait until both players have submitted their move for a given round.
168
+ * Polls every `pollInterval` ms.
169
+ */
170
+ waitForBothMoves(gameId: string, roundNumber: number): Promise<RoundResult>;
171
+ /**
172
+ * Wait until the opponent has submitted their move for a round.
173
+ * isPlayer1: true if you are player1, false if player2.
174
+ */
175
+ waitForOpponentMove(gameId: string, roundNumber: number, isPlayer1: boolean): Promise<string>;
176
+ /**
177
+ * Wait until the game reaches a specific status.
178
+ */
179
+ waitForStatus(gameId: string, status: GameStatus): Promise<GameState>;
180
+ /**
181
+ * Play a full game automatically.
182
+ * moveFn is called for each round — return your move in any format.
183
+ */
184
+ playGame(gameId: string, playerName: string, isPlayer1: boolean, moveFn: (state: GameState, round: number) => Promise<AnyMove>, gameHint?: string): Promise<JudgmentResult>;
185
+ getLeaderboard(gameName: string, playerType?: PlayerType | "all"): Promise<LeaderboardEntry[]>;
186
+ getTopPlayers(gameName: string, n?: number): Promise<LeaderboardEntry[]>;
187
+ getPlayerStats(gameName: string, playerName: string, playerType?: PlayerType | "all"): Promise<PlayerStats | null>;
188
+ createTournament(options: CreateTournamentOptions): Promise<string>;
189
+ joinTournament(tid: string, playerName: string, playerType?: PlayerType): Promise<void>;
190
+ startTournament(tid: string): Promise<void>;
191
+ getTournament(tid: string): Promise<Tournament | null>;
192
+ listTournaments(): Promise<Tournament[]>;
193
+ recordMatchResult(tid: string, matchId: number, winner: string): Promise<void>;
194
+ /** Normalize any move to a string without submitting */
195
+ normalizeMove(move: AnyMove, gameHint?: string): NormalizedMove;
196
+ /** Sleep helper */
197
+ private sleep;
198
+ }
199
+
200
+ declare function normalizeMove(move: AnyMove, gameHint?: string): NormalizedMove;
201
+
202
+ declare const NETWORKS: Record<NetworkId, NetworkConfig>;
203
+ declare function resolveNetwork(network: NetworkId | NetworkConfig): NetworkConfig;
204
+ declare function gidToNum(gid: string): number;
205
+
206
+ /**
207
+ * Create a TheRef client.
208
+ *
209
+ * @example
210
+ * // Agent (server-side)
211
+ * const ref = createTheRef({
212
+ * network: "bradbury",
213
+ * privateKey: process.env.AGENT_KEY as `0x${string}`,
214
+ * });
215
+ *
216
+ * @example
217
+ * // Browser wallet
218
+ * const ref = createTheRef({
219
+ * network: "bradbury",
220
+ * walletAddress: "0xYourWallet",
221
+ * });
222
+ *
223
+ * @example
224
+ * // Development (Studionet, no key needed)
225
+ * const ref = createTheRef({ network: "studionet" });
226
+ */
227
+ declare function createTheRef(config: TheRefConfig): TheRefClient;
228
+
229
+ export { type AnyMove, type BracketMatch, type ContractAddresses, type CreateGameOptions, type CreateTournamentOptions, type GameState, type GameStatus, type JudgmentResult, type LeaderboardEntry, NETWORKS, type NetworkConfig, type NetworkId, type NormalizedMove, type PlayerStats, type PlayerType, type RoundResult, TheRefClient, type TheRefConfig, type Tournament, createTheRef, gidToNum, normalizeMove, resolveNetwork };