jito-py 0.1.1__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.
jito_py-0.1.1/PKG-INFO ADDED
@@ -0,0 +1,59 @@
1
+ Metadata-Version: 2.1
2
+ Name: jito-py
3
+ Version: 0.1.1
4
+ Summary: A Python library for interacting with the Jito JSON-RPC
5
+ Author-email: "Matrix.Ye" <initsysctrl@outlook.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/MatrixYe/jito-py
8
+ Keywords: jito,solana,json-rpc
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.6
13
+ Description-Content-Type: text/markdown
14
+ Requires-Dist: requests
15
+
16
+ # jito-py
17
+
18
+ `jito-py` is a Python library for interacting with the Solana blockchain via JSON-RPC.
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ pip install jito_py
24
+
25
+ ## Usage
26
+ ```python
27
+ from jito_py.searcher import Searcher
28
+ from jito_py.block_engine import BlockEngine
29
+
30
+
31
+ # Get Block Engine Url
32
+ engines=BlockEngine.get_block_engines(network='mainnet')
33
+ print(engines)
34
+ block_engine_url=engine[0]['block_engine_url']
35
+
36
+ # Create a searcher instance
37
+ searcher = Searcher(block_engine_url)
38
+
39
+ # Get tip accounts
40
+ tip_accounts = searcher.get_tip_accounts()
41
+ print("Tip Accounts:", tip_accounts)
42
+
43
+ # Get bundle statuses
44
+ bundle_ids = ["your_bundle_id_here"]
45
+ bundle_statuses = searcher.get_bundle_statuses(bundle_ids)
46
+ print("Bundle Statuses:", bundle_statuses)
47
+
48
+ # Send a bundle
49
+ transactions = ["your_base58_encoded_transaction_here"]
50
+ bundle_id = searcher.send_bundle(transactions)
51
+ print("Sent Bundle ID:", bundle_id)
52
+
53
+ # Send a transaction
54
+ transaction = "your_base58_encoded_transaction_here"
55
+ transaction_id = searcher.send_transaction(transaction)
56
+ print("Sent Transaction ID:", transaction_id)
57
+
58
+
59
+ ```
@@ -0,0 +1,44 @@
1
+ # jito-py
2
+
3
+ `jito-py` is a Python library for interacting with the Solana blockchain via JSON-RPC.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install jito_py
9
+
10
+ ## Usage
11
+ ```python
12
+ from jito_py.searcher import Searcher
13
+ from jito_py.block_engine import BlockEngine
14
+
15
+
16
+ # Get Block Engine Url
17
+ engines=BlockEngine.get_block_engines(network='mainnet')
18
+ print(engines)
19
+ block_engine_url=engine[0]['block_engine_url']
20
+
21
+ # Create a searcher instance
22
+ searcher = Searcher(block_engine_url)
23
+
24
+ # Get tip accounts
25
+ tip_accounts = searcher.get_tip_accounts()
26
+ print("Tip Accounts:", tip_accounts)
27
+
28
+ # Get bundle statuses
29
+ bundle_ids = ["your_bundle_id_here"]
30
+ bundle_statuses = searcher.get_bundle_statuses(bundle_ids)
31
+ print("Bundle Statuses:", bundle_statuses)
32
+
33
+ # Send a bundle
34
+ transactions = ["your_base58_encoded_transaction_here"]
35
+ bundle_id = searcher.send_bundle(transactions)
36
+ print("Sent Bundle ID:", bundle_id)
37
+
38
+ # Send a transaction
39
+ transaction = "your_base58_encoded_transaction_here"
40
+ transaction_id = searcher.send_transaction(transaction)
41
+ print("Sent Transaction ID:", transaction_id)
42
+
43
+
44
+ ```
@@ -0,0 +1,7 @@
1
+ # -*- coding: utf-8 -*-#
2
+ # -------------------------------------------------------------------------------
3
+ # Name: a
4
+ # Author: yepeng
5
+ # Date: 2021/10/22 2:44 下午
6
+ # Description:
7
+ # -------------------------------------------------------------------------------
@@ -0,0 +1,55 @@
1
+ # -*- coding: utf-8 -*-#
2
+ # -------------------------------------------------------------------------------
3
+ # Name: a
4
+ # Author: yepeng
5
+ # Date: 2021/10/22 2:44 下午
6
+ # Description:
7
+ # -------------------------------------------------------------------------------
8
+ # noinspection HttpUrlsUsage
9
+ class BlockEngine:
10
+ MAINNET_ADDRESS = {
11
+ "Amsterdam": {
12
+ "block_engine_url": "https://amsterdam.mainnet.block-engine.jito.wtf",
13
+ "shred_receiver_addr": "74.118.140.240:1002",
14
+ "relayer_url": "http://amsterdam.mainnet.relayer.jito.wtf:8100",
15
+ },
16
+ "Frankfurt": {
17
+ "block_engine_url": "https://frankfurt.mainnet.block-engine.jito.wtf",
18
+ "shred_receiver_addr": "145.40.93.84:1002",
19
+ "relayer_url": "http://frankfurt.mainnet.relayer.jito.wtf:8100",
20
+ },
21
+ "York": {
22
+ "block_engine_url": "https://ny.mainnet.block-engine.jito.wtf",
23
+ "shred_receiver_addr": "141.98.216.96:1002",
24
+ "relayer_url": "http://ny.mainnet.relayer.jito.wtf:8100",
25
+ },
26
+ "Tokyo": {
27
+ "block_engine_url": "https://tokyo.mainnet.block-engine.jito.wtf",
28
+ "shred_receiver_addr": "202.8.9.160:1002",
29
+ "relayer_url": "http://tokyo.mainnet.relayer.jito.wtf:8100",
30
+ }
31
+
32
+ }
33
+ TESTNET_ADDRESS = {
34
+ "Dallas": {
35
+ "block_engine_url": "https://dallas.testnet.block-engine.jito.wtf",
36
+ "shred_receiver_addr": "147.28.154.132:1002",
37
+ "relayer_url": "http://dallas.testnet.relayer.jito.wtf:8100",
38
+ },
39
+
40
+ "York": {
41
+ "block_engine_url": "https://ny.testnet.block-engine.jito.wtf",
42
+ "shred_receiver_addr": "141.98.216.97:1002",
43
+ "relayer_url": "http://nyc.testnet.relayer.jito.wtf:8100",
44
+ },
45
+
46
+ }
47
+
48
+ # noinspection HttpUrlsUsage
49
+ @staticmethod
50
+ def get_block_engines(network="mainnet") -> dict | None:
51
+ if network == "mainnet":
52
+ return BlockEngine.MAINNET_ADDRESS
53
+ if network == "testnet":
54
+ return BlockEngine.TESTNET_ADDRESS
55
+ return None
@@ -0,0 +1,106 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import List, Optional, Dict, Any
3
+
4
+ import requests
5
+
6
+
7
+ @dataclass
8
+ class BundleStatus:
9
+ bundle_id: str
10
+ transactions: List[str]
11
+ slot: int
12
+ confirmation_status: str
13
+ err: Dict[str, Any]
14
+
15
+
16
+ @dataclass
17
+ class BundleStatusesResponse:
18
+ context_slot: int
19
+ statuses: List[BundleStatus] = field(default_factory=list)
20
+
21
+
22
+ class Searcher:
23
+ def __init__(self, block_engine_url: str):
24
+ self.block_engine_url = block_engine_url
25
+
26
+ @staticmethod
27
+ def _extract_result(response: Dict[str, Any], method: str) -> Any:
28
+ if 'result' in response:
29
+ return response['result']
30
+ else:
31
+ raise Exception(f"Error in {method} response: {response}")
32
+
33
+ def _send_rpc_request(self, endpoint: str, method: str, params: Optional[List] = None) -> Dict[str, Any]:
34
+ headers = {"Content-Type": "application/json"}
35
+ payload = {
36
+ "jsonrpc": "2.0",
37
+ "id": 1,
38
+ "method": method,
39
+ "params": params or []
40
+ }
41
+ try:
42
+ url = f"{self.block_engine_url}/{endpoint}"
43
+ response = requests.post(url=url, json=payload, headers=headers)
44
+ response.raise_for_status()
45
+ return response.json()
46
+ except requests.RequestException as e:
47
+ raise Exception(f"HTTP request failed: {e}")
48
+ except ValueError as e:
49
+ raise Exception(f"Invalid JSON response: {e}")
50
+
51
+ def get_bundle_statuses(self, bundle_ids: List[str]) -> BundleStatusesResponse:
52
+ """
53
+ Returns the status of submitted bundle(s).
54
+
55
+ :param bundle_ids: An array of bundle ids to confirm, as base-58 encoded strings (up to a maximum of 5).
56
+ :return: A BundleStatusesResponse object containing the context slot and a list of BundleStatus objects.
57
+ """
58
+ response = self._send_rpc_request("/api/v1/bundles", "getBundleStatuses", [bundle_ids])
59
+ result = self._extract_result(response, "getBundleStatuses")
60
+ context_slot = result['context']['slot']
61
+ statuses = [
62
+ BundleStatus(
63
+ bundle_id=status['bundle_id'],
64
+ transactions=status['transactions'],
65
+ slot=status['slot'],
66
+ confirmation_status=status['confirmation_status'],
67
+ err=status['err']
68
+ )
69
+ for status in result['value']
70
+ ]
71
+ return BundleStatusesResponse(context_slot=context_slot, statuses=statuses)
72
+
73
+ def get_tip_accounts(self) -> List[str]:
74
+ """
75
+ Retrieves the tip accounts designated for tip payments for bundles.
76
+
77
+ :return: Tip accounts as a list of strings.
78
+ """
79
+ response = self._send_rpc_request("/api/v1/bundles", "getTipAccounts")
80
+ return self._extract_result(response, "getTipAccounts")
81
+
82
+ def send_bundle(self, transactions: List[str]) -> str:
83
+ """
84
+ Submits a bundled list of signed transactions (base-58 encoded strings) to the cluster for processing.
85
+
86
+ :param transactions: Fully-signed transactions, as base-58 encoded strings (up to a maximum of 5).
87
+ Base-64 encoded transactions are not supported at this time.
88
+ :return: A bundle ID, used to identify the bundle. This is the SHA-256 hash of the bundle's transaction signatures.
89
+ """
90
+ response = self._send_rpc_request("/api/v1/bundles", "sendBundle", [transactions])
91
+ return self._extract_result(response, "sendBundle")
92
+
93
+ def send_transaction(self, transaction: str) -> str:
94
+ """
95
+ This method serves as a proxy to the Solana sendTransaction RPC method. It forwards the received transaction as a
96
+ regular Solana transaction via the Solana RPC method and submits it as a bundle. Jito sponsors the bundling and
97
+ provides a minimum tip for the bundle. However, please note that this minimum tip might not be sufficient to get
98
+ the bundle through the auction, especially during high-demand periods. If you set the query parameter bundleOnly=true,
99
+ the transaction will only be sent out as a bundle and not as a regular transaction via RPC.
100
+
101
+ :param transaction: First Transaction Signature embedded in the transaction, as base-58 encoded string.
102
+ :return: The result will be the same as described in the Solana RPC documentation. If sending as a bundle was
103
+ successful, you can get the bundle_id for further querying from the custom header in the response x-bundle-id.
104
+ """
105
+ response = self._send_rpc_request("/api/v1/transactions", "sendTransaction", [transaction])
106
+ return self._extract_result(response, "sendTransaction")
@@ -0,0 +1,59 @@
1
+ Metadata-Version: 2.1
2
+ Name: jito-py
3
+ Version: 0.1.1
4
+ Summary: A Python library for interacting with the Jito JSON-RPC
5
+ Author-email: "Matrix.Ye" <initsysctrl@outlook.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/MatrixYe/jito-py
8
+ Keywords: jito,solana,json-rpc
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.6
13
+ Description-Content-Type: text/markdown
14
+ Requires-Dist: requests
15
+
16
+ # jito-py
17
+
18
+ `jito-py` is a Python library for interacting with the Solana blockchain via JSON-RPC.
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ pip install jito_py
24
+
25
+ ## Usage
26
+ ```python
27
+ from jito_py.searcher import Searcher
28
+ from jito_py.block_engine import BlockEngine
29
+
30
+
31
+ # Get Block Engine Url
32
+ engines=BlockEngine.get_block_engines(network='mainnet')
33
+ print(engines)
34
+ block_engine_url=engine[0]['block_engine_url']
35
+
36
+ # Create a searcher instance
37
+ searcher = Searcher(block_engine_url)
38
+
39
+ # Get tip accounts
40
+ tip_accounts = searcher.get_tip_accounts()
41
+ print("Tip Accounts:", tip_accounts)
42
+
43
+ # Get bundle statuses
44
+ bundle_ids = ["your_bundle_id_here"]
45
+ bundle_statuses = searcher.get_bundle_statuses(bundle_ids)
46
+ print("Bundle Statuses:", bundle_statuses)
47
+
48
+ # Send a bundle
49
+ transactions = ["your_base58_encoded_transaction_here"]
50
+ bundle_id = searcher.send_bundle(transactions)
51
+ print("Sent Bundle ID:", bundle_id)
52
+
53
+ # Send a transaction
54
+ transaction = "your_base58_encoded_transaction_here"
55
+ transaction_id = searcher.send_transaction(transaction)
56
+ print("Sent Transaction ID:", transaction_id)
57
+
58
+
59
+ ```
@@ -0,0 +1,12 @@
1
+ README.md
2
+ pyproject.toml
3
+ setup.py
4
+ jito_py/__init__.py
5
+ jito_py/block_engine.py
6
+ jito_py/searcher.py
7
+ jito_py.egg-info/PKG-INFO
8
+ jito_py.egg-info/SOURCES.txt
9
+ jito_py.egg-info/dependency_links.txt
10
+ jito_py.egg-info/requires.txt
11
+ jito_py.egg-info/top_level.txt
12
+ tests/test_searcher.py
@@ -0,0 +1 @@
1
+ requests
@@ -0,0 +1 @@
1
+ jito_py
@@ -0,0 +1,26 @@
1
+ [build-system]
2
+ requires = ["setuptools>=42", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "jito-py"
7
+ version = "0.1.1"
8
+ description = "A Python library for interacting with the Jito JSON-RPC"
9
+ readme = "README.md"
10
+ authors = [
11
+ { name = "Matrix.Ye", email = "initsysctrl@outlook.com" }
12
+ ]
13
+ license = { text = "MIT" }
14
+ requires-python = ">=3.6"
15
+ dependencies = [
16
+ "requests"
17
+ ]
18
+ classifiers = [
19
+ "Programming Language :: Python :: 3",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Operating System :: OS Independent"
22
+ ]
23
+ keywords = ["jito", "solana", "json-rpc"]
24
+
25
+ [project.urls]
26
+ Homepage = "https://github.com/MatrixYe/jito-py"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
jito_py-0.1.1/setup.py ADDED
@@ -0,0 +1,10 @@
1
+ # -*- coding: utf-8 -*-#
2
+ # -------------------------------------------------------------------------------
3
+ # Name: a
4
+ # Author: yepeng
5
+ # Date: 2021/10/22 2:44 下午
6
+ # Description:
7
+ # -------------------------------------------------------------------------------
8
+ from setuptools import setup
9
+
10
+ setup()
@@ -0,0 +1,89 @@
1
+ import unittest
2
+ from unittest.mock import patch
3
+
4
+ from jito_py.searcher import Searcher, BundleStatusesResponse, BundleStatus
5
+
6
+
7
+ class TestSearcher(unittest.TestCase):
8
+ def setUp(self):
9
+ self.searcher = Searcher("https://mainnet.block-engine.jito.wtf")
10
+
11
+ @patch('jito_py.searcher.requests.post')
12
+ def test_get_tip_accounts(self, mock_post):
13
+ mock_post.return_value.json.return_value = {
14
+ "jsonrpc": "2.0",
15
+ "result": [
16
+ "96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5",
17
+ "HFqU5x63VTqvQss8hp11i4wVV8bD44PvwucfZ2bU7gRe",
18
+ "Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY",
19
+ "ADaUMid9yfUytqMBgopwjb2DTLSokTSzL1zt6iGPaS49",
20
+ "DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh",
21
+ "ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt",
22
+ "DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL",
23
+ "3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT"
24
+ ],
25
+ "id": 1
26
+ }
27
+ expected_response = [
28
+ "96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5",
29
+ "HFqU5x63VTqvQss8hp11i4wVV8bD44PvwucfZ2bU7gRe",
30
+ "Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY",
31
+ "ADaUMid9yfUytqMBgopwjb2DTLSokTSzL1zt6iGPaS49",
32
+ "DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh",
33
+ "ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt",
34
+ "DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL",
35
+ "3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT"
36
+ ]
37
+
38
+ result = self.searcher.get_tip_accounts()
39
+ print(result)
40
+
41
+ self.assertEqual(result, expected_response)
42
+
43
+ @patch('jito_py.searcher.requests.post')
44
+ def test_get_bundle_statuses(self, mock_post):
45
+ mock_post.return_value.json.return_value = {
46
+ "jsonrpc": "2.0",
47
+ "result": {
48
+ "context": {
49
+ "slot": 242806119
50
+ },
51
+ "value": [
52
+ {
53
+ "bundle_id": "892b79ed49138bfb3aa5441f0df6e06ef34f9ee8f3976c15b323605bae0cf51d",
54
+ "transactions": [
55
+ "3bC2M9fiACSjkTXZDgeNAuQ4ScTsdKGwR42ytFdhUvikqTmBheUxfsR1fDVsM5ADCMMspuwGkdm1uKbU246x5aE3",
56
+ "8t9hKYEYNbLvNqiSzP96S13XF1C2f1ro271Kdf7bkZ6EpjPLuDff1ywRy4gfaGSTubsM2FeYGDoT64ZwPm1cQUt"
57
+ ],
58
+ "slot": 242804011,
59
+ "confirmation_status": "finalized",
60
+ "err": {
61
+ "Ok": None
62
+ }
63
+ }
64
+ ]
65
+ },
66
+ "id": 1
67
+ }
68
+ expected_response = BundleStatusesResponse(
69
+ context_slot=242806119,
70
+ statuses=[
71
+ BundleStatus(
72
+ bundle_id="892b79ed49138bfb3aa5441f0df6e06ef34f9ee8f3976c15b323605bae0cf51d",
73
+ transactions=[
74
+ "3bC2M9fiACSjkTXZDgeNAuQ4ScTsdKGwR42ytFdhUvikqTmBheUxfsR1fDVsM5ADCMMspuwGkdm1uKbU246x5aE3",
75
+ "8t9hKYEYNbLvNqiSzP96S13XF1C2f1ro271Kdf7bkZ6EpjPLuDff1ywRy4gfaGSTubsM2FeYGDoT64ZwPm1cQUt"
76
+ ],
77
+ slot=242804011,
78
+ confirmation_status="finalized",
79
+ err={"Ok": None}
80
+ )
81
+ ]
82
+ )
83
+ result = self.searcher.get_bundle_statuses(["892b79ed49138bfb3aa5441f0df6e06ef34f9ee8f3976c15b323605bae0cf51d"])
84
+ print(result)
85
+ self.assertEqual(result, expected_response)
86
+
87
+
88
+ if __name__ == "__main__":
89
+ unittest.main()