mm-sol 0.5.4__py3-none-any.whl → 0.5.6__py3-none-any.whl

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.
mm_sol/account.py CHANGED
@@ -51,7 +51,7 @@ def derive_accounts(mnemonic: str, passphrase: str, derivation_path: str, limit:
51
51
  index=i,
52
52
  path=path,
53
53
  address=str(keypair.pubkey()),
54
- private_key=base58.b58encode(bytes(keypair.to_bytes_array())).decode("utf-8"),
54
+ private_key=base58.b58encode(bytes(keypair.to_bytes())).decode("utf-8"),
55
55
  )
56
56
  )
57
57
 
@@ -61,8 +61,8 @@ def derive_accounts(mnemonic: str, passphrase: str, derivation_path: str, limit:
61
61
  def generate_account() -> NewAccount:
62
62
  keypair = Keypair()
63
63
  public_key = str(keypair.pubkey())
64
- private_key_base58 = base58.b58encode(bytes(keypair.to_bytes_array())).decode("utf-8")
65
- private_key_arr = list(keypair.to_bytes_array())
64
+ private_key_base58 = base58.b58encode(bytes(keypair.to_bytes())).decode("utf-8")
65
+ private_key_arr = list(keypair.to_bytes())
66
66
  return NewAccount(public_key=public_key, private_key_base58=private_key_base58, private_key_arr=private_key_arr)
67
67
 
68
68
 
@@ -93,12 +93,12 @@ def get_public_key(private_key: str) -> str:
93
93
 
94
94
  def get_private_key_base58(private_key: str) -> str:
95
95
  keypair = get_keypair(private_key)
96
- return base58.b58encode(bytes(keypair.to_bytes_array())).decode("utf-8")
96
+ return base58.b58encode(bytes(keypair.to_bytes())).decode("utf-8")
97
97
 
98
98
 
99
99
  def get_private_key_arr(private_key: str) -> list[int]:
100
100
  keypair = get_keypair(private_key)
101
- return list(x for x in keypair.to_bytes_array()) # noqa: C400
101
+ return list(x for x in keypair.to_bytes()) # noqa: C400
102
102
 
103
103
 
104
104
  def get_private_key_arr_str(private_key: str) -> str:
mm_sol/async_rpc.py ADDED
@@ -0,0 +1,42 @@
1
+ from typing import Any
2
+
3
+ from mm_std import Result, ahr
4
+
5
+
6
+ async def rpc_call(
7
+ *,
8
+ node: str,
9
+ method: str,
10
+ params: list[Any],
11
+ id_: int = 1,
12
+ timeout: float = 10,
13
+ proxy: str | None = None,
14
+ ) -> Result[Any]:
15
+ data = {"jsonrpc": "2.0", "method": method, "params": params, "id": id_}
16
+ if node.startswith("http"):
17
+ return await _http_call(node, data, timeout, proxy)
18
+ raise NotImplementedError("ws is not implemented")
19
+
20
+
21
+ async def _http_call(node: str, data: dict[str, object], timeout: float, proxy: str | None) -> Result[Any]:
22
+ res = await ahr(node, method="POST", proxy=proxy, timeout=timeout, params=data, json_params=True)
23
+ try:
24
+ if res.is_error():
25
+ return res.to_err_result()
26
+
27
+ err = res.json.get("error", {}).get("message", "")
28
+ if err:
29
+ return res.to_err_result(f"service_error: {err}")
30
+ if "result" in res.json:
31
+ return res.to_ok_result(res.json["result"])
32
+
33
+ return res.to_err_result("unknown_response")
34
+ except Exception as e:
35
+ return res.to_err_result(f"exception: {e!s}")
36
+
37
+
38
+ async def get_balance(node: str, address: str, timeout: float = 10, proxy: str | None = None) -> Result[int]:
39
+ """Returns balance in lamports"""
40
+ return (await rpc_call(node=node, method="getBalance", params=[address], timeout=timeout, proxy=proxy)).and_then(
41
+ lambda r: r["value"]
42
+ )
mm_sol/balance.py CHANGED
@@ -7,16 +7,20 @@ from solders.pubkey import Pubkey
7
7
  from solders.rpc.errors import InvalidParamsMessage
8
8
  from spl.token.instructions import get_associated_token_address
9
9
 
10
- from mm_sol import rpc
11
- from mm_sol.utils import get_client
10
+ from mm_sol import async_rpc, rpc
11
+ from mm_sol.utils import get_async_client, get_client
12
12
 
13
13
 
14
- def get_sol_balance(node: str, address: str, timeout: int = 10, proxy: str | None = None) -> Result[int]:
14
+ def get_sol_balance(node: str, address: str, timeout: float = 10, proxy: str | None = None) -> Result[int]:
15
15
  return rpc.get_balance(node, address, timeout, proxy)
16
16
 
17
17
 
18
+ async def get_sol_balance_async(node: str, address: str, timeout: float = 10, proxy: str | None = None) -> Result[int]:
19
+ return await async_rpc.get_balance(node, address, timeout, proxy)
20
+
21
+
18
22
  def get_sol_balance_with_retries(
19
- nodes: Nodes, address: str, retries: int, timeout: int = 10, proxies: Proxies = None
23
+ nodes: Nodes, address: str, retries: int, timeout: float = 10, proxies: Proxies = None
20
24
  ) -> Result[int]:
21
25
  res: Result[int] = Err("not started yet")
22
26
  for _ in range(retries):
@@ -26,6 +30,17 @@ def get_sol_balance_with_retries(
26
30
  return res
27
31
 
28
32
 
33
+ async def get_sol_balance_with_retries_async(
34
+ nodes: Nodes, address: str, retries: int, timeout: float = 10, proxies: Proxies = None
35
+ ) -> Result[int]:
36
+ res: Result[int] = Err("not started yet")
37
+ for _ in range(retries):
38
+ res = await get_sol_balance_async(random_node(nodes), address, timeout=timeout, proxy=random_proxy(proxies))
39
+ if res.is_ok():
40
+ return res
41
+ return res
42
+
43
+
29
44
  def get_token_balance(
30
45
  node: str,
31
46
  owner_address: str,
@@ -48,11 +63,43 @@ def get_token_balance(
48
63
  return Ok(0)
49
64
  return Ok(int(res.value.amount), data=res.to_json())
50
65
  except RPCException as e:
51
- if len(e.args) > 1:
52
- s = e.args[0]
53
- if isinstance(s, InvalidParamsMessage) and "could not find account" in s.message:
54
- return Ok(0)
66
+ if "could not find account" in str(e):
67
+ return Ok(0)
68
+ return Err(e)
69
+ except httpx.HTTPStatusError as e:
70
+ return Err(f"http error: {e}")
71
+ except SolanaRpcException as e:
72
+ return Err(e.error_msg)
73
+ except Exception as e:
74
+ return Err(e)
75
+
76
+
77
+ async def get_token_balance_async(
78
+ node: str,
79
+ owner_address: str,
80
+ token_mint_address: str,
81
+ token_account: str | None = None,
82
+ timeout: float = 10,
83
+ proxy: str | None = None,
84
+ ) -> Result[int]:
85
+ try:
86
+ client = get_async_client(node, proxy=proxy, timeout=timeout)
87
+ if not token_account:
88
+ token_account = str(
89
+ get_associated_token_address(Pubkey.from_string(owner_address), Pubkey.from_string(token_mint_address))
90
+ )
91
+
92
+ res = await client.get_token_account_balance(Pubkey.from_string(token_account))
93
+
94
+ # Sometimes it not raise an error, but it returns this :(
95
+ if isinstance(res, InvalidParamsMessage) and "could not find account" in res.message:
96
+ return Ok(0)
97
+ return Ok(int(res.value.amount), data=res.to_json())
98
+ except RPCException as e:
99
+ if "could not find account" in str(e):
100
+ return Ok(0)
55
101
  return Err(e)
102
+
56
103
  except httpx.HTTPStatusError as e:
57
104
  return Err(f"http error: {e}")
58
105
  except SolanaRpcException as e:
@@ -84,3 +131,28 @@ def get_token_balance_with_retries(
84
131
  return res
85
132
 
86
133
  return res
134
+
135
+
136
+ async def get_token_balance_with_retries_async(
137
+ nodes: Nodes,
138
+ owner_address: str,
139
+ token_mint_address: str,
140
+ retries: int,
141
+ token_account: str | None = None,
142
+ timeout: float = 10,
143
+ proxies: Proxies = None,
144
+ ) -> Result[int]:
145
+ res: Result[int] = Err("not started yet")
146
+ for _ in range(retries):
147
+ res = await get_token_balance_async(
148
+ random_node(nodes),
149
+ owner_address,
150
+ token_mint_address,
151
+ token_account,
152
+ timeout=timeout,
153
+ proxy=random_proxy(proxies),
154
+ )
155
+ if res.is_ok():
156
+ return res
157
+
158
+ return res
mm_sol/rpc.py CHANGED
@@ -78,7 +78,7 @@ def rpc_call(
78
78
  method: str,
79
79
  params: list[Any],
80
80
  id_: int = 1,
81
- timeout: int = 10,
81
+ timeout: float = 10,
82
82
  proxy: str | None = None,
83
83
  ) -> Result[Any]:
84
84
  data = {"jsonrpc": "2.0", "method": method, "params": params, "id": id_}
@@ -87,7 +87,7 @@ def rpc_call(
87
87
  raise NotImplementedError("ws is not implemented")
88
88
 
89
89
 
90
- def _http_call(node: str, data: dict[str, object], timeout: int, proxy: str | None) -> Result[Any]:
90
+ def _http_call(node: str, data: dict[str, object], timeout: float, proxy: str | None) -> Result[Any]:
91
91
  res = hr(node, method="POST", proxy=proxy, timeout=timeout, params=data, json_params=True)
92
92
  try:
93
93
  if res.is_error():
@@ -104,38 +104,38 @@ def _http_call(node: str, data: dict[str, object], timeout: int, proxy: str | No
104
104
  return res.to_err_result(f"exception: {e!s}")
105
105
 
106
106
 
107
- def get_balance(node: str, address: str, timeout: int = 10, proxy: str | None = None) -> Result[int]:
107
+ def get_balance(node: str, address: str, timeout: float = 10, proxy: str | None = None) -> Result[int]:
108
108
  """Returns balance in lamports"""
109
109
  return rpc_call(node=node, method="getBalance", params=[address], timeout=timeout, proxy=proxy).and_then(lambda r: r["value"])
110
110
 
111
111
 
112
- def get_block_height(node: str, timeout: int = 10, proxy: str | None = None) -> Result[int]:
112
+ def get_block_height(node: str, timeout: float = 10, proxy: str | None = None) -> Result[int]:
113
113
  """Returns balance in lamports"""
114
114
  return rpc_call(node=node, method="getBlockHeight", params=[], timeout=timeout, proxy=proxy)
115
115
 
116
116
 
117
- def get_slot(node: str, timeout: int = 10, proxy: str | None = None) -> Result[int]:
117
+ def get_slot(node: str, timeout: float = 10, proxy: str | None = None) -> Result[int]:
118
118
  return rpc_call(node=node, method="getSlot", params=[], timeout=timeout, proxy=proxy)
119
119
 
120
120
 
121
- def get_epoch_info(node: str, epoch: int | None = None, timeout: int = 10, proxy: str | None = None) -> Result[EpochInfo]:
121
+ def get_epoch_info(node: str, epoch: int | None = None, timeout: float = 10, proxy: str | None = None) -> Result[EpochInfo]:
122
122
  params = [epoch] if epoch else []
123
123
  return rpc_call(node=node, method="getEpochInfo", params=params, timeout=timeout, proxy=proxy).and_then(
124
124
  lambda r: EpochInfo(**r),
125
125
  )
126
126
 
127
127
 
128
- def get_health(node: str, timeout: int = 10, proxy: str | None = None) -> Result[bool]:
128
+ def get_health(node: str, timeout: float = 10, proxy: str | None = None) -> Result[bool]:
129
129
  return rpc_call(node=node, method="getHealth", params=[], timeout=timeout, proxy=proxy).and_then(lambda r: r == "ok")
130
130
 
131
131
 
132
- def get_cluster_nodes(node: str, timeout: int = 30, proxy: str | None = None) -> Result[list[ClusterNode]]:
132
+ def get_cluster_nodes(node: str, timeout: float = 30, proxy: str | None = None) -> Result[list[ClusterNode]]:
133
133
  return rpc_call(node=node, method="getClusterNodes", timeout=timeout, proxy=proxy, params=[]).and_then(
134
134
  lambda r: [ClusterNode(**n) for n in r],
135
135
  )
136
136
 
137
137
 
138
- def get_vote_accounts(node: str, timeout: int = 30, proxy: str | None = None) -> Result[list[VoteAccount]]:
138
+ def get_vote_accounts(node: str, timeout: float = 30, proxy: str | None = None) -> Result[list[VoteAccount]]:
139
139
  res = rpc_call(node=node, method="getVoteAccounts", timeout=timeout, proxy=proxy, params=[])
140
140
  if res.is_err():
141
141
  return res
@@ -182,7 +182,7 @@ def get_vote_accounts(node: str, timeout: int = 30, proxy: str | None = None) ->
182
182
  def get_leader_scheduler(
183
183
  node: str,
184
184
  slot: int | None = None,
185
- timeout: int = 10,
185
+ timeout: float = 10,
186
186
  proxy: str | None = None,
187
187
  ) -> Result[dict[str, list[int]]]:
188
188
  return rpc_call(
@@ -194,7 +194,7 @@ def get_leader_scheduler(
194
194
  )
195
195
 
196
196
 
197
- def get_block_production(node: str, timeout: int = 60, proxy: str | None = None) -> Result[BlockProduction]:
197
+ def get_block_production(node: str, timeout: float = 60, proxy: str | None = None) -> Result[BlockProduction]:
198
198
  res = rpc_call(node=node, method="getBlockProduction", timeout=timeout, proxy=proxy, params=[])
199
199
  if res.is_err():
200
200
  return res
@@ -211,7 +211,7 @@ def get_block_production(node: str, timeout: int = 60, proxy: str | None = None)
211
211
  return Err(e, data=res.data)
212
212
 
213
213
 
214
- def get_stake_activation(node: str, address: str, timeout: int = 60, proxy: str | None = None) -> Result[StakeActivation]:
214
+ def get_stake_activation(node: str, address: str, timeout: float = 60, proxy: str | None = None) -> Result[StakeActivation]:
215
215
  return rpc_call(node=node, method="getStakeActivation", timeout=timeout, proxy=proxy, params=[address]).and_then(
216
216
  lambda ok: StakeActivation(**ok),
217
217
  )
@@ -222,7 +222,7 @@ def get_transaction(
222
222
  signature: str,
223
223
  max_supported_transaction_version: int | None = None,
224
224
  encoding: str = "json",
225
- timeout: int = 60,
225
+ timeout: float = 60,
226
226
  proxy: str | None = None,
227
227
  ) -> Result[dict[str, object] | None]:
228
228
  if max_supported_transaction_version is not None:
mm_sol/utils.py CHANGED
@@ -1,4 +1,5 @@
1
1
  from solana.rpc.api import Client
2
+ from solana.rpc.async_api import AsyncClient
2
3
  from solana.rpc.commitment import Commitment
3
4
  from solders.pubkey import Pubkey
4
5
 
@@ -13,6 +14,16 @@ def get_client(
13
14
  return Client(endpoint, commitment=commitment, extra_headers=extra_headers, timeout=timeout, proxy=proxy)
14
15
 
15
16
 
17
+ def get_async_client(
18
+ endpoint: str,
19
+ commitment: Commitment | None = None,
20
+ extra_headers: dict[str, str] | None = None,
21
+ proxy: str | None = None,
22
+ timeout: float = 10,
23
+ ) -> AsyncClient:
24
+ return AsyncClient(endpoint, commitment=commitment, extra_headers=extra_headers, timeout=timeout, proxy=proxy)
25
+
26
+
16
27
  def pubkey(value: str | Pubkey) -> Pubkey:
17
28
  if isinstance(value, Pubkey):
18
29
  return value
@@ -1,11 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mm-sol
3
- Version: 0.5.4
3
+ Version: 0.5.6
4
4
  Requires-Python: >=3.12
5
5
  Requires-Dist: base58~=2.1.1
6
6
  Requires-Dist: jinja2>=3.1.6
7
- Requires-Dist: mm-crypto-utils>=0.2.8
7
+ Requires-Dist: mm-crypto-utils>=0.2.9
8
8
  Requires-Dist: mnemonic==0.21
9
9
  Requires-Dist: socksio>=1.0.0
10
10
  Requires-Dist: solana~=0.36.6
11
+ Requires-Dist: solders~=0.26.0
11
12
  Requires-Dist: typer>=0.15.2
@@ -1,15 +1,16 @@
1
1
  mm_sol/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- mm_sol/account.py,sha256=0pjvNxwhpmDHoXY3oTY2fNlQHoWPmlS77r8JcP8lAy4,4545
3
- mm_sol/balance.py,sha256=qpjYkcZveyyBy1dSDI-bWlpkEtEoz7h68mhti_gqIRA,2803
2
+ mm_sol/account.py,sha256=9aDP5si-QJfSF8fz8K6geGUGh9GL83YJNkdU1qd4Xu8,4515
3
+ mm_sol/async_rpc.py,sha256=VpAovAgtDT-5OmwGyT8b-Ky_EtrGPKENKxZGGnw3_D8,1406
4
+ mm_sol/balance.py,sha256=5sSIQbipNUeB_Hn7piwrYt-PuSEf4ZKB8puUmC986iY,5112
4
5
  mm_sol/block.py,sha256=4Lc4TANgpGvPflVumC9MR-3vIl1dedGyci3cgzczuds,1794
5
6
  mm_sol/constants.py,sha256=WSpfz5_cq_8XbIrNFJGu9okwbfPTL00zsyR_k9-7O0o,29
6
7
  mm_sol/converters.py,sha256=rBxe3SIADZS8hG7TYl4FgjmvKH-ykaTmNbnWWQDiFZ4,1430
7
8
  mm_sol/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- mm_sol/rpc.py,sha256=TspD_KZQp_KJDQzRknxaT8DR03okok26UWDQWF7Zflg,8031
9
+ mm_sol/rpc.py,sha256=Tw7THbU0lShjTGNGe4-Mc6q1U5E2dgjY2LIfrMTSfeA,8057
9
10
  mm_sol/solana_cli.py,sha256=ig3OoTvmkrl7MFQSZjRHIraLSmtse0_9kn5Nsw8_zb0,8258
10
11
  mm_sol/token.py,sha256=O8z3UE3iZGYLWw8fnd9weYMcoQO0m88noqbRO_jntGg,1092
11
12
  mm_sol/transfer.py,sha256=taf2NTLpo-bxISeaILARXEGLldUvqvP-agp5IDva7Hw,5825
12
- mm_sol/utils.py,sha256=NE0G564GiT9d7rW_lPPxUb1eq62WiXh28xtvtzNQIqw,556
13
+ mm_sol/utils.py,sha256=oD06NsMSMhN6lqsM6mSgLTtiKwA1uAsen9WR82ofRTE,923
13
14
  mm_sol/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
15
  mm_sol/cli/calcs.py,sha256=-r9RlsQyOziTDf84uIsvTgZmsUdNrVeazu3vTj9hhNA,1887
15
16
  mm_sol/cli/cli.py,sha256=a28Cy1X2bRSIAAJu2HHoPoTJYOPvff-anVcL0BJnwRI,4610
@@ -26,7 +27,7 @@ mm_sol/cli/cmd/wallet/keypair_cmd.py,sha256=cRHVVTs9zNYmUozZ8ZlJoutn9V6r8I1AEHBr
26
27
  mm_sol/cli/cmd/wallet/mnemonic_cmd.py,sha256=IiON_fJT5AFfIr_E1LR6_iDYZ3c_jWCFc-wSYqk61V8,648
27
28
  mm_sol/cli/examples/balances.toml,sha256=333g2EkyYBDW7OWFGMIWVZGkdFQMMo0Ag-bg-BvS4Zg,349
28
29
  mm_sol/cli/examples/transfer.toml,sha256=kOCdmuwmhlOam4LVtlcYTKF0PoZYHWMlv9gWxNSXMOk,1624
29
- mm_sol-0.5.4.dist-info/METADATA,sha256=0-qHBRgp0VFOPh7HkO6FPW6qXOP5hx0EIhAm0mNJQQE,289
30
- mm_sol-0.5.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
31
- mm_sol-0.5.4.dist-info/entry_points.txt,sha256=MrYnosumy9nsITSAw5TiR3WXDwsdoF0YvUIlZ38TLLs,46
32
- mm_sol-0.5.4.dist-info/RECORD,,
30
+ mm_sol-0.5.6.dist-info/METADATA,sha256=ZAo75jqkghH06Uqiw_8bIU79xwX3Y3En599R3R_9A_4,320
31
+ mm_sol-0.5.6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
32
+ mm_sol-0.5.6.dist-info/entry_points.txt,sha256=MrYnosumy9nsITSAw5TiR3WXDwsdoF0YvUIlZ38TLLs,46
33
+ mm_sol-0.5.6.dist-info/RECORD,,
File without changes