nexum-sdk 0.1.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.
@@ -0,0 +1,12 @@
1
+ Metadata-Version: 2.4
2
+ Name: nexum-sdk
3
+ Version: 0.1.0
4
+ Summary: Official Python SDK for NEXUM Protocol on Solana
5
+ Author-email: NEXUM Protocol <protocolnexum@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://nexum-protocol.netlify.app
8
+ Project-URL: Repository, https://github.com/Nexumprotocol/nexum-sdk
9
+ Requires-Python: >=3.10
10
+ Requires-Dist: httpx>=0.27.0
11
+ Requires-Dist: base58>=2.1.1
12
+ Requires-Dist: solders>=0.21.0
@@ -0,0 +1,124 @@
1
+ # nexum-sdk (Python)
2
+
3
+ Official Python SDK for [NEXUM Protocol](https://nexum-protocol.netlify.app) — a decentralized freelance marketplace built on Solana.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install nexum-sdk
9
+ ```
10
+
11
+ ## Requirements
12
+
13
+ - Python 3.10+
14
+ - Dependencies: `httpx`, `base58`, `solders`
15
+
16
+ ## Quick Start
17
+
18
+ ```python
19
+ from nexum_sdk import NexumClient, Network
20
+
21
+ # Connect to devnet
22
+ client = NexumClient.devnet()
23
+
24
+ # Connect to mainnet
25
+ client = NexumClient.mainnet()
26
+
27
+ # Custom RPC
28
+ client = NexumClient(network=Network.DEVNET, rpc_url="https://your-custom-rpc.com")
29
+ ```
30
+
31
+ ## Tasks (async)
32
+
33
+ ```python
34
+ import asyncio
35
+ from nexum_sdk import NexumClient, TaskStatus
36
+
37
+ client = NexumClient.devnet()
38
+
39
+ async def main():
40
+ # Fetch all open tasks
41
+ tasks = await client.get_open_tasks()
42
+ for task in tasks:
43
+ print(task.title, task.reward_sol, "SOL")
44
+ print(task.skills_list) # ['Rust', 'Solana']
45
+
46
+ # Fetch a specific task
47
+ task = await client.get_task(1)
48
+ if task:
49
+ print(task.title)
50
+ print(task.status) # TaskStatus.OPEN
51
+
52
+ # Fetch all tasks
53
+ all_tasks = await client.get_all_tasks()
54
+
55
+ # Total value locked
56
+ tvl = await client.get_tvl()
57
+ print(f"TVL: {tvl:.2f} SOL")
58
+
59
+ asyncio.run(main())
60
+ ```
61
+
62
+ ## Tasks (sync helpers)
63
+
64
+ ```python
65
+ client = NexumClient.devnet()
66
+
67
+ # Synchronous wrappers — no async/await needed
68
+ tasks = client.get_all_tasks_sync()
69
+ tvl = client.get_tvl_sync()
70
+ ```
71
+
72
+ ## Utilities
73
+
74
+ ```python
75
+ from nexum_sdk import (
76
+ sol_to_lamports,
77
+ lamports_to_sol,
78
+ get_sbt_level,
79
+ get_sbt_label,
80
+ days_left,
81
+ short_address,
82
+ )
83
+
84
+ sol_to_lamports(1.5) # 1500000000
85
+ lamports_to_sol(1_000_000_000) # 1.0
86
+
87
+ get_sbt_level(20) # 3
88
+ get_sbt_label(3) # "Expert"
89
+
90
+ days_left(deadline_unix) # 7
91
+
92
+ short_address("7yn8tuqH...NNzA") # "7yn8...NNzA"
93
+ ```
94
+
95
+ ## Constants
96
+
97
+ ```python
98
+ from nexum_sdk import (
99
+ NEXUM_PROGRAM_ID,
100
+ NEXUM_DEVNET_RPC,
101
+ PLATFORM_FEE_BPS,
102
+ SBT_LEVELS,
103
+ )
104
+ ```
105
+
106
+ ## Types
107
+
108
+ ```python
109
+ from nexum_sdk import NexumTask, NexumProfile, NexumDispute, TaskStatus, Network, TaskFilter
110
+
111
+ # Filter tasks
112
+ filter_ = TaskFilter(status=TaskStatus.IN_PROGRESS)
113
+ tasks = await client.get_all_tasks(filter_)
114
+ ```
115
+
116
+ ## Links
117
+
118
+ - [NEXUM Protocol](https://nexum-protocol.netlify.app)
119
+ - [GitHub](https://github.com/Nexumprotocol/nexum-sdk)
120
+ - [PyPI](https://pypi.org/project/nexum-sdk)
121
+
122
+ ## License
123
+
124
+ MIT
@@ -0,0 +1,6 @@
1
+ from .client import NexumClient
2
+ from .types import NexumTask, NexumProfile, NexumDispute, TaskStatus, Network, TaskFilter
3
+ from .constants import NEXUM_PROGRAM_ID, NEXUM_DEVNET_RPC, PLATFORM_FEE_BPS, SBT_LEVELS
4
+ from .utils import sol_to_lamports, lamports_to_sol, get_sbt_level, get_sbt_label, days_left, short_address
5
+
6
+ __version__ = "0.1.0"
@@ -0,0 +1,77 @@
1
+ import struct, asyncio, base64
2
+ from typing import Optional, List
3
+ import httpx
4
+ from .constants import NEXUM_PROGRAM_ID, NEXUM_DEVNET_RPC, NEXUM_MAINNET_RPC
5
+ from .types import NexumTask, NexumProfile, NexumDispute, TaskStatus, Network, TaskFilter
6
+
7
+ class NexumClient:
8
+ def __init__(self, network=Network.DEVNET, rpc_url=None):
9
+ self.network = network
10
+ self.program_id = NEXUM_PROGRAM_ID
11
+ self.rpc_url = rpc_url or (NEXUM_DEVNET_RPC if network == Network.DEVNET else NEXUM_MAINNET_RPC)
12
+
13
+ @classmethod
14
+ def devnet(cls, rpc_url=None): return cls(Network.DEVNET, rpc_url)
15
+ @classmethod
16
+ def mainnet(cls, rpc_url=None): return cls(Network.MAINNET, rpc_url)
17
+
18
+ async def _rpc(self, method, params):
19
+ async with httpx.AsyncClient(timeout=30) as c:
20
+ r = await c.post(self.rpc_url, json={"jsonrpc":"2.0","id":1,"method":method,"params":params})
21
+ return r.json().get("result")
22
+
23
+ async def get_open_tasks(self): return await self.get_all_tasks(TaskFilter(status=TaskStatus.OPEN))
24
+
25
+ async def get_all_tasks(self, filter_=None):
26
+ result = await self._rpc("getProgramAccounts",[self.program_id,{"encoding":"base64","filters":[{"dataSize":892}]}])
27
+ if not result: return []
28
+ tasks = []
29
+ for item in result:
30
+ try:
31
+ data = base64.b64decode(item["account"]["data"][0])
32
+ tasks.append(self._deserialize_task(data))
33
+ except: continue
34
+ if filter_ and filter_.status:
35
+ tasks = [t for t in tasks if t.status == filter_.status]
36
+ return tasks
37
+
38
+ async def get_task(self, task_id):
39
+ try:
40
+ from .utils import sol_to_lamports
41
+ from solders.pubkey import Pubkey
42
+ import struct
43
+ id_bytes = struct.pack('<Q', task_id)
44
+ pda, _ = Pubkey.find_program_address([b"task", id_bytes], Pubkey.from_string(self.program_id))
45
+ result = await self._rpc("getAccountInfo",[str(pda),{"encoding":"base64"}])
46
+ if not result or not result.get("value"): return None
47
+ data = base64.b64decode(result["value"]["data"][0])
48
+ return self._deserialize_task(data)
49
+ except: return None
50
+
51
+ async def get_tvl(self):
52
+ tasks = await self.get_all_tasks()
53
+ return sum(t.reward_sol for t in tasks if t.status in [TaskStatus.OPEN, TaskStatus.IN_PROGRESS])
54
+
55
+ def _deserialize_task(self, data):
56
+ o = 8
57
+ task_id = struct.unpack_from('<Q',data,o)[0]; o+=8
58
+ creator = self._pk(data,o); o+=32
59
+ tl=struct.unpack_from('<I',data,o)[0];o+=4; title=data[o:o+tl].decode();o+=tl
60
+ dl=struct.unpack_from('<I',data,o)[0];o+=4; desc=data[o:o+dl].decode();o+=dl
61
+ sl=struct.unpack_from('<I',data,o)[0];o+=4; skills=data[o:o+sl].decode();o+=sl
62
+ reward=struct.unpack_from('<Q',data,o)[0];o+=8
63
+ deadline=struct.unpack_from('<q',data,o)[0];o+=8
64
+ sm={0:TaskStatus.OPEN,1:TaskStatus.IN_PROGRESS,2:TaskStatus.COMPLETED,3:TaskStatus.DISPUTED,4:TaskStatus.CANCELLED}
65
+ status=sm.get(data[o],TaskStatus.OPEN);o+=1
66
+ hw=data[o]==1;o+=1
67
+ worker=self._pk(data,o) if hw else None
68
+ if hw: o+=32
69
+ bump=data[o];o+=1; eb=data[o]
70
+ return NexumTask(task_id,creator,title,desc,skills,reward,deadline,status,worker,bump,eb)
71
+
72
+ def _pk(self,data,o):
73
+ import base58
74
+ return base58.b58encode(data[o:o+32]).decode()
75
+
76
+ def get_all_tasks_sync(self, filter_=None): return asyncio.run(self.get_all_tasks(filter_))
77
+ def get_tvl_sync(self): return asyncio.run(self.get_tvl())
@@ -0,0 +1,8 @@
1
+ NEXUM_PROGRAM_ID = "7yn8tuqHbNFRojEgiWeSoJkYjYtmdh1w4dKA2bCgNNzA"
2
+ NEXUM_DEVNET_RPC = "https://api.devnet.solana.com"
3
+ NEXUM_MAINNET_RPC = "https://api.mainnet-beta.solana.com"
4
+ PLATFORM_FEE_BPS = 250
5
+ LAMPORTS_PER_SOL = 1_000_000_000
6
+ SBT_LEVELS = {0:"Newcomer",1:"Contributor",2:"Builder",3:"Expert",4:"Legend"}
7
+ SBT_THRESHOLDS = [0, 5, 15, 30, 50]
8
+ SEEDS = {"task":b"task","escrow":b"escrow","profile":b"profile","dispute":b"dispute"}
@@ -0,0 +1,43 @@
1
+ from dataclasses import dataclass
2
+ from enum import Enum
3
+ from typing import Optional
4
+
5
+ class TaskStatus(str, Enum):
6
+ OPEN = "open"
7
+ IN_PROGRESS = "inProgress"
8
+ COMPLETED = "completed"
9
+ DISPUTED = "disputed"
10
+ CANCELLED = "cancelled"
11
+
12
+ class Network(str, Enum):
13
+ DEVNET = "devnet"
14
+ MAINNET = "mainnet-beta"
15
+
16
+ @dataclass
17
+ class NexumTask:
18
+ task_id: int; creator: str; title: str; description: str
19
+ required_skills: str; reward_lamports: int; deadline_unix: int
20
+ status: TaskStatus; worker: Optional[str]; bump: int; escrow_bump: int
21
+ @property
22
+ def reward_sol(self): return self.reward_lamports / 1_000_000_000
23
+ @property
24
+ def skills_list(self): return [s.strip() for s in self.required_skills.split(',')]
25
+
26
+ @dataclass
27
+ class NexumProfile:
28
+ owner: str; username: str; skills: str; reputation: int
29
+ tasks_completed: int; tasks_created: int; sbt_level: int; bump: int
30
+ @property
31
+ def sbt_label(self):
32
+ from .constants import SBT_LEVELS
33
+ return SBT_LEVELS.get(self.sbt_level, "Unknown")
34
+
35
+ @dataclass
36
+ class NexumDispute:
37
+ task_id: int; opened_by: str; reason: str; resolved: bool; bump: int
38
+
39
+ @dataclass
40
+ class TaskFilter:
41
+ status: Optional[TaskStatus] = None
42
+ creator: Optional[str] = None
43
+ worker: Optional[str] = None
@@ -0,0 +1,15 @@
1
+ import time, struct
2
+ from .constants import LAMPORTS_PER_SOL, SBT_LEVELS, SBT_THRESHOLDS, PLATFORM_FEE_BPS
3
+
4
+ def sol_to_lamports(sol): return int(sol * LAMPORTS_PER_SOL)
5
+ def lamports_to_sol(lamps): return lamps / LAMPORTS_PER_SOL
6
+ def get_sbt_level(tasks):
7
+ for i in range(len(SBT_THRESHOLDS)-1,-1,-1):
8
+ if tasks >= SBT_THRESHOLDS[i]: return i
9
+ return 0
10
+ def get_sbt_label(level): return SBT_LEVELS.get(level, "Unknown")
11
+ def days_left(deadline): return max(0, (deadline - int(time.time())) // 86400)
12
+ def short_address(pk): return f"{pk[:4]}...{pk[-4:]}"
13
+ def explorer_url(val, type_="address", cluster="devnet"):
14
+ cp = f"?cluster={cluster}" if cluster != "mainnet-beta" else ""
15
+ return f"https://explorer.solana.com/{type_}/{val}{cp}"
@@ -0,0 +1,12 @@
1
+ Metadata-Version: 2.4
2
+ Name: nexum-sdk
3
+ Version: 0.1.0
4
+ Summary: Official Python SDK for NEXUM Protocol on Solana
5
+ Author-email: NEXUM Protocol <protocolnexum@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://nexum-protocol.netlify.app
8
+ Project-URL: Repository, https://github.com/Nexumprotocol/nexum-sdk
9
+ Requires-Python: >=3.10
10
+ Requires-Dist: httpx>=0.27.0
11
+ Requires-Dist: base58>=2.1.1
12
+ Requires-Dist: solders>=0.21.0
@@ -0,0 +1,12 @@
1
+ README.md
2
+ pyproject.toml
3
+ nexum_sdk/__init__.py
4
+ nexum_sdk/client.py
5
+ nexum_sdk/constants.py
6
+ nexum_sdk/types.py
7
+ nexum_sdk/utils.py
8
+ nexum_sdk.egg-info/PKG-INFO
9
+ nexum_sdk.egg-info/SOURCES.txt
10
+ nexum_sdk.egg-info/dependency_links.txt
11
+ nexum_sdk.egg-info/requires.txt
12
+ nexum_sdk.egg-info/top_level.txt
@@ -0,0 +1,3 @@
1
+ httpx>=0.27.0
2
+ base58>=2.1.1
3
+ solders>=0.21.0
@@ -0,0 +1 @@
1
+ nexum_sdk
@@ -0,0 +1,20 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "nexum-sdk"
7
+ version = "0.1.0"
8
+ description = "Official Python SDK for NEXUM Protocol on Solana"
9
+ license = {text = "MIT"}
10
+ authors = [{name = "NEXUM Protocol", email = "protocolnexum@gmail.com"}]
11
+ requires-python = ">=3.10"
12
+ dependencies = ["httpx>=0.27.0", "base58>=2.1.1", "solders>=0.21.0"]
13
+
14
+ [project.urls]
15
+ Homepage = "https://nexum-protocol.netlify.app"
16
+ Repository = "https://github.com/Nexumprotocol/nexum-sdk"
17
+
18
+ [tool.setuptools.packages.find]
19
+ where = ["."]
20
+ include = ["nexum_sdk*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+