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.
- token_network-0.1.0/PKG-INFO +137 -0
- token_network-0.1.0/README.md +115 -0
- token_network-0.1.0/pyproject.toml +42 -0
- token_network-0.1.0/setup.cfg +4 -0
- token_network-0.1.0/setup.py +38 -0
- token_network-0.1.0/tests/test_network.py +60 -0
- token_network-0.1.0/token_network/__init__.py +23 -0
- token_network-0.1.0/token_network/_accessor.py +92 -0
- token_network-0.1.0/token_network/_loader.py +185 -0
- token_network-0.1.0/token_network/data/networks.yaml +89 -0
- token_network-0.1.0/token_network/data/token_networks.yaml +97 -0
- token_network-0.1.0/token_network/data/tokens.yaml +82 -0
- token_network-0.1.0/token_network.egg-info/PKG-INFO +137 -0
- token_network-0.1.0/token_network.egg-info/SOURCES.txt +21 -0
- token_network-0.1.0/token_network.egg-info/dependency_links.txt +1 -0
- token_network-0.1.0/token_network.egg-info/requires.txt +4 -0
- token_network-0.1.0/token_network.egg-info/top_level.txt +1 -0
|
@@ -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,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 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
token_network
|