m2mcent-sdk 1.0.3__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.
- m2mcent_sdk-1.0.3/PKG-INFO +40 -0
- m2mcent_sdk-1.0.3/README.md +22 -0
- m2mcent_sdk-1.0.3/m2mcent/__init__.py +4 -0
- m2mcent_sdk-1.0.3/m2mcent/client.py +164 -0
- m2mcent_sdk-1.0.3/m2mcent/langchain_toolkit.py +93 -0
- m2mcent_sdk-1.0.3/m2mcent_sdk.egg-info/PKG-INFO +40 -0
- m2mcent_sdk-1.0.3/m2mcent_sdk.egg-info/SOURCES.txt +10 -0
- m2mcent_sdk-1.0.3/m2mcent_sdk.egg-info/dependency_links.txt +1 -0
- m2mcent_sdk-1.0.3/m2mcent_sdk.egg-info/requires.txt +2 -0
- m2mcent_sdk-1.0.3/m2mcent_sdk.egg-info/top_level.txt +1 -0
- m2mcent_sdk-1.0.3/setup.cfg +4 -0
- m2mcent_sdk-1.0.3/setup.py +21 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: m2mcent-sdk
|
|
3
|
+
Version: 1.0.3
|
|
4
|
+
Summary: Official Python SDK & LangChain Toolkit for M2MCent x402 V2 Protocol on Base Mainnet (1,057 Deterministic Nodes, Vouch Grade A)
|
|
5
|
+
Author: M2MCent Protocol
|
|
6
|
+
Author-email: hello@m2mcent.com
|
|
7
|
+
Requires-Python: >=3.8
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: requests>=2.28.0
|
|
10
|
+
Requires-Dist: eth-account>=0.10.0
|
|
11
|
+
Dynamic: author
|
|
12
|
+
Dynamic: author-email
|
|
13
|
+
Dynamic: description
|
|
14
|
+
Dynamic: description-content-type
|
|
15
|
+
Dynamic: requires-dist
|
|
16
|
+
Dynamic: requires-python
|
|
17
|
+
Dynamic: summary
|
|
18
|
+
|
|
19
|
+
# ๐ m2mcent-sdk (v1.0.3)
|
|
20
|
+
|
|
21
|
+
Official Python SDK (`M2MClient`, `M2MCentToolkit`) for the **M2MCent x402 V2 Protocol** on **Base Mainnet (`eip155:8453`)**.
|
|
22
|
+
|
|
23
|
+
- **1,057 Deterministic Micro-Services** (`$0.010`โ`$0.250` USDC, `<250ms` compute SLA)
|
|
24
|
+
- **Vouch Trust Index:** Grade A (`100/100`) ยท Post-Quantum `ML-DSA-65` (FIPS 204)
|
|
25
|
+
- **Smart Contract Escrow:** `0x5d47070A36A37DAf417e64FF27a1e5B3F1c84efa`
|
|
26
|
+
- **Institutional Safe Treasury:** `0x8aaBAB75bE8825d0f5D514a9a5cBa04B7bF84920`
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
```bash
|
|
30
|
+
pip install m2mcent-sdk
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Quickstart
|
|
34
|
+
```python
|
|
35
|
+
from m2mcent import M2MCentToolkit
|
|
36
|
+
|
|
37
|
+
tk = M2MCentToolkit(private_key="0xYOUR_BASE_WALLET_KEY")
|
|
38
|
+
preview = tk.preview_tool("autonomous-trading-bot-mcp", {"symbol": "ETH"})
|
|
39
|
+
result = tk.call_tool("autonomous-trading-bot-mcp", {"symbol": "ETH"}, validate_preview=True)
|
|
40
|
+
```
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# ๐ m2mcent-sdk (v1.0.3)
|
|
2
|
+
|
|
3
|
+
Official Python SDK (`M2MClient`, `M2MCentToolkit`) for the **M2MCent x402 V2 Protocol** on **Base Mainnet (`eip155:8453`)**.
|
|
4
|
+
|
|
5
|
+
- **1,057 Deterministic Micro-Services** (`$0.010`โ`$0.250` USDC, `<250ms` compute SLA)
|
|
6
|
+
- **Vouch Trust Index:** Grade A (`100/100`) ยท Post-Quantum `ML-DSA-65` (FIPS 204)
|
|
7
|
+
- **Smart Contract Escrow:** `0x5d47070A36A37DAf417e64FF27a1e5B3F1c84efa`
|
|
8
|
+
- **Institutional Safe Treasury:** `0x8aaBAB75bE8825d0f5D514a9a5cBa04B7bF84920`
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
```bash
|
|
12
|
+
pip install m2mcent-sdk
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quickstart
|
|
16
|
+
```python
|
|
17
|
+
from m2mcent import M2MCentToolkit
|
|
18
|
+
|
|
19
|
+
tk = M2MCentToolkit(private_key="0xYOUR_BASE_WALLET_KEY")
|
|
20
|
+
preview = tk.preview_tool("autonomous-trading-bot-mcp", {"symbol": "ETH"})
|
|
21
|
+
result = tk.call_tool("autonomous-trading-bot-mcp", {"symbol": "ETH"}, validate_preview=True)
|
|
22
|
+
```
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
import base64
|
|
3
|
+
import json
|
|
4
|
+
import time
|
|
5
|
+
import secrets
|
|
6
|
+
from eth_account import Account
|
|
7
|
+
from eth_account.messages import encode_typed_data
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class M2MClient:
|
|
11
|
+
"""
|
|
12
|
+
M2MCent SDK Client (Python v2.0 - x402 V2 Compliant)
|
|
13
|
+
Implements automated x402 V2 EIP-3009 payment protocol on Base Mainnet (8453).
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
ESCROW_ADDRESS = "0x5d47070A36A37DAf417e64FF27a1e5B3F1c84efa"
|
|
17
|
+
TREASURY_ADDRESS = "0x8aaBAB75bE8825d0f5D514a9a5cBa04B7bF84920"
|
|
18
|
+
USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
|
|
19
|
+
CHAIN_ID = 8453 # Base Mainnet
|
|
20
|
+
|
|
21
|
+
USDC_DOMAIN_NAME = "USD Coin"
|
|
22
|
+
USDC_VERSION = "2"
|
|
23
|
+
|
|
24
|
+
def __init__(self, private_key: str, rpc_url: str = "https://mainnet.base.org", gateway_url: str = "https://api.m2mcent.com"):
|
|
25
|
+
clean_key = private_key if private_key.startswith("0x") else f"0x{private_key}"
|
|
26
|
+
self.account = Account.from_key(clean_key)
|
|
27
|
+
self.rpc_url = rpc_url
|
|
28
|
+
self.gateway_url = gateway_url.rstrip("/")
|
|
29
|
+
|
|
30
|
+
def _parse_402_challenge(self, response: requests.Response) -> dict:
|
|
31
|
+
header_b64 = response.headers.get("Payment-Required") or response.headers.get("payment-required")
|
|
32
|
+
if header_b64:
|
|
33
|
+
try:
|
|
34
|
+
decoded = json.loads(base64.b64decode(header_b64).decode("utf-8"))
|
|
35
|
+
accepts = decoded.get("accepts") or []
|
|
36
|
+
if accepts:
|
|
37
|
+
acc = accepts[0]
|
|
38
|
+
amount = acc.get("amount") or acc.get("maxAmountRequired")
|
|
39
|
+
if amount:
|
|
40
|
+
return {
|
|
41
|
+
"amountRaw": int(amount),
|
|
42
|
+
"escrow": acc.get("escrow") or (acc.get("extra") or {}).get("escrow") or acc.get("payTo") or self.ESCROW_ADDRESS,
|
|
43
|
+
"asset": acc.get("asset") or self.USDC_ADDRESS,
|
|
44
|
+
}
|
|
45
|
+
if decoded.get("amountRaw"):
|
|
46
|
+
return {
|
|
47
|
+
"amountRaw": int(decoded["amountRaw"]),
|
|
48
|
+
"escrow": decoded.get("escrow") or self.ESCROW_ADDRESS,
|
|
49
|
+
"asset": decoded.get("contract") or self.USDC_ADDRESS,
|
|
50
|
+
}
|
|
51
|
+
except Exception:
|
|
52
|
+
pass
|
|
53
|
+
|
|
54
|
+
try:
|
|
55
|
+
body = response.json()
|
|
56
|
+
except Exception:
|
|
57
|
+
body = {}
|
|
58
|
+
|
|
59
|
+
challenge = body.get("challenge") or {}
|
|
60
|
+
if challenge.get("amount"):
|
|
61
|
+
return {
|
|
62
|
+
"amountRaw": int(challenge["amount"]),
|
|
63
|
+
"escrow": challenge.get("escrow") or self.ESCROW_ADDRESS,
|
|
64
|
+
"asset": challenge.get("asset") or self.USDC_ADDRESS,
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
price_hdr = response.headers.get("x-402-price")
|
|
68
|
+
if price_hdr:
|
|
69
|
+
return {
|
|
70
|
+
"amountRaw": int(round(float(price_hdr) * 1_000_000)),
|
|
71
|
+
"escrow": response.headers.get("x-402-contract") or self.ESCROW_ADDRESS,
|
|
72
|
+
"asset": self.USDC_ADDRESS,
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
raise ValueError("Unable to parse HTTP 402 x402 V2 challenge from response.")
|
|
76
|
+
|
|
77
|
+
def _sign_authorization(self, challenge_meta: dict) -> str:
|
|
78
|
+
amount_raw = int(challenge_meta["amountRaw"])
|
|
79
|
+
escrow_addr = challenge_meta.get("escrow") or self.ESCROW_ADDRESS
|
|
80
|
+
usdc_addr = challenge_meta.get("asset") or self.USDC_ADDRESS
|
|
81
|
+
|
|
82
|
+
domain = {
|
|
83
|
+
"name": self.USDC_DOMAIN_NAME,
|
|
84
|
+
"version": self.USDC_VERSION,
|
|
85
|
+
"chainId": self.CHAIN_ID,
|
|
86
|
+
"verifyingContract": usdc_addr,
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
types = {
|
|
90
|
+
"TransferWithAuthorization": [
|
|
91
|
+
{"name": "from", "type": "address"},
|
|
92
|
+
{"name": "to", "type": "address"},
|
|
93
|
+
{"name": "value", "type": "uint256"},
|
|
94
|
+
{"name": "validAfter", "type": "uint256"},
|
|
95
|
+
{"name": "validBefore", "type": "uint256"},
|
|
96
|
+
{"name": "nonce", "type": "bytes32"},
|
|
97
|
+
]
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
valid_after = 0
|
|
101
|
+
valid_before = int(time.time()) + 3600
|
|
102
|
+
nonce_hex = "0x" + secrets.token_hex(32)
|
|
103
|
+
|
|
104
|
+
message = {
|
|
105
|
+
"from": self.account.address,
|
|
106
|
+
"to": escrow_addr,
|
|
107
|
+
"value": amount_raw,
|
|
108
|
+
"validAfter": valid_after,
|
|
109
|
+
"validBefore": valid_before,
|
|
110
|
+
"nonce": nonce_hex,
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
signable_message = encode_typed_data(domain_data=domain, message_types=types, message_data=message)
|
|
114
|
+
signed = self.account.sign_message(signable_message)
|
|
115
|
+
sig_hex = signed.signature.hex()
|
|
116
|
+
if not sig_hex.startswith("0x"):
|
|
117
|
+
sig_hex = "0x" + sig_hex
|
|
118
|
+
|
|
119
|
+
auth_str = {
|
|
120
|
+
"from": self.account.address,
|
|
121
|
+
"to": escrow_addr,
|
|
122
|
+
"value": str(amount_raw),
|
|
123
|
+
"validAfter": valid_after,
|
|
124
|
+
"validBefore": valid_before,
|
|
125
|
+
"nonce": nonce_hex,
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
payload = {
|
|
129
|
+
"x402Version": 2,
|
|
130
|
+
"scheme": "exact",
|
|
131
|
+
"network": f"eip155:{self.CHAIN_ID}",
|
|
132
|
+
"payload": {
|
|
133
|
+
"signature": sig_hex,
|
|
134
|
+
"authorization": auth_str,
|
|
135
|
+
},
|
|
136
|
+
**auth_str,
|
|
137
|
+
"signature": sig_hex,
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return base64.b64encode(json.dumps(payload).encode("utf-8")).decode("utf-8")
|
|
141
|
+
|
|
142
|
+
def request(self, method: str, url: str, max_retries: int = 2, **kwargs) -> requests.Response:
|
|
143
|
+
response = requests.request(method, url, **kwargs)
|
|
144
|
+
|
|
145
|
+
if response.status_code == 402:
|
|
146
|
+
challenge_meta = self._parse_402_challenge(response)
|
|
147
|
+
sig_payload_b64 = self._sign_authorization(challenge_meta)
|
|
148
|
+
|
|
149
|
+
headers = dict(kwargs.get("headers") or {})
|
|
150
|
+
headers["Payment-Signature"] = sig_payload_b64
|
|
151
|
+
headers["x-payment"] = sig_payload_b64
|
|
152
|
+
kwargs["headers"] = headers
|
|
153
|
+
|
|
154
|
+
for i in range(max_retries):
|
|
155
|
+
retry_resp = requests.request(method, url, **kwargs)
|
|
156
|
+
if retry_resp.status_code != 402:
|
|
157
|
+
return retry_resp
|
|
158
|
+
time.sleep((i + 1) * 1.5)
|
|
159
|
+
return retry_resp
|
|
160
|
+
|
|
161
|
+
return response
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
M2MCentClient = M2MClient
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""
|
|
2
|
+
M2MCent LangChain & LangGraph Toolkit (x402 V2 Compliant)
|
|
3
|
+
Enables autonomous LangChain agents to discover, preview, quote, and invoke 1,057+
|
|
4
|
+
monetized deterministic x402 tools on Base Mainnet (chainId: 8453).
|
|
5
|
+
|
|
6
|
+
Smart Contract Escrow: 0x5d47070A36A37DAf417e64FF27a1e5B3F1c84efa
|
|
7
|
+
Institutional Safe Treasury: 0x8aaBAB75bE8825d0f5D514a9a5cBa04B7bF84920
|
|
8
|
+
Vouch Protocol: Grade A (100/100) Certified | Post-Quantum ML-DSA-65 Ready
|
|
9
|
+
"""
|
|
10
|
+
import requests
|
|
11
|
+
from typing import List, Dict, Any, Optional
|
|
12
|
+
from .client import M2MClient
|
|
13
|
+
|
|
14
|
+
ESCROW_CONTRACT_ADDRESS = "0x5d47070A36A37DAf417e64FF27a1e5B3F1c84efa"
|
|
15
|
+
TREASURY_SAFE_ADDRESS = "0x8aaBAB75bE8825d0f5D514a9a5cBa04B7bF84920"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class M2MCentToolkit:
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
gateway_url: str = "https://api.m2mcent.com",
|
|
22
|
+
private_key: Optional[str] = None,
|
|
23
|
+
rpc_url: str = "https://mainnet.base.org",
|
|
24
|
+
):
|
|
25
|
+
self.gateway_url = gateway_url.rstrip("/")
|
|
26
|
+
self.private_key = private_key
|
|
27
|
+
self.client = M2MClient(private_key, rpc_url=rpc_url, gateway_url=self.gateway_url) if private_key else None
|
|
28
|
+
self._tools_cache: List[Dict[str, Any]] = []
|
|
29
|
+
|
|
30
|
+
def _normalize_slug(self, tool_name_or_slug: str) -> str:
|
|
31
|
+
# Support both underscore function names (autonomous_trading_bot_mcp) and slugs (autonomous-trading-bot-mcp)
|
|
32
|
+
if self._tools_cache:
|
|
33
|
+
for t in self._tools_cache:
|
|
34
|
+
if t.get("id") == tool_name_or_slug or t.get("name") == tool_name_or_slug:
|
|
35
|
+
return t.get("id") or tool_name_or_slug.replace("_", "-")
|
|
36
|
+
return tool_name_or_slug.replace("_", "-")
|
|
37
|
+
|
|
38
|
+
def fetch_tools(self, limit: int = 1062) -> List[Dict[str, Any]]:
|
|
39
|
+
"""Fetch available tools from M2MCent Gateway (/api/v1/tools)."""
|
|
40
|
+
resp = requests.get(f"{self.gateway_url}/api/v1/tools", params={"limit": limit}, timeout=10)
|
|
41
|
+
if resp.status_code == 200:
|
|
42
|
+
self._tools_cache = resp.json().get("tools", [])
|
|
43
|
+
return self._tools_cache
|
|
44
|
+
return []
|
|
45
|
+
|
|
46
|
+
def quote_tool(self, tool_name: str) -> Dict[str, Any]:
|
|
47
|
+
"""Free pre-flight pricing quote (/:id/quote)."""
|
|
48
|
+
slug = self._normalize_slug(tool_name)
|
|
49
|
+
resp = requests.get(f"{self.gateway_url}/{slug}/quote", timeout=10)
|
|
50
|
+
return resp.json()
|
|
51
|
+
|
|
52
|
+
def preview_tool(self, tool_name: str, payload: Dict[str, Any]) -> Dict[str, Any]:
|
|
53
|
+
"""Free syntactic schema validation & dry-run preview (/:id/api/preview)."""
|
|
54
|
+
slug = self._normalize_slug(tool_name)
|
|
55
|
+
resp = requests.post(f"{self.gateway_url}/{slug}/api/preview", json=payload, timeout=10)
|
|
56
|
+
return resp.json()
|
|
57
|
+
|
|
58
|
+
def call_tool(
|
|
59
|
+
self,
|
|
60
|
+
tool_name: str,
|
|
61
|
+
payload: Dict[str, Any],
|
|
62
|
+
payment_signature: Optional[str] = None,
|
|
63
|
+
validate_preview: bool = False,
|
|
64
|
+
) -> Dict[str, Any]:
|
|
65
|
+
"""Invoke an M2MCent deterministic tool on /{slug}/api/process with automatic EIP-3009 signing."""
|
|
66
|
+
slug = self._normalize_slug(tool_name)
|
|
67
|
+
if validate_preview:
|
|
68
|
+
prev = self.preview_tool(slug, payload)
|
|
69
|
+
if prev.get("status") == "VALIDATION_FAILED":
|
|
70
|
+
return prev
|
|
71
|
+
|
|
72
|
+
endpoint = f"{self.gateway_url}/{slug}/api/process"
|
|
73
|
+
headers = {"Content-Type": "application/json"}
|
|
74
|
+
|
|
75
|
+
if payment_signature:
|
|
76
|
+
headers["Payment-Signature"] = payment_signature
|
|
77
|
+
headers["x-payment"] = payment_signature
|
|
78
|
+
response = requests.post(endpoint, json=payload, headers=headers, timeout=20)
|
|
79
|
+
return response.json()
|
|
80
|
+
|
|
81
|
+
if self.client:
|
|
82
|
+
response = self.client.request("POST", endpoint, json=payload, headers=headers, timeout=20)
|
|
83
|
+
return response.json()
|
|
84
|
+
|
|
85
|
+
response = requests.post(endpoint, json=payload, headers=headers, timeout=20)
|
|
86
|
+
if response.status_code == 402:
|
|
87
|
+
return {
|
|
88
|
+
"status": "Payment Required",
|
|
89
|
+
"code": 402,
|
|
90
|
+
"challenge": response.headers.get("Payment-Required") or response.headers.get("payment-required"),
|
|
91
|
+
"details": response.json(),
|
|
92
|
+
}
|
|
93
|
+
return response.json()
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: m2mcent-sdk
|
|
3
|
+
Version: 1.0.3
|
|
4
|
+
Summary: Official Python SDK & LangChain Toolkit for M2MCent x402 V2 Protocol on Base Mainnet (1,057 Deterministic Nodes, Vouch Grade A)
|
|
5
|
+
Author: M2MCent Protocol
|
|
6
|
+
Author-email: hello@m2mcent.com
|
|
7
|
+
Requires-Python: >=3.8
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: requests>=2.28.0
|
|
10
|
+
Requires-Dist: eth-account>=0.10.0
|
|
11
|
+
Dynamic: author
|
|
12
|
+
Dynamic: author-email
|
|
13
|
+
Dynamic: description
|
|
14
|
+
Dynamic: description-content-type
|
|
15
|
+
Dynamic: requires-dist
|
|
16
|
+
Dynamic: requires-python
|
|
17
|
+
Dynamic: summary
|
|
18
|
+
|
|
19
|
+
# ๐ m2mcent-sdk (v1.0.3)
|
|
20
|
+
|
|
21
|
+
Official Python SDK (`M2MClient`, `M2MCentToolkit`) for the **M2MCent x402 V2 Protocol** on **Base Mainnet (`eip155:8453`)**.
|
|
22
|
+
|
|
23
|
+
- **1,057 Deterministic Micro-Services** (`$0.010`โ`$0.250` USDC, `<250ms` compute SLA)
|
|
24
|
+
- **Vouch Trust Index:** Grade A (`100/100`) ยท Post-Quantum `ML-DSA-65` (FIPS 204)
|
|
25
|
+
- **Smart Contract Escrow:** `0x5d47070A36A37DAf417e64FF27a1e5B3F1c84efa`
|
|
26
|
+
- **Institutional Safe Treasury:** `0x8aaBAB75bE8825d0f5D514a9a5cBa04B7bF84920`
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
```bash
|
|
30
|
+
pip install m2mcent-sdk
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Quickstart
|
|
34
|
+
```python
|
|
35
|
+
from m2mcent import M2MCentToolkit
|
|
36
|
+
|
|
37
|
+
tk = M2MCentToolkit(private_key="0xYOUR_BASE_WALLET_KEY")
|
|
38
|
+
preview = tk.preview_tool("autonomous-trading-bot-mcp", {"symbol": "ETH"})
|
|
39
|
+
result = tk.call_tool("autonomous-trading-bot-mcp", {"symbol": "ETH"}, validate_preview=True)
|
|
40
|
+
```
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
setup.py
|
|
3
|
+
m2mcent/__init__.py
|
|
4
|
+
m2mcent/client.py
|
|
5
|
+
m2mcent/langchain_toolkit.py
|
|
6
|
+
m2mcent_sdk.egg-info/PKG-INFO
|
|
7
|
+
m2mcent_sdk.egg-info/SOURCES.txt
|
|
8
|
+
m2mcent_sdk.egg-info/dependency_links.txt
|
|
9
|
+
m2mcent_sdk.egg-info/requires.txt
|
|
10
|
+
m2mcent_sdk.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
m2mcent
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
readme_path = Path(__file__).parent / "README.md"
|
|
5
|
+
long_desc = readme_path.read_text(encoding="utf-8") if readme_path.exists() else ""
|
|
6
|
+
|
|
7
|
+
setup(
|
|
8
|
+
name="m2mcent-sdk",
|
|
9
|
+
version="1.0.3",
|
|
10
|
+
description="Official Python SDK & LangChain Toolkit for M2MCent x402 V2 Protocol on Base Mainnet (1,057 Deterministic Nodes, Vouch Grade A)",
|
|
11
|
+
long_description=long_desc,
|
|
12
|
+
long_description_content_type="text/markdown",
|
|
13
|
+
author="M2MCent Protocol",
|
|
14
|
+
author_email="hello@m2mcent.com",
|
|
15
|
+
packages=find_packages(),
|
|
16
|
+
install_requires=[
|
|
17
|
+
"requests>=2.28.0",
|
|
18
|
+
"eth-account>=0.10.0",
|
|
19
|
+
],
|
|
20
|
+
python_requires=">=3.8",
|
|
21
|
+
)
|