token-network 0.1.0__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.
@@ -0,0 +1,137 @@
1
+ Metadata-Version: 2.4
2
+ Name: token-network
3
+ Version: 0.1.0
4
+ Summary: Validate input and return token network config (e.g. network.bitcoin, network.bsc.usdt)
5
+ License: MIT
6
+ Keywords: blockchain,tokens,networks,crypto,config
7
+ Classifier: Development Status :: 3 - Alpha
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.8
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Requires-Python: >=3.8
17
+ Description-Content-Type: text/markdown
18
+ Requires-Dist: PyYAML>=6.0
19
+ Provides-Extra: dev
20
+ Requires-Dist: pytest>=7.0; extra == "dev"
21
+ Dynamic: requires-python
22
+
23
+ # token-network
24
+
25
+ Python library that validates input and returns token network config. Use attribute access like `network.bitcoin` or `network.bsc.usdt` to get network and token data.
26
+
27
+ ## Install
28
+
29
+ From PyPI (after publishing):
30
+
31
+ ```bash
32
+ pip install token-network
33
+ ```
34
+
35
+ From source (development):
36
+
37
+ ```bash
38
+ pip install -e .
39
+ ```
40
+
41
+ ## Publishing to PyPI (so others can `pip install token-network`)
42
+
43
+ 1. Create an account on [pypi.org](https://pypi.org) (and optionally [test.pypi.org](https://test.pypi.org) for testing).
44
+
45
+ 2. Install build and twine:
46
+ ```bash
47
+ pip install build twine
48
+ ```
49
+
50
+ 3. Build the package:
51
+ ```bash
52
+ cd /path/to/token-network
53
+ python -m build
54
+ ```
55
+
56
+ 4. Upload to PyPI (you’ll be prompted for your PyPI username and password or token):
57
+ ```bash
58
+ twine upload dist/*
59
+ ```
60
+ To try Test PyPI first: `twine upload --repository testpypi dist/*`, then install with:
61
+ `pip install --index-url https://test.pypi.org/simple/ token-network`
62
+
63
+ 5. After that, anyone can run:
64
+ ```bash
65
+ pip install token-network
66
+ ```
67
+
68
+ ## Usage
69
+
70
+ ```python
71
+ from token_network import network, TokenNetworkError
72
+ ```
73
+
74
+ ### Get all config for a network
75
+
76
+ ```python
77
+ # Network config only
78
+ network.bitcoin.config
79
+ # {'network_type': 'UTXO', 'token_standard': 'BTC', 'base_token': 'BTC', ...}
80
+
81
+ # Tokens on that network (with contract_address, decimal, native, token_info)
82
+ network.bitcoin.tokens
83
+
84
+ # Full payload: config + tokens
85
+ network.bitcoin.to_dict()
86
+ # {"config": {...}, "tokens": [...]}
87
+ ```
88
+
89
+ ### Get data for a token on a network
90
+
91
+ ```python
92
+ # All data for USDT on BSC: network config, token info, contract_address, decimal, native
93
+ network.bsc.usdt
94
+ # {
95
+ # 'network': {...},
96
+ # 'token': {'slug': 'usdt', 'symbol': 'USDT', 'name': 'tether', ...},
97
+ # 'contract_address': '0x55d398326f99059fF775485246999027B3197955',
98
+ # 'decimal': 18,
99
+ # 'native': False
100
+ # }
101
+
102
+ network.ethereum.usdt
103
+ network.tron.usdt
104
+ ```
105
+
106
+ ### Validation
107
+
108
+ Unknown network or token raises `TokenNetworkError`:
109
+
110
+ ```python
111
+ try:
112
+ network.unknown_chain
113
+ except TokenNetworkError as e:
114
+ print(e) # Unknown network: 'unknown_chain'. Known networks: bitcoin, bsc, ...
115
+
116
+ try:
117
+ network.bsc.unknown_token
118
+ except TokenNetworkError as e:
119
+ print(e) # Token 'UNKNOWN_TOKEN' is not defined on network 'bsc'. Available tokens: [...]
120
+ ```
121
+
122
+ ## Data sources
123
+
124
+ Config is loaded from YAML inside the package:
125
+
126
+ - `networks.yaml` — chain config (network_type, token_standard, base_token, confirmation_number, …)
127
+ - `tokens.yaml` — token definitions (symbol, name, precision, factor)
128
+ - `token_networks.yaml` — which token exists on which network (contract_address, decimal, native)
129
+
130
+ To change data, edit the YAML files in `token_network/data/` (or the repo root and sync into the package).
131
+
132
+ ## Development
133
+
134
+ ```bash
135
+ pip install -e ".[dev]"
136
+ pytest
137
+ ```
@@ -0,0 +1,115 @@
1
+ # token-network
2
+
3
+ Python library that validates input and returns token network config. Use attribute access like `network.bitcoin` or `network.bsc.usdt` to get network and token data.
4
+
5
+ ## Install
6
+
7
+ From PyPI (after publishing):
8
+
9
+ ```bash
10
+ pip install token-network
11
+ ```
12
+
13
+ From source (development):
14
+
15
+ ```bash
16
+ pip install -e .
17
+ ```
18
+
19
+ ## Publishing to PyPI (so others can `pip install token-network`)
20
+
21
+ 1. Create an account on [pypi.org](https://pypi.org) (and optionally [test.pypi.org](https://test.pypi.org) for testing).
22
+
23
+ 2. Install build and twine:
24
+ ```bash
25
+ pip install build twine
26
+ ```
27
+
28
+ 3. Build the package:
29
+ ```bash
30
+ cd /path/to/token-network
31
+ python -m build
32
+ ```
33
+
34
+ 4. Upload to PyPI (you’ll be prompted for your PyPI username and password or token):
35
+ ```bash
36
+ twine upload dist/*
37
+ ```
38
+ To try Test PyPI first: `twine upload --repository testpypi dist/*`, then install with:
39
+ `pip install --index-url https://test.pypi.org/simple/ token-network`
40
+
41
+ 5. After that, anyone can run:
42
+ ```bash
43
+ pip install token-network
44
+ ```
45
+
46
+ ## Usage
47
+
48
+ ```python
49
+ from token_network import network, TokenNetworkError
50
+ ```
51
+
52
+ ### Get all config for a network
53
+
54
+ ```python
55
+ # Network config only
56
+ network.bitcoin.config
57
+ # {'network_type': 'UTXO', 'token_standard': 'BTC', 'base_token': 'BTC', ...}
58
+
59
+ # Tokens on that network (with contract_address, decimal, native, token_info)
60
+ network.bitcoin.tokens
61
+
62
+ # Full payload: config + tokens
63
+ network.bitcoin.to_dict()
64
+ # {"config": {...}, "tokens": [...]}
65
+ ```
66
+
67
+ ### Get data for a token on a network
68
+
69
+ ```python
70
+ # All data for USDT on BSC: network config, token info, contract_address, decimal, native
71
+ network.bsc.usdt
72
+ # {
73
+ # 'network': {...},
74
+ # 'token': {'slug': 'usdt', 'symbol': 'USDT', 'name': 'tether', ...},
75
+ # 'contract_address': '0x55d398326f99059fF775485246999027B3197955',
76
+ # 'decimal': 18,
77
+ # 'native': False
78
+ # }
79
+
80
+ network.ethereum.usdt
81
+ network.tron.usdt
82
+ ```
83
+
84
+ ### Validation
85
+
86
+ Unknown network or token raises `TokenNetworkError`:
87
+
88
+ ```python
89
+ try:
90
+ network.unknown_chain
91
+ except TokenNetworkError as e:
92
+ print(e) # Unknown network: 'unknown_chain'. Known networks: bitcoin, bsc, ...
93
+
94
+ try:
95
+ network.bsc.unknown_token
96
+ except TokenNetworkError as e:
97
+ print(e) # Token 'UNKNOWN_TOKEN' is not defined on network 'bsc'. Available tokens: [...]
98
+ ```
99
+
100
+ ## Data sources
101
+
102
+ Config is loaded from YAML inside the package:
103
+
104
+ - `networks.yaml` — chain config (network_type, token_standard, base_token, confirmation_number, …)
105
+ - `tokens.yaml` — token definitions (symbol, name, precision, factor)
106
+ - `token_networks.yaml` — which token exists on which network (contract_address, decimal, native)
107
+
108
+ To change data, edit the YAML files in `token_network/data/` (or the repo root and sync into the package).
109
+
110
+ ## Development
111
+
112
+ ```bash
113
+ pip install -e ".[dev]"
114
+ pytest
115
+ ```
@@ -0,0 +1,42 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "token-network"
7
+ version = "0.1.0"
8
+ description = "Validate input and return token network config (e.g. network.bitcoin, network.bsc.usdt)"
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ license = { text = "MIT" }
12
+ authors = []
13
+ keywords = ["blockchain", "tokens", "networks", "crypto", "config"]
14
+ classifiers = [
15
+ "Development Status :: 3 - Alpha",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3.8",
20
+ "Programming Language :: Python :: 3.9",
21
+ "Programming Language :: Python :: 3.10",
22
+ "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ ]
25
+ dependencies = [
26
+ "PyYAML>=6.0",
27
+ ]
28
+
29
+ [project.optional-dependencies]
30
+ dev = [
31
+ "pytest>=7.0",
32
+ ]
33
+
34
+ [tool.setuptools.packages.find]
35
+ where = ["."]
36
+ include = ["token_network*"]
37
+
38
+ [tool.setuptools.package-dir]
39
+ "" = "."
40
+
41
+ [tool.setuptools.package-data]
42
+ token_network = ["data/*.yaml"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,38 @@
1
+ from pathlib import Path
2
+
3
+ from setuptools import setup, find_packages
4
+
5
+ _readme = Path(__file__).parent / "README.md"
6
+ long_description = _readme.read_text(encoding="utf-8") if _readme.exists() else ""
7
+
8
+ setup(
9
+ name="token-network",
10
+ version="0.1.0",
11
+ description="Validate input and return token network config (e.g. network.bitcoin, network.bsc.usdt)",
12
+ long_description=long_description or None,
13
+ long_description_content_type="text/markdown" if long_description else None,
14
+ packages=find_packages(where=".", include=["token_network*"]),
15
+ package_dir={"": "."},
16
+ package_data={"token_network": ["data/*.yaml"]},
17
+ python_requires=">=3.8",
18
+ install_requires=[
19
+ "PyYAML>=6.0",
20
+ ],
21
+ extras_require={
22
+ "dev": [
23
+ "pytest>=7.0",
24
+ ],
25
+ },
26
+ keywords=["blockchain", "tokens", "networks", "crypto", "config"],
27
+ classifiers=[
28
+ "Development Status :: 3 - Alpha",
29
+ "Intended Audience :: Developers",
30
+ "License :: OSI Approved :: MIT License",
31
+ "Programming Language :: Python :: 3",
32
+ "Programming Language :: Python :: 3.8",
33
+ "Programming Language :: Python :: 3.9",
34
+ "Programming Language :: Python :: 3.10",
35
+ "Programming Language :: Python :: 3.11",
36
+ "Programming Language :: Python :: 3.12",
37
+ ],
38
+ )
@@ -0,0 +1,60 @@
1
+ """Tests for token_network package."""
2
+
3
+ import pytest
4
+ from token_network import network, TokenNetworkError
5
+
6
+
7
+ def test_network_bitcoin_returns_config():
8
+ cfg = network.bitcoin.config
9
+ assert cfg["network_type"] == "UTXO"
10
+ assert cfg["base_token"] == "BTC"
11
+ assert cfg["base_token_decimal"] == 8
12
+
13
+
14
+ def test_network_bitcoin_tokens():
15
+ tokens = network.bitcoin.tokens
16
+ assert len(tokens) >= 1
17
+ btc = next(t for t in tokens if t["token"] == "BTC")
18
+ assert btc["native"] is True
19
+ assert btc["decimal"] == 8
20
+ assert btc["token_info"]["symbol"] == "BTC"
21
+
22
+
23
+ def test_network_bitcoin_to_dict():
24
+ data = network.bitcoin.to_dict()
25
+ assert "config" in data
26
+ assert "tokens" in data
27
+ assert data["config"]["base_token"] == "BTC"
28
+
29
+
30
+ def test_network_bsc_usdt():
31
+ data = network.bsc.usdt
32
+ assert data["network"]["network_type"] == "EVM"
33
+ assert data["token"]["symbol"] == "USDT"
34
+ assert data["contract_address"] == "0x55d398326f99059fF775485246999027B3197955"
35
+ assert data["decimal"] == 18
36
+ assert data["native"] is False
37
+
38
+
39
+ def test_unknown_network_raises():
40
+ with pytest.raises(TokenNetworkError) as exc_info:
41
+ _ = network.nonexistent_chain
42
+ assert "Unknown network" in str(exc_info.value)
43
+ assert "nonexistent_chain" in str(exc_info.value)
44
+
45
+
46
+ def test_unknown_token_on_network_raises():
47
+ with pytest.raises(TokenNetworkError) as exc_info:
48
+ _ = network.bsc.nonexistent_token
49
+ assert "not defined on network" in str(exc_info.value)
50
+ assert "bsc" in str(exc_info.value)
51
+
52
+
53
+ def test_case_insensitive_network():
54
+ assert network.BSC.config == network.bsc.config
55
+ assert network.Bitcoin.config == network.bitcoin.config
56
+
57
+
58
+ def test_case_insensitive_token():
59
+ assert network.bsc.USDT == network.bsc.usdt
60
+ assert network.ethereum.Usdt["token"]["symbol"] == "USDT"
@@ -0,0 +1,23 @@
1
+ """
2
+ token_network: validate input and return token network config.
3
+
4
+ Usage:
5
+ from token_network import network
6
+
7
+ # All config for a network (config + tokens on that network)
8
+ network.bitcoin.config
9
+ network.bitcoin.tokens
10
+ network.bitcoin.to_dict() # {"config": {...}, "tokens": [...]}
11
+
12
+ # Data for a specific token on a network
13
+ network.bsc.usdt # dict: network config, token info, contract_address, decimal, native
14
+ network.ethereum.usdt
15
+ network.tron.usdt
16
+
17
+ Unknown network or token raises token_network.TokenNetworkError.
18
+ """
19
+
20
+ from ._accessor import TokenNetworkError, NetworkAccessor, network
21
+
22
+ __all__ = ["network", "TokenNetworkError", "NetworkAccessor"]
23
+ __version__ = "0.1.0"
@@ -0,0 +1,92 @@
1
+ """Attribute-based access to network and token config: network.bitcoin, network.bsc.usdt."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from ._loader import load_all
8
+
9
+
10
+ class TokenNetworkError(Exception):
11
+ """Raised when a network or token is unknown or invalid."""
12
+
13
+
14
+ class _NetworkNode:
15
+ """Represents one network. Supports .config, .tokens, and .<token_symbol> (e.g. .usdt)."""
16
+
17
+ __slots__ = ("_net_key", "_network_tokens", "_token_on_network")
18
+
19
+ def __init__(
20
+ self,
21
+ net_key: str,
22
+ network_tokens: dict[str, dict[str, Any]],
23
+ token_on_network: dict[tuple[str, str], dict[str, Any]],
24
+ ) -> None:
25
+ self._net_key = net_key
26
+ self._network_tokens = network_tokens
27
+ self._token_on_network = token_on_network
28
+
29
+ @property
30
+ def config(self) -> dict[str, Any]:
31
+ """Network config for this network."""
32
+ if self._net_key not in self._network_tokens:
33
+ raise TokenNetworkError(f"Unknown network: {self._net_key!r}")
34
+ return dict(self._network_tokens[self._net_key]["config"])
35
+
36
+ @property
37
+ def tokens(self) -> list[dict[str, Any]]:
38
+ """List of token bindings on this network (each with token_info, contract_address, etc.)."""
39
+ if self._net_key not in self._network_tokens:
40
+ raise TokenNetworkError(f"Unknown network: {self._net_key!r}")
41
+ return list(self._network_tokens[self._net_key]["tokens"])
42
+
43
+ def __getattr__(self, name: str) -> Any:
44
+ if name.startswith("_"):
45
+ raise AttributeError(name)
46
+ token_sym = name.upper()
47
+ key = (self._net_key, token_sym)
48
+ if key not in self._token_on_network:
49
+ raise TokenNetworkError(
50
+ f"Token {token_sym!r} is not defined on network {self._net_key!r}. "
51
+ f"Available tokens: {[t['token'] for t in self.tokens]}"
52
+ )
53
+ return dict(self._token_on_network[key])
54
+
55
+ def to_dict(self) -> dict[str, Any]:
56
+ """Return full network data: config and tokens (e.g. 'all bitcoin config')."""
57
+ return {"config": self.config, "tokens": self.tokens}
58
+
59
+
60
+ class NetworkAccessor:
61
+ """
62
+ Attribute-based access to token network config.
63
+ - network.bitcoin -> network node (use .config, .tokens, or .to_dict() for full config)
64
+ - network.bsc.usdt -> dict with network config, token info, contract_address, decimal, native
65
+ """
66
+
67
+ __slots__ = ("_network_tokens", "_token_on_network")
68
+
69
+ def __init__(self) -> None:
70
+ self._network_tokens, self._token_on_network, _ = load_all()
71
+
72
+ def __getattr__(self, name: str) -> _NetworkNode:
73
+ if name.startswith("_"):
74
+ raise AttributeError(name)
75
+ net_key = name.lower()
76
+ if net_key not in self._network_tokens:
77
+ known = ", ".join(sorted(self._network_tokens.keys()))
78
+ raise TokenNetworkError(
79
+ f"Unknown network: {name!r}. Known networks: {known}"
80
+ )
81
+ return _NetworkNode(
82
+ net_key,
83
+ self._network_tokens,
84
+ self._token_on_network,
85
+ )
86
+
87
+ def __dir__(self) -> list[str]:
88
+ return sorted(self._network_tokens.keys())
89
+
90
+
91
+ # Singleton used as `network`
92
+ network = NetworkAccessor()
@@ -0,0 +1,185 @@
1
+ """Load and validate networks, tokens, and token_networks from YAML."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import sys
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ import yaml
10
+
11
+ # Package data path: support both installed package and development layout
12
+ def _data_dir() -> Path:
13
+ if getattr(sys, "frozen", False):
14
+ return Path(sys._MEIPASS) / "token_network" / "data"
15
+ here = Path(__file__).resolve().parent
16
+ return here / "data"
17
+
18
+
19
+ def _load_yaml(name: str) -> dict[str, Any]:
20
+ path = _data_dir() / name
21
+ if not path.exists():
22
+ raise FileNotFoundError(f"Config file not found: {path}")
23
+ with open(path, encoding="utf-8") as f:
24
+ return yaml.safe_load(f) or {}
25
+
26
+
27
+ def load_networks() -> dict[str, dict[str, Any]]:
28
+ data = _load_yaml("networks.yaml")
29
+ networks = data.get("networks") or {}
30
+ if not isinstance(networks, dict):
31
+ raise ValueError("networks.yaml: 'networks' must be a mapping")
32
+ return {k.lower(): dict(v) for k, v in networks.items()}
33
+
34
+
35
+ def load_tokens() -> dict[str, dict[str, Any]]:
36
+ data = _load_yaml("tokens.yaml")
37
+ tokens_list = data.get("tokens") or []
38
+ if not isinstance(tokens_list, list):
39
+ raise ValueError("tokens.yaml: 'tokens' must be a list")
40
+ by_symbol: dict[str, dict[str, Any]] = {}
41
+ for t in tokens_list:
42
+ sym = (t.get("symbol") or "").strip().upper()
43
+ if not sym:
44
+ continue
45
+ by_symbol[sym] = dict(t)
46
+ return by_symbol
47
+
48
+
49
+ # Wise standard: NetworkSymbolType (wise_market) uses COIN / TOKEN
50
+ TYPE_COIN = "COIN"
51
+ TYPE_TOKEN = "TOKEN"
52
+
53
+
54
+ def load_token_networks() -> list[dict[str, Any]]:
55
+ data = _load_yaml("token_networks.yaml")
56
+ tn = data.get("token_networks") or []
57
+ if not isinstance(tn, list):
58
+ raise ValueError("token_networks.yaml: 'token_networks' must be a list")
59
+ return [dict(entry) for entry in tn]
60
+
61
+
62
+ def _normalize_token_network_entry(
63
+ entry: dict[str, Any],
64
+ tokens: dict[str, dict[str, Any]],
65
+ slug_to_symbol: dict[str, str],
66
+ ) -> dict[str, Any] | None:
67
+ """
68
+ Normalize a token_network entry to wise standard (network_slug, symbol_slug, decimals, type).
69
+ Accepts both legacy (network, token, decimal, native) and wise (network_slug, symbol_slug, decimals, type).
70
+ """
71
+ net_key = (entry.get("network_slug") or entry.get("network") or "").strip().lower()
72
+ symbol_slug = (entry.get("symbol_slug") or "").strip().lower()
73
+ token_sym = (entry.get("token") or "").strip().upper()
74
+ if symbol_slug and not token_sym:
75
+ token_sym = slug_to_symbol.get(symbol_slug, "").upper()
76
+ if not net_key or not token_sym:
77
+ return None
78
+ if token_sym not in tokens:
79
+ return None
80
+
81
+ decimals = entry.get("decimals") if entry.get("decimals") is not None else entry.get("decimal")
82
+ type_raw = (entry.get("type") or "").strip().upper()
83
+ if type_raw in (TYPE_COIN, TYPE_TOKEN):
84
+ native = type_raw == TYPE_COIN
85
+ type_val = type_raw
86
+ else:
87
+ native = bool(entry.get("native", True))
88
+ type_val = TYPE_COIN if native else TYPE_TOKEN
89
+
90
+ return {
91
+ "network": net_key,
92
+ "network_slug": net_key,
93
+ "token": token_sym,
94
+ "symbol_slug": tokens[token_sym].get("slug", "").lower(),
95
+ "contract_address": entry.get("contract_address"),
96
+ "decimal": decimals,
97
+ "decimals": decimals,
98
+ "native": native,
99
+ "type": type_val,
100
+ }
101
+
102
+
103
+ def build_index(
104
+ networks: dict[str, dict[str, Any]],
105
+ tokens: dict[str, dict[str, Any]],
106
+ token_networks: list[dict[str, Any]],
107
+ ) -> tuple[
108
+ dict[str, dict[str, Any]],
109
+ dict[tuple[str, str], dict[str, Any]],
110
+ ]:
111
+ """
112
+ Build indexes:
113
+ - network_tokens: network_id -> { "config": network_config, "tokens": [token_network_entries] }
114
+ - token_on_network: (network_id, token_symbol) -> merged token_network + token + network
115
+ Supports wise standard: network_slug, symbol_slug, decimals, type (COIN/TOKEN).
116
+ """
117
+ slug_to_symbol = {
118
+ (v.get("slug") or "").strip().lower(): k
119
+ for k, v in tokens.items()
120
+ if (v.get("slug") or "").strip()
121
+ }
122
+ network_tokens: dict[str, dict[str, Any]] = {}
123
+ token_on_network: dict[tuple[str, str], dict[str, Any]] = {}
124
+
125
+ for entry in token_networks:
126
+ normalized = _normalize_token_network_entry(entry, tokens, slug_to_symbol)
127
+ if normalized is None:
128
+ continue
129
+ net_key = normalized["network"]
130
+ if net_key not in networks:
131
+ continue
132
+
133
+ token_sym = normalized["token"]
134
+ net_config = networks[net_key]
135
+ token_info = tokens[token_sym]
136
+ binding = {
137
+ "network": net_key,
138
+ "network_slug": net_key,
139
+ "token": token_sym,
140
+ "symbol_slug": normalized["symbol_slug"],
141
+ "contract_address": normalized["contract_address"],
142
+ "decimal": normalized["decimal"],
143
+ "decimals": normalized["decimals"],
144
+ "native": normalized["native"],
145
+ "type": normalized["type"],
146
+ }
147
+
148
+ if net_key not in network_tokens:
149
+ network_tokens[net_key] = {"config": net_config, "tokens": []}
150
+ network_tokens[net_key]["tokens"].append({
151
+ **binding,
152
+ "token_info": token_info,
153
+ })
154
+
155
+ key = (net_key, token_sym)
156
+ token_on_network[key] = {
157
+ "network": net_config,
158
+ "token": token_info,
159
+ "contract_address": binding["contract_address"],
160
+ "decimal": binding["decimal"],
161
+ "decimals": binding["decimals"],
162
+ "native": binding["native"],
163
+ "type": binding["type"],
164
+ }
165
+
166
+ # Ensure every network from networks.yaml appears (even if no tokens listed)
167
+ for net_key, net_config in networks.items():
168
+ if net_key not in network_tokens:
169
+ network_tokens[net_key] = {"config": net_config, "tokens": []}
170
+
171
+ return network_tokens, token_on_network
172
+
173
+
174
+ def load_all() -> tuple[
175
+ dict[str, dict[str, Any]],
176
+ dict[str, dict[str, Any]],
177
+ dict[tuple[str, str], dict[str, Any]],
178
+ ]:
179
+ """Load YAMLs and return (network_tokens, token_on_network, networks_only)."""
180
+ networks = load_networks()
181
+ tokens = load_tokens()
182
+ token_networks = load_token_networks()
183
+ network_tokens, token_on_network = build_index(networks, tokens, token_networks)
184
+ networks_only = {k: v["config"] for k, v in network_tokens.items()}
185
+ return network_tokens, token_on_network, networks_only
@@ -0,0 +1,89 @@
1
+ # Blockchain network configuration (wise standard: slug = key, name = display name).
2
+ # Consumed by network-manager via NETWORK_CONFIG_FILE (expects this file to have a top-level "networks" key).
3
+ # Schema matches config.network_config_loader.NetworkConfig.
4
+
5
+ networks:
6
+ ethereum:
7
+ slug: ethereum
8
+ name: Ethereum
9
+ network_type: EVM
10
+ token_standard: ERC20
11
+ base_token: ETH
12
+ base_token_decimal: 18
13
+ confirmation_number: 10
14
+ confirmation_check_time: 2
15
+ resource_providing_amount: 0.0005
16
+ resource_providing_below_threshold: 0.0001
17
+ is_tag_based: false
18
+ bsc:
19
+ slug: bsc
20
+ name: BNB Smart Chain
21
+ network_type: EVM
22
+ token_standard: ERC20 # BEP20
23
+ base_token: BNB
24
+ base_token_decimal: 18
25
+ confirmation_number: 10
26
+ confirmation_check_time: 1
27
+ resource_providing_amount: 0.0005
28
+ resource_providing_below_threshold: 0.0001
29
+ is_tag_based: false
30
+ tron:
31
+ slug: tron
32
+ name: Tron
33
+ network_type: TVM
34
+ token_standard: TRC20
35
+ base_token: TRX
36
+ base_token_decimal: 6
37
+ confirmation_number: 20
38
+ confirmation_check_time: 1
39
+ resource_providing_amount: 10
40
+ resource_providing_below_threshold: 7
41
+ is_tag_based: false
42
+ solana:
43
+ slug: solana
44
+ name: Solana
45
+ network_type: SOLANA
46
+ token_standard: SPL
47
+ base_token: SOL
48
+ base_token_decimal: 9
49
+ confirmation_number: 5
50
+ confirmation_check_time: 1
51
+ resource_providing_amount: 0.0005
52
+ resource_providing_below_threshold: 0.0005
53
+ is_tag_based: false
54
+ bitcoin:
55
+ slug: bitcoin
56
+ name: Bitcoin
57
+ network_type: UTXO
58
+ token_standard: BTC
59
+ base_token: BTC
60
+ base_token_decimal: 8
61
+ confirmation_number: 2
62
+ confirmation_check_time: 2
63
+ resource_providing_amount: 0
64
+ resource_providing_below_threshold: 0
65
+ is_tag_based: false
66
+ ripple:
67
+ slug: ripple
68
+ name: XRP Ledger
69
+ network_type: XRPL
70
+ token_standard: XRP
71
+ base_token: XRP
72
+ base_token_decimal: 6
73
+ confirmation_number: 1
74
+ confirmation_check_time: 1
75
+ resource_providing_amount: 0
76
+ resource_providing_below_threshold: 0
77
+ is_tag_based: true
78
+ dogecoin:
79
+ slug: dogecoin
80
+ name: Dogecoin
81
+ network_type: UTXO
82
+ token_standard: DOGE
83
+ base_token: DOGE
84
+ base_token_decimal: 8
85
+ confirmation_number: 6
86
+ confirmation_check_time: 5
87
+ resource_providing_amount: 0
88
+ resource_providing_below_threshold: 0
89
+ is_tag_based: false
@@ -0,0 +1,97 @@
1
+ # Token–network bindings (wise standard): network_slug, symbol_slug, decimals, type (COIN/TOKEN).
2
+ # References: network_slug = key in networks.yaml; symbol_slug = slug in tokens.yaml.
3
+ # type: COIN = native, TOKEN = non-native. Sorted by network_slug.
4
+
5
+ token_networks:
6
+ # bitcoin
7
+ - network_slug: bitcoin
8
+ symbol_slug: btc
9
+ contract_address: null
10
+ decimals: 8
11
+ type: COIN
12
+ # bsc
13
+ - network_slug: bsc
14
+ symbol_slug: bnb
15
+ contract_address: null
16
+ decimals: 18
17
+ type: COIN
18
+ - network_slug: bsc
19
+ symbol_slug: usdc
20
+ contract_address: "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d"
21
+ decimals: 18
22
+ type: TOKEN
23
+ - network_slug: bsc
24
+ symbol_slug: usdt
25
+ contract_address: "0x55d398326f99059fF775485246999027B3197955"
26
+ decimals: 18
27
+ type: TOKEN
28
+ - network_slug: bsc
29
+ symbol_slug: btc
30
+ contract_address: "0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c"
31
+ decimals: 18
32
+ type: TOKEN
33
+ # dogecoin
34
+ - network_slug: dogecoin
35
+ symbol_slug: doge
36
+ contract_address: null
37
+ decimals: 8
38
+ type: COIN
39
+ # ethereum
40
+ - network_slug: ethereum
41
+ symbol_slug: eth
42
+ contract_address: null
43
+ decimals: 18
44
+ type: COIN
45
+ - network_slug: ethereum
46
+ symbol_slug: usdc
47
+ contract_address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
48
+ decimals: 6
49
+ type: TOKEN
50
+ - network_slug: ethereum
51
+ symbol_slug: usdt
52
+ contract_address: "0xdAC17F958D2ee523a2206206994597C13D831ec7"
53
+ decimals: 6
54
+ type: TOKEN
55
+ - network_slug: ethereum
56
+ symbol_slug: shib
57
+ contract_address: "0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE"
58
+ decimals: 18
59
+ type: TOKEN
60
+ - network_slug: ethereum
61
+ symbol_slug: link
62
+ contract_address: "0x514910771AF9Ca656af840dff83E8264EcF986CA"
63
+ decimals: 18
64
+ type: TOKEN
65
+ - network_slug: ethereum
66
+ symbol_slug: aave
67
+ contract_address: "0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9"
68
+ decimals: 18
69
+ type: TOKEN
70
+ - network_slug: ethereum
71
+ symbol_slug: uni
72
+ contract_address: "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"
73
+ decimals: 18
74
+ type: TOKEN
75
+ # ripple
76
+ - network_slug: ripple
77
+ symbol_slug: xrp
78
+ contract_address: null
79
+ decimals: 6
80
+ type: COIN
81
+ # solana
82
+ - network_slug: solana
83
+ symbol_slug: sol
84
+ contract_address: null
85
+ decimals: 9
86
+ type: COIN
87
+ # tron
88
+ - network_slug: tron
89
+ symbol_slug: trx
90
+ contract_address: null
91
+ decimals: 6
92
+ type: COIN
93
+ - network_slug: tron
94
+ symbol_slug: usdt
95
+ contract_address: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"
96
+ decimals: 6
97
+ type: TOKEN
@@ -0,0 +1,82 @@
1
+ # Token definitions: slug, symbol, standard_symbol, name, precision, factor.
2
+ # Reference tokens in token_networks.yaml by symbol (e.g. ETH, USDT).
3
+
4
+ tokens:
5
+ - slug: sol
6
+ symbol: SOL
7
+ standard_symbol: SOL
8
+ name: solana
9
+ precision: 9
10
+ factor: 1e9
11
+ - slug: usdt
12
+ symbol: USDT
13
+ standard_symbol: USDT
14
+ name: tether
15
+ precision: 6
16
+ factor: 1e6
17
+ - slug: aave
18
+ symbol: AAVE
19
+ standard_symbol: AAVE
20
+ name: Aave
21
+ precision: 18
22
+ factor: 1e18
23
+ - slug: doge
24
+ symbol: DOGE
25
+ standard_symbol: DOGE
26
+ name: doge
27
+ precision: 8
28
+ factor: 1e8
29
+ - slug: shib
30
+ symbol: SHIB
31
+ standard_symbol: SHIB
32
+ name: SHIBA INU
33
+ precision: 18
34
+ factor: 1e18
35
+ - slug: link
36
+ symbol: LINK
37
+ standard_symbol: LINK
38
+ name: Chainlink
39
+ precision: 18
40
+ factor: 1e18
41
+ - slug: xrp
42
+ symbol: XRP
43
+ standard_symbol: XRP
44
+ name: ripple
45
+ precision: 6
46
+ factor: 1e6
47
+ - slug: btc
48
+ symbol: BTC
49
+ standard_symbol: BTC
50
+ name: Bitcoin
51
+ precision: 8
52
+ factor: 1e8
53
+ - slug: eth
54
+ symbol: ETH
55
+ standard_symbol: ETH
56
+ name: ethereum
57
+ precision: 18
58
+ factor: 1e18
59
+ - slug: trx
60
+ symbol: TRX
61
+ standard_symbol: TRX
62
+ name: Tron
63
+ precision: 6
64
+ factor: 1e6
65
+ - slug: usdc
66
+ symbol: USDC
67
+ standard_symbol: USDC
68
+ name: USD Coin
69
+ precision: 6
70
+ factor: 1e6
71
+ - slug: bnb
72
+ symbol: BNB
73
+ standard_symbol: BNB
74
+ name: Binance Coin
75
+ precision: 18
76
+ factor: 1e18
77
+ - slug: uni
78
+ symbol: UNI
79
+ standard_symbol: UNI
80
+ name: Uniswap
81
+ precision: 18
82
+ factor: 1e18
@@ -0,0 +1,137 @@
1
+ Metadata-Version: 2.4
2
+ Name: token-network
3
+ Version: 0.1.0
4
+ Summary: Validate input and return token network config (e.g. network.bitcoin, network.bsc.usdt)
5
+ License: MIT
6
+ Keywords: blockchain,tokens,networks,crypto,config
7
+ Classifier: Development Status :: 3 - Alpha
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.8
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Requires-Python: >=3.8
17
+ Description-Content-Type: text/markdown
18
+ Requires-Dist: PyYAML>=6.0
19
+ Provides-Extra: dev
20
+ Requires-Dist: pytest>=7.0; extra == "dev"
21
+ Dynamic: requires-python
22
+
23
+ # token-network
24
+
25
+ Python library that validates input and returns token network config. Use attribute access like `network.bitcoin` or `network.bsc.usdt` to get network and token data.
26
+
27
+ ## Install
28
+
29
+ From PyPI (after publishing):
30
+
31
+ ```bash
32
+ pip install token-network
33
+ ```
34
+
35
+ From source (development):
36
+
37
+ ```bash
38
+ pip install -e .
39
+ ```
40
+
41
+ ## Publishing to PyPI (so others can `pip install token-network`)
42
+
43
+ 1. Create an account on [pypi.org](https://pypi.org) (and optionally [test.pypi.org](https://test.pypi.org) for testing).
44
+
45
+ 2. Install build and twine:
46
+ ```bash
47
+ pip install build twine
48
+ ```
49
+
50
+ 3. Build the package:
51
+ ```bash
52
+ cd /path/to/token-network
53
+ python -m build
54
+ ```
55
+
56
+ 4. Upload to PyPI (you’ll be prompted for your PyPI username and password or token):
57
+ ```bash
58
+ twine upload dist/*
59
+ ```
60
+ To try Test PyPI first: `twine upload --repository testpypi dist/*`, then install with:
61
+ `pip install --index-url https://test.pypi.org/simple/ token-network`
62
+
63
+ 5. After that, anyone can run:
64
+ ```bash
65
+ pip install token-network
66
+ ```
67
+
68
+ ## Usage
69
+
70
+ ```python
71
+ from token_network import network, TokenNetworkError
72
+ ```
73
+
74
+ ### Get all config for a network
75
+
76
+ ```python
77
+ # Network config only
78
+ network.bitcoin.config
79
+ # {'network_type': 'UTXO', 'token_standard': 'BTC', 'base_token': 'BTC', ...}
80
+
81
+ # Tokens on that network (with contract_address, decimal, native, token_info)
82
+ network.bitcoin.tokens
83
+
84
+ # Full payload: config + tokens
85
+ network.bitcoin.to_dict()
86
+ # {"config": {...}, "tokens": [...]}
87
+ ```
88
+
89
+ ### Get data for a token on a network
90
+
91
+ ```python
92
+ # All data for USDT on BSC: network config, token info, contract_address, decimal, native
93
+ network.bsc.usdt
94
+ # {
95
+ # 'network': {...},
96
+ # 'token': {'slug': 'usdt', 'symbol': 'USDT', 'name': 'tether', ...},
97
+ # 'contract_address': '0x55d398326f99059fF775485246999027B3197955',
98
+ # 'decimal': 18,
99
+ # 'native': False
100
+ # }
101
+
102
+ network.ethereum.usdt
103
+ network.tron.usdt
104
+ ```
105
+
106
+ ### Validation
107
+
108
+ Unknown network or token raises `TokenNetworkError`:
109
+
110
+ ```python
111
+ try:
112
+ network.unknown_chain
113
+ except TokenNetworkError as e:
114
+ print(e) # Unknown network: 'unknown_chain'. Known networks: bitcoin, bsc, ...
115
+
116
+ try:
117
+ network.bsc.unknown_token
118
+ except TokenNetworkError as e:
119
+ print(e) # Token 'UNKNOWN_TOKEN' is not defined on network 'bsc'. Available tokens: [...]
120
+ ```
121
+
122
+ ## Data sources
123
+
124
+ Config is loaded from YAML inside the package:
125
+
126
+ - `networks.yaml` — chain config (network_type, token_standard, base_token, confirmation_number, …)
127
+ - `tokens.yaml` — token definitions (symbol, name, precision, factor)
128
+ - `token_networks.yaml` — which token exists on which network (contract_address, decimal, native)
129
+
130
+ To change data, edit the YAML files in `token_network/data/` (or the repo root and sync into the package).
131
+
132
+ ## Development
133
+
134
+ ```bash
135
+ pip install -e ".[dev]"
136
+ pytest
137
+ ```
@@ -0,0 +1,21 @@
1
+ README.md
2
+ pyproject.toml
3
+ setup.py
4
+ ./token_network/__init__.py
5
+ ./token_network/_accessor.py
6
+ ./token_network/_loader.py
7
+ ./token_network/data/networks.yaml
8
+ ./token_network/data/token_networks.yaml
9
+ ./token_network/data/tokens.yaml
10
+ tests/test_network.py
11
+ token_network/__init__.py
12
+ token_network/_accessor.py
13
+ token_network/_loader.py
14
+ token_network.egg-info/PKG-INFO
15
+ token_network.egg-info/SOURCES.txt
16
+ token_network.egg-info/dependency_links.txt
17
+ token_network.egg-info/requires.txt
18
+ token_network.egg-info/top_level.txt
19
+ token_network/data/networks.yaml
20
+ token_network/data/token_networks.yaml
21
+ token_network/data/tokens.yaml
@@ -0,0 +1,4 @@
1
+ PyYAML>=6.0
2
+
3
+ [dev]
4
+ pytest>=7.0
@@ -0,0 +1 @@
1
+ token_network