nirium 0.2.1__tar.gz → 0.5.0__tar.gz

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.
@@ -1,17 +1,19 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nirium
3
- Version: 0.2.1
4
- Summary: Official Python SDK for the Nirium autonomous DeFi agent on Stellar
3
+ Version: 0.5.0
4
+ Summary: Official Python SDK for Nirium autonomous agents on Stellar (x402 + MPP)
5
5
  Author: Nirium Protocol
6
6
  License: MIT
7
7
  Project-URL: Homepage, https://nirium.dev
8
8
  Project-URL: Repository, https://github.com/nirium/nirium
9
9
  Project-URL: Documentation, https://nirium.dev/docs
10
- Keywords: nirium,stellar,defi,sdk,soroban,agent
11
- Requires-Python: >=3.10
10
+ Keywords: nirium,stellar,defi,sdk,soroban,agent,x402,mpp,agentic-payments,usdc
11
+ Requires-Python: >=3.9
12
12
  Description-Content-Type: text/markdown
13
13
  Requires-Dist: aiohttp>=3.9.0
14
14
  Requires-Dist: websockets>=13.0
15
+ Requires-Dist: stellar-sdk>=11.0.0
16
+ Dynamic: requires-python
15
17
 
16
18
  # nirium
17
19
 
@@ -86,7 +88,7 @@ agent = Agent(api_url="https://api.nirium.xyz", api_key="sk_inst_...", token="ey
86
88
  |---|---|
87
89
  | Health | `ping()`, `health()`, `system_health()` |
88
90
  | Execution | `execute()`, `execute_demo()` |
89
- | Market | `get_market()`, `get_loop_status()`, `start_loop()`, `stop_loop()`, `trigger_scan()` |
91
+ | Market | `get_tickers()`, `get_market()`, `get_stats()`, `get_loop_status()`, `start_loop()`, `stop_loop()`, `trigger_scan()` |
90
92
  | Signals | `get_recent_signals()` |
91
93
  | Skills | `get_skills()`, `install_skill()`, `uninstall_skill()` |
92
94
  | Webhooks | `register_webhook()`, `get_webhooks()`, `delete_webhook()`, `test_webhook()` |
@@ -71,7 +71,7 @@ agent = Agent(api_url="https://api.nirium.xyz", api_key="sk_inst_...", token="ey
71
71
  |---|---|
72
72
  | Health | `ping()`, `health()`, `system_health()` |
73
73
  | Execution | `execute()`, `execute_demo()` |
74
- | Market | `get_market()`, `get_loop_status()`, `start_loop()`, `stop_loop()`, `trigger_scan()` |
74
+ | Market | `get_tickers()`, `get_market()`, `get_stats()`, `get_loop_status()`, `start_loop()`, `stop_loop()`, `trigger_scan()` |
75
75
  | Signals | `get_recent_signals()` |
76
76
  | Skills | `get_skills()`, `install_skill()`, `uninstall_skill()` |
77
77
  | Webhooks | `register_webhook()`, `get_webhooks()`, `delete_webhook()`, `test_webhook()` |
@@ -4,16 +4,17 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "nirium"
7
- version = "0.2.1"
8
- description = "Official Python SDK for the Nirium autonomous DeFi agent on Stellar"
7
+ version = "0.5.0"
8
+ description = "Official Python SDK for Nirium autonomous agents on Stellar (x402 + MPP)"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
11
11
  license = {text = "MIT"}
12
12
  authors = [{name = "Nirium Protocol"}]
13
- keywords = ["nirium", "stellar", "defi", "sdk", "soroban", "agent"]
13
+ keywords = ["nirium", "stellar", "defi", "sdk", "soroban", "agent", "x402", "mpp", "agentic-payments", "usdc"]
14
14
  dependencies = [
15
15
  "aiohttp>=3.9.0",
16
16
  "websockets>=13.0",
17
+ "stellar-sdk>=11.0.0",
17
18
  ]
18
19
 
19
20
  [project.urls]
nirium-0.5.0/setup.py ADDED
@@ -0,0 +1,17 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ setup(
4
+ name="nirium",
5
+ version="0.4.0",
6
+ package_dir={"": "src"},
7
+ packages=find_packages(where="src"),
8
+ install_requires=[
9
+ "websockets>=11.0.3",
10
+ "aiohttp>=3.8.4",
11
+ "stellar-sdk>=11.0.0",
12
+ ],
13
+ author="Nirium Team",
14
+ description="Official Python SDK for Nirium autonomous agents on Stellar (x402 + MPP)",
15
+ keywords=["nirium", "stellar", "defi", "x402", "mpp", "agentic-payments", "soroban"],
16
+ python_requires=">=3.9",
17
+ )
@@ -2,5 +2,5 @@
2
2
 
3
3
  from .client import Agent # type: ignore
4
4
 
5
- __version__ = "0.1.0"
5
+ __version__ = "0.3.0"
6
6
  __all__ = ["Agent"]
@@ -1,5 +1,5 @@
1
1
  # ═══════════════════════════════════════════════════════════════
2
- # Nirium Python SDK v0.2.0 — Official Quantitative Client
2
+ # Nirium Python SDK v0.4.0 — Official Client (x402 + MPP)
3
3
  # Synced with backend API (real Horizon data, Soroban execution)
4
4
  # ═══════════════════════════════════════════════════════════════
5
5
  import asyncio
@@ -8,6 +8,7 @@ import logging
8
8
  import aiohttp # type: ignore
9
9
  import websockets # type: ignore
10
10
  from typing import Callable, Dict, Any, List, Optional
11
+ from stellar_sdk import Keypair, Network, Server, TransactionBuilder, Asset # type: ignore
11
12
 
12
13
  logger = logging.getLogger("nirium.client")
13
14
 
@@ -59,14 +60,16 @@ class Agent:
59
60
 
60
61
  # ─── HTTP Helpers ─────────────────────────────────────────
61
62
 
62
- async def _get(self, path: str) -> Any:
63
- async with aiohttp.ClientSession(headers=self.headers) as session:
63
+ async def _get(self, path: str, extra_headers: Optional[Dict[str, str]] = None) -> Any:
64
+ headers = {**self.headers, **(extra_headers or {})}
65
+ async with aiohttp.ClientSession(headers=headers) as session:
64
66
  async with session.get(f"{self.api_url}{path}") as resp:
65
67
  resp.raise_for_status()
66
68
  return await resp.json()
67
69
 
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 def _post(self, path: str, payload: Optional[Dict[str, Any]] = None, extra_headers: Optional[Dict[str, str]] = None) -> Any:
71
+ headers = {**self.headers, **(extra_headers or {})}
72
+ async with aiohttp.ClientSession(headers=headers) as session:
70
73
  async with session.post(f"{self.api_url}{path}", json=payload or {}) as resp:
71
74
  resp.raise_for_status()
72
75
  return await resp.json()
@@ -97,10 +100,18 @@ class Agent:
97
100
 
98
101
  # ─── Market Data ─────────────────────────────────────────
99
102
 
103
+ async def get_tickers(self) -> Dict[str, Any]:
104
+ """Get asset price tickers (XLM, USDC) from Stellar Horizon."""
105
+ return await self._get("/api/tickers")
106
+
100
107
  async def get_market(self) -> Dict[str, Any]:
101
108
  """Fetch real market state from Horizon (XLM price, SDEX spread, fees, paths)."""
102
109
  return await self._get("/api/market")
103
110
 
111
+ async def get_stats(self) -> Dict[str, Any]:
112
+ """Get global protocol statistics."""
113
+ return await self._get("/api/stats/global")
114
+
104
115
  async def get_loop_status(self) -> Dict[str, Any]:
105
116
  """Get autonomous loop status."""
106
117
  return await self._get("/api/loop/status")
@@ -119,19 +130,37 @@ class Agent:
119
130
 
120
131
  # ─── Execution ───────────────────────────────────────────
121
132
 
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.
133
+ async def execute(
134
+ self,
135
+ strategy: str,
136
+ asset: str,
137
+ params: Optional[Dict[str, Any]] = None,
138
+ stellar_account: Optional[str] = None,
139
+ ) -> Dict[str, Any]:
140
+ """Execute a strategy via real Soroban contract transaction on Stellar.
124
141
 
125
142
  Strategies: flash-loan-arb, path-arbitrage, cross-dex, blend-yield, soroswap-swap
143
+
144
+ Args:
145
+ strategy: Strategy name (maps to a NiriumVault contract function)
146
+ asset: Base asset symbol (e.g. 'XLM')
147
+ params: Optional dict — supports 'amount' in stroops (default 1000)
148
+ stellar_account: Your Stellar wallet address. Required for legal consent verification.
126
149
  """
127
- return await self._post("/api/execute", {
128
- "strategy": strategy,
129
- "asset": asset,
130
- "params": params or {},
131
- })
150
+ extra: Dict[str, str] = {}
151
+ if stellar_account:
152
+ extra["x-stellar-account"] = stellar_account
153
+ payload: Dict[str, Any] = {"strategy": strategy, "asset": asset}
154
+ if params:
155
+ payload.update(params)
156
+ return await self._post("/api/execute", payload, extra_headers=extra)
132
157
 
133
158
  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)."""
159
+ """Execute a strategy in demo mode (Soroban dry-run, no TX submitted).
160
+
161
+ Returns a professional market assessment message.
162
+ Response keys: success, simulated_profit, gas_consumed, message
163
+ """
135
164
  return await self._post("/api/execute-demo", {
136
165
  "strategy": strategy,
137
166
  "asset": asset,
@@ -175,6 +204,155 @@ class Agent:
175
204
  """Send a test event to a webhook."""
176
205
  return await self._post(f"/api/webhooks/{webhook_id}/test")
177
206
 
207
+ # ─── x402 Protocol ───────────────────────────────────────
208
+
209
+ def init_x402(self, secret_key: str, network: str = "stellar:testnet"):
210
+ """
211
+ Initialize x402 pay-per-request client.
212
+
213
+ Python SDK implements the x402 HTTP flow directly:
214
+ 1. GET resource -> receive 402 + payment requirements
215
+ 2. Build Soroban SAC USDC transfer auth entry
216
+ 3. Retry with X-PAYMENT header containing signed auth entry
217
+
218
+ Args:
219
+ secret_key: Stellar secret key (S...) for signing
220
+ network: CAIP-2 network ID ('stellar:testnet' or 'stellar:pubnet')
221
+ """
222
+ self._x402_keypair = Keypair.from_secret(secret_key)
223
+ self._x402_network = network
224
+ self._x402_passphrase = (
225
+ Network.TESTNET_NETWORK_PASSPHRASE if "testnet" in network
226
+ else Network.PUBLIC_NETWORK_PASSPHRASE
227
+ )
228
+ self._x402_horizon = Server(
229
+ "https://horizon-testnet.stellar.org" if "testnet" in network
230
+ else "https://horizon.stellar.org"
231
+ )
232
+
233
+ async def x402_fetch(self, url: str, method: str = "GET") -> Dict[str, Any]:
234
+ """
235
+ Fetch a paid resource via x402 protocol.
236
+
237
+ Sends the initial request, receives 402 with payment requirements,
238
+ builds and signs a USDC payment, retries with the payment proof.
239
+
240
+ Returns the JSON payload from the paid resource.
241
+ """
242
+ if not hasattr(self, "_x402_keypair"):
243
+ raise RuntimeError("x402 client not initialized. Call agent.init_x402() first.")
244
+
245
+ async with aiohttp.ClientSession() as session:
246
+ # Step 1: Initial request — expect 402
247
+ async with session.request(method, url) as resp:
248
+ if resp.status != 402:
249
+ return await resp.json()
250
+
251
+ requirements = await resp.json()
252
+
253
+ # Step 2: Build USDC payment from requirements
254
+ pay_req = requirements.get("paymentRequirements", [{}])[0]
255
+ dest = pay_req.get("receiver") or pay_req.get("destination", "")
256
+ amount = pay_req.get("maxAmountRequired") or pay_req.get("amount", "0.01")
257
+ usdc_issuer = "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"
258
+ usdc_asset = Asset("USDC", usdc_issuer)
259
+
260
+ account = self._x402_horizon.load_account(self._x402_keypair.public_key)
261
+ tx = (
262
+ TransactionBuilder(
263
+ source_account=account,
264
+ network_passphrase=self._x402_passphrase,
265
+ base_fee=100,
266
+ )
267
+ .append_payment_op(dest, usdc_asset, str(amount))
268
+ .set_timeout(30)
269
+ .build()
270
+ )
271
+ tx.sign(self._x402_keypair)
272
+ xdr = tx.to_xdr()
273
+
274
+ # Step 3: Retry with payment proof
275
+ payment_header = json.dumps({"transaction": xdr})
276
+ headers = {"X-PAYMENT": payment_header, "Content-Type": "application/json"}
277
+ async with session.request(method, url, headers=headers) as resp:
278
+ resp.raise_for_status()
279
+ return await resp.json()
280
+
281
+ # ─── MPP Protocol (Charge Mode) ─────────────────────────
282
+
283
+ def init_mpp(self, secret_key: str, network: str = "stellar:testnet"):
284
+ """
285
+ Initialize MPP Charge client for per-request Soroban SAC payments.
286
+
287
+ Python SDK implements the MPP charge flow directly:
288
+ 1. GET resource -> receive 402 + charge challenge
289
+ 2. Sign Soroban auth entries for SAC USDC transfer
290
+ 3. Retry with signed auth in X-PAYMENT header
291
+
292
+ Args:
293
+ secret_key: Stellar secret key (S...) for signing
294
+ network: CAIP-2 network ID ('stellar:testnet' or 'stellar:pubnet')
295
+ """
296
+ self._mpp_keypair = Keypair.from_secret(secret_key)
297
+ self._mpp_network = network
298
+ self._mpp_passphrase = (
299
+ Network.TESTNET_NETWORK_PASSPHRASE if "testnet" in network
300
+ else Network.PUBLIC_NETWORK_PASSPHRASE
301
+ )
302
+ self._mpp_horizon = Server(
303
+ "https://horizon-testnet.stellar.org" if "testnet" in network
304
+ else "https://horizon.stellar.org"
305
+ )
306
+
307
+ async def mpp_fetch(self, url: str, method: str = "GET") -> Dict[str, Any]:
308
+ """
309
+ Fetch a paid resource via MPP Charge protocol.
310
+
311
+ Sends the initial request, receives 402 with charge challenge,
312
+ builds and signs a USDC payment, retries with payment proof.
313
+ In pull mode, the server assembles and broadcasts the Soroban tx.
314
+
315
+ Returns the JSON payload from the paid resource.
316
+ """
317
+ if not hasattr(self, "_mpp_keypair"):
318
+ raise RuntimeError("MPP client not initialized. Call agent.init_mpp() first.")
319
+
320
+ async with aiohttp.ClientSession() as session:
321
+ # Step 1: Initial request — expect 402
322
+ async with session.request(method, url) as resp:
323
+ if resp.status != 402:
324
+ return await resp.json()
325
+
326
+ challenge = await resp.json()
327
+
328
+ # Step 2: Build USDC payment from challenge
329
+ pay_req = challenge.get("paymentRequirements", [{}])[0]
330
+ dest = pay_req.get("receiver") or pay_req.get("destination", "")
331
+ amount = pay_req.get("maxAmountRequired") or pay_req.get("amount", "0.01")
332
+ usdc_issuer = "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"
333
+ usdc_asset = Asset("USDC", usdc_issuer)
334
+
335
+ account = self._mpp_horizon.load_account(self._mpp_keypair.public_key)
336
+ tx = (
337
+ TransactionBuilder(
338
+ source_account=account,
339
+ network_passphrase=self._mpp_passphrase,
340
+ base_fee=100,
341
+ )
342
+ .append_payment_op(dest, usdc_asset, str(amount))
343
+ .set_timeout(30)
344
+ .build()
345
+ )
346
+ tx.sign(self._mpp_keypair)
347
+ xdr = tx.to_xdr()
348
+
349
+ # Step 3: Retry with payment proof
350
+ payment_header = json.dumps({"transaction": xdr, "mode": "pull"})
351
+ headers = {"X-PAYMENT": payment_header, "Content-Type": "application/json"}
352
+ async with session.request(method, url, headers=headers) as resp:
353
+ resp.raise_for_status()
354
+ return await resp.json()
355
+
178
356
  # ─── WebSocket ───────────────────────────────────────────
179
357
 
180
358
  async def subscribe(self, callback: Optional[Callable] = None):
@@ -1,17 +1,19 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nirium
3
- Version: 0.2.1
4
- Summary: Official Python SDK for the Nirium autonomous DeFi agent on Stellar
3
+ Version: 0.5.0
4
+ Summary: Official Python SDK for Nirium autonomous agents on Stellar (x402 + MPP)
5
5
  Author: Nirium Protocol
6
6
  License: MIT
7
7
  Project-URL: Homepage, https://nirium.dev
8
8
  Project-URL: Repository, https://github.com/nirium/nirium
9
9
  Project-URL: Documentation, https://nirium.dev/docs
10
- Keywords: nirium,stellar,defi,sdk,soroban,agent
11
- Requires-Python: >=3.10
10
+ Keywords: nirium,stellar,defi,sdk,soroban,agent,x402,mpp,agentic-payments,usdc
11
+ Requires-Python: >=3.9
12
12
  Description-Content-Type: text/markdown
13
13
  Requires-Dist: aiohttp>=3.9.0
14
14
  Requires-Dist: websockets>=13.0
15
+ Requires-Dist: stellar-sdk>=11.0.0
16
+ Dynamic: requires-python
15
17
 
16
18
  # nirium
17
19
 
@@ -86,7 +88,7 @@ agent = Agent(api_url="https://api.nirium.xyz", api_key="sk_inst_...", token="ey
86
88
  |---|---|
87
89
  | Health | `ping()`, `health()`, `system_health()` |
88
90
  | Execution | `execute()`, `execute_demo()` |
89
- | Market | `get_market()`, `get_loop_status()`, `start_loop()`, `stop_loop()`, `trigger_scan()` |
91
+ | Market | `get_tickers()`, `get_market()`, `get_stats()`, `get_loop_status()`, `start_loop()`, `stop_loop()`, `trigger_scan()` |
90
92
  | Signals | `get_recent_signals()` |
91
93
  | Skills | `get_skills()`, `install_skill()`, `uninstall_skill()` |
92
94
  | Webhooks | `register_webhook()`, `get_webhooks()`, `delete_webhook()`, `test_webhook()` |
@@ -1,2 +1,3 @@
1
1
  aiohttp>=3.9.0
2
2
  websockets>=13.0
3
+ stellar-sdk>=11.0.0
nirium-0.2.1/setup.py DELETED
@@ -1,14 +0,0 @@
1
- from setuptools import setup, find_packages
2
-
3
- setup(
4
- name="nirium-sdk",
5
- version="1.0.0",
6
- package_dir={"": "src"},
7
- packages=find_packages(where="src"),
8
- install_requires=[
9
- "websockets>=11.0.3",
10
- "aiohttp>=3.8.4",
11
- ],
12
- author="Nirium Team",
13
- description="Official Python SDK for Nirium Autonomous Agents",
14
- )
File without changes