mm-btc 0.0.4__tar.gz → 0.0.6__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.
- {mm_btc-0.0.4 → mm_btc-0.0.6}/PKG-INFO +3 -1
- mm_btc-0.0.6/README.txt +9 -0
- {mm_btc-0.0.4 → mm_btc-0.0.6}/pyproject.toml +4 -2
- mm_btc-0.0.6/src/mm_btc/blockstream.py +91 -0
- {mm_btc-0.0.4 → mm_btc-0.0.6}/src/mm_btc/cli/cli.py +32 -3
- mm_btc-0.0.6/src/mm_btc/cli/cmd/address_cmd.py +10 -0
- mm_btc-0.0.6/src/mm_btc/cli/cmd/create_tx_cmd.py +27 -0
- mm_btc-0.0.6/src/mm_btc/cli/cmd/decode_tx_cmd.py +8 -0
- mm_btc-0.0.6/src/mm_btc/cli/cmd/utxo_cmd.py +11 -0
- mm_btc-0.0.6/src/mm_btc/tx.py +5 -0
- {mm_btc-0.0.4 → mm_btc-0.0.6}/src/mm_btc/wallet.py +4 -0
- {mm_btc-0.0.4 → mm_btc-0.0.6}/src/mm_btc.egg-info/PKG-INFO +3 -1
- {mm_btc-0.0.4 → mm_btc-0.0.6}/src/mm_btc.egg-info/SOURCES.txt +5 -0
- {mm_btc-0.0.4 → mm_btc-0.0.6}/src/mm_btc.egg-info/requires.txt +2 -0
- mm_btc-0.0.6/tests/test_blockstream.py +28 -0
- mm_btc-0.0.4/README.txt +0 -1
- mm_btc-0.0.4/src/mm_btc/blockstream.py +0 -63
- mm_btc-0.0.4/tests/test_blockstream.py +0 -24
- {mm_btc-0.0.4 → mm_btc-0.0.6}/setup.cfg +0 -0
- {mm_btc-0.0.4 → mm_btc-0.0.6}/src/mm_btc/__init__.py +0 -0
- {mm_btc-0.0.4 → mm_btc-0.0.6}/src/mm_btc/cli/__init__.py +0 -0
- {mm_btc-0.0.4 → mm_btc-0.0.6}/src/mm_btc/cli/cli_utils.py +0 -0
- {mm_btc-0.0.4 → mm_btc-0.0.6}/src/mm_btc/cli/cmd/__init__.py +0 -0
- {mm_btc-0.0.4 → mm_btc-0.0.6}/src/mm_btc/cli/cmd/mnemonic_cmd.py +0 -0
- {mm_btc-0.0.4 → mm_btc-0.0.6}/src/mm_btc/py.typed +0 -0
- {mm_btc-0.0.4 → mm_btc-0.0.6}/src/mm_btc.egg-info/dependency_links.txt +0 -0
- {mm_btc-0.0.4 → mm_btc-0.0.6}/src/mm_btc.egg-info/entry_points.txt +0 -0
- {mm_btc-0.0.4 → mm_btc-0.0.6}/src/mm_btc.egg-info/top_level.txt +0 -0
- {mm_btc-0.0.4 → mm_btc-0.0.6}/tests/test_wallet.py +0 -0
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: mm-btc
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.6
|
|
4
4
|
Requires-Python: >=3.12
|
|
5
5
|
Requires-Dist: mm-std~=0.1.0
|
|
6
6
|
Requires-Dist: hdwallet~=2.2.1
|
|
7
|
+
Requires-Dist: bit~=0.8.0
|
|
8
|
+
Requires-Dist: bitcoinlib~=0.6.15
|
|
7
9
|
Requires-Dist: typer~=0.12.3
|
|
8
10
|
Provides-Extra: dev
|
|
9
11
|
Requires-Dist: build~=1.2.1; extra == "dev"
|
mm_btc-0.0.6/README.txt
ADDED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "mm-btc"
|
|
3
|
-
version = "0.0.
|
|
3
|
+
version = "0.0.6"
|
|
4
4
|
description = ""
|
|
5
5
|
dependencies = [
|
|
6
6
|
"mm-std~=0.1.0",
|
|
7
7
|
"hdwallet~=2.2.1",
|
|
8
|
+
"bit~=0.8.0",
|
|
9
|
+
"bitcoinlib~=0.6.15",
|
|
8
10
|
"typer~=0.12.3"
|
|
9
11
|
]
|
|
10
12
|
requires-python = ">=3.12"
|
|
@@ -39,7 +41,7 @@ warn_no_return = false
|
|
|
39
41
|
strict = true
|
|
40
42
|
exclude = ["^tests/", "^tmp/"]
|
|
41
43
|
[[tool.mypy.overrides]]
|
|
42
|
-
module = ["hdwallet.*", "hdwallet.symbols.*", "
|
|
44
|
+
module = ["hdwallet.*", "hdwallet.symbols.*", "bit.*", "bitcoinlib.transactions.*"]
|
|
43
45
|
ignore_missing_imports = true
|
|
44
46
|
|
|
45
47
|
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
from collections.abc import Sequence
|
|
2
|
+
from typing import TypeAlias
|
|
3
|
+
|
|
4
|
+
from mm_std import Err, HResponse, Ok, Result, hr
|
|
5
|
+
from mm_std.random_ import random_str_choice
|
|
6
|
+
from pydantic import BaseModel
|
|
7
|
+
|
|
8
|
+
MAINNET_BASE_URL = "https://blockstream.info/api"
|
|
9
|
+
TESTNET_BASE_URL = "https://blockstream.info/testnet/api"
|
|
10
|
+
|
|
11
|
+
ERROR_INVALID_ADDRESS = "INVALID_ADDRESS"
|
|
12
|
+
ERROR_INVALID_NETWORK = "INVALID_NETWORK"
|
|
13
|
+
|
|
14
|
+
Proxy: TypeAlias = str | Sequence[str] | None
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Address(BaseModel):
|
|
18
|
+
class ChainStats(BaseModel):
|
|
19
|
+
funded_txo_count: int
|
|
20
|
+
funded_txo_sum: int
|
|
21
|
+
spent_txo_count: int
|
|
22
|
+
spent_txo_sum: int
|
|
23
|
+
tx_count: int
|
|
24
|
+
|
|
25
|
+
class MempoolStats(BaseModel):
|
|
26
|
+
funded_txo_count: int
|
|
27
|
+
funded_txo_sum: int
|
|
28
|
+
spent_txo_count: int
|
|
29
|
+
spent_txo_sum: int
|
|
30
|
+
tx_count: int
|
|
31
|
+
|
|
32
|
+
chain_stats: ChainStats
|
|
33
|
+
mempool_stats: MempoolStats
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class Utxo(BaseModel):
|
|
37
|
+
class Status(BaseModel):
|
|
38
|
+
confirmed: bool
|
|
39
|
+
block_height: int
|
|
40
|
+
block_hash: str
|
|
41
|
+
block_time: int
|
|
42
|
+
|
|
43
|
+
txid: str
|
|
44
|
+
vout: int
|
|
45
|
+
status: Status
|
|
46
|
+
value: int
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class BlockstreamClient:
|
|
50
|
+
def __init__(self, testnet: bool = False, timeout: int = 10, proxies: Proxy = None, attempts: int = 1):
|
|
51
|
+
self.testnet = testnet
|
|
52
|
+
self.timeout = timeout
|
|
53
|
+
self.proxies = proxies
|
|
54
|
+
self.attempts = attempts
|
|
55
|
+
self.base_url = TESTNET_BASE_URL if testnet else MAINNET_BASE_URL
|
|
56
|
+
|
|
57
|
+
def get_address(self, address: str) -> Result[Address]:
|
|
58
|
+
result: Result[Address] = Err("not started yet")
|
|
59
|
+
data = None
|
|
60
|
+
for _ in range(self.attempts):
|
|
61
|
+
try:
|
|
62
|
+
res = self._request(f"/address/{address}")
|
|
63
|
+
data = res.to_dict()
|
|
64
|
+
if res.code == 400 and (
|
|
65
|
+
"invalid bitcoin address" in res.body.lower() or "bech32 segwit decoding error" in res.body.lower()
|
|
66
|
+
):
|
|
67
|
+
return Err(ERROR_INVALID_ADDRESS, data=data)
|
|
68
|
+
elif res.code == 400 and "invalid network" in res.body.lower():
|
|
69
|
+
return Err(ERROR_INVALID_NETWORK, data=data)
|
|
70
|
+
return Ok(Address(**res.json), data=data)
|
|
71
|
+
except Exception as err:
|
|
72
|
+
result = Err(err, data=data)
|
|
73
|
+
return result
|
|
74
|
+
|
|
75
|
+
def get_confirmed_balance(self, address: str) -> Result[int]:
|
|
76
|
+
return self.get_address(address).and_then(lambda a: Ok(a.chain_stats.funded_txo_sum - a.chain_stats.spent_txo_sum))
|
|
77
|
+
|
|
78
|
+
def get_utxo(self, address: str) -> Result[list[Utxo]]:
|
|
79
|
+
result: Result[list[Utxo]] = Err("not started yet")
|
|
80
|
+
data = None
|
|
81
|
+
for _ in range(self.attempts):
|
|
82
|
+
try:
|
|
83
|
+
res = self._request(f"/address/{address}/utxo")
|
|
84
|
+
data = res.to_dict()
|
|
85
|
+
return Ok([Utxo(**out) for out in res.json], data=data)
|
|
86
|
+
except Exception as err:
|
|
87
|
+
result = Err(err, data=data)
|
|
88
|
+
return result
|
|
89
|
+
|
|
90
|
+
def _request(self, url: str) -> HResponse:
|
|
91
|
+
return hr(f"{self.base_url}{url}", timeout=self.timeout, proxy=random_str_choice(self.proxies))
|
|
@@ -1,15 +1,18 @@
|
|
|
1
|
+
from pathlib import Path
|
|
1
2
|
from typing import Annotated
|
|
2
3
|
|
|
3
4
|
import typer
|
|
5
|
+
import typer.core
|
|
4
6
|
from mm_std import print_plain
|
|
5
7
|
|
|
6
8
|
from mm_btc.cli import cli_utils
|
|
7
|
-
from mm_btc.cli.cmd import mnemonic_cmd
|
|
9
|
+
from mm_btc.cli.cmd import address_cmd, create_tx_cmd, decode_tx_cmd, mnemonic_cmd, utxo_cmd
|
|
8
10
|
|
|
9
11
|
app = typer.Typer(no_args_is_help=True, pretty_exceptions_enable=False, add_completion=False)
|
|
10
12
|
|
|
11
13
|
|
|
12
|
-
@app.command(
|
|
14
|
+
@app.command("mnemonic")
|
|
15
|
+
@app.command(name="m", hidden=True)
|
|
13
16
|
def mnemonic_command( # nosec B107:hardcoded_password_default
|
|
14
17
|
mnemonic: Annotated[str, typer.Option("--mnemonic", "-m", help="")] = "",
|
|
15
18
|
passphrase: Annotated[str, typer.Option("--passphrase", "-p")] = "",
|
|
@@ -19,6 +22,7 @@ def mnemonic_command( # nosec B107:hardcoded_password_default
|
|
|
19
22
|
limit: int = typer.Option(10, "--limit", "-l"),
|
|
20
23
|
testnet: bool = typer.Option(False, "--testnet", "-t", help="Testnet network"),
|
|
21
24
|
) -> None:
|
|
25
|
+
"""Generate keys based on a mnemonic"""
|
|
22
26
|
mnemonic_cmd.run(
|
|
23
27
|
mnemonic_cmd.Args(
|
|
24
28
|
mnemonic=mnemonic,
|
|
@@ -32,9 +36,34 @@ def mnemonic_command( # nosec B107:hardcoded_password_default
|
|
|
32
36
|
)
|
|
33
37
|
|
|
34
38
|
|
|
39
|
+
@app.command(name="address")
|
|
40
|
+
@app.command(name="a", hidden=True)
|
|
41
|
+
def address_command(address: str) -> None:
|
|
42
|
+
"""Get address info from Blockstream API"""
|
|
43
|
+
address_cmd.run(address)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@app.command("create-tx")
|
|
47
|
+
def create_tx_command(config_path: Annotated[Path, typer.Argument(exists=True)]) -> None:
|
|
48
|
+
"""Create a transaction"""
|
|
49
|
+
create_tx_cmd.run(config_path)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@app.command("decode-tx")
|
|
53
|
+
def decode_tx_command(tx_hex: str, testnet: Annotated[bool, typer.Option("--testnet", "-t")] = False) -> None:
|
|
54
|
+
"""Decode a transaction"""
|
|
55
|
+
decode_tx_cmd.run(tx_hex, testnet)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@app.command("utxo")
|
|
59
|
+
def utxo_command(address: str) -> None:
|
|
60
|
+
"""Get UTXOs from Blockstream API"""
|
|
61
|
+
utxo_cmd.run(address)
|
|
62
|
+
|
|
63
|
+
|
|
35
64
|
def version_callback(value: bool) -> None:
|
|
36
65
|
if value:
|
|
37
|
-
print_plain(f"mm-
|
|
66
|
+
print_plain(f"mm-btc: v{cli_utils.get_version()}")
|
|
38
67
|
raise typer.Exit()
|
|
39
68
|
|
|
40
69
|
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from mm_std import print_json
|
|
2
|
+
|
|
3
|
+
from mm_btc.blockstream import BlockstreamClient
|
|
4
|
+
from mm_btc.wallet import is_testnet_address
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def run(address: str) -> None:
|
|
8
|
+
client = BlockstreamClient(testnet=is_testnet_address(address))
|
|
9
|
+
res = client.get_address(address)
|
|
10
|
+
print_json(res)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from bit import PrivateKey, PrivateKeyTestnet
|
|
4
|
+
from mm_std import BaseConfig, print_console
|
|
5
|
+
|
|
6
|
+
from mm_btc.wallet import is_testnet_address
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Config(BaseConfig):
|
|
10
|
+
class Output(BaseConfig):
|
|
11
|
+
address: str
|
|
12
|
+
amount: int
|
|
13
|
+
|
|
14
|
+
from_address: str
|
|
15
|
+
private: str
|
|
16
|
+
outputs: list[Output]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def run(config_path: Path) -> None:
|
|
20
|
+
config = Config.read_config(config_path)
|
|
21
|
+
testnet = is_testnet_address(config.from_address)
|
|
22
|
+
key = PrivateKeyTestnet(config.private) if testnet else PrivateKey(config.private)
|
|
23
|
+
|
|
24
|
+
outputs = [(o.address, o.amount, "satoshi") for o in config.outputs]
|
|
25
|
+
|
|
26
|
+
tx = key.create_transaction(outputs)
|
|
27
|
+
print_console(tx)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from mm_std import print_json
|
|
2
|
+
|
|
3
|
+
from mm_btc.blockstream import BlockstreamClient
|
|
4
|
+
from mm_btc.wallet import is_testnet_address
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def run(address: str) -> None:
|
|
8
|
+
client = BlockstreamClient(testnet=is_testnet_address(address))
|
|
9
|
+
res = client.get_utxo(address)
|
|
10
|
+
|
|
11
|
+
print_json(res.ok_or_err())
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: mm-btc
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.6
|
|
4
4
|
Requires-Python: >=3.12
|
|
5
5
|
Requires-Dist: mm-std~=0.1.0
|
|
6
6
|
Requires-Dist: hdwallet~=2.2.1
|
|
7
|
+
Requires-Dist: bit~=0.8.0
|
|
8
|
+
Requires-Dist: bitcoinlib~=0.6.15
|
|
7
9
|
Requires-Dist: typer~=0.12.3
|
|
8
10
|
Provides-Extra: dev
|
|
9
11
|
Requires-Dist: build~=1.2.1; extra == "dev"
|
|
@@ -3,6 +3,7 @@ pyproject.toml
|
|
|
3
3
|
src/mm_btc/__init__.py
|
|
4
4
|
src/mm_btc/blockstream.py
|
|
5
5
|
src/mm_btc/py.typed
|
|
6
|
+
src/mm_btc/tx.py
|
|
6
7
|
src/mm_btc/wallet.py
|
|
7
8
|
src/mm_btc.egg-info/PKG-INFO
|
|
8
9
|
src/mm_btc.egg-info/SOURCES.txt
|
|
@@ -14,6 +15,10 @@ src/mm_btc/cli/__init__.py
|
|
|
14
15
|
src/mm_btc/cli/cli.py
|
|
15
16
|
src/mm_btc/cli/cli_utils.py
|
|
16
17
|
src/mm_btc/cli/cmd/__init__.py
|
|
18
|
+
src/mm_btc/cli/cmd/address_cmd.py
|
|
19
|
+
src/mm_btc/cli/cmd/create_tx_cmd.py
|
|
20
|
+
src/mm_btc/cli/cmd/decode_tx_cmd.py
|
|
17
21
|
src/mm_btc/cli/cmd/mnemonic_cmd.py
|
|
22
|
+
src/mm_btc/cli/cmd/utxo_cmd.py
|
|
18
23
|
tests/test_blockstream.py
|
|
19
24
|
tests/test_wallet.py
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from mm_btc import blockstream
|
|
2
|
+
from mm_btc.blockstream import BlockstreamClient
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def test_get_address(binance_address, proxies):
|
|
6
|
+
client = BlockstreamClient(proxies=proxies, timeout=5, attempts=5)
|
|
7
|
+
|
|
8
|
+
# non-empty address
|
|
9
|
+
res = client.get_address(binance_address)
|
|
10
|
+
assert res.unwrap().chain_stats.tx_count > 800
|
|
11
|
+
|
|
12
|
+
# empty address
|
|
13
|
+
res = client.get_address("bc1pa48c294qk7yd7sc8y0wxydc3a2frv5j83e65rvm48v3ej098s5zs8kvh6d")
|
|
14
|
+
assert res.unwrap().chain_stats.tx_count == 0
|
|
15
|
+
|
|
16
|
+
# invalid address
|
|
17
|
+
res = client.get_address("bc1pa48c294qk7yd7sc8y0wxydc3a2frv5j83e65rvm48v3ej098s5zs8kvh5d")
|
|
18
|
+
assert res.unwrap_err() == blockstream.ERROR_INVALID_ADDRESS
|
|
19
|
+
|
|
20
|
+
# invalid network
|
|
21
|
+
res = client.get_address("mqkwWDWdgXhYunfoKvQfYyydwB5vdma3cK")
|
|
22
|
+
assert res.unwrap_err() == blockstream.ERROR_INVALID_NETWORK
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_get_confirmed_balance(binance_address, proxies):
|
|
26
|
+
client = BlockstreamClient(proxies=proxies)
|
|
27
|
+
res = client.get_confirmed_balance(binance_address)
|
|
28
|
+
assert res.unwrap() > 0
|
mm_btc-0.0.4/README.txt
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
mm-btc
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
from collections.abc import Sequence
|
|
2
|
-
from typing import TypeAlias
|
|
3
|
-
|
|
4
|
-
from mm_std import Err, Ok, Result, hr
|
|
5
|
-
from mm_std.random_ import random_str_choice
|
|
6
|
-
from pydantic import BaseModel
|
|
7
|
-
|
|
8
|
-
MAINNET_BASE_URL = "https://blockstream.info/api"
|
|
9
|
-
TESTNET_BASE_URL = "https://blockstream.info/testnet/api"
|
|
10
|
-
|
|
11
|
-
ERROR_INVALID_ADDRESS = "INVALID_ADDRESS"
|
|
12
|
-
ERROR_INVALID_NETWORK = "INVALID_NETWORK"
|
|
13
|
-
|
|
14
|
-
Proxy: TypeAlias = str | Sequence[str] | None
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class Address(BaseModel):
|
|
18
|
-
class ChainStats(BaseModel):
|
|
19
|
-
funded_txo_count: int
|
|
20
|
-
funded_txo_sum: int
|
|
21
|
-
spent_txo_count: int
|
|
22
|
-
spent_txo_sum: int
|
|
23
|
-
tx_count: int
|
|
24
|
-
|
|
25
|
-
class MempoolStats(BaseModel):
|
|
26
|
-
funded_txo_count: int
|
|
27
|
-
funded_txo_sum: int
|
|
28
|
-
spent_txo_count: int
|
|
29
|
-
spent_txo_sum: int
|
|
30
|
-
tx_count: int
|
|
31
|
-
|
|
32
|
-
chain_stats: ChainStats
|
|
33
|
-
mempool_stats: MempoolStats
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def get_address(
|
|
37
|
-
address: str, testnet: bool = False, timeout: int = 10, proxies: Proxy = None, attempts: int = 1
|
|
38
|
-
) -> Result[Address]:
|
|
39
|
-
result: Result[Address] = Err("not started yet")
|
|
40
|
-
data = None
|
|
41
|
-
base_url = TESTNET_BASE_URL if testnet else MAINNET_BASE_URL
|
|
42
|
-
for _ in range(attempts):
|
|
43
|
-
try:
|
|
44
|
-
res = hr(f"{base_url}/address/{address}", timeout=timeout, proxy=random_str_choice(proxies))
|
|
45
|
-
data = res.to_dict()
|
|
46
|
-
if res.code == 400 and (
|
|
47
|
-
"invalid bitcoin address" in res.body.lower() or "bech32 segwit decoding error" in res.body.lower()
|
|
48
|
-
):
|
|
49
|
-
return Err(ERROR_INVALID_ADDRESS, data=data)
|
|
50
|
-
elif res.code == 400 and "invalid network" in res.body.lower():
|
|
51
|
-
return Err(ERROR_INVALID_NETWORK, data=data)
|
|
52
|
-
return Ok(Address(**res.json))
|
|
53
|
-
except Exception as err:
|
|
54
|
-
result = Err(err, data=data)
|
|
55
|
-
return result
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
def get_confirmed_balance(
|
|
59
|
-
address: str, testnet: bool = False, timeout: int = 10, proxies: Proxy = None, attempts: int = 1
|
|
60
|
-
) -> Result[int]:
|
|
61
|
-
return get_address(address, testnet=testnet, timeout=timeout, proxies=proxies, attempts=attempts).and_then(
|
|
62
|
-
lambda a: Ok(a.chain_stats.funded_txo_sum - a.chain_stats.spent_txo_sum),
|
|
63
|
-
)
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
from mm_btc import blockstream
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
def test_get_address(binance_address, proxies):
|
|
5
|
-
# non-empty address
|
|
6
|
-
res = blockstream.get_address(binance_address, proxies=proxies)
|
|
7
|
-
assert res.unwrap().chain_stats.tx_count > 800
|
|
8
|
-
|
|
9
|
-
# empty address
|
|
10
|
-
res = blockstream.get_address("bc1pa48c294qk7yd7sc8y0wxydc3a2frv5j83e65rvm48v3ej098s5zs8kvh6d", proxies=proxies)
|
|
11
|
-
assert res.unwrap().chain_stats.tx_count == 0
|
|
12
|
-
|
|
13
|
-
# invalid address
|
|
14
|
-
res = blockstream.get_address("bc1pa48c294qk7yd7sc8y0wxydc3a2frv5j83e65rvm48v3ej098s5zs8kvh5d", proxies=proxies)
|
|
15
|
-
assert res.unwrap_err() == blockstream.ERROR_INVALID_ADDRESS
|
|
16
|
-
|
|
17
|
-
# invalid network
|
|
18
|
-
res = blockstream.get_address(binance_address, testnet=True, proxies=proxies)
|
|
19
|
-
assert res.unwrap_err() == blockstream.ERROR_INVALID_NETWORK
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def test_get_confirmed_balance(binance_address, proxies):
|
|
23
|
-
res = blockstream.get_confirmed_balance(binance_address, proxies=proxies)
|
|
24
|
-
assert res.unwrap() > 0
|
|
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
|