soltex-router 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.
- soltex_router-0.1.0/PKG-INFO +112 -0
- soltex_router-0.1.0/README.md +86 -0
- soltex_router-0.1.0/setup.cfg +4 -0
- soltex_router-0.1.0/setup.py +28 -0
- soltex_router-0.1.0/soltex_router/__init__.py +0 -0
- soltex_router-0.1.0/soltex_router/client.py +203 -0
- soltex_router-0.1.0/soltex_router.egg-info/PKG-INFO +112 -0
- soltex_router-0.1.0/soltex_router.egg-info/SOURCES.txt +9 -0
- soltex_router-0.1.0/soltex_router.egg-info/dependency_links.txt +1 -0
- soltex_router-0.1.0/soltex_router.egg-info/requires.txt +3 -0
- soltex_router-0.1.0/soltex_router.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: soltex_router
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Enterprise-grade MEV-protected transaction router & fee sponsor for AI Agents on Solana
|
|
5
|
+
Home-page: https://github.com/soltex-router/SOLTEX_ROUTER
|
|
6
|
+
Author: SOLTEX_ROUTER
|
|
7
|
+
Author-email: soltex_router@protonmail.com
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
12
|
+
Requires-Python: >=3.10
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
Requires-Dist: requests>=2.25.1
|
|
15
|
+
Requires-Dist: solders>=0.23.0
|
|
16
|
+
Requires-Dist: base58>=2.1.1
|
|
17
|
+
Dynamic: author
|
|
18
|
+
Dynamic: author-email
|
|
19
|
+
Dynamic: classifier
|
|
20
|
+
Dynamic: description
|
|
21
|
+
Dynamic: description-content-type
|
|
22
|
+
Dynamic: home-page
|
|
23
|
+
Dynamic: requires-dist
|
|
24
|
+
Dynamic: requires-python
|
|
25
|
+
Dynamic: summary
|
|
26
|
+
|
|
27
|
+
# SOLTEX_ROUTER Agent SDK
|
|
28
|
+
**Fund one treasury. Run 10,000 autonomous agents.**
|
|
29
|
+
|
|
30
|
+
Solana's first zero-gas, MEV-protected intent router for AI Agents.
|
|
31
|
+
|
|
32
|
+
Stop manually funding hundreds of bot wallets with SOL dust. `soltex router` is a meta-routing SDK that completely abstracts gas fees and Jito tips, allowing your AI agents to execute swaps with 0.0000 SOL balance.
|
|
33
|
+
|
|
34
|
+
## ā” Why SOLTEX Router?
|
|
35
|
+
|
|
36
|
+
### ā The Old Way (Painful)
|
|
37
|
+
Managing 50 AI trading bots meant funding 50 separate Keypairs with SOL, calculating dynamic priority fees, guessing Jito tip percentiles, and handling RPC rate limits.
|
|
38
|
+
|
|
39
|
+
### ā
The SOLTEX Way (Intent-Centric)
|
|
40
|
+
Deposit SOL into a single Treasury Dashboard. Your agents just sign the intent locally. The SOLTEX Backend sponsors the transaction, auto-injects the 75th-percentile priority fee, routes through Jito Block Engine, and broadcasts it.
|
|
41
|
+
|
|
42
|
+
## š„ Core Features
|
|
43
|
+
- ā½ **Absolute Gas Abstraction:** Bots can operate with completely empty wallets.
|
|
44
|
+
- š”ļø **Default MEV Protection:** 100% of transactions are routed via Jito Private Mempool. Zero sandwich attacks.
|
|
45
|
+
- š **Jupiter API Native:** Built-in wrapper for optimal swap routes and instant execution.
|
|
46
|
+
- š **Trustless Architecture:** Your agent's private key never leaves the local environment. We only receive a locally `partial_signed` payload.
|
|
47
|
+
|
|
48
|
+
## š¦ Installation
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install soltex-router
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## š 1-Minute Quick Start
|
|
55
|
+
Look how incredibly simple it is to swap tokens without worrying about gas fees.
|
|
56
|
+
|
|
57
|
+
> ā ļø **IMPORTANT NOTE:** Your agent's wallet needs **exactly 0.000 SOL** to pay for gas, but it **MUST contain the tokens you are trying to swap** (e.g., 10 USDC).
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
import logging
|
|
61
|
+
from solders.keypair import Keypair
|
|
62
|
+
from client import AgentRouter
|
|
63
|
+
|
|
64
|
+
logging.basicConfig(level=logging.INFO)
|
|
65
|
+
|
|
66
|
+
# 1. Load your AI agent's wallet
|
|
67
|
+
# (Ensure this wallet holds the USDC you want to swap. 0 SOL is perfectly fine!)
|
|
68
|
+
# but receiving a BRAND NEW token type may require ~0.002 SOL for ATA creation rent!)
|
|
69
|
+
PRIVATE_KEY_BASE58 = "your_agent_private_key"
|
|
70
|
+
bot_wallet = Keypair.from_base58_string(PRIVATE_KEY_BASE58)
|
|
71
|
+
print(f"Agent Wallet: {bot_wallet.pubkey()}")
|
|
72
|
+
|
|
73
|
+
# 2. Connect to SOLTEX
|
|
74
|
+
router = AgentRouter(
|
|
75
|
+
api_key="SOLTEX_your_actual_api_key", # Issued via SOLTEX Dashboard
|
|
76
|
+
payer=bot_wallet,
|
|
77
|
+
rpc_url="https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY",
|
|
78
|
+
server_url="https://api.soltex-router.com"
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
def main():
|
|
82
|
+
# 3. Execute Swap via Jupiter (Zero SOL required for gas or tips!)
|
|
83
|
+
print("\nSwapping 10 USDC ā SOL...")
|
|
84
|
+
result = router.swap(
|
|
85
|
+
input_mint="EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", # USDC
|
|
86
|
+
output_mint="So11111111111111111111111111111111111111112", # SOL
|
|
87
|
+
amount=10_000_000, # 10 USDC
|
|
88
|
+
slippage_bps=100 # 1% slippage
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
if result["success"]:
|
|
92
|
+
print(f"\nā
Gasless Swap Confirmed!")
|
|
93
|
+
print(f"TX Hash: {result['tx_hash']}")
|
|
94
|
+
print(f"Explorer: https://solscan.io/tx/{result['tx_hash']}")
|
|
95
|
+
else:
|
|
96
|
+
print(f"\nā Swap failed: {result['error']}")
|
|
97
|
+
|
|
98
|
+
if __name__ == "__main__":
|
|
99
|
+
main()
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
š Security & ToS
|
|
103
|
+
By using this SDK, you agree to the SOLTEX Terms of Service.
|
|
104
|
+
Open Source: This client SDK is 100% transparent. Inspect the code to verify that keys remain strictly on your machine.
|
|
105
|
+
|
|
106
|
+
## āļø Legal & Compliance
|
|
107
|
+
- For more detail, please visit https://github.com/soltex-router/SOLTEX_ROUTER
|
|
108
|
+
|
|
109
|
+
**Disclaimer**: This software is provided "AS IS". Use at your own risk.
|
|
110
|
+
Not financial advice. Not a custodial service.
|
|
111
|
+
|
|
112
|
+
contact: soltex_router@protonmail.com
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# SOLTEX_ROUTER Agent SDK
|
|
2
|
+
**Fund one treasury. Run 10,000 autonomous agents.**
|
|
3
|
+
|
|
4
|
+
Solana's first zero-gas, MEV-protected intent router for AI Agents.
|
|
5
|
+
|
|
6
|
+
Stop manually funding hundreds of bot wallets with SOL dust. `soltex router` is a meta-routing SDK that completely abstracts gas fees and Jito tips, allowing your AI agents to execute swaps with 0.0000 SOL balance.
|
|
7
|
+
|
|
8
|
+
## ā” Why SOLTEX Router?
|
|
9
|
+
|
|
10
|
+
### ā The Old Way (Painful)
|
|
11
|
+
Managing 50 AI trading bots meant funding 50 separate Keypairs with SOL, calculating dynamic priority fees, guessing Jito tip percentiles, and handling RPC rate limits.
|
|
12
|
+
|
|
13
|
+
### ā
The SOLTEX Way (Intent-Centric)
|
|
14
|
+
Deposit SOL into a single Treasury Dashboard. Your agents just sign the intent locally. The SOLTEX Backend sponsors the transaction, auto-injects the 75th-percentile priority fee, routes through Jito Block Engine, and broadcasts it.
|
|
15
|
+
|
|
16
|
+
## š„ Core Features
|
|
17
|
+
- ā½ **Absolute Gas Abstraction:** Bots can operate with completely empty wallets.
|
|
18
|
+
- š”ļø **Default MEV Protection:** 100% of transactions are routed via Jito Private Mempool. Zero sandwich attacks.
|
|
19
|
+
- š **Jupiter API Native:** Built-in wrapper for optimal swap routes and instant execution.
|
|
20
|
+
- š **Trustless Architecture:** Your agent's private key never leaves the local environment. We only receive a locally `partial_signed` payload.
|
|
21
|
+
|
|
22
|
+
## š¦ Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install soltex-router
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## š 1-Minute Quick Start
|
|
29
|
+
Look how incredibly simple it is to swap tokens without worrying about gas fees.
|
|
30
|
+
|
|
31
|
+
> ā ļø **IMPORTANT NOTE:** Your agent's wallet needs **exactly 0.000 SOL** to pay for gas, but it **MUST contain the tokens you are trying to swap** (e.g., 10 USDC).
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
import logging
|
|
35
|
+
from solders.keypair import Keypair
|
|
36
|
+
from client import AgentRouter
|
|
37
|
+
|
|
38
|
+
logging.basicConfig(level=logging.INFO)
|
|
39
|
+
|
|
40
|
+
# 1. Load your AI agent's wallet
|
|
41
|
+
# (Ensure this wallet holds the USDC you want to swap. 0 SOL is perfectly fine!)
|
|
42
|
+
# but receiving a BRAND NEW token type may require ~0.002 SOL for ATA creation rent!)
|
|
43
|
+
PRIVATE_KEY_BASE58 = "your_agent_private_key"
|
|
44
|
+
bot_wallet = Keypair.from_base58_string(PRIVATE_KEY_BASE58)
|
|
45
|
+
print(f"Agent Wallet: {bot_wallet.pubkey()}")
|
|
46
|
+
|
|
47
|
+
# 2. Connect to SOLTEX
|
|
48
|
+
router = AgentRouter(
|
|
49
|
+
api_key="SOLTEX_your_actual_api_key", # Issued via SOLTEX Dashboard
|
|
50
|
+
payer=bot_wallet,
|
|
51
|
+
rpc_url="https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY",
|
|
52
|
+
server_url="https://api.soltex-router.com"
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
def main():
|
|
56
|
+
# 3. Execute Swap via Jupiter (Zero SOL required for gas or tips!)
|
|
57
|
+
print("\nSwapping 10 USDC ā SOL...")
|
|
58
|
+
result = router.swap(
|
|
59
|
+
input_mint="EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", # USDC
|
|
60
|
+
output_mint="So11111111111111111111111111111111111111112", # SOL
|
|
61
|
+
amount=10_000_000, # 10 USDC
|
|
62
|
+
slippage_bps=100 # 1% slippage
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
if result["success"]:
|
|
66
|
+
print(f"\nā
Gasless Swap Confirmed!")
|
|
67
|
+
print(f"TX Hash: {result['tx_hash']}")
|
|
68
|
+
print(f"Explorer: https://solscan.io/tx/{result['tx_hash']}")
|
|
69
|
+
else:
|
|
70
|
+
print(f"\nā Swap failed: {result['error']}")
|
|
71
|
+
|
|
72
|
+
if __name__ == "__main__":
|
|
73
|
+
main()
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
š Security & ToS
|
|
77
|
+
By using this SDK, you agree to the SOLTEX Terms of Service.
|
|
78
|
+
Open Source: This client SDK is 100% transparent. Inspect the code to verify that keys remain strictly on your machine.
|
|
79
|
+
|
|
80
|
+
## āļø Legal & Compliance
|
|
81
|
+
- For more detail, please visit https://github.com/soltex-router/SOLTEX_ROUTER
|
|
82
|
+
|
|
83
|
+
**Disclaimer**: This software is provided "AS IS". Use at your own risk.
|
|
84
|
+
Not financial advice. Not a custodial service.
|
|
85
|
+
|
|
86
|
+
contact: soltex_router@protonmail.com
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
with open("README.md", "r", encoding="utf-8") as fh:
|
|
4
|
+
long_description = fh.read()
|
|
5
|
+
|
|
6
|
+
setup(
|
|
7
|
+
name="soltex_router",
|
|
8
|
+
version="0.1.0",
|
|
9
|
+
author="SOLTEX_ROUTER",
|
|
10
|
+
author_email="soltex_router@protonmail.com",
|
|
11
|
+
description="Enterprise-grade MEV-protected transaction router & fee sponsor for AI Agents on Solana",
|
|
12
|
+
long_description=long_description,
|
|
13
|
+
long_description_content_type="text/markdown",
|
|
14
|
+
url="https://github.com/soltex-router/SOLTEX_ROUTER",
|
|
15
|
+
packages=find_packages(),
|
|
16
|
+
install_requires=[
|
|
17
|
+
"requests>=2.25.1",
|
|
18
|
+
"solders>=0.23.0",
|
|
19
|
+
"base58>=2.1.1",
|
|
20
|
+
],
|
|
21
|
+
classifiers=[
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"License :: OSI Approved :: MIT License",
|
|
24
|
+
"Operating System :: OS Independent",
|
|
25
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
26
|
+
],
|
|
27
|
+
python_requires='>=3.10',
|
|
28
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"""
|
|
2
|
+
solana-agent-router | Client SDK v0.3.0
|
|
3
|
+
Copyright (c) 2026 SOLTEX Labs. MIT License.
|
|
4
|
+
|
|
5
|
+
ā ļø BY USING THIS SDK, YOU AGREE TO THE TERMS IN TERMS.md
|
|
6
|
+
- Non-custodial: Your keys never leave your machine
|
|
7
|
+
- Best-effort MEV protection via Jito Block Engine
|
|
8
|
+
- Gas sponsorship is a service credit, not a deposit account
|
|
9
|
+
"""
|
|
10
|
+
import time, logging, base64
|
|
11
|
+
from typing import Optional, List
|
|
12
|
+
import requests
|
|
13
|
+
import uuid
|
|
14
|
+
import base58
|
|
15
|
+
|
|
16
|
+
from solders.keypair import Keypair
|
|
17
|
+
from solders.pubkey import Pubkey
|
|
18
|
+
from solders.transaction import Transaction, VersionedTransaction
|
|
19
|
+
from solders.message import Message
|
|
20
|
+
from solders.instruction import Instruction
|
|
21
|
+
from solders.signature import Signature
|
|
22
|
+
from solders.compute_budget import set_compute_unit_price
|
|
23
|
+
from solders.system_program import TransferParams, transfer
|
|
24
|
+
from solders.hash import Hash
|
|
25
|
+
|
|
26
|
+
logger = logging.getLogger("solana-agent-router-sdk")
|
|
27
|
+
|
|
28
|
+
class BlockhashExpiredError(Exception): pass
|
|
29
|
+
class RateLimitError(Exception): pass
|
|
30
|
+
class RouterError(Exception): pass
|
|
31
|
+
|
|
32
|
+
class AgentRouter:
|
|
33
|
+
def __init__(self, api_key, payer: Keypair, rpc_url, server_url, max_retries=3):
|
|
34
|
+
self.api_key = api_key
|
|
35
|
+
self.payer = payer
|
|
36
|
+
self.rpc_url = rpc_url
|
|
37
|
+
self.server_url = server_url.rstrip("/")
|
|
38
|
+
self.max_retries = max_retries
|
|
39
|
+
|
|
40
|
+
def swap(self, input_mint, output_mint, amount, slippage_bps=50):
|
|
41
|
+
last_error = None
|
|
42
|
+
for attempt in range(self.max_retries):
|
|
43
|
+
try:
|
|
44
|
+
blockhash = self._get_recent_blockhash()
|
|
45
|
+
resp = requests.post(
|
|
46
|
+
f"{self.server_url}/api/v1/build-swap",
|
|
47
|
+
json={
|
|
48
|
+
"inputMint": input_mint,
|
|
49
|
+
"outputMint": output_mint,
|
|
50
|
+
"amount": amount,
|
|
51
|
+
"slippageBps": slippage_bps,
|
|
52
|
+
"user_wallet": str(self.payer.pubkey()),
|
|
53
|
+
"recent_blockhash": str(blockhash),
|
|
54
|
+
},
|
|
55
|
+
headers={"Authorization": f"Bearer {self.api_key}"},
|
|
56
|
+
timeout=15,
|
|
57
|
+
)
|
|
58
|
+
resp.raise_for_status()
|
|
59
|
+
data = resp.json()
|
|
60
|
+
tx_b58 = data["tx_bytes"]
|
|
61
|
+
request_id = data["request_id"]
|
|
62
|
+
tx_bytes = base58.b58decode(tx_b58)
|
|
63
|
+
vtx = VersionedTransaction.from_bytes(tx_bytes)
|
|
64
|
+
msg = vtx.message
|
|
65
|
+
|
|
66
|
+
payer_str = str(self.payer.pubkey())
|
|
67
|
+
signer_idx = None
|
|
68
|
+
for i in range(msg.header.num_required_signatures):
|
|
69
|
+
if str(msg.account_keys[i]) == payer_str:
|
|
70
|
+
signer_idx = i
|
|
71
|
+
break
|
|
72
|
+
if signer_idx is None:
|
|
73
|
+
raise RuntimeError("Payer not in signers")
|
|
74
|
+
|
|
75
|
+
num_sigs = tx_bytes[0]
|
|
76
|
+
if signer_idx >= num_sigs:
|
|
77
|
+
raise RuntimeError(f"Edge case detected: signer_idx ({signer_idx}) >= num_sigs ({num_sigs})")
|
|
78
|
+
|
|
79
|
+
num_sigs = tx_bytes[0]
|
|
80
|
+
msg_start = 1 + (num_sigs * 64)
|
|
81
|
+
msg_bytes = tx_bytes[msg_start:]
|
|
82
|
+
|
|
83
|
+
user_sig = self.payer.sign_message(msg_bytes)
|
|
84
|
+
|
|
85
|
+
sig_start = 1 + (signer_idx * 64)
|
|
86
|
+
sig_end = sig_start + 64
|
|
87
|
+
new_tx_bytes = tx_bytes[:sig_start] + bytes(user_sig) + tx_bytes[sig_end:]
|
|
88
|
+
|
|
89
|
+
print(f"[CLIENT] Signatures injected directly! req_id: {request_id[:16]}...")
|
|
90
|
+
|
|
91
|
+
result = self._post_route(new_tx_bytes, request_id)
|
|
92
|
+
if result.get("status") == "confirmed":
|
|
93
|
+
logger.info("Swap confirmed: %s (method=%s)", result["tx_hash"], result.get("method"))
|
|
94
|
+
return {"success": True, "tx_hash": result["tx_hash"]}
|
|
95
|
+
last_error = result.get("error")
|
|
96
|
+
|
|
97
|
+
except BlockhashExpiredError:
|
|
98
|
+
logger.warning("Attempt %d: blockhash expired", attempt + 1)
|
|
99
|
+
last_error = "Blockhash expired"
|
|
100
|
+
continue
|
|
101
|
+
except RateLimitError:
|
|
102
|
+
wait = 2 ** attempt
|
|
103
|
+
logger.warning("Attempt %d: rate limited, wait %ds", attempt + 1, wait)
|
|
104
|
+
time.sleep(wait)
|
|
105
|
+
last_error = "Rate limited"
|
|
106
|
+
continue
|
|
107
|
+
except requests.exceptions.HTTPError as e:
|
|
108
|
+
last_error = str(e)
|
|
109
|
+
logger.error("Attempt %d: HTTP error: %s", attempt + 1, e)
|
|
110
|
+
break
|
|
111
|
+
except Exception as e:
|
|
112
|
+
last_error = str(e)
|
|
113
|
+
logger.error("Attempt %d: error: %s", attempt + 1, e)
|
|
114
|
+
break
|
|
115
|
+
|
|
116
|
+
return {"success": False, "error": last_error or "Max retries"}
|
|
117
|
+
|
|
118
|
+
def send(self, instructions: List[Instruction], additional_signers=None):
|
|
119
|
+
last_error = None
|
|
120
|
+
for attempt in range(self.max_retries):
|
|
121
|
+
try:
|
|
122
|
+
params = self._get_params()
|
|
123
|
+
request_id = uuid.uuid4().hex
|
|
124
|
+
tx = self._build_transaction(instructions, params, additional_signers)
|
|
125
|
+
result = self._post_route(bytes(tx), request_id)
|
|
126
|
+
if result.get("status") == "confirmed":
|
|
127
|
+
return {"success": True, "tx_hash": result["tx_hash"]}
|
|
128
|
+
last_error = result.get("error")
|
|
129
|
+
except BlockhashExpiredError:
|
|
130
|
+
last_error = "Blockhash expired"
|
|
131
|
+
continue
|
|
132
|
+
except RateLimitError:
|
|
133
|
+
time.sleep(2 ** attempt)
|
|
134
|
+
last_error = "Rate limited"
|
|
135
|
+
continue
|
|
136
|
+
except Exception as e:
|
|
137
|
+
last_error = str(e)
|
|
138
|
+
break
|
|
139
|
+
return {"success": False, "error": last_error or "Max retries"}
|
|
140
|
+
|
|
141
|
+
def _build_transaction(self, instructions, params, additional_signers=None):
|
|
142
|
+
fee_payer = Pubkey.from_string(params["fee_payer"])
|
|
143
|
+
tip_addr = Pubkey.from_string(params["jito_tip_address"])
|
|
144
|
+
|
|
145
|
+
tip_ix = transfer(TransferParams(
|
|
146
|
+
from_pubkey=fee_payer, to_pubkey=tip_addr,
|
|
147
|
+
lamports=params["jito_tip_lamports"]
|
|
148
|
+
))
|
|
149
|
+
priority_ix = set_compute_unit_price(params["priority_fee_lamports"])
|
|
150
|
+
|
|
151
|
+
all_ixs = [tip_ix, priority_ix] + instructions
|
|
152
|
+
blockhash = self._get_recent_blockhash()
|
|
153
|
+
msg = Message.new_with_blockhash(all_ixs, fee_payer, blockhash)
|
|
154
|
+
msg_bytes = bytes(msg)
|
|
155
|
+
|
|
156
|
+
all_signers = [self.payer] + (additional_signers or [])
|
|
157
|
+
signer_map = {str(kp.pubkey()): kp for kp in all_signers}
|
|
158
|
+
|
|
159
|
+
signatures = []
|
|
160
|
+
for pubkey in msg.account_keys[:msg.header.num_required_signatures]:
|
|
161
|
+
pk_str = str(pubkey)
|
|
162
|
+
if pk_str in signer_map:
|
|
163
|
+
signatures.append(signer_map[pk_str].sign_message(msg_bytes))
|
|
164
|
+
else:
|
|
165
|
+
signatures.append(Signature.default())
|
|
166
|
+
|
|
167
|
+
return Transaction.populate(msg, signatures)
|
|
168
|
+
|
|
169
|
+
def _get_params(self):
|
|
170
|
+
resp = requests.get(
|
|
171
|
+
f"{self.server_url}/api/v1/params",
|
|
172
|
+
headers={"Authorization": f"Bearer {self.api_key}"},
|
|
173
|
+
timeout=10,
|
|
174
|
+
)
|
|
175
|
+
resp.raise_for_status()
|
|
176
|
+
return resp.json()
|
|
177
|
+
|
|
178
|
+
def _post_route(self, tx_bytes, request_id):
|
|
179
|
+
resp = requests.post(
|
|
180
|
+
f"{self.server_url}/api/v1/route",
|
|
181
|
+
json={
|
|
182
|
+
"signed_tx": base64.b64encode(tx_bytes).decode(),
|
|
183
|
+
"api_key": self.api_key,
|
|
184
|
+
"request_id": request_id,
|
|
185
|
+
},
|
|
186
|
+
timeout=65,
|
|
187
|
+
)
|
|
188
|
+
if resp.status_code == 408:
|
|
189
|
+
raise BlockhashExpiredError("blockhash expired")
|
|
190
|
+
if resp.status_code == 429:
|
|
191
|
+
raise RateLimitError("rate limit")
|
|
192
|
+
if resp.status_code != 200:
|
|
193
|
+
raise RouterError(f"Server {resp.status_code}: {resp.text}")
|
|
194
|
+
return resp.json()
|
|
195
|
+
|
|
196
|
+
def _get_recent_blockhash(self):
|
|
197
|
+
resp = requests.post(self.rpc_url, json={
|
|
198
|
+
"jsonrpc": "2.0", "id": 1,
|
|
199
|
+
"method": "getLatestBlockhash",
|
|
200
|
+
"params": [{"commitment": "confirmed"}]
|
|
201
|
+
}, timeout=10)
|
|
202
|
+
resp.raise_for_status()
|
|
203
|
+
return Hash.from_string(resp.json()["result"]["value"]["blockhash"])
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: soltex_router
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Enterprise-grade MEV-protected transaction router & fee sponsor for AI Agents on Solana
|
|
5
|
+
Home-page: https://github.com/soltex-router/SOLTEX_ROUTER
|
|
6
|
+
Author: SOLTEX_ROUTER
|
|
7
|
+
Author-email: soltex_router@protonmail.com
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
12
|
+
Requires-Python: >=3.10
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
Requires-Dist: requests>=2.25.1
|
|
15
|
+
Requires-Dist: solders>=0.23.0
|
|
16
|
+
Requires-Dist: base58>=2.1.1
|
|
17
|
+
Dynamic: author
|
|
18
|
+
Dynamic: author-email
|
|
19
|
+
Dynamic: classifier
|
|
20
|
+
Dynamic: description
|
|
21
|
+
Dynamic: description-content-type
|
|
22
|
+
Dynamic: home-page
|
|
23
|
+
Dynamic: requires-dist
|
|
24
|
+
Dynamic: requires-python
|
|
25
|
+
Dynamic: summary
|
|
26
|
+
|
|
27
|
+
# SOLTEX_ROUTER Agent SDK
|
|
28
|
+
**Fund one treasury. Run 10,000 autonomous agents.**
|
|
29
|
+
|
|
30
|
+
Solana's first zero-gas, MEV-protected intent router for AI Agents.
|
|
31
|
+
|
|
32
|
+
Stop manually funding hundreds of bot wallets with SOL dust. `soltex router` is a meta-routing SDK that completely abstracts gas fees and Jito tips, allowing your AI agents to execute swaps with 0.0000 SOL balance.
|
|
33
|
+
|
|
34
|
+
## ā” Why SOLTEX Router?
|
|
35
|
+
|
|
36
|
+
### ā The Old Way (Painful)
|
|
37
|
+
Managing 50 AI trading bots meant funding 50 separate Keypairs with SOL, calculating dynamic priority fees, guessing Jito tip percentiles, and handling RPC rate limits.
|
|
38
|
+
|
|
39
|
+
### ā
The SOLTEX Way (Intent-Centric)
|
|
40
|
+
Deposit SOL into a single Treasury Dashboard. Your agents just sign the intent locally. The SOLTEX Backend sponsors the transaction, auto-injects the 75th-percentile priority fee, routes through Jito Block Engine, and broadcasts it.
|
|
41
|
+
|
|
42
|
+
## š„ Core Features
|
|
43
|
+
- ā½ **Absolute Gas Abstraction:** Bots can operate with completely empty wallets.
|
|
44
|
+
- š”ļø **Default MEV Protection:** 100% of transactions are routed via Jito Private Mempool. Zero sandwich attacks.
|
|
45
|
+
- š **Jupiter API Native:** Built-in wrapper for optimal swap routes and instant execution.
|
|
46
|
+
- š **Trustless Architecture:** Your agent's private key never leaves the local environment. We only receive a locally `partial_signed` payload.
|
|
47
|
+
|
|
48
|
+
## š¦ Installation
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install soltex-router
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## š 1-Minute Quick Start
|
|
55
|
+
Look how incredibly simple it is to swap tokens without worrying about gas fees.
|
|
56
|
+
|
|
57
|
+
> ā ļø **IMPORTANT NOTE:** Your agent's wallet needs **exactly 0.000 SOL** to pay for gas, but it **MUST contain the tokens you are trying to swap** (e.g., 10 USDC).
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
import logging
|
|
61
|
+
from solders.keypair import Keypair
|
|
62
|
+
from client import AgentRouter
|
|
63
|
+
|
|
64
|
+
logging.basicConfig(level=logging.INFO)
|
|
65
|
+
|
|
66
|
+
# 1. Load your AI agent's wallet
|
|
67
|
+
# (Ensure this wallet holds the USDC you want to swap. 0 SOL is perfectly fine!)
|
|
68
|
+
# but receiving a BRAND NEW token type may require ~0.002 SOL for ATA creation rent!)
|
|
69
|
+
PRIVATE_KEY_BASE58 = "your_agent_private_key"
|
|
70
|
+
bot_wallet = Keypair.from_base58_string(PRIVATE_KEY_BASE58)
|
|
71
|
+
print(f"Agent Wallet: {bot_wallet.pubkey()}")
|
|
72
|
+
|
|
73
|
+
# 2. Connect to SOLTEX
|
|
74
|
+
router = AgentRouter(
|
|
75
|
+
api_key="SOLTEX_your_actual_api_key", # Issued via SOLTEX Dashboard
|
|
76
|
+
payer=bot_wallet,
|
|
77
|
+
rpc_url="https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY",
|
|
78
|
+
server_url="https://api.soltex-router.com"
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
def main():
|
|
82
|
+
# 3. Execute Swap via Jupiter (Zero SOL required for gas or tips!)
|
|
83
|
+
print("\nSwapping 10 USDC ā SOL...")
|
|
84
|
+
result = router.swap(
|
|
85
|
+
input_mint="EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", # USDC
|
|
86
|
+
output_mint="So11111111111111111111111111111111111111112", # SOL
|
|
87
|
+
amount=10_000_000, # 10 USDC
|
|
88
|
+
slippage_bps=100 # 1% slippage
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
if result["success"]:
|
|
92
|
+
print(f"\nā
Gasless Swap Confirmed!")
|
|
93
|
+
print(f"TX Hash: {result['tx_hash']}")
|
|
94
|
+
print(f"Explorer: https://solscan.io/tx/{result['tx_hash']}")
|
|
95
|
+
else:
|
|
96
|
+
print(f"\nā Swap failed: {result['error']}")
|
|
97
|
+
|
|
98
|
+
if __name__ == "__main__":
|
|
99
|
+
main()
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
š Security & ToS
|
|
103
|
+
By using this SDK, you agree to the SOLTEX Terms of Service.
|
|
104
|
+
Open Source: This client SDK is 100% transparent. Inspect the code to verify that keys remain strictly on your machine.
|
|
105
|
+
|
|
106
|
+
## āļø Legal & Compliance
|
|
107
|
+
- For more detail, please visit https://github.com/soltex-router/SOLTEX_ROUTER
|
|
108
|
+
|
|
109
|
+
**Disclaimer**: This software is provided "AS IS". Use at your own risk.
|
|
110
|
+
Not financial advice. Not a custodial service.
|
|
111
|
+
|
|
112
|
+
contact: soltex_router@protonmail.com
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
setup.py
|
|
3
|
+
soltex_router/__init__.py
|
|
4
|
+
soltex_router/client.py
|
|
5
|
+
soltex_router.egg-info/PKG-INFO
|
|
6
|
+
soltex_router.egg-info/SOURCES.txt
|
|
7
|
+
soltex_router.egg-info/dependency_links.txt
|
|
8
|
+
soltex_router.egg-info/requires.txt
|
|
9
|
+
soltex_router.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
soltex_router
|