nirium 0.2.0__py3-none-any.whl

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.
nirium/__init__.py ADDED
@@ -0,0 +1,6 @@
1
+ """Nirium — Official Python SDK for the Nirium autonomous DeFi agent."""
2
+
3
+ from .client import Agent # type: ignore
4
+
5
+ __version__ = "0.1.0"
6
+ __all__ = ["Agent"]
nirium/client.py ADDED
@@ -0,0 +1,201 @@
1
+ # ═══════════════════════════════════════════════════════════════
2
+ # Nirium Python SDK v0.2.0 — Official Quantitative Client
3
+ # Synced with backend API (real Horizon data, Soroban execution)
4
+ # ═══════════════════════════════════════════════════════════════
5
+ import asyncio
6
+ import json
7
+ import logging
8
+ import aiohttp # type: ignore
9
+ import websockets # type: ignore
10
+ from typing import Callable, Dict, Any, List, Optional
11
+
12
+ logger = logging.getLogger("nirium.client")
13
+
14
+
15
+ class Agent:
16
+ """
17
+ Nirium Agent — Full API + WebSocket client for the Nirium autonomous agent.
18
+
19
+ Usage:
20
+ agent = Agent(api_url="http://localhost:3001", api_key="nrm_your_key")
21
+ market = await agent.get_market()
22
+ print(f"XLM Price: ${market['xlmPrice']:.4f}")
23
+ """
24
+
25
+ def __init__(self, api_url: str = "http://localhost:3001", api_key: Optional[str] = None, token: Optional[str] = None):
26
+ self.api_url = api_url.rstrip('/')
27
+ self.ws_url = self.api_url.replace("http", "ws") + "/ws/signals"
28
+ self.api_key = api_key
29
+ self.token = token
30
+
31
+ api_key_local = self.api_key
32
+ token_local = self.token
33
+
34
+ self.headers: Dict[str, str] = {"Content-Type": "application/json"}
35
+ if api_key_local is not None:
36
+ self.headers["x-api-key"] = api_key_local
37
+ elif token_local is not None:
38
+ self.headers["Authorization"] = f"Bearer {token_local}"
39
+
40
+ self.callbacks: Dict[str, List[Callable]] = {"signal": [], "log": [], "connected": []}
41
+
42
+ # ─── Decorators ────────────────────────────────────────────
43
+
44
+ def on(self, event_type: str):
45
+ """Decorator to register event callbacks."""
46
+ def decorator(func: Callable):
47
+ if event_type not in self.callbacks:
48
+ self.callbacks[event_type] = []
49
+ self.callbacks[event_type].append(func)
50
+ return func
51
+ return decorator
52
+
53
+ async def _emit(self, event_type: str, data: Any):
54
+ for callback in self.callbacks.get(event_type, []):
55
+ if asyncio.iscoroutinefunction(callback):
56
+ await callback(data)
57
+ else:
58
+ callback(data)
59
+
60
+ # ─── HTTP Helpers ─────────────────────────────────────────
61
+
62
+ async def _get(self, path: str) -> Any:
63
+ async with aiohttp.ClientSession(headers=self.headers) as session:
64
+ async with session.get(f"{self.api_url}{path}") as resp:
65
+ resp.raise_for_status()
66
+ return await resp.json()
67
+
68
+ async def _post(self, path: str, payload: Optional[Dict[str, Any]] = None) -> Any:
69
+ async with aiohttp.ClientSession(headers=self.headers) as session:
70
+ async with session.post(f"{self.api_url}{path}", json=payload or {}) as resp:
71
+ resp.raise_for_status()
72
+ return await resp.json()
73
+
74
+ async def _delete(self, path: str) -> Any:
75
+ async with aiohttp.ClientSession(headers=self.headers) as session:
76
+ async with session.delete(f"{self.api_url}{path}") as resp:
77
+ resp.raise_for_status()
78
+ return await resp.json()
79
+
80
+ # ─── Health ───────────────────────────────────────────────
81
+
82
+ async def ping(self) -> bool:
83
+ """Check if the agent is reachable."""
84
+ try:
85
+ data = await self._get("/health")
86
+ return data.get("status") == "operational"
87
+ except Exception:
88
+ return False
89
+
90
+ async def health(self) -> Dict[str, Any]:
91
+ """Get detailed health info."""
92
+ return await self._get("/health")
93
+
94
+ async def system_health(self) -> Dict[str, Any]:
95
+ """Get full system health (Horizon, Soroban, WebSocket, IPFS, LLM)."""
96
+ return await self._get("/api/system/health")
97
+
98
+ # ─── Market Data ─────────────────────────────────────────
99
+
100
+ async def get_market(self) -> Dict[str, Any]:
101
+ """Fetch real market state from Horizon (XLM price, SDEX spread, fees, paths)."""
102
+ return await self._get("/api/market")
103
+
104
+ async def get_loop_status(self) -> Dict[str, Any]:
105
+ """Get autonomous loop status."""
106
+ return await self._get("/api/loop/status")
107
+
108
+ async def start_loop(self, config: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
109
+ """Start the autonomous scanning loop."""
110
+ return await self._post("/api/loop/start", {"config": config or {}})
111
+
112
+ async def stop_loop(self) -> Dict[str, Any]:
113
+ """Stop the autonomous scanning loop."""
114
+ return await self._post("/api/loop/stop")
115
+
116
+ async def trigger_scan(self) -> Dict[str, Any]:
117
+ """Trigger a manual market scan."""
118
+ return await self._post("/api/loop/scan")
119
+
120
+ # ─── Execution ───────────────────────────────────────────
121
+
122
+ async def execute(self, strategy: str, asset: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
123
+ """Execute a strategy via real Soroban contract call.
124
+
125
+ Strategies: flash-loan-arb, path-arbitrage, cross-dex, blend-yield, soroswap-swap
126
+ """
127
+ return await self._post("/api/execute", {
128
+ "strategy": strategy,
129
+ "asset": asset,
130
+ "params": params or {},
131
+ })
132
+
133
+ async def execute_demo(self, strategy: str, asset: str) -> Dict[str, Any]:
134
+ """Execute a strategy in demo mode (Soroban dry-run, no TX submitted)."""
135
+ return await self._post("/api/execute-demo", {
136
+ "strategy": strategy,
137
+ "asset": asset,
138
+ })
139
+
140
+ # ─── Signals ─────────────────────────────────────────────
141
+
142
+ async def get_recent_signals(self, count: int = 20) -> Any:
143
+ """Get recent market signals."""
144
+ return await self._get(f"/api/signals/recent?count={count}")
145
+
146
+ # ─── Skills ──────────────────────────────────────────────
147
+
148
+ async def get_skills(self) -> Any:
149
+ """List all loaded skills (built-in + user-installed)."""
150
+ return await self._get("/api/skills")
151
+
152
+ async def install_skill(self, source: str) -> Dict[str, Any]:
153
+ """Install a skill by slug."""
154
+ return await self._post("/api/skills/install", {"source": source})
155
+
156
+ async def uninstall_skill(self, slug: str) -> Dict[str, Any]:
157
+ """Uninstall a user-installed skill by slug."""
158
+ return await self._delete(f"/api/skills/{slug}")
159
+
160
+ # ─── Webhooks ────────────────────────────────────────────
161
+
162
+ async def register_webhook(self, url: str, events: List[str], secret: Optional[str] = None) -> Dict[str, Any]:
163
+ """Register a webhook endpoint with HMAC signing."""
164
+ return await self._post("/api/webhooks", {"url": url, "events": events, "secret": secret})
165
+
166
+ async def get_webhooks(self) -> List[Dict[str, Any]]:
167
+ """List all registered webhooks."""
168
+ return await self._get("/api/webhooks")
169
+
170
+ async def delete_webhook(self, webhook_id: str) -> Dict[str, Any]:
171
+ """Delete a webhook by ID."""
172
+ return await self._delete(f"/api/webhooks/{webhook_id}")
173
+
174
+ async def test_webhook(self, webhook_id: str) -> Dict[str, Any]:
175
+ """Send a test event to a webhook."""
176
+ return await self._post(f"/api/webhooks/{webhook_id}/test")
177
+
178
+ # ─── WebSocket ───────────────────────────────────────────
179
+
180
+ async def subscribe(self, callback: Optional[Callable] = None):
181
+ """Start real-time WebSocket connection for signals."""
182
+ if callback:
183
+ self.callbacks.setdefault("signal", []).append(callback)
184
+
185
+ auth_query = f"?token={self.token}" if self.token else ""
186
+ url = f"{self.ws_url}{auth_query}"
187
+
188
+ while True:
189
+ try:
190
+ async with websockets.connect(url) as ws:
191
+ logger.info("Connected to Nirium Signal Stream")
192
+ await self._emit("connected", None)
193
+
194
+ async for message in ws:
195
+ data = json.loads(message)
196
+ event = data.get("type")
197
+ if event in self.callbacks:
198
+ await self._emit(event, data)
199
+ except Exception as e:
200
+ logger.error(f"WS Disconnected: {e}. Reconnecting in 5s...")
201
+ await asyncio.sleep(5)
@@ -0,0 +1,103 @@
1
+ Metadata-Version: 2.4
2
+ Name: nirium
3
+ Version: 0.2.0
4
+ Summary: Official Python SDK for the Nirium autonomous DeFi agent on Stellar
5
+ Author: Nirium Protocol
6
+ License: MIT
7
+ Project-URL: Homepage, https://nirium.dev
8
+ Project-URL: Repository, https://github.com/nirium/nirium
9
+ Project-URL: Documentation, https://nirium.dev/docs
10
+ Keywords: nirium,stellar,defi,sdk,soroban,agent
11
+ Requires-Python: >=3.10
12
+ Description-Content-Type: text/markdown
13
+ Requires-Dist: aiohttp>=3.9.0
14
+ Requires-Dist: websockets>=13.0
15
+
16
+ # nirium
17
+
18
+ Official Python SDK for the **Nirium Protocol** — autonomous DeFi agent on Stellar/Soroban.
19
+
20
+ ## Install
21
+
22
+ ```bash
23
+ pip install nirium
24
+ ```
25
+
26
+ ## Quick Start
27
+
28
+ ```python
29
+ import asyncio
30
+ from nirium import Agent
31
+
32
+ agent = Agent(
33
+ api_url="https://api.nirium.xyz",
34
+ api_key="sk_inst_your_key_here",
35
+ )
36
+
37
+ async def main():
38
+ # Health check
39
+ alive = await agent.ping()
40
+ print(f"Agent alive: {alive}")
41
+
42
+ # Real market data from Stellar Horizon
43
+ market = await agent.get_market()
44
+ print(f"XLM Price: ${market['xlmPrice']:.4f}")
45
+
46
+ # Execute a strategy
47
+ result = await agent.execute("flash-loan-arb", "XLM-USDC", {"amount": 5000})
48
+ print(f"Profit: {result['profit']}")
49
+
50
+ asyncio.run(main())
51
+ ```
52
+
53
+ ## Real-Time Signals (WebSocket)
54
+
55
+ ```python
56
+ agent = Agent(api_url="https://api.nirium.xyz", api_key="sk_inst_...", token="eyJhbG...")
57
+
58
+ @agent.on("signal")
59
+ async def on_signal(data):
60
+ print(f"Signal: {data['signal_type']} — {data['data']['details']}")
61
+
62
+ asyncio.run(agent.subscribe())
63
+ ```
64
+
65
+ ## Authentication
66
+
67
+ ```python
68
+ # API Key for REST endpoints
69
+ agent = Agent(api_url="https://api.nirium.xyz", api_key="sk_inst_...")
70
+
71
+ # With JWT token for WebSocket
72
+ agent = Agent(api_url="https://api.nirium.xyz", api_key="sk_inst_...", token="eyJhbG...")
73
+ ```
74
+
75
+ ### Endpoint Access Model
76
+
77
+ | Access | Endpoints |
78
+ |---|---|
79
+ | **Public** (no key) | `health`, `loop/status`, `execute-demo`, `signals/recent`, `skills` list |
80
+ | **Protected** (API key) | `execute`, `market`, `loop/start\|stop\|scan`, `subscriptions`, `skills/install`, `webhooks` |
81
+ | **WebSocket** (JWT) | `/ws/signals` — real-time signal stream |
82
+
83
+ ## API Coverage
84
+
85
+ | Category | Methods |
86
+ |---|---|
87
+ | Health | `ping()`, `health()`, `system_health()` |
88
+ | Execution | `execute()`, `execute_demo()` |
89
+ | Market | `get_market()`, `get_loop_status()`, `start_loop()`, `stop_loop()`, `trigger_scan()` |
90
+ | Signals | `get_recent_signals()` |
91
+ | Skills | `get_skills()`, `install_skill()`, `uninstall_skill()` |
92
+ | Webhooks | `register_webhook()`, `get_webhooks()`, `delete_webhook()`, `test_webhook()` |
93
+ | WebSocket | `subscribe()`, `on()` decorator |
94
+
95
+ ## Requirements
96
+
97
+ - Python >= 3.10
98
+ - aiohttp >= 3.9.0
99
+ - websockets >= 13.0
100
+
101
+ ## License
102
+
103
+ MIT — Nirium Protocol
@@ -0,0 +1,6 @@
1
+ nirium/__init__.py,sha256=J5M-koNyzVHeTn0SGSJYbnTUKQ2B0rEI6zD_NU00z3Q,161
2
+ nirium/client.py,sha256=VrfHjEvp9uyn376T_272enYZXx3E2t2oKX9pQZ6d4Tc,9229
3
+ nirium-0.2.0.dist-info/METADATA,sha256=qvQYJftJCM7KQqNGYSB1IsnR6AEyjkP6kWRw-glFncA,2715
4
+ nirium-0.2.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
5
+ nirium-0.2.0.dist-info/top_level.txt,sha256=zxpE7vZKWqwB4nVbBlI-mtZS6lcRLGJW4ws9zHJA4Dg,7
6
+ nirium-0.2.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ nirium