mm-sol 0.5.9__py3-none-any.whl → 0.6.1__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/transfer.py CHANGED
@@ -1,22 +1,20 @@
1
- import mm_crypto_utils
2
1
  import pydash
3
- from mm_crypto_utils import Nodes, Proxies
4
- from mm_std import Err, Ok, Result
2
+ from mm_std import Result
5
3
  from pydantic import BaseModel
6
4
  from solders.message import Message
7
5
  from solders.pubkey import Pubkey
8
6
  from solders.signature import Signature
9
7
  from solders.system_program import TransferParams, transfer
10
8
  from solders.transaction import Transaction
11
- from spl.token.client import Token
9
+ from spl.token.async_client import AsyncToken
12
10
  from spl.token.constants import TOKEN_PROGRAM_ID
13
11
  from spl.token.instructions import get_associated_token_address
14
12
 
15
- from mm_sol import rpc, utils
13
+ from mm_sol import rpc_sync, utils
16
14
  from mm_sol.account import check_private_key, get_keypair
17
15
 
18
16
 
19
- def transfer_token(
17
+ async def transfer_token(
20
18
  *,
21
19
  node: str,
22
20
  token_mint_address: str | Pubkey,
@@ -29,73 +27,44 @@ def transfer_token(
29
27
  timeout: float = 10,
30
28
  create_token_account_if_not_exists: bool = True,
31
29
  ) -> Result[Signature]:
30
+ # TODO: try/except this function!!!
32
31
  acc = get_keypair(private_key)
33
32
  if not check_private_key(from_address, private_key):
34
- return Err("invalid_private_key")
33
+ return Result.err("invalid_private_key")
35
34
 
36
35
  from_address = utils.pubkey(from_address)
37
36
  token_mint_address = utils.pubkey(token_mint_address)
38
37
  to_address = utils.pubkey(to_address)
39
38
 
40
- client = utils.get_client(node, proxy=proxy, timeout=timeout)
41
- token_client = Token(conn=client, pubkey=token_mint_address, program_id=TOKEN_PROGRAM_ID, payer=acc)
39
+ client = utils.get_async_client(node, proxy=proxy, timeout=timeout)
40
+ token_client = AsyncToken(conn=client, pubkey=token_mint_address, program_id=TOKEN_PROGRAM_ID, payer=acc)
42
41
 
43
42
  recipient_token_account = get_associated_token_address(to_address, token_mint_address, token_program_id=TOKEN_PROGRAM_ID)
44
43
  from_token_account = get_associated_token_address(from_address, token_mint_address, token_program_id=TOKEN_PROGRAM_ID)
45
- data: list[object] = []
44
+ logs: list[object] = []
46
45
 
47
- account_info_res = client.get_account_info(recipient_token_account)
46
+ account_info_res = await client.get_account_info(recipient_token_account)
48
47
  if account_info_res.value is None:
49
48
  if create_token_account_if_not_exists:
50
49
  create_account_res = token_client.create_associated_token_account(to_address, skip_confirmation=False)
51
- data.append(create_account_res)
50
+ logs.append(create_account_res)
52
51
  else:
53
- return Err("no_token_account")
52
+ return Result.err("no_token_account")
54
53
 
55
- res = token_client.transfer_checked(
54
+ res = await token_client.transfer_checked(
56
55
  source=from_token_account,
57
56
  dest=recipient_token_account,
58
57
  owner=from_address,
59
58
  amount=amount,
60
59
  decimals=decimals,
60
+ multi_signers=None,
61
61
  )
62
- data.append(res)
62
+ logs.append(res)
63
63
 
64
- return Ok(res.value, data=data)
64
+ return Result.ok(res.value, {"logs": logs})
65
65
 
66
66
 
67
- def transfer_token_with_retries(
68
- *,
69
- nodes: Nodes,
70
- token_mint_address: str | Pubkey,
71
- from_address: str | Pubkey,
72
- private_key: str,
73
- to_address: str | Pubkey,
74
- amount: int, # smallest unit
75
- decimals: int,
76
- proxies: Proxies = None,
77
- timeout: float = 10,
78
- retries: int = 3,
79
- ) -> Result[Signature]:
80
- res: Result[Signature] = Err("not started yet")
81
- for _ in range(retries):
82
- res = transfer_token(
83
- node=mm_crypto_utils.random_node(nodes),
84
- token_mint_address=token_mint_address,
85
- from_address=from_address,
86
- private_key=private_key,
87
- to_address=to_address,
88
- amount=amount,
89
- decimals=decimals,
90
- proxy=mm_crypto_utils.random_proxy(proxies),
91
- timeout=timeout,
92
- )
93
- if res.is_ok():
94
- return res
95
- return res
96
-
97
-
98
- def transfer_sol(
67
+ async def transfer_sol(
99
68
  *,
100
69
  node: str,
101
70
  from_address: str,
@@ -107,46 +76,20 @@ def transfer_sol(
107
76
  ) -> Result[Signature]:
108
77
  acc = get_keypair(private_key)
109
78
  if not check_private_key(from_address, private_key):
110
- return Err("invalid_private_key")
79
+ return Result.err("invalid_private_key")
111
80
 
112
- client = utils.get_client(node, proxy=proxy, timeout=timeout)
81
+ client = utils.get_async_client(node, proxy=proxy, timeout=timeout)
113
82
  data = None
114
83
  try:
115
84
  ixs = [transfer(TransferParams(from_pubkey=acc.pubkey(), to_pubkey=Pubkey.from_string(to_address), lamports=lamports))]
116
85
  msg = Message(ixs, acc.pubkey())
117
- tx = Transaction([acc], msg, client.get_latest_blockhash().value.blockhash)
118
- res = client.send_transaction(tx)
86
+ blockhash = await client.get_latest_blockhash()
87
+ tx = Transaction([acc], msg, blockhash.value.blockhash)
88
+ res = await client.send_transaction(tx)
119
89
  data = res.to_json()
120
- return Ok(res.value, data=data)
90
+ return Result.ok(res.value, {"response": data})
121
91
  except Exception as e:
122
- return Err(e, data=data)
123
-
124
-
125
- def transfer_sol_with_retries(
126
- *,
127
- nodes: Nodes,
128
- from_address: str,
129
- private_key: str,
130
- to_address: str,
131
- lamports: int,
132
- proxies: Proxies = None,
133
- timeout: float = 10,
134
- retries: int = 3,
135
- ) -> Result[Signature]:
136
- res: Result[Signature] = Err("not started yet")
137
- for _ in range(retries):
138
- res = transfer_sol(
139
- node=mm_crypto_utils.random_node(nodes),
140
- from_address=from_address,
141
- private_key=private_key,
142
- to_address=to_address,
143
- lamports=lamports,
144
- proxy=mm_crypto_utils.random_proxy(proxies),
145
- timeout=timeout,
146
- )
147
- if res.is_ok():
148
- return res
149
- return res
92
+ return Result.err(e, {"response": data})
150
93
 
151
94
 
152
95
  class SolTransferInfo(BaseModel):
@@ -156,7 +99,7 @@ class SolTransferInfo(BaseModel):
156
99
 
157
100
 
158
101
  def find_sol_transfers(node: str, tx_signature: str) -> Result[list[SolTransferInfo]]:
159
- res = rpc.get_transaction(node, tx_signature, encoding="jsonParsed")
102
+ res = rpc_sync.get_transaction(node, tx_signature, encoding="jsonParsed")
160
103
  if res.is_err():
161
104
  return res # type: ignore[return-value]
162
105
  result = []
@@ -170,6 +113,6 @@ def find_sol_transfers(node: str, tx_signature: str) -> Result[list[SolTransferI
170
113
  lamports = pydash.get(ix, "parsed.info.lamports")
171
114
  if source and destination and lamports:
172
115
  result.append(SolTransferInfo(source=source, destination=destination, lamports=lamports))
173
- return Ok(result, data=res.data)
116
+ return res.with_value(result)
174
117
  except Exception as e:
175
- return Err(e, res.data)
118
+ return Result.err(e, res.extra)
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mm-sol
3
- Version: 0.5.9
3
+ Version: 0.6.1
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.15
7
+ Requires-Dist: mm-crypto-utils>=0.3.4
8
8
  Requires-Dist: mnemonic==0.21
9
9
  Requires-Dist: socksio>=1.0.0
10
10
  Requires-Dist: solana~=0.36.6
@@ -0,0 +1,31 @@
1
+ mm_sol/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ mm_sol/account.py,sha256=cVcxRQBuV_Gfm2WgQIwaYuAQijeIJqDDxLC22PN0XSs,3493
3
+ mm_sol/constants.py,sha256=WSpfz5_cq_8XbIrNFJGu9okwbfPTL00zsyR_k9-7O0o,29
4
+ mm_sol/converters.py,sha256=rBxe3SIADZS8hG7TYl4FgjmvKH-ykaTmNbnWWQDiFZ4,1430
5
+ mm_sol/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ mm_sol/retry.py,sha256=9ejCcrHbJFOcZVKdbUASynLs1YHw04VAIKGH8mIJ1OI,2894
7
+ mm_sol/rpc.py,sha256=sYZ6y47qQa2WOHul9H3gcM4tJ61Z2yy6UpITR2DnX8s,2457
8
+ mm_sol/rpc_sync.py,sha256=vxWh1nmTgDelvfBDo9haxQmpDnXFZzeInsKIw3LLyy0,7183
9
+ mm_sol/spl_token.py,sha256=hEWVch17EdudlL_tj3ZInCa9wB0iK8hwwpFucmVi7Pc,1941
10
+ mm_sol/transfer.py,sha256=6CXzeMe91JtG8SuTadYQ-DLHJFyskytmBItGVEPh7Os,4410
11
+ mm_sol/utils.py,sha256=oD06NsMSMhN6lqsM6mSgLTtiKwA1uAsen9WR82ofRTE,923
12
+ mm_sol/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
+ mm_sol/cli/calcs.py,sha256=TR-mWQWYyHPdJYi_rvqiebqBqRsXsaqaSdvwCoSax1g,1675
14
+ mm_sol/cli/cli.py,sha256=0MflYgO-UzFdoaXFCIBuQ1Y6AOQUquX__AhSWOO64KY,4735
15
+ mm_sol/cli/cli_utils.py,sha256=nFdY8tJFZxyssEBEFCc3VTNJt447e6vMnugx4GBPL4o,1840
16
+ mm_sol/cli/validators.py,sha256=M_Rr7JoG3TUYTDAGkjQLDH6l9i9FOrSpss30KdY3UlM,1379
17
+ mm_sol/cli/cmd/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ mm_sol/cli/cmd/balance_cmd.py,sha256=ot6X7gTSoMcjapVkAgDlA9Wyo4YeFBIRA7GLjTXsu98,2469
19
+ mm_sol/cli/cmd/balances_cmd.py,sha256=XNNyU02mvSxPdfD3usxucNiiHagxSnLe1rKihj-ya78,2676
20
+ mm_sol/cli/cmd/example_cmd.py,sha256=ZLTy1-cmapiCyYvjFInVE-pQCGKZzDgYKUhsOwtbSIY,234
21
+ mm_sol/cli/cmd/node_cmd.py,sha256=xKjaMdv3_C4kePo-exjE4dQqUHtHWC4eHGROWLkWpS0,347
22
+ mm_sol/cli/cmd/transfer_cmd.py,sha256=Q1GvT1NPDqOESZwfwPYnLqOSQ_VNJCj9ihi7hZhj8xw,10913
23
+ mm_sol/cli/cmd/wallet/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
+ mm_sol/cli/cmd/wallet/keypair_cmd.py,sha256=cRHVVTs9zNYmUozZ8ZlJoutn9V6r8I1AEHBrszR7dTE,538
25
+ mm_sol/cli/cmd/wallet/mnemonic_cmd.py,sha256=IiON_fJT5AFfIr_E1LR6_iDYZ3c_jWCFc-wSYqk61V8,648
26
+ mm_sol/cli/examples/balances.toml,sha256=333g2EkyYBDW7OWFGMIWVZGkdFQMMo0Ag-bg-BvS4Zg,349
27
+ mm_sol/cli/examples/transfer.toml,sha256=kOCdmuwmhlOam4LVtlcYTKF0PoZYHWMlv9gWxNSXMOk,1624
28
+ mm_sol-0.6.1.dist-info/METADATA,sha256=SQ0YVupNyQKaMg7eZ7_NWj6u2oU63HL-ExQztVQbW3c,320
29
+ mm_sol-0.6.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
30
+ mm_sol-0.6.1.dist-info/entry_points.txt,sha256=MrYnosumy9nsITSAw5TiR3WXDwsdoF0YvUIlZ38TLLs,46
31
+ mm_sol-0.6.1.dist-info/RECORD,,
mm_sol/async_rpc.py DELETED
@@ -1,42 +0,0 @@
1
- from typing import Any
2
-
3
- from mm_std import Result, hra
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 hra(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 DELETED
@@ -1,158 +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 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 "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)
101
- return Err(e)
102
-
103
- except httpx.HTTPStatusError as e:
104
- return Err(f"http error: {e}")
105
- except SolanaRpcException as e:
106
- return Err(e.error_msg)
107
- except Exception as e:
108
- return Err(e)
109
-
110
-
111
- def get_token_balance_with_retries(
112
- nodes: Nodes,
113
- owner_address: str,
114
- token_mint_address: str,
115
- retries: int,
116
- token_account: str | None = None,
117
- timeout: float = 10,
118
- proxies: Proxies = None,
119
- ) -> Result[int]:
120
- res: Result[int] = Err("not started yet")
121
- for _ in range(retries):
122
- res = get_token_balance(
123
- random_node(nodes),
124
- owner_address,
125
- token_mint_address,
126
- token_account,
127
- timeout=timeout,
128
- proxy=random_proxy(proxies),
129
- )
130
- if res.is_ok():
131
- return res
132
-
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/block.py DELETED
@@ -1,58 +0,0 @@
1
- from mm_std import Err, Ok, Result
2
- from pydantic import BaseModel
3
-
4
- from mm_sol.rpc import rpc_call
5
-
6
-
7
- class BlockTxCount(BaseModel):
8
- slot: int
9
- block_time: int | None
10
- vote_tx_ok: int
11
- vote_tx_error: int
12
- non_vote_tx_ok: int
13
- non_vote_tx_error: int
14
-
15
-
16
- def calc_block_tx_count(node: str, slot: int, timeout: int = 10, proxy: str | None = None) -> Result[BlockTxCount]:
17
- res = rpc_call(node=node, method="getBlock", params=[slot], timeout=timeout, proxy=proxy)
18
- if res.is_err():
19
- return res
20
- vote_tx_ok = 0
21
- vote_tx_error = 0
22
- non_vote_tx_ok = 0
23
- non_vote_tx_error = 0
24
- vote_tx_keys = [
25
- "SysvarS1otHashes111111111111111111111111111",
26
- "SysvarC1ock11111111111111111111111111111111",
27
- "Vote111111111111111111111111111111111111111",
28
- ]
29
- try:
30
- res_ok = res.unwrap()
31
- txs = res_ok["transactions"]
32
- block_time = res_ok["blockTime"]
33
- for tx in txs:
34
- is_error = tx["meta"]["err"] is not None
35
- account_keys = tx["transaction"]["message"]["accountKeys"]
36
- if len(account_keys) == 5 and vote_tx_keys == account_keys[2:]:
37
- if is_error:
38
- vote_tx_error += 1
39
- else:
40
- vote_tx_ok += 1
41
- elif is_error:
42
- non_vote_tx_error += 1
43
- else:
44
- non_vote_tx_ok += 1
45
-
46
- return Ok(
47
- BlockTxCount(
48
- slot=slot,
49
- vote_tx_ok=vote_tx_ok,
50
- vote_tx_error=vote_tx_error,
51
- non_vote_tx_ok=non_vote_tx_ok,
52
- non_vote_tx_error=non_vote_tx_error,
53
- block_time=block_time,
54
- ),
55
- res.data,
56
- )
57
- except Exception as e:
58
- return Err(e, data=res.data)
mm_sol/rpc_async.py DELETED
@@ -1,65 +0,0 @@
1
- import json
2
- from collections.abc import Sequence
3
- from typing import Any
4
-
5
- import websockets
6
- from mm_std import DataResult, http_request
7
-
8
-
9
- async def rpc_call(
10
- node: str,
11
- method: str,
12
- params: Sequence[object],
13
- timeout: float,
14
- proxy: str | None,
15
- id_: int = 1,
16
- ) -> DataResult[Any]:
17
- data = {"jsonrpc": "2.0", "method": method, "params": params, "id": id_}
18
- if node.startswith("http"):
19
- return await _http_call(node, data, timeout, proxy)
20
- return await _ws_call(node, data, timeout)
21
-
22
-
23
- async def _http_call(node: str, data: dict[str, object], timeout: float, proxy: str | None) -> DataResult[Any]:
24
- res = await http_request(node, method="POST", proxy=proxy, timeout=timeout, json=data)
25
- if res.is_error():
26
- return res.to_data_result_err()
27
- try:
28
- parsed_body = res.parse_json_body()
29
- err = parsed_body.get("error", {}).get("message", "")
30
- if err:
31
- return res.to_data_result_err(f"service_error: {err}")
32
- if "result" in parsed_body:
33
- return res.to_data_result_ok(parsed_body["result"])
34
- return res.to_data_result_err("unknown_response")
35
- except Exception as err:
36
- return res.to_data_result_err(f"exception: {err}")
37
-
38
-
39
- async def _ws_call(node: str, data: dict[str, object], timeout: float) -> DataResult[Any]:
40
- try:
41
- async with websockets.connect(node, open_timeout=timeout) as ws:
42
- await ws.send(json.dumps(data))
43
- response = json.loads(await ws.recv())
44
-
45
- err = response.get("error", {}).get("message", "")
46
- if err:
47
- return DataResult.err(f"service_error: {err}", {"res": response})
48
- if "result" in response:
49
- return DataResult.ok(response["result"], {"res": response})
50
- return DataResult.err("unknown_response", {"res": response})
51
- except TimeoutError:
52
- return DataResult.err("timeout")
53
- except Exception as err:
54
- return DataResult.exception(err)
55
-
56
-
57
- async def get_block_height(node: str, timeout: float = 10, proxy: str | None = None) -> DataResult[int]:
58
- return await rpc_call(node=node, method="getBlockHeight", params=[], timeout=timeout, proxy=proxy)
59
-
60
-
61
- async def get_balance(node: str, address: str, timeout: float = 10, proxy: str | None = None) -> DataResult[int]:
62
- """Returns balance in lamports"""
63
- return (await rpc_call(node=node, method="getBalance", params=[address], timeout=timeout, proxy=proxy)).map(
64
- lambda r: r["value"]
65
- )