mm-sol 0.5.4__tar.gz → 0.5.5__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.
Files changed (53) hide show
  1. {mm_sol-0.5.4 → mm_sol-0.5.5}/PKG-INFO +2 -2
  2. {mm_sol-0.5.4 → mm_sol-0.5.5}/README.md +3 -0
  3. {mm_sol-0.5.4 → mm_sol-0.5.5}/pyproject.toml +4 -3
  4. mm_sol-0.5.5/src/mm_sol/async_rpc.py +42 -0
  5. mm_sol-0.5.5/src/mm_sol/balance.py +161 -0
  6. {mm_sol-0.5.4 → mm_sol-0.5.5}/src/mm_sol/rpc.py +13 -13
  7. {mm_sol-0.5.4 → mm_sol-0.5.5}/src/mm_sol/utils.py +11 -0
  8. {mm_sol-0.5.4 → mm_sol-0.5.5}/tests/conftest.py +6 -1
  9. mm_sol-0.5.5/tests/test_async_rpc.py +10 -0
  10. mm_sol-0.5.5/tests/test_balance.py +25 -0
  11. {mm_sol-0.5.4 → mm_sol-0.5.5}/uv.lock +53 -31
  12. mm_sol-0.5.4/src/mm_sol/balance.py +0 -86
  13. mm_sol-0.5.4/tests/test_balance.py +0 -6
  14. {mm_sol-0.5.4 → mm_sol-0.5.5}/.env.example +0 -0
  15. {mm_sol-0.5.4 → mm_sol-0.5.5}/.gitignore +0 -0
  16. {mm_sol-0.5.4 → mm_sol-0.5.5}/dict.dic +0 -0
  17. {mm_sol-0.5.4 → mm_sol-0.5.5}/justfile +0 -0
  18. {mm_sol-0.5.4 → mm_sol-0.5.5}/src/mm_sol/__init__.py +0 -0
  19. {mm_sol-0.5.4 → mm_sol-0.5.5}/src/mm_sol/account.py +0 -0
  20. {mm_sol-0.5.4 → mm_sol-0.5.5}/src/mm_sol/block.py +0 -0
  21. {mm_sol-0.5.4 → mm_sol-0.5.5}/src/mm_sol/cli/__init__.py +0 -0
  22. {mm_sol-0.5.4 → mm_sol-0.5.5}/src/mm_sol/cli/calcs.py +0 -0
  23. {mm_sol-0.5.4 → mm_sol-0.5.5}/src/mm_sol/cli/cli.py +0 -0
  24. {mm_sol-0.5.4 → mm_sol-0.5.5}/src/mm_sol/cli/cli_utils.py +0 -0
  25. {mm_sol-0.5.4 → mm_sol-0.5.5}/src/mm_sol/cli/cmd/__init__.py +0 -0
  26. {mm_sol-0.5.4 → mm_sol-0.5.5}/src/mm_sol/cli/cmd/balance_cmd.py +0 -0
  27. {mm_sol-0.5.4 → mm_sol-0.5.5}/src/mm_sol/cli/cmd/balances_cmd.py +0 -0
  28. {mm_sol-0.5.4 → mm_sol-0.5.5}/src/mm_sol/cli/cmd/example_cmd.py +0 -0
  29. {mm_sol-0.5.4 → mm_sol-0.5.5}/src/mm_sol/cli/cmd/node_cmd.py +0 -0
  30. {mm_sol-0.5.4 → mm_sol-0.5.5}/src/mm_sol/cli/cmd/transfer_cmd.py +0 -0
  31. {mm_sol-0.5.4 → mm_sol-0.5.5}/src/mm_sol/cli/cmd/wallet/__init__.py +0 -0
  32. {mm_sol-0.5.4 → mm_sol-0.5.5}/src/mm_sol/cli/cmd/wallet/keypair_cmd.py +0 -0
  33. {mm_sol-0.5.4 → mm_sol-0.5.5}/src/mm_sol/cli/cmd/wallet/mnemonic_cmd.py +0 -0
  34. {mm_sol-0.5.4 → mm_sol-0.5.5}/src/mm_sol/cli/examples/balances.toml +0 -0
  35. {mm_sol-0.5.4 → mm_sol-0.5.5}/src/mm_sol/cli/examples/transfer.toml +0 -0
  36. {mm_sol-0.5.4 → mm_sol-0.5.5}/src/mm_sol/cli/validators.py +0 -0
  37. {mm_sol-0.5.4 → mm_sol-0.5.5}/src/mm_sol/constants.py +0 -0
  38. {mm_sol-0.5.4 → mm_sol-0.5.5}/src/mm_sol/converters.py +0 -0
  39. {mm_sol-0.5.4 → mm_sol-0.5.5}/src/mm_sol/py.typed +0 -0
  40. {mm_sol-0.5.4 → mm_sol-0.5.5}/src/mm_sol/solana_cli.py +0 -0
  41. {mm_sol-0.5.4 → mm_sol-0.5.5}/src/mm_sol/token.py +0 -0
  42. {mm_sol-0.5.4 → mm_sol-0.5.5}/src/mm_sol/transfer.py +0 -0
  43. {mm_sol-0.5.4 → mm_sol-0.5.5}/tests/__init__.py +0 -0
  44. {mm_sol-0.5.4 → mm_sol-0.5.5}/tests/cli/__init__.py +0 -0
  45. {mm_sol-0.5.4 → mm_sol-0.5.5}/tests/cli/cmd/__init__.py +0 -0
  46. {mm_sol-0.5.4 → mm_sol-0.5.5}/tests/cli/cmd/wallet/__init__.py +0 -0
  47. {mm_sol-0.5.4 → mm_sol-0.5.5}/tests/cli/cmd/wallet/test_keypair_cmd.py +0 -0
  48. {mm_sol-0.5.4 → mm_sol-0.5.5}/tests/cli/cmd/wallet/test_mnemonic_cmd.py +0 -0
  49. {mm_sol-0.5.4 → mm_sol-0.5.5}/tests/test_account.py +0 -0
  50. {mm_sol-0.5.4 → mm_sol-0.5.5}/tests/test_client.py +0 -0
  51. {mm_sol-0.5.4 → mm_sol-0.5.5}/tests/test_converters.py +0 -0
  52. {mm_sol-0.5.4 → mm_sol-0.5.5}/tests/test_rpc.py +0 -0
  53. {mm_sol-0.5.4 → mm_sol-0.5.5}/tests/test_token.py +0 -0
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mm-sol
3
- Version: 0.5.4
3
+ Version: 0.5.5
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
@@ -8,3 +8,6 @@ sudo curl -LsSf https://astral.sh/uv/install.sh | sh
8
8
  source $HOME/.local/bin/env
