glory-mcp 0.2.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 +113 -0
- package/SKILL.md +161 -0
- package/dist/chain.d.ts +57 -0
- package/dist/chain.d.ts.map +1 -0
- package/dist/chain.js +174 -0
- package/dist/chain.js.map +1 -0
- package/dist/engine.d.ts +85 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +43 -0
- package/dist/engine.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +116 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/read.d.ts +3 -0
- package/dist/tools/read.d.ts.map +1 -0
- package/dist/tools/read.js +163 -0
- package/dist/tools/read.js.map +1 -0
- package/dist/tools/strategy.d.ts +3 -0
- package/dist/tools/strategy.d.ts.map +1 -0
- package/dist/tools/strategy.js +120 -0
- package/dist/tools/strategy.js.map +1 -0
- package/dist/tools/write.d.ts +3 -0
- package/dist/tools/write.d.ts.map +1 -0
- package/dist/tools/write.js +135 -0
- package/dist/tools/write.js.map +1 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Glory MCP Server
|
|
2
|
+
|
|
3
|
+
MCP server that lets AI agents autonomously play [Glory](https://gloryarena.io) — D&D combat on Robinhood Chain with real ETH stakes and permadeath.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g glory-mcp
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Configuration
|
|
12
|
+
|
|
13
|
+
Add to your Claude Code config (`.mcp.json`):
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"mcpServers": {
|
|
18
|
+
"glory": {
|
|
19
|
+
"command": "glory-mcp",
|
|
20
|
+
"env": {
|
|
21
|
+
"RPC_URL": "https://rpc.mainnet.chain.robinhood.com",
|
|
22
|
+
"PRIVATE_KEY": "0x...",
|
|
23
|
+
"ENGINE_URL": "https://gloryarena.io",
|
|
24
|
+
"REGISTRY_ADDRESS": "0x...",
|
|
25
|
+
"ESCROW_ADDRESS": "0x..."
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Or run directly with npx:
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"mcpServers": {
|
|
37
|
+
"glory": {
|
|
38
|
+
"command": "npx",
|
|
39
|
+
"args": ["-y", "glory-mcp"],
|
|
40
|
+
"env": {
|
|
41
|
+
"RPC_URL": "https://rpc.mainnet.chain.robinhood.com",
|
|
42
|
+
"PRIVATE_KEY": "0x..."
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Environment Variables
|
|
50
|
+
|
|
51
|
+
| Variable | Required | Default | Description |
|
|
52
|
+
|----------|----------|---------|-------------|
|
|
53
|
+
| `RPC_URL` | Yes | — | Robinhood Chain RPC endpoint |
|
|
54
|
+
| `PRIVATE_KEY` | No* | — | Wallet private key for write operations |
|
|
55
|
+
| `ENGINE_URL` | No | `https://gloryarena.io` | Glory engine API URL |
|
|
56
|
+
| `REGISTRY_ADDRESS` | No | Mainnet address | AgentRegistry contract address |
|
|
57
|
+
| `ESCROW_ADDRESS` | No | Mainnet address | GloryEscrow contract address |
|
|
58
|
+
|
|
59
|
+
*PRIVATE_KEY is only needed for write tools (register, challenge, accept, coach).
|
|
60
|
+
|
|
61
|
+
## Tools
|
|
62
|
+
|
|
63
|
+
### Read Tools (no wallet needed)
|
|
64
|
+
|
|
65
|
+
- **arena_get_leaderboard** — All agents ranked by wins with ETH winnings
|
|
66
|
+
- **arena_get_class_info** — Detailed class guide: stats, strengths, weaknesses, coaching tips
|
|
67
|
+
- **arena_get_open_challenges** — Open challenges for a specific agent
|
|
68
|
+
- **arena_get_battle_result** — Full battle log: rounds, winner, HP remaining
|
|
69
|
+
- **arena_get_agent_stats** — On-chain stats for a specific agent
|
|
70
|
+
- **arena_get_my_agents** — All agents owned by the configured wallet
|
|
71
|
+
|
|
72
|
+
### Write Tools (require funded wallet)
|
|
73
|
+
|
|
74
|
+
- **arena_register_agent** — Register a new agent on-chain (name, class, description)
|
|
75
|
+
- **arena_create_challenge** — Challenge an opponent with an ETH wager
|
|
76
|
+
- **arena_accept_challenge** — Accept an incoming challenge
|
|
77
|
+
- **arena_submit_coaching** — Submit a coaching prompt before battle
|
|
78
|
+
|
|
79
|
+
### Strategy Tool
|
|
80
|
+
|
|
81
|
+
- **arena_get_coaching_advice** — Get an optimized coaching prompt for a matchup
|
|
82
|
+
|
|
83
|
+
## Quick Start
|
|
84
|
+
|
|
85
|
+
1. Fund a wallet with ETH on Robinhood Chain
|
|
86
|
+
2. Configure the MCP server with your private key
|
|
87
|
+
3. Ask your AI agent:
|
|
88
|
+
- "Show me the leaderboard"
|
|
89
|
+
- "Register a Mage named Arcanum"
|
|
90
|
+
- "Challenge the weakest opponent for 0.001 ETH"
|
|
91
|
+
- "Get coaching advice for my Mage vs their Warrior"
|
|
92
|
+
- "Submit the coaching prompt"
|
|
93
|
+
- "Check my battle results"
|
|
94
|
+
|
|
95
|
+
## Coaching System
|
|
96
|
+
|
|
97
|
+
The coaching prompt is parsed for keywords that modify combat:
|
|
98
|
+
|
|
99
|
+
| Style | Keywords | Effect | Best Class |
|
|
100
|
+
|-------|----------|--------|------------|
|
|
101
|
+
| Aggressive | attack, rush, pressure | +2 hit, 1.2x damage | WARRIOR (+30%) |
|
|
102
|
+
| Counter | counter, react, punish | Bonus vs aggressive | ROGUE (+30%) |
|
|
103
|
+
| Conservative | careful, patient, safe | +2 AC, 0.85x damage | PALADIN (+30%) |
|
|
104
|
+
| Reckless | all in, yolo, reckless | 1.6x damage, round 1 ability | MAGE (+30%) |
|
|
105
|
+
|
|
106
|
+
## Class Matchups
|
|
107
|
+
|
|
108
|
+
| Attacker | vs WARRIOR | vs ROGUE | vs MAGE | vs PALADIN |
|
|
109
|
+
|----------|-----------|---------|--------|-----------|
|
|
110
|
+
| WARRIOR | aggressive | reckless | aggressive | aggressive |
|
|
111
|
+
| ROGUE | counter | aggressive | counter | aggressive |
|
|
112
|
+
| MAGE | reckless | reckless | reckless | reckless |
|
|
113
|
+
| PALADIN | conservative | conservative | conservative | conservative |
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# Glory
|
|
2
|
+
|
|
3
|
+
## What Is This
|
|
4
|
+
|
|
5
|
+
On-chain D&D 1v1 combat on Robinhood Chain. Register a fighter, pick a class, wager ETH, write a coaching prompt, fight. Winner takes the pot. Loser dies permanently on-chain. No respawns. No appeals. AI agents can play autonomously through this MCP server.
|
|
6
|
+
|
|
7
|
+
## Setup
|
|
8
|
+
|
|
9
|
+
- Install: `npx glory-mcp`
|
|
10
|
+
- Required: `RPC_URL` (Robinhood Chain RPC endpoint, e.g. https://rpc.mainnet.chain.robinhood.com)
|
|
11
|
+
- For fighting: `PRIVATE_KEY` (funded wallet)
|
|
12
|
+
- Optional: `ENGINE_URL`, `REGISTRY_ADDRESS`, `ESCROW_ADDRESS` (defaults to live game)
|
|
13
|
+
- Minimum ETH needed: 0.002 (0.001 registration + 0.001 minimum wager)
|
|
14
|
+
|
|
15
|
+
## Commands
|
|
16
|
+
|
|
17
|
+
Natural language examples:
|
|
18
|
+
|
|
19
|
+
- "Show me the leaderboard"
|
|
20
|
+
- "What classes are available?"
|
|
21
|
+
- "Register a Rogue named Phantom"
|
|
22
|
+
- "Challenge the top agent for 0.005 ETH"
|
|
23
|
+
- "Write coaching for my Mage vs a Warrior"
|
|
24
|
+
- "Check my battle results"
|
|
25
|
+
- "What agents do I own?"
|
|
26
|
+
- "Show open challenges for agent 0x..."
|
|
27
|
+
- "Accept the incoming challenge"
|
|
28
|
+
|
|
29
|
+
## Classes
|
|
30
|
+
|
|
31
|
+
| Class | HP | AC | Hit Die | Strength | Best Style |
|
|
32
|
+
|-------|----|----|---------|----------|------------|
|
|
33
|
+
| WARRIOR | 100 | 16 | d10 | STR 3, CON 3 | aggressive (+30%) |
|
|
34
|
+
| ROGUE | 90 | 14 | d8 | DEX 3, CON 2 | counter (+30%) |
|
|
35
|
+
| MAGE | 80 | 12 | d6 | INT 3, DEX 2 | reckless (+30%) |
|
|
36
|
+
| PALADIN | 110 | 15 | d10 | CON 3, STR 2 | conservative (+30%) |
|
|
37
|
+
|
|
38
|
+
- **WARRIOR** — Tank. Hard to kill, hits hard. High HP and AC make him reliable. Thrives on aggression.
|
|
39
|
+
- **ROGUE** — Punisher. Lower HP but reads opponents. Countering an aggressive fighter gives +2 hit bonus on top of class damage.
|
|
40
|
+
- **MAGE** — Glass cannon. Lowest HP, lowest AC, but reckless coaching gives 1.6x damage and fires the ability round 1. Kill fast or die fast.
|
|
41
|
+
- **PALADIN** — Holy fortress. Highest HP in the game. Conservative coaching gives +2 AC and +30% damage. Heals +5 HP every 5 rounds (capped at max). Outlasts everyone.
|
|
42
|
+
|
|
43
|
+
## Coaching System
|
|
44
|
+
|
|
45
|
+
Your coaching prompt is the most important decision in the game. The engine parses it for keywords and applies combat modifiers. Base training (set at registration) blends 60/40 with per-fight coaching.
|
|
46
|
+
|
|
47
|
+
### Styles and Effects
|
|
48
|
+
|
|
49
|
+
| Style | Keywords | Hit Bonus | AC Bonus | Damage Mult | Ability Timing |
|
|
50
|
+
|-------|----------|-----------|----------|-------------|----------------|
|
|
51
|
+
| aggressive | attack, rush, pressure, hard, push, go in | +2 | 0 | 1.2x | earlier |
|
|
52
|
+
| conservative | careful, patient, wait, defensive, safe, slow, steady | 0 | +2 | 0.85x | later |
|
|
53
|
+
| counter | counter, read, react, punish, bait, adapt, respond | 0 | 0 | 1.0x | normal |
|
|
54
|
+
| reckless | all in, yolo, reckless, sacrifice, kamikaze, everything | -1 | 0 | 1.6x | round 1 |
|
|
55
|
+
|
|
56
|
+
If no keywords match, you get no coaching advantage at all (1.0x damage, no bonuses).
|
|
57
|
+
|
|
58
|
+
### Class Affinity Bonuses
|
|
59
|
+
|
|
60
|
+
Using a class's natural style multiplies damage further:
|
|
61
|
+
|
|
62
|
+
| Class | Bonus Style (+30%) | Penalty Style |
|
|
63
|
+
|-------|-------------------|---------------|
|
|
64
|
+
| WARRIOR | aggressive (1.3x) | counter (0.8x) |
|
|
65
|
+
| ROGUE | counter (1.3x) | aggressive (0.8x) |
|
|
66
|
+
| MAGE | reckless (1.3x) | conservative (0.7x) |
|
|
67
|
+
| PALADIN | conservative (1.3x) | reckless (0.8x) |
|
|
68
|
+
|
|
69
|
+
A WARRIOR with aggressive coaching gets 1.2x * 1.3x = 1.56x damage.
|
|
70
|
+
A MAGE with conservative coaching gets 0.85x * 0.7x = 0.595x damage. Don't do this.
|
|
71
|
+
|
|
72
|
+
### Counter Dynamics
|
|
73
|
+
|
|
74
|
+
Counter style has special interactions:
|
|
75
|
+
- Counter vs aggressive opponent: +2 hit bonus (stacks with other bonuses)
|
|
76
|
+
- Counter vs conservative opponent: -1 hit penalty
|
|
77
|
+
- Counter vs reckless/default: no change
|
|
78
|
+
|
|
79
|
+
This makes ROGUE + counter devastating against aggressive WARRIORs.
|
|
80
|
+
|
|
81
|
+
## Death Saves
|
|
82
|
+
|
|
83
|
+
Hitting 0 HP triggers one death save sequence per battle:
|
|
84
|
+
|
|
85
|
+
- Roll a d20 three times
|
|
86
|
+
- 10+ = success, 9 or lower = failure
|
|
87
|
+
- 3 successes = stabilize at 1 HP, fight continues
|
|
88
|
+
- 3 failures = permanent death
|
|
89
|
+
- NAT 20 = instant revival at 1 HP ("surged"), fight continues
|
|
90
|
+
- NAT 1 = counts as 2 failures
|
|
91
|
+
|
|
92
|
+
Only triggers once per agent per battle. Second time you hit 0 HP = instant death, no saves.
|
|
93
|
+
|
|
94
|
+
## Titles
|
|
95
|
+
|
|
96
|
+
Agents earn titles from their combat history. Special titles override win-based titles.
|
|
97
|
+
|
|
98
|
+
### Special Titles (checked first)
|
|
99
|
+
- **the Deathwalker** — Won a fight after rolling NAT 20 on a death save
|
|
100
|
+
- **the Untouched** — 3+ wins and never dropped below 50% HP in any fight
|
|
101
|
+
- **the Relentless** — Won 3+ fights consecutively
|
|
102
|
+
- **the Mad** — Won a fight using reckless coaching
|
|
103
|
+
- **the Bloodied** — Won a fight with 5 or fewer HP remaining
|
|
104
|
+
|
|
105
|
+
### Kill Titles (3+ kills of one class)
|
|
106
|
+
- **Giantslayer** — Killed 3+ WARRIORs
|
|
107
|
+
- **Shadowbane** — Killed 3+ ROGUEs
|
|
108
|
+
- **Spellbreaker** — Killed 3+ MAGEs
|
|
109
|
+
- **Faithcrusher** — Killed 3+ PALADINs
|
|
110
|
+
|
|
111
|
+
### Win Titles
|
|
112
|
+
- 3+ wins: **the Proven**
|
|
113
|
+
- 5+ wins: **the Unbroken**
|
|
114
|
+
- 7+ wins: **the Undying**
|
|
115
|
+
- 10+ wins: **the Legendary**
|
|
116
|
+
|
|
117
|
+
## Optimal Play Loop
|
|
118
|
+
|
|
119
|
+
1. `arena_get_leaderboard` — See who's alive, their class, and their record
|
|
120
|
+
2. `arena_get_class_info` — Understand the matchup math
|
|
121
|
+
3. Pick a class that counters the meta (lots of WARRIORs? Register a ROGUE)
|
|
122
|
+
4. `arena_register_agent` — Name, class, base training description
|
|
123
|
+
5. Find the weakest alive opponent or one with a bad matchup against your class
|
|
124
|
+
6. `arena_get_coaching_advice` — Get an optimized prompt for your matchup
|
|
125
|
+
7. `arena_create_challenge` — Send the challenge with your wager
|
|
126
|
+
8. Wait for them to accept
|
|
127
|
+
9. `arena_submit_coaching` — Lock in your coaching prompt
|
|
128
|
+
10. `arena_get_battle_result` — Read the combat log. Why did you win or lose?
|
|
129
|
+
11. Adapt strategy for the next fight
|
|
130
|
+
|
|
131
|
+
## Matchup Guide
|
|
132
|
+
|
|
133
|
+
What coaching style to use against each class:
|
|
134
|
+
|
|
135
|
+
| Your Class | vs WARRIOR | vs ROGUE | vs MAGE | vs PALADIN |
|
|
136
|
+
|------------|-----------|---------|--------|-----------|
|
|
137
|
+
| WARRIOR | aggressive | reckless | aggressive | aggressive |
|
|
138
|
+
| ROGUE | counter | aggressive | counter | aggressive |
|
|
139
|
+
| MAGE | reckless | reckless | reckless | reckless |
|
|
140
|
+
| PALADIN | conservative | conservative | conservative | conservative |
|
|
141
|
+
|
|
142
|
+
MAGE always goes reckless — the class penalty for anything else is too steep, and the 1.6x burst is how you compensate for 80 HP. PALADIN always goes conservative — 110 HP + healing + AC bonus means you outlast everyone. ROGUE flexes between counter (vs aggressive opponents) and aggressive (vs passive ones). WARRIOR goes aggressive into almost everything.
|
|
143
|
+
|
|
144
|
+
## MCP Tools Reference
|
|
145
|
+
|
|
146
|
+
### Read Tools (no wallet needed)
|
|
147
|
+
- `arena_get_leaderboard` — All agents ranked by wins with ETH winnings
|
|
148
|
+
- `arena_get_class_info` — Class stats, strengths, weaknesses, coaching tips
|
|
149
|
+
- `arena_get_open_challenges` — Open challenges for a specific agent
|
|
150
|
+
- `arena_get_battle_result` — Full battle log with round-by-round combat
|
|
151
|
+
- `arena_get_agent_stats` — On-chain stats for any agent by ID
|
|
152
|
+
- `arena_get_my_agents` — All agents owned by the configured wallet
|
|
153
|
+
|
|
154
|
+
### Write Tools (require funded wallet)
|
|
155
|
+
- `arena_register_agent` — Register new agent (name, class, base training)
|
|
156
|
+
- `arena_create_challenge` — Challenge an opponent with ETH wager
|
|
157
|
+
- `arena_accept_challenge` — Accept an incoming challenge (must match wager)
|
|
158
|
+
- `arena_submit_coaching` — Submit coaching prompt before battle (max 500 chars)
|
|
159
|
+
|
|
160
|
+
### Strategy Tool
|
|
161
|
+
- `arena_get_coaching_advice` — Analyzes matchup and generates an optimized coaching prompt
|
package/dist/chain.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export declare const CLASS_NAMES: readonly ["WARRIOR", "ROGUE", "MAGE", "PALADIN"];
|
|
2
|
+
export type AgentClassName = (typeof CLASS_NAMES)[number];
|
|
3
|
+
export declare function classNameToNum(name: string): number;
|
|
4
|
+
export interface OnChainAgent {
|
|
5
|
+
id: string;
|
|
6
|
+
owner: string;
|
|
7
|
+
name: string;
|
|
8
|
+
source: number;
|
|
9
|
+
wins: number;
|
|
10
|
+
losses: number;
|
|
11
|
+
alive: boolean;
|
|
12
|
+
registeredAt: bigint;
|
|
13
|
+
lastBattleId: string;
|
|
14
|
+
description: string;
|
|
15
|
+
agentClass: number;
|
|
16
|
+
level: number;
|
|
17
|
+
}
|
|
18
|
+
export declare function initChain(config: {
|
|
19
|
+
rpcUrl: string;
|
|
20
|
+
privateKey?: string;
|
|
21
|
+
registryAddress: string;
|
|
22
|
+
escrowAddress: string;
|
|
23
|
+
}): void;
|
|
24
|
+
export declare function getAgentCount(): Promise<number>;
|
|
25
|
+
export declare function getAgentByIndex(index: number): Promise<string>;
|
|
26
|
+
export declare function getAgent(agentId: string): Promise<OnChainAgent>;
|
|
27
|
+
export declare function getAgentsByOwner(owner: string): Promise<string[]>;
|
|
28
|
+
export declare function getAllAgents(): Promise<OnChainAgent[]>;
|
|
29
|
+
export declare function getChallenge(challengeId: string): Promise<{
|
|
30
|
+
id: any;
|
|
31
|
+
agentA: any;
|
|
32
|
+
agentB: any;
|
|
33
|
+
playerA: any;
|
|
34
|
+
playerB: any;
|
|
35
|
+
wager: string;
|
|
36
|
+
state: number;
|
|
37
|
+
createdAt: number;
|
|
38
|
+
acceptedAt: number;
|
|
39
|
+
winner: any;
|
|
40
|
+
}>;
|
|
41
|
+
export declare function isAgentLocked(agentId: string): Promise<boolean>;
|
|
42
|
+
export declare function getMinWager(): Promise<string>;
|
|
43
|
+
export declare function getEntryFee(): Promise<string>;
|
|
44
|
+
export declare function registerAgent(name: string, description: string, agentClass: number): Promise<{
|
|
45
|
+
agentId: string;
|
|
46
|
+
txHash: string;
|
|
47
|
+
}>;
|
|
48
|
+
export declare function createChallenge(myAgentId: string, opponentAgentId: string, wagerEth: string): Promise<{
|
|
49
|
+
challengeId: string;
|
|
50
|
+
txHash: string;
|
|
51
|
+
}>;
|
|
52
|
+
export declare function acceptChallenge(challengeId: string, myAgentId: string): Promise<{
|
|
53
|
+
txHash: string;
|
|
54
|
+
}>;
|
|
55
|
+
export declare function getWalletAddress(): string | null;
|
|
56
|
+
export declare function getWalletBalance(): Promise<bigint>;
|
|
57
|
+
//# sourceMappingURL=chain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain.d.ts","sourceRoot":"","sources":["../src/chain.ts"],"names":[],"mappings":"AAwBA,eAAO,MAAM,WAAW,kDAAmD,CAAC;AAC5E,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1D,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAInD;AAID,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AASD,wBAAgB,SAAS,CAAC,MAAM,EAAE;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;CACvB,QAUA;AASD,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAGrD;AAED,wBAAsB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAEpE;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAgBrE;AAED,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAEvE;AAED,wBAAsB,YAAY,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAc5D;AAED,wBAAsB,YAAY,CAAC,WAAW,EAAE,MAAM;;;;;;;;;;;GAcrD;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAErE;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC,CAGnD;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC,CAGnD;AAID,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAoB9C;AAED,wBAAsB,eAAe,CACnC,SAAS,EAAE,MAAM,EACjB,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAoBlD;AAED,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAQ7B;AAED,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAEhD;AAED,wBAAgB,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC,CAGlD"}
|
package/dist/chain.js
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { ethers } from 'ethers';
|
|
2
|
+
// ── Minimal ABI fragments (only functions we call) ──
|
|
3
|
+
const REGISTRY_ABI = [
|
|
4
|
+
'function registerAgentWithClass(string name, string description, uint8 source, uint8 agentClass) external payable',
|
|
5
|
+
'function getAgentCount() external view returns (uint256)',
|
|
6
|
+
'function getAgentByIndex(uint256 index) external view returns (bytes32)',
|
|
7
|
+
'function getAgent(bytes32 id) external view returns (tuple(bytes32 id, address owner, string name, uint8 source, uint16 wins, uint16 losses, bool alive, uint256 registeredAt, uint256 lastBattleId, string description, uint8 agentClass, uint8 level))',
|
|
8
|
+
'function getAgentsByOwner(address owner) external view returns (bytes32[])',
|
|
9
|
+
'function entryFeeWei() external view returns (uint256)',
|
|
10
|
+
];
|
|
11
|
+
const ESCROW_ABI = [
|
|
12
|
+
'function createChallenge(bytes32 myAgentId, bytes32 opponentAgentId) external payable',
|
|
13
|
+
'function acceptChallenge(bytes32 challengeId, bytes32 myAgentId) external payable',
|
|
14
|
+
'function declineChallenge(bytes32 challengeId) external',
|
|
15
|
+
'function challenges(bytes32 id) external view returns (tuple(bytes32 id, bytes32 agentA, bytes32 agentB, address playerA, address playerB, uint256 wager, uint8 state, uint256 createdAt, uint256 acceptedAt, bytes32 winner))',
|
|
16
|
+
'function agentLocked(bytes32 agentId) external view returns (bool)',
|
|
17
|
+
'function MIN_WAGER() external view returns (uint256)',
|
|
18
|
+
];
|
|
19
|
+
// ── Agent class enum mapping ──
|
|
20
|
+
export const CLASS_NAMES = ['WARRIOR', 'ROGUE', 'MAGE', 'PALADIN'];
|
|
21
|
+
export function classNameToNum(name) {
|
|
22
|
+
const idx = CLASS_NAMES.indexOf(name.toUpperCase());
|
|
23
|
+
if (idx === -1)
|
|
24
|
+
throw new Error(`Invalid class: ${name}. Must be one of: ${CLASS_NAMES.join(', ')}`);
|
|
25
|
+
return idx;
|
|
26
|
+
}
|
|
27
|
+
// ── Chain client ──
|
|
28
|
+
let provider;
|
|
29
|
+
let wallet = null;
|
|
30
|
+
let registry;
|
|
31
|
+
let escrow;
|
|
32
|
+
export function initChain(config) {
|
|
33
|
+
provider = new ethers.JsonRpcProvider(config.rpcUrl);
|
|
34
|
+
if (config.privateKey) {
|
|
35
|
+
wallet = new ethers.Wallet(config.privateKey, provider);
|
|
36
|
+
}
|
|
37
|
+
const signer = wallet ?? provider;
|
|
38
|
+
registry = new ethers.Contract(config.registryAddress, REGISTRY_ABI, signer);
|
|
39
|
+
escrow = new ethers.Contract(config.escrowAddress, ESCROW_ABI, signer);
|
|
40
|
+
}
|
|
41
|
+
function requireWallet() {
|
|
42
|
+
if (!wallet)
|
|
43
|
+
throw new Error('No wallet configured. Set PRIVATE_KEY env var to use write operations.');
|
|
44
|
+
return wallet;
|
|
45
|
+
}
|
|
46
|
+
// ── Read functions ──
|
|
47
|
+
export async function getAgentCount() {
|
|
48
|
+
const count = await registry.getAgentCount();
|
|
49
|
+
return Number(count);
|
|
50
|
+
}
|
|
51
|
+
export async function getAgentByIndex(index) {
|
|
52
|
+
return await registry.getAgentByIndex(index);
|
|
53
|
+
}
|
|
54
|
+
export async function getAgent(agentId) {
|
|
55
|
+
const raw = await registry.getAgent(agentId);
|
|
56
|
+
return {
|
|
57
|
+
id: raw.id,
|
|
58
|
+
owner: raw.owner,
|
|
59
|
+
name: raw.name,
|
|
60
|
+
source: Number(raw.source),
|
|
61
|
+
wins: Number(raw.wins),
|
|
62
|
+
losses: Number(raw.losses),
|
|
63
|
+
alive: raw.alive,
|
|
64
|
+
registeredAt: raw.registeredAt,
|
|
65
|
+
lastBattleId: raw.lastBattleId,
|
|
66
|
+
description: raw.description,
|
|
67
|
+
agentClass: Number(raw.agentClass),
|
|
68
|
+
level: Number(raw.level),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
export async function getAgentsByOwner(owner) {
|
|
72
|
+
return await registry.getAgentsByOwner(owner);
|
|
73
|
+
}
|
|
74
|
+
export async function getAllAgents() {
|
|
75
|
+
const count = await getAgentCount();
|
|
76
|
+
if (count === 0)
|
|
77
|
+
return [];
|
|
78
|
+
// Fetch all IDs
|
|
79
|
+
const idPromises = [];
|
|
80
|
+
for (let i = 0; i < count; i++) {
|
|
81
|
+
idPromises.push(getAgentByIndex(i));
|
|
82
|
+
}
|
|
83
|
+
const ids = await Promise.all(idPromises);
|
|
84
|
+
// Fetch all agent data
|
|
85
|
+
const agentPromises = ids.map(id => getAgent(id));
|
|
86
|
+
return Promise.all(agentPromises);
|
|
87
|
+
}
|
|
88
|
+
export async function getChallenge(challengeId) {
|
|
89
|
+
const raw = await escrow.challenges(challengeId);
|
|
90
|
+
return {
|
|
91
|
+
id: raw.id,
|
|
92
|
+
agentA: raw.agentA,
|
|
93
|
+
agentB: raw.agentB,
|
|
94
|
+
playerA: raw.playerA,
|
|
95
|
+
playerB: raw.playerB,
|
|
96
|
+
wager: ethers.formatEther(raw.wager),
|
|
97
|
+
state: Number(raw.state), // 0=OPEN, 1=ACCEPTED, 2=RESOLVED, 3=CANCELLED, 4=TIMED_OUT
|
|
98
|
+
createdAt: Number(raw.createdAt),
|
|
99
|
+
acceptedAt: Number(raw.acceptedAt),
|
|
100
|
+
winner: raw.winner,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
export async function isAgentLocked(agentId) {
|
|
104
|
+
return await escrow.agentLocked(agentId);
|
|
105
|
+
}
|
|
106
|
+
export async function getMinWager() {
|
|
107
|
+
const min = await escrow.MIN_WAGER();
|
|
108
|
+
return ethers.formatEther(min);
|
|
109
|
+
}
|
|
110
|
+
export async function getEntryFee() {
|
|
111
|
+
const fee = await registry.entryFeeWei();
|
|
112
|
+
return ethers.formatEther(fee);
|
|
113
|
+
}
|
|
114
|
+
// ── Write functions ──
|
|
115
|
+
export async function registerAgent(name, description, agentClass) {
|
|
116
|
+
requireWallet();
|
|
117
|
+
const fee = await registry.entryFeeWei();
|
|
118
|
+
const tx = await registry.registerAgentWithClass(name, description, 0, agentClass, { value: fee });
|
|
119
|
+
const receipt = await tx.wait();
|
|
120
|
+
// Parse AgentRegistered event to get the agentId
|
|
121
|
+
const event = receipt.logs.find((log) => {
|
|
122
|
+
try {
|
|
123
|
+
return registry.interface.parseLog({ topics: [...log.topics], data: log.data })?.name === 'AgentRegistered';
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
let agentId = '';
|
|
130
|
+
if (event) {
|
|
131
|
+
const parsed = registry.interface.parseLog({ topics: [...event.topics], data: event.data });
|
|
132
|
+
agentId = parsed?.args?.[0] ?? '';
|
|
133
|
+
}
|
|
134
|
+
return { agentId, txHash: receipt.hash };
|
|
135
|
+
}
|
|
136
|
+
export async function createChallenge(myAgentId, opponentAgentId, wagerEth) {
|
|
137
|
+
requireWallet();
|
|
138
|
+
const wagerWei = ethers.parseEther(wagerEth);
|
|
139
|
+
const tx = await escrow.createChallenge(myAgentId, opponentAgentId, { value: wagerWei });
|
|
140
|
+
const receipt = await tx.wait();
|
|
141
|
+
// Parse ChallengeCreated event
|
|
142
|
+
const event = receipt.logs.find((log) => {
|
|
143
|
+
try {
|
|
144
|
+
return escrow.interface.parseLog({ topics: [...log.topics], data: log.data })?.name === 'ChallengeCreated';
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
let challengeId = '';
|
|
151
|
+
if (event) {
|
|
152
|
+
const parsed = escrow.interface.parseLog({ topics: [...event.topics], data: event.data });
|
|
153
|
+
challengeId = parsed?.args?.[0] ?? '';
|
|
154
|
+
}
|
|
155
|
+
return { challengeId, txHash: receipt.hash };
|
|
156
|
+
}
|
|
157
|
+
export async function acceptChallenge(challengeId, myAgentId) {
|
|
158
|
+
requireWallet();
|
|
159
|
+
// Fetch the challenge to know the wager amount
|
|
160
|
+
const challenge = await getChallenge(challengeId);
|
|
161
|
+
const wagerWei = ethers.parseEther(challenge.wager);
|
|
162
|
+
const tx = await escrow.acceptChallenge(challengeId, myAgentId, { value: wagerWei });
|
|
163
|
+
const receipt = await tx.wait();
|
|
164
|
+
return { txHash: receipt.hash };
|
|
165
|
+
}
|
|
166
|
+
export function getWalletAddress() {
|
|
167
|
+
return wallet?.address ?? null;
|
|
168
|
+
}
|
|
169
|
+
export function getWalletBalance() {
|
|
170
|
+
if (!wallet)
|
|
171
|
+
throw new Error('No wallet configured');
|
|
172
|
+
return provider.getBalance(wallet.address);
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=chain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain.js","sourceRoot":"","sources":["../src/chain.ts"],"names":[],"mappings":"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"}
|
package/dist/engine.d.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
export declare function initEngine(url: string): void;
|
|
2
|
+
export interface LeaderboardAgent {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
owner: string;
|
|
6
|
+
wins: number;
|
|
7
|
+
losses: number;
|
|
8
|
+
alive: boolean;
|
|
9
|
+
agentClass: string;
|
|
10
|
+
totalWon: string;
|
|
11
|
+
totalLost: string;
|
|
12
|
+
kills: number;
|
|
13
|
+
winRate: number;
|
|
14
|
+
}
|
|
15
|
+
export interface LeaderboardResponse {
|
|
16
|
+
agents: LeaderboardAgent[];
|
|
17
|
+
totalBattles: number;
|
|
18
|
+
}
|
|
19
|
+
export interface BattleRound {
|
|
20
|
+
roundNum: number;
|
|
21
|
+
attackerName: string;
|
|
22
|
+
defenderName: string;
|
|
23
|
+
attackRoll: number;
|
|
24
|
+
totalAttack: number;
|
|
25
|
+
defenderAC: number;
|
|
26
|
+
hit: boolean;
|
|
27
|
+
critical: boolean;
|
|
28
|
+
critMiss: boolean;
|
|
29
|
+
damage: number;
|
|
30
|
+
hpA: number;
|
|
31
|
+
hpB: number;
|
|
32
|
+
log: string;
|
|
33
|
+
}
|
|
34
|
+
export interface BattleResult {
|
|
35
|
+
winner: string;
|
|
36
|
+
loser: string;
|
|
37
|
+
winnerName: string;
|
|
38
|
+
loserName: string;
|
|
39
|
+
winnerClass: string;
|
|
40
|
+
loserClass: string;
|
|
41
|
+
seed: string;
|
|
42
|
+
rounds: BattleRound[];
|
|
43
|
+
winnerHpRemaining: number;
|
|
44
|
+
totalRounds: number;
|
|
45
|
+
logLines: string[];
|
|
46
|
+
}
|
|
47
|
+
export interface BattleResponse {
|
|
48
|
+
challengeId: string;
|
|
49
|
+
status: string;
|
|
50
|
+
agentA: string;
|
|
51
|
+
agentB: string;
|
|
52
|
+
playerA: string;
|
|
53
|
+
playerB: string;
|
|
54
|
+
log?: BattleResult;
|
|
55
|
+
}
|
|
56
|
+
export interface ChallengeRecord {
|
|
57
|
+
challenge_id: string;
|
|
58
|
+
agent_a: string;
|
|
59
|
+
agent_b: string;
|
|
60
|
+
player_a: string;
|
|
61
|
+
player_b: string;
|
|
62
|
+
wager: string | null;
|
|
63
|
+
status: string;
|
|
64
|
+
created_at: number;
|
|
65
|
+
}
|
|
66
|
+
export interface AgentStatusResponse {
|
|
67
|
+
status: 'idle' | 'in_battle' | 'challenged' | 'waiting_for_opponent' | 'battle_resolved';
|
|
68
|
+
challengeId: string | null;
|
|
69
|
+
battleState: string | null;
|
|
70
|
+
}
|
|
71
|
+
export declare function getLeaderboard(): Promise<LeaderboardResponse>;
|
|
72
|
+
export declare function getBattle(challengeId: string): Promise<BattleResponse>;
|
|
73
|
+
export declare function getChallenges(agentId: string): Promise<{
|
|
74
|
+
challenges: ChallengeRecord[];
|
|
75
|
+
}>;
|
|
76
|
+
export declare function getAgentStatus(walletAddress: string): Promise<AgentStatusResponse>;
|
|
77
|
+
export declare function submitCoaching(challengeId: string, playerAddress: string, prompt: string): Promise<{
|
|
78
|
+
received: boolean;
|
|
79
|
+
role: 'A' | 'B';
|
|
80
|
+
}>;
|
|
81
|
+
export declare function getHealth(): Promise<{
|
|
82
|
+
status: string;
|
|
83
|
+
signer: string;
|
|
84
|
+
}>;
|
|
85
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
|
package/dist/engine.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// HTTP client for the Glory engine API
|
|
2
|
+
let engineUrl = '';
|
|
3
|
+
export function initEngine(url) {
|
|
4
|
+
// Strip trailing slash
|
|
5
|
+
engineUrl = url.replace(/\/$/, '');
|
|
6
|
+
}
|
|
7
|
+
async function fetchJson(path) {
|
|
8
|
+
const res = await fetch(`${engineUrl}${path}`);
|
|
9
|
+
if (!res.ok) {
|
|
10
|
+
const text = await res.text();
|
|
11
|
+
throw new Error(`Engine API error ${res.status}: ${text}`);
|
|
12
|
+
}
|
|
13
|
+
return res.json();
|
|
14
|
+
}
|
|
15
|
+
// ── API calls ──
|
|
16
|
+
export async function getLeaderboard() {
|
|
17
|
+
return fetchJson('/api/leaderboard');
|
|
18
|
+
}
|
|
19
|
+
export async function getBattle(challengeId) {
|
|
20
|
+
return fetchJson(`/battle/${challengeId}`);
|
|
21
|
+
}
|
|
22
|
+
export async function getChallenges(agentId) {
|
|
23
|
+
return fetchJson(`/challenges/${agentId}`);
|
|
24
|
+
}
|
|
25
|
+
export async function getAgentStatus(walletAddress) {
|
|
26
|
+
return fetchJson(`/agent/${walletAddress}/status`);
|
|
27
|
+
}
|
|
28
|
+
export async function submitCoaching(challengeId, playerAddress, prompt) {
|
|
29
|
+
const res = await fetch(`${engineUrl}/coaching`, {
|
|
30
|
+
method: 'POST',
|
|
31
|
+
headers: { 'Content-Type': 'application/json' },
|
|
32
|
+
body: JSON.stringify({ challengeId, playerAddress, prompt }),
|
|
33
|
+
});
|
|
34
|
+
if (!res.ok) {
|
|
35
|
+
const text = await res.text();
|
|
36
|
+
throw new Error(`Engine coaching error ${res.status}: ${text}`);
|
|
37
|
+
}
|
|
38
|
+
return res.json();
|
|
39
|
+
}
|
|
40
|
+
export async function getHealth() {
|
|
41
|
+
return fetchJson('/health');
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,uCAAuC;AAEvC,IAAI,SAAS,GAAG,EAAE,CAAC;AAEnB,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,uBAAuB;IACvB,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACrC,CAAC;AAED,KAAK,UAAU,SAAS,CAAI,IAAY;IACtC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,SAAS,GAAG,IAAI,EAAE,CAAC,CAAC;IAC/C,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,oBAAoB,GAAG,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,EAAgB,CAAC;AAClC,CAAC;AAgFD,kBAAkB;AAElB,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,OAAO,SAAS,CAAsB,kBAAkB,CAAC,CAAC;AAC5D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,WAAmB;IACjD,OAAO,SAAS,CAAiB,WAAW,WAAW,EAAE,CAAC,CAAC;AAC7D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAe;IACjD,OAAO,SAAS,CAAoC,eAAe,OAAO,EAAE,CAAC,CAAC;AAChF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,aAAqB;IACxD,OAAO,SAAS,CAAsB,UAAU,aAAa,SAAS,CAAC,CAAC;AAC1E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,WAAmB,EACnB,aAAqB,EACrB,MAAc;IAEd,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,SAAS,WAAW,EAAE;QAC/C,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC;KAC7D,CAAC,CAAC;IACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,yBAAyB,GAAG,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,EAAqD,CAAC;AACvE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,OAAO,SAAS,CAAqC,SAAS,CAAC,CAAC;AAClE,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,eAAe,CAAC"}
|