9
9
  uv tool install mm-sol
10
10
  ```
11
+
12
+ ### Notes
13
+ - AsyncClient from solana-py with socks5 proxy ignores timeout. Use http proxy.
@@ -1,10 +1,10 @@
1
1
  [project]
2
2
  name = "mm-sol"
3
- version = "0.5.4"
3
+ version = "0.5.5"
4
4
  description = ""
5
5
  requires-python = ">=3.12"
6
6
  dependencies = [
7
- "mm-crypto-utils>=0.2.8",
7
+ "mm-crypto-utils>=0.2.9",
8
8
  "solana~=0.36.6",
9
9
  "base58~=2.1.1",
10
10
  "mnemonic==0.21",
@@ -23,7 +23,7 @@ build-backend = "hatchling.build"
23
23
  dev-dependencies = [
24
24
  "pytest~=8.3.5",
25
25
  "pytest-xdist~=3.6.1",
26
- "ruff~=0.10.0",
26
+ "ruff~=0.11.2",
27
27
  "pip-audit~=2.8.0",
28
28
  "bandit~=1.8.3",
29
29
  "mypy~=1.15.0",
@@ -64,6 +64,7 @@ ignore = [
64
64
  "TD003", # flake8-todos: missing-todo-link
65
65
  "RET503", # flake8-return: implicit-return
66
66
  "COM812", # it's used in ruff formatter
67
+ "ASYNC109", # flake8-async: async-function-with-timeout
67
68
  ]
68
69
  [tool.ruff.lint.pep8-naming]
69
70
  classmethod-decorators = ["field_validator"]
@@ -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
+ )
@@ -0,0 +1,161 @@
1
+ import httpx
2
+ from mm_crypto_utils import Nodes, Proxies, random_node, random_proxy
3
+ from mm_std import Err, Ok, Result
4
+ from solana.exceptions import SolanaRpcException
5
+ from solana.rpc.core import RPCException
6
+ from solders.pubkey import Pubkey
7
+ from solders.rpc.errors import InvalidParamsMessage
8
+ from spl.token.instructions import get_associated_token_address
9
+
10
+ from mm_sol import async_rpc, rpc
11
+ from mm_sol.utils import get_async_client, get_client
12
+
13
+
14
+ def get_sol_balance(node: str, address: str, timeout: float = 10, proxy: str | None = None) -> Result[int]:
15
+ return rpc.get_balance(node, address, timeout, proxy)
16
+
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
+
22
+ def get_sol_balance_with_retries(
23
+ nodes: Nodes, address: str, retries: int, timeout: float = 10, proxies: Proxies = None
24
+ ) -> Result[int]:
25
+ res: Result[int] = Err("not started yet")
26
+ for _ in range(retries):
27
+ res = get_sol_balance(random_node(nodes), address, timeout=timeout, proxy=random_proxy(proxies))
28
+ if res.is_ok():
29
+ return res
30
+ return res
31
+
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
+
44
+ def get_token_balance(
45
+ node: str,
46
+ owner_address: str,
47
+ token_mint_address: str,
48
+ token_account: str | None = None,
49
+ timeout: float = 10,
50
+ proxy: str | None = None,
51
+ ) -> Result[int]:
52
+ try:
53
+ client = get_client(node, proxy=proxy, timeout=timeout)
54
+ if not token_account:
55
+ token_account = str(
56
+ get_associated_token_address(Pubkey.from_string(owner_address), Pubkey.from_string(token_mint_address))
57
+ )
58
+
59
+ res = client.get_token_account_balance(Pubkey.from_string(token_account))
60
+
61
+ # Sometimes it not raise an error, but it returns this :(
62
+ if isinstance(res, InvalidParamsMessage) and "could not find account" in res.message:
63
+ return Ok(0)
64
+ return Ok(int(res.value.amount), data=res.to_json())
65
+ except RPCException as e:
66
+ if len(e.args) > 1:
67
+ s = e.args[0]
68
+ if isinstance(s, InvalidParamsMessage) and "could not find account" in s.message:
69
+ return Ok(0)
70
+ return Err(e)
71
+ except httpx.HTTPStatusError as e:
72
+ return Err(f"http error: {e}")
73
+ except SolanaRpcException as e:
74
+ return Err(e.error_msg)
75
+ except Exception as e:
76
+ return Err(e)
77
+
78
+
79
+ async def get_token_balance_async(
80
+ node: str,
81
+ owner_address: str,
82
+ token_mint_address: str,
83
+ token_account: str | None = None,
84
+ timeout: float = 10,
85
+ proxy: str | None = None,
86
+ ) -> Result[int]:
87
+ try:
88
+ client = get_async_client(node, proxy=proxy, timeout=timeout)
89
+ if not token_account:
90
+ token_account = str(
91
+ get_associated_token_address(Pubkey.from_string(owner_address), Pubkey.from_string(token_mint_address))
92
+ )
93
+
94
+ res = await client.get_token_account_balance(Pubkey.from_string(token_account))
95
+
96
+ # Sometimes it not raise an error, but it returns this :(
97
+ if isinstance(res, InvalidParamsMessage) and "could not find account" in res.message:
98
+ return Ok(0)
99
+ return Ok(int(res.value.amount), data=res.to_json())
100
+ except RPCException as e:
101
+ if len(e.args) > 1:
102
+ s = e.args[0]
103
+ if isinstance(s, InvalidParamsMessage) and "could not find account" in s.message:
104
+ return Ok(0)
105
+ return Err(e)
106
+ except httpx.HTTPStatusError as e:
107
+ return Err(f"http error: {e}")
108
+ except SolanaRpcException as e:
109
+ return Err(e.error_msg)
110
+ except Exception as e:
111
+ return Err(e)
112
+
113
+
114
+ def get_token_balance_with_retries(
115
+ nodes: Nodes,
116
+ owner_address: str,
117
+ token_mint_address: str,
118
+ retries: int,
119
+ token_account: str | None = None,
120
+ timeout: float = 10,
121
+ proxies: Proxies = None,
122
+ ) -> Result[int]:
123
+ res: Result[int] = Err("not started yet")
124
+ for _ in range(retries):
125
+ res = get_token_balance(
126
+ random_node(nodes),
127
+ owner_address,
128
+ token_mint_address,
129
+ token_account,
130
+ timeout=timeout,
131
+ proxy=random_proxy(proxies),
132
+ )
133
+ if res.is_ok():
134
+ return res
135
+
136
+ return res
137
+
138
+
139
+ async def get_token_balance_with_retries_async(
140
+ nodes: Nodes,
141
+ owner_address: str,
142
+ token_mint_address: str,
143
+ retries: int,
144
+ token_account: str | None = None,
145
+ timeout: float = 10,
146
+ proxies: Proxies = None,
147
+ ) -> Result[int]:
148
+ res: Result[int] = Err("not started yet")
149
+ for _ in range(retries):
150
+ res = await get_token_balance_async(
151
+ random_node(nodes),
152
+ owner_address,
153
+ token_mint_address,
154
+ token_account,
155
+ timeout=timeout,
156
+ proxy=random_proxy(proxies),
157
+ )
158
+ if res.is_ok():
159
+ return res
160
+
161
+ return res
@@ -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:
@@ -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
@@ -5,7 +5,12 @@ import pytest
5
5
  from dotenv import load_dotenv
6
6
  from typer.testing import CliRunner
7
7
 
8
- load_dotenv(".env")
8
+ load_dotenv()
9
+
10
+
11
+ @pytest.fixture
12
+ def anyio_backend():
13
+ return "asyncio"
9
14
 
10
15
 
11
16
  @pytest.fixture
@@ -0,0 +1,10 @@
1
+ import pytest
2
+
3
+ from mm_sol import async_rpc
4
+
5
+ pytestmark = pytest.mark.anyio
6
+
7
+
8
+ async def test_get_balance(mainnet_node, binance_wallet, random_proxy):
9
+ res = await async_rpc.get_balance(mainnet_node, binance_wallet, proxy=random_proxy)
10
+ assert res.unwrap() > 10_000_000
@@ -0,0 +1,25 @@
1
+ import pytest
2
+
3
+ from mm_sol.balance import get_sol_balance, get_sol_balance_async, get_token_balance, get_token_balance_async
4
+
5
+ pytestmark = pytest.mark.anyio
6
+
7
+
8
+ def test_get_sol_balance(mainnet_node, usdt_owner_address, random_proxy):
9
+ res = get_sol_balance(mainnet_node, usdt_owner_address, proxy=random_proxy)
10
+ assert res.unwrap() > 10
11
+
12
+
13
+ async def test_get_sol_balance_async(mainnet_node, usdt_owner_address, random_proxy):
14
+ res = await get_sol_balance_async(mainnet_node, usdt_owner_address, proxy=random_proxy)
15
+ assert res.unwrap() > 10
16
+
17
+
18
+ def test_get_token_balance(mainnet_node, binance_wallet, usdt_token_address, random_proxy):
19
+ res = get_token_balance(mainnet_node, binance_wallet, usdt_token_address, proxy=random_proxy)
20
+ assert res.unwrap() > 10
21
+
22
+
23
+ async def test_get_token_balance_async(mainnet_node, binance_wallet, usdt_token_address, random_proxy):
24
+ res = await get_token_balance_async(mainnet_node, binance_wallet, usdt_token_address, proxy=random_proxy)
25
+ assert res.unwrap() > 10
@@ -13,15 +13,16 @@ wheels = [
13
13
 
14
14
  [[package]]
15
15
  name = "anyio"
16
- version = "4.6.2.post1"
16
+ version = "4.9.0"
17
17
  source = { registry = "https://pypi.org/simple" }
18
18
  dependencies = [
19
19
  { name = "idna" },
20
20
  { name = "sniffio" },
21
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
21
22
  ]
22
- sdist = { url = "https://files.pythonhosted.org/packages/9f/09/45b9b7a6d4e45c6bcb5bf61d19e3ab87df68e0601fa8c5293de3542546cc/anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c", size = 173422 }
23
+ sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949 }
23
24
  wheels = [
24
- { url = "https://files.pythonhosted.org/packages/e4/f5/f2b75d2fc6f1a260f340f0e7c6a060f4dd2961cc16884ed851b0d18da06a/anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d", size = 90377 },
25
+ { url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916 },
25
26
  ]
26
27
 
27
28
  [[package]]
@@ -309,6 +310,11 @@ wheels = [
309
310
  { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517 },
310
311
  ]
311
312
 
313
+ [package.optional-dependencies]
314
+ socks = [
315
+ { name = "socksio" },
316
+ ]
317
+
312
318
  [[package]]
313
319
  name = "idna"
314
320
  version = "3.10"
@@ -434,19 +440,19 @@ wheels = [
434
440
 
435
441
  [[package]]
436
442
  name = "mm-crypto-utils"
437
- version = "0.2.8"
443
+ version = "0.2.9"
438
444
  source = { registry = "https://pypi.org/simple" }
439
445
  dependencies = [
440
446
  { name = "loguru" },
441
447
  { name = "mm-std" },
442
448
  ]
443
449
  wheels = [
444
- { url = "https://files.pythonhosted.org/packages/c2/1c/0c6ad62e4671970eb643524742573cf3ee0dd8b2e1f58c6a7458efe8ae5e/mm_crypto_utils-0.2.8-py3-none-any.whl", hash = "sha256:04be8b12968e66973c916390737e31d55682cb5ce746cef73261e7d0381b2f7b", size = 8273 },
450
+ { url = "https://files.pythonhosted.org/packages/bb/4c/c790acb5b025d35a391dd4fef1ebb3b6432a874154844a618d27b10a0a0f/mm_crypto_utils-0.2.9-py3-none-any.whl", hash = "sha256:0b569067e4c4f8e568599134febe23aacbb903bb80799e4258180ec4a51bec9b", size = 8273 },
445
451
  ]
446
452
 
447
453
  [[package]]
448
454
  name = "mm-sol"
449
- version = "0.5.4"
455
+ version = "0.5.5"
450
456
  source = { editable = "." }
451
457
  dependencies = [
452
458
  { name = "base58" },
@@ -472,7 +478,7 @@ dev = [
472
478
  requires-dist = [
473
479
  { name = "base58", specifier = "~=2.1.1" },
474
480
  { name = "jinja2", specifier = ">=3.1.6" },
475
- { name = "mm-crypto-utils", specifier = ">=0.2.8" },
481
+ { name = "mm-crypto-utils", specifier = ">=0.2.9" },
476
482
  { name = "mnemonic", specifier = "==0.21" },
477
483
  { name = "socksio", specifier = ">=1.0.0" },
478
484
  { name = "solana", specifier = "~=0.36.6" },
@@ -486,16 +492,19 @@ dev = [
486
492
  { name = "pip-audit", specifier = "~=2.8.0" },
487
493
  { name = "pytest", specifier = "~=8.3.5" },
488
494
  { name = "pytest-xdist", specifier = "~=3.6.1" },
489
- { name = "ruff", specifier = "~=0.10.0" },
495
+ { name = "ruff", specifier = "~=0.11.2" },
490
496
  ]
491
497
 
492
498
  [[package]]
493
499
  name = "mm-std"
494
- version = "0.3.9"
500
+ version = "0.3.14"
495
501
  source = { registry = "https://pypi.org/simple" }
496
502
  dependencies = [
503
+ { name = "anyio" },
497
504
  { name = "cryptography" },
505
+ { name = "httpx", extra = ["socks"] },
498
506
  { name = "pydantic" },
507
+ { name = "pydantic-settings" },
499
508
  { name = "pydash" },
500
509
  { name = "python-dotenv" },
501
510
  { name = "requests", extra = ["socks"] },
@@ -503,7 +512,7 @@ dependencies = [
503
512
  { name = "tomlkit" },
504
513
  ]
505
514
  wheels = [
506
- { url = "https://files.pythonhosted.org/packages/c7/74/072e33a54a0cdbd7699a17f32950f8fd57e766ce74b768ccb4128cc5da24/mm_std-0.3.9-py3-none-any.whl", hash = "sha256:3ad5ee2fe720e939169a23aa7c9a5f3c7cee25232a184bb3415720ef740ddd04", size = 15581 },
515
+ { url = "https://files.pythonhosted.org/packages/47/61/cd5cbfc1868493ffda46c7d86d94459110ec4dd28c1883936f18f36bfab0/mm_std-0.3.14-py3-none-any.whl", hash = "sha256:db0a3a66590f456ad8c3f268d545803be63339c4b72f3197bc377d101a93ad02", size = 20219 },
507
516
  ]
508
517
 
509
518
  [[package]]
@@ -752,6 +761,19 @@ wheels = [
752
761
  { url = "https://files.pythonhosted.org/packages/51/b2/b2b50d5ecf21acf870190ae5d093602d95f66c9c31f9d5de6062eb329ad1/pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", size = 1885186 },
753
762
  ]
754
763
 
764
+ [[package]]
765
+ name = "pydantic-settings"
766
+ version = "2.8.1"
767
+ source = { registry = "https://pypi.org/simple" }
768
+ dependencies = [
769
+ { name = "pydantic" },
770
+ { name = "python-dotenv" },
771
+ ]
772
+ sdist = { url = "https://files.pythonhosted.org/packages/88/82/c79424d7d8c29b994fb01d277da57b0a9b09cc03c3ff875f9bd8a86b2145/pydantic_settings-2.8.1.tar.gz", hash = "sha256:d5c663dfbe9db9d5e1c646b2e161da12f0d734d422ee56f567d0ea2cee4e8585", size = 83550 }
773
+ wheels = [
774
+ { url = "https://files.pythonhosted.org/packages/0b/53/a64f03044927dc47aafe029c42a5b7aabc38dfb813475e0e1bf71c4a59d0/pydantic_settings-2.8.1-py3-none-any.whl", hash = "sha256:81942d5ac3d905f7f3ee1a70df5dfb62d5569c12f51a5a647defc1c3d9ee2e9c", size = 30839 },
775
+ ]
776
+
755
777
  [[package]]
756
778
  name = "pydash"
757
779
  version = "8.0.5"
@@ -889,27 +911,27 @@ wheels = [
889
911
 
890
912
  [[package]]
891
913
  name = "ruff"
892
- version = "0.10.0"
893
- source = { registry = "https://pypi.org/simple" }
894
- sdist = { url = "https://files.pythonhosted.org/packages/4c/ec/9c59d2956566517c98ac8267554f4eaceafb2a19710a429368518b7fab43/ruff-0.10.0.tar.gz", hash = "sha256:fa1554e18deaf8aa097dbcfeafaf38b17a2a1e98fdc18f50e62e8a836abee392", size = 3789921 }
895
- wheels = [
896
- { url = "https://files.pythonhosted.org/packages/bf/3f/742afe91b43def2a75990b293c676355576c0ff9cdbcf4249f78fa592544/ruff-0.10.0-py3-none-linux_armv6l.whl", hash = "sha256:46a2aa0eaae5048e5f804f0be9489d8a661633e23277b7293089e70d5c1a35c4", size = 10078369 },
897
- { url = "https://files.pythonhosted.org/packages/8d/a0/8696fb4862e82f7b40bbbc2917137594b22826cc62d77278a91391507514/ruff-0.10.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:775a6bc61af9dd0a2e1763406522a137e62aabb743d8b43ed95f019cdd1526c7", size = 10876912 },
898
- { url = "https://files.pythonhosted.org/packages/40/aa/0d48b7b7d7a1f168bb8fd893ed559d633c7d68c4a8ef9b996f0c2bd07aca/ruff-0.10.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:8b03e6fcd39d20f0004f9956f0ed5eadc404d3a299f9d9286323884e3b663730", size = 10229962 },
899
- { url = "https://files.pythonhosted.org/packages/21/de/861ced2f75b045d8cfc038d68961d8ac117344df1f43a11abdd05bf7991b/ruff-0.10.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:621101d1af80248827f2409a78c8177c8319986a57b4663613b9c72f8617bfcd", size = 10404627 },
900
- { url = "https://files.pythonhosted.org/packages/21/69/666e0b840191c3ce433962c0d05fc0f6800afe259ea5d230cc731655d8e2/ruff-0.10.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e2dfe85cb6bfbd4259801e7d4982f2a72bdbd5749dc73a09d68a6dbf77f2209a", size = 9939383 },
901
- { url = "https://files.pythonhosted.org/packages/76/bf/34a2adc58092c99cdfa9f1303acd82d840d56412022e477e2ab20c261d2d/ruff-0.10.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43ac3879a20c22fdc57e559f0bb27f0c71828656841d0b42d3505b1e5b3a83c8", size = 11492269 },
902
- { url = "https://files.pythonhosted.org/packages/31/3d/f7ccfcf69f15948623b190feea9d411d5029ae39725fcc078f8d43bd07a6/ruff-0.10.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:ef5e3aac421bbc62f8a7aab21edd49a359ed42205f7a5091a74386bca1efa293", size = 12186939 },
903
- { url = "https://files.pythonhosted.org/packages/6e/3e/c557c0abfdea85c7d238a3cb238c73e7b6d17c30a584234c4fd8fe2cafb6/ruff-0.10.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9f4f62d7fac8b748fce67ad308116b4d4cc1a9f964b4804fc5408fbd06e13ba9", size = 11655896 },
904
- { url = "https://files.pythonhosted.org/packages/3b/8e/3bfa110f37e5192eb3943f14943d05fbb9a76fea380aa87655e6f6276a54/ruff-0.10.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:02f9f6205c5b0d626f98da01a0e75b724a64c21c554bba24b12522c9e9ba6a04", size = 13885502 },
905
- { url = "https://files.pythonhosted.org/packages/51/4a/22cdab59b5563dd7f4c504d0f1e6bb25fc800a5a057395bc24f8ff3a85b2/ruff-0.10.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46a97f3d55f68464c48d1e929a8582c7e5bb80ac73336bbc7b0da894d8e6cd9e", size = 11344767 },
906
- { url = "https://files.pythonhosted.org/packages/3d/0f/8f85de2ac565f82f47c6d8fb7ae04383e6300560f2d1b91c1268ff91e507/ruff-0.10.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a0b811197d0dc96c13d610f8cfdc56030b405bcff5c2f10eab187b329da0ca4a", size = 10300331 },
907
- { url = "https://files.pythonhosted.org/packages/90/4a/b337df327832cb30bd8607e8d1fdf1b6b5ca228307d5008dd49028fb66ae/ruff-0.10.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a13a3fda0870c1c964b47ff5d73805ae80d2a9de93ee2d185d453b8fddf85a84", size = 9926551 },
908
- { url = "https://files.pythonhosted.org/packages/d7/e9/141233730b85675ac806c4b62f70516bd9c0aae8a55823f3a6589ed411be/ruff-0.10.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6ceb8d9f062e90ddcbad929f6136edf764bbf6411420a07e8357602ea28cd99f", size = 10925061 },
909
- { url = "https://files.pythonhosted.org/packages/24/09/02987935b55c2d353a226ac1b4f9718830e2e195834929f46c07eeede746/ruff-0.10.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:c41d07d573617ed2f287ea892af2446fd8a8d877481e8e1ba6928e020665d240", size = 11394949 },
910
- { url = "https://files.pythonhosted.org/packages/d6/ec/054f9879fb6f4122d43ffe5c9f88c8c323a9cd14220d5c813aea5805e02c/ruff-0.10.0-py3-none-win32.whl", hash = "sha256:76e2de0cbdd587e373cd3b4050d2c45babdd7014c1888a6f121c29525c748a15", size = 10272077 },
911
- { url = "https://files.pythonhosted.org/packages/6e/49/915d8682f24645b904fe6a1aac36101464fc814923fdf293c1388dc5533c/ruff-0.10.0-py3-none-win_amd64.whl", hash = "sha256:f943acdecdcc6786a8d1dad455dd9f94e6d57ccc115be4993f9b52ef8316027a", size = 11393300 },
912
- { url = "https://files.pythonhosted.org/packages/82/ed/5c59941634c9026ceeccc7c119f23f4356f09aafd28c15c1bc734ac66b01/ruff-0.10.0-py3-none-win_arm64.whl", hash = "sha256:935a943bdbd9ff0685acd80d484ea91088e27617537b5f7ef8907187d19d28d0", size = 10510133 },
914
+ version = "0.11.2"
915
+ source = { registry = "https://pypi.org/simple" }
916
+ sdist = { url = "https://files.pythonhosted.org/packages/90/61/fb87430f040e4e577e784e325351186976516faef17d6fcd921fe28edfd7/ruff-0.11.2.tar.gz", hash = "sha256:ec47591497d5a1050175bdf4e1a4e6272cddff7da88a2ad595e1e326041d8d94", size = 3857511 }
917
+ wheels = [
918
+ { url = "https://files.pythonhosted.org/packages/62/99/102578506f0f5fa29fd7e0df0a273864f79af044757aef73d1cae0afe6ad/ruff-0.11.2-py3-none-linux_armv6l.whl", hash = "sha256:c69e20ea49e973f3afec2c06376eb56045709f0212615c1adb0eda35e8a4e477", size = 10113146 },
919
+ { url = "https://files.pythonhosted.org/packages/74/ad/5cd4ba58ab602a579997a8494b96f10f316e874d7c435bcc1a92e6da1b12/ruff-0.11.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:2c5424cc1c4eb1d8ecabe6d4f1b70470b4f24a0c0171356290b1953ad8f0e272", size = 10867092 },
920
+ { url = "https://files.pythonhosted.org/packages/fc/3e/d3f13619e1d152c7b600a38c1a035e833e794c6625c9a6cea6f63dbf3af4/ruff-0.11.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:ecf20854cc73f42171eedb66f006a43d0a21bfb98a2523a809931cda569552d9", size = 10224082 },
921
+ { url = "https://files.pythonhosted.org/packages/90/06/f77b3d790d24a93f38e3806216f263974909888fd1e826717c3ec956bbcd/ruff-0.11.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c543bf65d5d27240321604cee0633a70c6c25c9a2f2492efa9f6d4b8e4199bb", size = 10394818 },
922
+ { url = "https://files.pythonhosted.org/packages/99/7f/78aa431d3ddebfc2418cd95b786642557ba8b3cb578c075239da9ce97ff9/ruff-0.11.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:20967168cc21195db5830b9224be0e964cc9c8ecf3b5a9e3ce19876e8d3a96e3", size = 9952251 },
923
+ { url = "https://files.pythonhosted.org/packages/30/3e/f11186d1ddfaca438c3bbff73c6a2fdb5b60e6450cc466129c694b0ab7a2/ruff-0.11.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:955a9ce63483999d9f0b8f0b4a3ad669e53484232853054cc8b9d51ab4c5de74", size = 11563566 },
924
+ { url = "https://files.pythonhosted.org/packages/22/6c/6ca91befbc0a6539ee133d9a9ce60b1a354db12c3c5d11cfdbf77140f851/ruff-0.11.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:86b3a27c38b8fce73bcd262b0de32e9a6801b76d52cdb3ae4c914515f0cef608", size = 12208721 },
925
+ { url = "https://files.pythonhosted.org/packages/19/b0/24516a3b850d55b17c03fc399b681c6a549d06ce665915721dc5d6458a5c/ruff-0.11.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3b66a03b248c9fcd9d64d445bafdf1589326bee6fc5c8e92d7562e58883e30f", size = 11662274 },
926
+ { url = "https://files.pythonhosted.org/packages/d7/65/76be06d28ecb7c6070280cef2bcb20c98fbf99ff60b1c57d2fb9b8771348/ruff-0.11.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0397c2672db015be5aa3d4dac54c69aa012429097ff219392c018e21f5085147", size = 13792284 },
927
+ { url = "https://files.pythonhosted.org/packages/ce/d2/4ceed7147e05852876f3b5f3fdc23f878ce2b7e0b90dd6e698bda3d20787/ruff-0.11.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:869bcf3f9abf6457fbe39b5a37333aa4eecc52a3b99c98827ccc371a8e5b6f1b", size = 11327861 },
928
+ { url = "https://files.pythonhosted.org/packages/c4/78/4935ecba13706fd60ebe0e3dc50371f2bdc3d9bc80e68adc32ff93914534/ruff-0.11.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:2a2b50ca35457ba785cd8c93ebbe529467594087b527a08d487cf0ee7b3087e9", size = 10276560 },
929
+ { url = "https://files.pythonhosted.org/packages/81/7f/1b2435c3f5245d410bb5dc80f13ec796454c21fbda12b77d7588d5cf4e29/ruff-0.11.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:7c69c74bf53ddcfbc22e6eb2f31211df7f65054bfc1f72288fc71e5f82db3eab", size = 9945091 },
930
+ { url = "https://files.pythonhosted.org/packages/39/c4/692284c07e6bf2b31d82bb8c32f8840f9d0627d92983edaac991a2b66c0a/ruff-0.11.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6e8fb75e14560f7cf53b15bbc55baf5ecbe373dd5f3aab96ff7aa7777edd7630", size = 10977133 },
931
+ { url = "https://files.pythonhosted.org/packages/94/cf/8ab81cb7dd7a3b0a3960c2769825038f3adcd75faf46dd6376086df8b128/ruff-0.11.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:842a472d7b4d6f5924e9297aa38149e5dcb1e628773b70e6387ae2c97a63c58f", size = 11378514 },
932
+ { url = "https://files.pythonhosted.org/packages/d9/3a/a647fa4f316482dacf2fd68e8a386327a33d6eabd8eb2f9a0c3d291ec549/ruff-0.11.2-py3-none-win32.whl", hash = "sha256:aca01ccd0eb5eb7156b324cfaa088586f06a86d9e5314b0eb330cb48415097cc", size = 10319835 },
933
+ { url = "https://files.pythonhosted.org/packages/86/54/3c12d3af58012a5e2cd7ebdbe9983f4834af3f8cbea0e8a8c74fa1e23b2b/ruff-0.11.2-py3-none-win_amd64.whl", hash = "sha256:3170150172a8f994136c0c66f494edf199a0bbea7a409f649e4bc8f4d7084080", size = 11373713 },
934
+ { url = "https://files.pythonhosted.org/packages/d6/d4/dd813703af8a1e2ac33bf3feb27e8a5ad514c9f219df80c64d69807e7f71/ruff-0.11.2-py3-none-win_arm64.whl", hash = "sha256:52933095158ff328f4c77af3d74f0379e34fd52f175144cefc1b192e7ccd32b4", size = 10441990 },
913
935
  ]
914
936
 
915
937
  [[package]]
@@ -1,86 +0,0 @@
1
- import httpx
2
- from mm_crypto_utils import Nodes, Proxies, random_node, random_proxy
3
- from mm_std import Err, Ok, Result
4
- from solana.exceptions import SolanaRpcException
5
- from solana.rpc.core import RPCException
6
- from solders.pubkey import Pubkey
7
- from solders.rpc.errors import InvalidParamsMessage
8
- from spl.token.instructions import get_associated_token_address
9
-
10
- from mm_sol import rpc
11
- from mm_sol.utils import get_client
12
-
13
-
14
- def get_sol_balance(node: str, address: str, timeout: int = 10, proxy: str | None = None) -> Result[int]:
15
- return rpc.get_balance(node, address, timeout, proxy)
16
-
17
-
18
- def get_sol_balance_with_retries(
19
- nodes: Nodes, address: str, retries: int, timeout: int = 10, proxies: Proxies = None
20
- ) -> Result[int]:
21
- res: Result[int] = Err("not started yet")
22
- for _ in range(retries):
23
- res = get_sol_balance(random_node(nodes), address, timeout=timeout, proxy=random_proxy(proxies))
24
- if res.is_ok():
25
- return res
26
- return res
27
-
28
-
29
- def get_token_balance(
30
- node: str,
31
- owner_address: str,
32
- token_mint_address: str,
33
- token_account: str | None = None,
34
- timeout: float = 10,
35
- proxy: str | None = None,
36
- ) -> Result[int]:
37
- try:
38
- client = get_client(node, proxy=proxy, timeout=timeout)
39
- if not token_account:
40
- token_account = str(
41
- get_associated_token_address(Pubkey.from_string(owner_address), Pubkey.from_string(token_mint_address))
42
- )
43
-
44
- res = client.get_token_account_balance(Pubkey.from_string(token_account))
45
-
46
- # Sometimes it not raise an error, but it returns this :(
47
- if isinstance(res, InvalidParamsMessage) and "could not find account" in res.message:
48
- return Ok(0)
49
- return Ok(int(res.value.amount), data=res.to_json())
50
- 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)
55
- return Err(e)
56
- except httpx.HTTPStatusError as e:
57
- return Err(f"http error: {e}")
58
- except SolanaRpcException as e:
59
- return Err(e.error_msg)
60
- except Exception as e:
61
- return Err(e)
62
-
63
-
64
- def get_token_balance_with_retries(
65
- nodes: Nodes,
66
- owner_address: str,
67
- token_mint_address: str,
68
- retries: int,
69
- token_account: str | None = None,
70
- timeout: float = 10,
71
- proxies: Proxies = None,
72
- ) -> Result[int]:
73
- res: Result[int] = Err("not started yet")
74
- for _ in range(retries):
75
- res = get_token_balance(
76
- random_node(nodes),
77
- owner_address,
78
- token_mint_address,
79
- token_account,
80
- timeout=timeout,
81
- proxy=random_proxy(proxies),
82
- )
83
- if res.is_ok():
84
- return res
85
-
86
- return res
@@ -1,6 +0,0 @@
1
- from mm_sol.balance import get_sol_balance
2
-
3
-
4
- def test_get_balance(mainnet_node, usdt_owner_address, random_proxy):
5
- res = get_sol_balance(mainnet_node, usdt_owner_address, proxy=random_proxy)
6
- assert res.unwrap() > 10
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes