kaleido-sdk 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.
- kaleido_sdk-0.1.0/.gitignore +120 -0
- kaleido_sdk-0.1.0/PKG-INFO +83 -0
- kaleido_sdk-0.1.0/README.md +52 -0
- kaleido_sdk-0.1.0/examples/01_hello.py +65 -0
- kaleido_sdk-0.1.0/examples/02_get_quote.py +104 -0
- kaleido_sdk-0.1.0/examples/03_websocket.py +102 -0
- kaleido_sdk-0.1.0/examples/04_create_swap_order.py +120 -0
- kaleido_sdk-0.1.0/examples/05_quote_logging_demo.py +100 -0
- kaleido_sdk-0.1.0/examples/06_multi_route_streaming.py +102 -0
- kaleido_sdk-0.1.0/examples/07_swap_demo.py +77 -0
- kaleido_sdk-0.1.0/examples/08_advanced_market_data.py +79 -0
- kaleido_sdk-0.1.0/examples/09_error_handling.py +110 -0
- kaleido_sdk-0.1.0/kaleido_sdk/__init__.py +260 -0
- kaleido_sdk-0.1.0/kaleido_sdk/_generated/__init__.py +9 -0
- kaleido_sdk-0.1.0/kaleido_sdk/_generated/api_types.py +1190 -0
- kaleido_sdk-0.1.0/kaleido_sdk/_generated/node_types.py +1138 -0
- kaleido_sdk-0.1.0/kaleido_sdk/_http_client.py +267 -0
- kaleido_sdk-0.1.0/kaleido_sdk/_logging.py +46 -0
- kaleido_sdk-0.1.0/kaleido_sdk/_maker_client.py +720 -0
- kaleido_sdk-0.1.0/kaleido_sdk/_rln_client.py +740 -0
- kaleido_sdk-0.1.0/kaleido_sdk/_utils/__init__.py +23 -0
- kaleido_sdk-0.1.0/kaleido_sdk/_utils/precision.py +241 -0
- kaleido_sdk-0.1.0/kaleido_sdk/_ws_client.py +494 -0
- kaleido_sdk-0.1.0/kaleido_sdk/client.py +243 -0
- kaleido_sdk-0.1.0/kaleido_sdk/errors.py +241 -0
- kaleido_sdk-0.1.0/kaleido_sdk/py.typed +0 -0
- kaleido_sdk-0.1.0/kaleido_sdk/rln/__init__.py +255 -0
- kaleido_sdk-0.1.0/kaleido_sdk/types.py +181 -0
- kaleido_sdk-0.1.0/pyproject.toml +86 -0
- kaleido_sdk-0.1.0/tests/__init__.py +1 -0
- kaleido_sdk-0.1.0/tests/conftest.py +55 -0
- kaleido_sdk-0.1.0/tests/integration/test_maker_client.py +439 -0
- kaleido_sdk-0.1.0/tests/integration/test_rln_client.py +391 -0
- kaleido_sdk-0.1.0/tests/integration/test_websocket_client.py +23 -0
- kaleido_sdk-0.1.0/tests/unit/test_client.py +258 -0
- kaleido_sdk-0.1.0/tests/unit/test_errors.py +204 -0
- kaleido_sdk-0.1.0/tests/unit/test_precision.py +148 -0
- kaleido_sdk-0.1.0/tests/unit/test_websocket.py +95 -0
- kaleido_sdk-0.1.0/tests/utils.py +77 -0
- kaleido_sdk-0.1.0/uv.lock +1026 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
target/
|
|
2
|
+
|
|
3
|
+
# Node.js
|
|
4
|
+
node_modules/
|
|
5
|
+
|
|
6
|
+
# TypeScript SDK build artifacts
|
|
7
|
+
typescript-sdk/dist/
|
|
8
|
+
typescript-sdk/coverage/
|
|
9
|
+
typescript-sdk/*.js
|
|
10
|
+
typescript-sdk/*.js.map
|
|
11
|
+
typescript-sdk/*.d.ts
|
|
12
|
+
!typescript-sdk/jest.config.js
|
|
13
|
+
!typescript-sdk/.eslintrc.js
|
|
14
|
+
|
|
15
|
+
# NAPI-RS build artifacts (Node.js native modules)
|
|
16
|
+
*.node
|
|
17
|
+
!node_modules/**/*.node
|
|
18
|
+
|
|
19
|
+
# Lock files - only pnpm is used
|
|
20
|
+
package-lock.json
|
|
21
|
+
npm-shrinkwrap.json
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# Package.json filtering
|
|
25
|
+
package-lock.json
|
|
26
|
+
!crates/*/package.json
|
|
27
|
+
|
|
28
|
+
# Python
|
|
29
|
+
__pycache__/
|
|
30
|
+
*.py[cod]
|
|
31
|
+
*$py.class
|
|
32
|
+
|
|
33
|
+
# C extensions
|
|
34
|
+
*.so
|
|
35
|
+
|
|
36
|
+
# Distribution / packaging
|
|
37
|
+
.Python
|
|
38
|
+
build/
|
|
39
|
+
develop-eggs/
|
|
40
|
+
dist/
|
|
41
|
+
downloads/
|
|
42
|
+
eggs/
|
|
43
|
+
.eggs/
|
|
44
|
+
lib/
|
|
45
|
+
lib64/
|
|
46
|
+
!typescript/packages/*/src/lib/
|
|
47
|
+
parts/
|
|
48
|
+
sdist/
|
|
49
|
+
var/
|
|
50
|
+
wheels/
|
|
51
|
+
*.egg-info/
|
|
52
|
+
.installed.cfg
|
|
53
|
+
*.egg
|
|
54
|
+
|
|
55
|
+
# Unit test / coverage reports
|
|
56
|
+
htmlcov/
|
|
57
|
+
.tox/
|
|
58
|
+
.nox/
|
|
59
|
+
.coverage
|
|
60
|
+
.coverage.*
|
|
61
|
+
.cache
|
|
62
|
+
nosetests.xml
|
|
63
|
+
coverage.xml
|
|
64
|
+
test-results.xml
|
|
65
|
+
*.cover
|
|
66
|
+
*.py,cover
|
|
67
|
+
.hypothesis/
|
|
68
|
+
.pytest_cache/
|
|
69
|
+
|
|
70
|
+
# Environments
|
|
71
|
+
.env
|
|
72
|
+
.venv
|
|
73
|
+
env/
|
|
74
|
+
venv/
|
|
75
|
+
ENV/
|
|
76
|
+
env.bak/
|
|
77
|
+
venv.bak/
|
|
78
|
+
|
|
79
|
+
# IDE specific files
|
|
80
|
+
.idea/
|
|
81
|
+
.vscode/
|
|
82
|
+
*.swp
|
|
83
|
+
*.swo
|
|
84
|
+
.DS_Store
|
|
85
|
+
|
|
86
|
+
# Jupyter Notebook
|
|
87
|
+
.ipynb_checkpoints
|
|
88
|
+
|
|
89
|
+
# mypy
|
|
90
|
+
.mypy_cache/
|
|
91
|
+
.dmypy.json
|
|
92
|
+
dmypy.json
|
|
93
|
+
|
|
94
|
+
# Ruff
|
|
95
|
+
.ruff_cache/
|
|
96
|
+
|
|
97
|
+
# Rope project settings
|
|
98
|
+
.ropeproject
|
|
99
|
+
|
|
100
|
+
# mkdocs documentation
|
|
101
|
+
/site
|
|
102
|
+
|
|
103
|
+
# Sphinx documentation
|
|
104
|
+
docs/_build/
|
|
105
|
+
|
|
106
|
+
# pyenv
|
|
107
|
+
.python-version
|
|
108
|
+
|
|
109
|
+
# Log files
|
|
110
|
+
*.log
|
|
111
|
+
*.log.*
|
|
112
|
+
logs/
|
|
113
|
+
log/
|
|
114
|
+
|
|
115
|
+
*.pyc
|
|
116
|
+
__pycache__/
|
|
117
|
+
*.DS_Store
|
|
118
|
+
|
|
119
|
+
# Generated spec snapshots
|
|
120
|
+
specs/backup/
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: kaleido-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python SDK for the Kaleidoswap protocol - Trade RGB assets on Lightning Network
|
|
5
|
+
Project-URL: Homepage, https://kaleidoswap.com
|
|
6
|
+
Project-URL: Documentation, https://docs.kaleidoswap.com
|
|
7
|
+
Project-URL: Repository, https://github.com/kaleidoswap/kaleido-sdk
|
|
8
|
+
Author-email: Kaleidoswap <dev@kaleidoswap.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
Keywords: bitcoin,lightning,rgb,sdk,swap,trading
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Requires-Dist: httpx>=0.27.0
|
|
23
|
+
Requires-Dist: pydantic[email]>=2.0
|
|
24
|
+
Requires-Dist: websockets>=12.0
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: datamodel-code-generator[ruff]>=0.54.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# Kaleidoswap Python SDK
|
|
33
|
+
|
|
34
|
+
[](https://pypi.org/project/kaleido-sdk/)
|
|
35
|
+
|
|
36
|
+
Python SDK for trading RGB assets on the Lightning Network via the Kaleidoswap protocol.
|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install kaleido-sdk
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Quick Start
|
|
45
|
+
|
|
46
|
+
The SDK exposes two sub-clients depending on what you need:
|
|
47
|
+
|
|
48
|
+
| Sub-client | Config key | What it does |
|
|
49
|
+
|---|---|---|
|
|
50
|
+
| `client.maker` | `base_url` | Kaleidoswap market API — assets, quotes, swap orders, LSP |
|
|
51
|
+
| `client.rln` | `node_url` | Your RGB Lightning Node — wallet, channels, payments, RGB assets |
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from kaleido_sdk import KaleidoClient
|
|
55
|
+
|
|
56
|
+
# Zero-config — defaults to regtest
|
|
57
|
+
client = KaleidoClient.create()
|
|
58
|
+
assets = await client.maker.list_assets()
|
|
59
|
+
|
|
60
|
+
# Maker API only
|
|
61
|
+
client = KaleidoClient.create(base_url="https://api.kaleidoswap.com")
|
|
62
|
+
assets = await client.maker.list_assets()
|
|
63
|
+
|
|
64
|
+
# Node only (base_url still defaults to regtest)
|
|
65
|
+
client = KaleidoClient.create(node_url="http://localhost:3001")
|
|
66
|
+
info = await client.rln.get_node_info()
|
|
67
|
+
|
|
68
|
+
# Both together
|
|
69
|
+
client = KaleidoClient.create(
|
|
70
|
+
base_url="https://api.kaleidoswap.com",
|
|
71
|
+
node_url="http://localhost:3001",
|
|
72
|
+
)
|
|
73
|
+
pairs = await client.maker.list_pairs()
|
|
74
|
+
channels = await client.rln.list_channels()
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Documentation
|
|
78
|
+
|
|
79
|
+
Full usage guide, API reference, and examples at **https://docs.kaleidoswap.com/sdk/introduction**
|
|
80
|
+
|
|
81
|
+
## License
|
|
82
|
+
|
|
83
|
+
MIT
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Kaleidoswap Python SDK
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/kaleido-sdk/)
|
|
4
|
+
|
|
5
|
+
Python SDK for trading RGB assets on the Lightning Network via the Kaleidoswap protocol.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install kaleido-sdk
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
The SDK exposes two sub-clients depending on what you need:
|
|
16
|
+
|
|
17
|
+
| Sub-client | Config key | What it does |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| `client.maker` | `base_url` | Kaleidoswap market API — assets, quotes, swap orders, LSP |
|
|
20
|
+
| `client.rln` | `node_url` | Your RGB Lightning Node — wallet, channels, payments, RGB assets |
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from kaleido_sdk import KaleidoClient
|
|
24
|
+
|
|
25
|
+
# Zero-config — defaults to regtest
|
|
26
|
+
client = KaleidoClient.create()
|
|
27
|
+
assets = await client.maker.list_assets()
|
|
28
|
+
|
|
29
|
+
# Maker API only
|
|
30
|
+
client = KaleidoClient.create(base_url="https://api.kaleidoswap.com")
|
|
31
|
+
assets = await client.maker.list_assets()
|
|
32
|
+
|
|
33
|
+
# Node only (base_url still defaults to regtest)
|
|
34
|
+
client = KaleidoClient.create(node_url="http://localhost:3001")
|
|
35
|
+
info = await client.rln.get_node_info()
|
|
36
|
+
|
|
37
|
+
# Both together
|
|
38
|
+
client = KaleidoClient.create(
|
|
39
|
+
base_url="https://api.kaleidoswap.com",
|
|
40
|
+
node_url="http://localhost:3001",
|
|
41
|
+
)
|
|
42
|
+
pairs = await client.maker.list_pairs()
|
|
43
|
+
channels = await client.rln.list_channels()
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Documentation
|
|
47
|
+
|
|
48
|
+
Full usage guide, API reference, and examples at **https://docs.kaleidoswap.com/sdk/introduction**
|
|
49
|
+
|
|
50
|
+
## License
|
|
51
|
+
|
|
52
|
+
MIT
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Example 01: Hello Kaleidoswap
|
|
4
|
+
|
|
5
|
+
Basic example showing how to create a client and list assets.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
import logging
|
|
10
|
+
import os
|
|
11
|
+
|
|
12
|
+
from kaleido_sdk import KaleidoClient, get_sdk_name, get_version
|
|
13
|
+
|
|
14
|
+
API_URL = os.getenv("KALEIDO_API_URL", "https://api.staging.kaleidoswap.com")
|
|
15
|
+
|
|
16
|
+
# ---------------------------------------------------------------------------
|
|
17
|
+
# Logging setup (application's responsibility — the SDK never does this)
|
|
18
|
+
# ---------------------------------------------------------------------------
|
|
19
|
+
# Show all SDK log levels. Change to logging.INFO or logging.WARNING to reduce noise.
|
|
20
|
+
logging.basicConfig(
|
|
21
|
+
level=logging.DEBUG,
|
|
22
|
+
format="%(asctime)s [%(levelname)-8s] %(name)s — %(message)s",
|
|
23
|
+
datefmt="%H:%M:%S",
|
|
24
|
+
)
|
|
25
|
+
# Optionally silence the HTTP sub-logger if you only care about higher-level events:
|
|
26
|
+
# logging.getLogger("kaleido_sdk.http").setLevel(logging.WARNING)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
async def main() -> None:
|
|
30
|
+
"""Main entry point."""
|
|
31
|
+
# Print SDK info
|
|
32
|
+
print(f"{get_sdk_name()} v{get_version()}")
|
|
33
|
+
print("-" * 40)
|
|
34
|
+
|
|
35
|
+
# Create client — log_level tells the SDK which records to emit
|
|
36
|
+
client = KaleidoClient.create(
|
|
37
|
+
base_url=API_URL,
|
|
38
|
+
log_level=logging.DEBUG,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# List available assets
|
|
42
|
+
print("\nFetching assets...")
|
|
43
|
+
assets_response = await client.maker.list_assets()
|
|
44
|
+
|
|
45
|
+
print(f"\nFound {assets_response.total} assets:")
|
|
46
|
+
for asset in assets_response.assets[:5]:
|
|
47
|
+
print(f" - {asset.ticker}: {asset.name} (precision: {asset.precision})")
|
|
48
|
+
|
|
49
|
+
if assets_response.total > 5:
|
|
50
|
+
print(f" ... and {assets_response.total - 5} more")
|
|
51
|
+
|
|
52
|
+
# List trading pairs
|
|
53
|
+
print("\nFetching trading pairs...")
|
|
54
|
+
pairs_response = await client.maker.list_pairs()
|
|
55
|
+
|
|
56
|
+
print(f"\nFound {pairs_response.total} pairs:")
|
|
57
|
+
for pair in pairs_response.pairs[:5]:
|
|
58
|
+
print(f" - {pair.base.ticker}/{pair.quote.ticker}")
|
|
59
|
+
|
|
60
|
+
if pairs_response.total > 5:
|
|
61
|
+
print(f" ... and {pairs_response.total - 5} more")
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
if __name__ == "__main__":
|
|
65
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Example 02: Get Quote
|
|
4
|
+
|
|
5
|
+
Example showing how to get a quote for a swap.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
import logging
|
|
10
|
+
import os
|
|
11
|
+
|
|
12
|
+
from kaleido_sdk import (
|
|
13
|
+
KaleidoClient,
|
|
14
|
+
Layer,
|
|
15
|
+
PairQuoteRequest,
|
|
16
|
+
SwapLegInput,
|
|
17
|
+
to_display_units,
|
|
18
|
+
to_smallest_units,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
API_URL = os.getenv("KALEIDO_API_URL", "https://api.staging.kaleidoswap.com")
|
|
22
|
+
|
|
23
|
+
# ---------------------------------------------------------------------------
|
|
24
|
+
# Logging setup (application's responsibility — the SDK never does this)
|
|
25
|
+
# ---------------------------------------------------------------------------
|
|
26
|
+
logging.basicConfig(
|
|
27
|
+
level=logging.DEBUG,
|
|
28
|
+
format="%(asctime)s [%(levelname)-8s] %(name)s — %(message)s",
|
|
29
|
+
datefmt="%H:%M:%S",
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
async def main() -> None:
|
|
34
|
+
"""Main entry point."""
|
|
35
|
+
client = KaleidoClient.create(
|
|
36
|
+
base_url=API_URL,
|
|
37
|
+
log_level=logging.DEBUG,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
# Discover trading pairs
|
|
41
|
+
print("Fetching available pairs...")
|
|
42
|
+
pairs = await client.maker.list_pairs()
|
|
43
|
+
|
|
44
|
+
if not pairs.pairs:
|
|
45
|
+
print("No trading pairs available")
|
|
46
|
+
return
|
|
47
|
+
|
|
48
|
+
pair = pairs.pairs[0]
|
|
49
|
+
print(f"\nUsing pair: {pair.base.ticker}/{pair.quote.ticker}")
|
|
50
|
+
print(f" Base precision: {pair.base.precision}")
|
|
51
|
+
print(f" Quote precision: {pair.quote.precision}")
|
|
52
|
+
|
|
53
|
+
if pair.routes:
|
|
54
|
+
print(" Available routes:")
|
|
55
|
+
for route in pair.routes:
|
|
56
|
+
print(f" - {route.from_layer} -> {route.to_layer}")
|
|
57
|
+
|
|
58
|
+
# Get a quote for 0.001 BTC
|
|
59
|
+
amount = 0.001
|
|
60
|
+
amount_raw = to_smallest_units(amount, pair.base.precision)
|
|
61
|
+
|
|
62
|
+
print(f"\nGetting quote for {amount} {pair.base.ticker}...")
|
|
63
|
+
print(f" (raw amount: {amount_raw})")
|
|
64
|
+
|
|
65
|
+
if pair.routes:
|
|
66
|
+
from_layer = Layer(pair.routes[0].from_layer)
|
|
67
|
+
to_layer = Layer(pair.routes[0].to_layer)
|
|
68
|
+
else:
|
|
69
|
+
from_layer = Layer.BTC_LN
|
|
70
|
+
to_layer = Layer.RGB_LN
|
|
71
|
+
|
|
72
|
+
quote_request = PairQuoteRequest(
|
|
73
|
+
from_asset=SwapLegInput(
|
|
74
|
+
asset_id=pair.base.ticker,
|
|
75
|
+
layer=from_layer,
|
|
76
|
+
amount=amount_raw,
|
|
77
|
+
),
|
|
78
|
+
to_asset=SwapLegInput(
|
|
79
|
+
asset_id=pair.quote.ticker,
|
|
80
|
+
layer=to_layer,
|
|
81
|
+
),
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
try:
|
|
85
|
+
quote = await client.maker.get_quote(quote_request)
|
|
86
|
+
|
|
87
|
+
from_display = to_display_units(quote.from_asset.amount, quote.from_asset.precision)
|
|
88
|
+
to_display = to_display_units(quote.to_asset.amount, quote.to_asset.precision)
|
|
89
|
+
|
|
90
|
+
print("\nQuote received:")
|
|
91
|
+
print(f" RFQ ID: {quote.rfq_id}")
|
|
92
|
+
print(f" From: {from_display} {quote.from_asset.ticker}")
|
|
93
|
+
print(f" To: {to_display} {quote.to_asset.ticker}")
|
|
94
|
+
print(f" Price: {quote.price}")
|
|
95
|
+
print(f" Fee: {quote.fee.final_fee} {quote.fee.fee_asset}")
|
|
96
|
+
print(f" Expires at: {quote.expires_at}")
|
|
97
|
+
|
|
98
|
+
except Exception as e:
|
|
99
|
+
print(f"\nError getting quote: {e}")
|
|
100
|
+
print("(This is expected if the pair doesn't support the requested route)")
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
if __name__ == "__main__":
|
|
104
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Example 03: WebSocket Streaming
|
|
4
|
+
|
|
5
|
+
Example showing how to stream real-time quotes via WebSocket.
|
|
6
|
+
The SDK automatically requests quotes at a configurable interval.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import asyncio
|
|
10
|
+
import logging
|
|
11
|
+
import os
|
|
12
|
+
|
|
13
|
+
from kaleido_sdk import KaleidoClient, Layer
|
|
14
|
+
|
|
15
|
+
API_URL = os.getenv("KALEIDO_API_URL", "https://api.staging.kaleidoswap.com")
|
|
16
|
+
WS_URL = os.getenv("KALEIDO_WS_URL", "wss://api.staging.kaleidoswap.com/api/v1/market/ws")
|
|
17
|
+
|
|
18
|
+
# ---------------------------------------------------------------------------
|
|
19
|
+
# Logging setup (application's responsibility — the SDK never does this)
|
|
20
|
+
# ---------------------------------------------------------------------------
|
|
21
|
+
# DEBUG shows every WS message, HTTP request, ping, reconnect, etc.
|
|
22
|
+
# Switch to logging.INFO to see only meaningful lifecycle events.
|
|
23
|
+
logging.basicConfig(
|
|
24
|
+
level=logging.DEBUG,
|
|
25
|
+
format="%(asctime)s [%(levelname)-8s] %(name)s — %(message)s",
|
|
26
|
+
datefmt="%H:%M:%S",
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
async def main() -> None:
|
|
31
|
+
"""Main entry point."""
|
|
32
|
+
client = KaleidoClient.create(
|
|
33
|
+
base_url=API_URL,
|
|
34
|
+
log_level=logging.DEBUG,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
# Enable WebSocket
|
|
38
|
+
ws = client.maker.enable_websocket(WS_URL)
|
|
39
|
+
|
|
40
|
+
quotes_received = 0
|
|
41
|
+
max_quotes = 5
|
|
42
|
+
|
|
43
|
+
def on_quote(quote: dict) -> None:
|
|
44
|
+
nonlocal quotes_received
|
|
45
|
+
quotes_received += 1
|
|
46
|
+
|
|
47
|
+
from_asset = quote.get("from_asset", {})
|
|
48
|
+
to_asset = quote.get("to_asset", {})
|
|
49
|
+
|
|
50
|
+
print(f"\nQuote #{quotes_received}:")
|
|
51
|
+
print(
|
|
52
|
+
f" From: {from_asset.get('amount')} {from_asset.get('ticker')} ({from_asset.get('layer')})"
|
|
53
|
+
)
|
|
54
|
+
print(f" To: {to_asset.get('amount')} {to_asset.get('ticker')} ({to_asset.get('layer')})")
|
|
55
|
+
print(f" Price: {quote.get('price')}")
|
|
56
|
+
print(f" RFQ ID: {quote.get('rfq_id')}")
|
|
57
|
+
|
|
58
|
+
ws.on("connected", lambda: print("Connected to WebSocket!"))
|
|
59
|
+
ws.on("disconnected", lambda: print("Disconnected from WebSocket"))
|
|
60
|
+
ws.on("error", lambda e: print(f"WebSocket error: {e}"))
|
|
61
|
+
|
|
62
|
+
try:
|
|
63
|
+
print("Finding available routes...")
|
|
64
|
+
routes = await client.maker.get_available_routes("BTC", "USDT")
|
|
65
|
+
|
|
66
|
+
if not routes:
|
|
67
|
+
print("No routes found for BTC/USDT")
|
|
68
|
+
return
|
|
69
|
+
|
|
70
|
+
print(f"Found {len(routes)} routes:")
|
|
71
|
+
for route in routes:
|
|
72
|
+
print(f" - {route.from_layer} -> {route.to_layer}")
|
|
73
|
+
|
|
74
|
+
print("\nStreaming quotes for BTC/USDT (automatically requests every 2 seconds)...")
|
|
75
|
+
|
|
76
|
+
# Start streaming - quotes are automatically requested every 2 seconds
|
|
77
|
+
stop = await client.maker.stream_quotes(
|
|
78
|
+
from_asset="BTC",
|
|
79
|
+
to_asset="USDT",
|
|
80
|
+
from_amount=100000,
|
|
81
|
+
from_layer=Layer(routes[0].from_layer),
|
|
82
|
+
to_layer=Layer(routes[0].to_layer),
|
|
83
|
+
on_update=on_quote,
|
|
84
|
+
poll_interval=2.0, # Request new quotes every 2 seconds
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
# Wait for quotes to arrive via callback
|
|
88
|
+
while quotes_received < max_quotes:
|
|
89
|
+
await asyncio.sleep(0.5)
|
|
90
|
+
|
|
91
|
+
# Stop streaming and disconnect
|
|
92
|
+
stop()
|
|
93
|
+
ws.disconnect()
|
|
94
|
+
print(f"\nReceived {quotes_received} quotes. Done!")
|
|
95
|
+
|
|
96
|
+
except Exception as e:
|
|
97
|
+
print(f"\nError: {e}")
|
|
98
|
+
print("(WebSocket streaming requires a working WebSocket endpoint)")
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
if __name__ == "__main__":
|
|
102
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Example 04: Create Swap Order
|
|
4
|
+
|
|
5
|
+
Test-backed swap-order flow:
|
|
6
|
+
1. Find the RGB asset ID for USDT
|
|
7
|
+
2. Get a fresh quote for USDT(RGB_LN) -> BTC(BTC_L1)
|
|
8
|
+
3. Ask the local node for a valid BTC receiver address
|
|
9
|
+
4. Create a swap order
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import asyncio
|
|
13
|
+
import logging
|
|
14
|
+
import os
|
|
15
|
+
|
|
16
|
+
from kaleido_sdk import (
|
|
17
|
+
CreateSwapOrderRequest,
|
|
18
|
+
KaleidoClient,
|
|
19
|
+
Layer,
|
|
20
|
+
PairQuoteRequest,
|
|
21
|
+
ReceiverAddress,
|
|
22
|
+
ReceiverAddressFormat,
|
|
23
|
+
SwapLegInput,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
API_URL = os.getenv("KALEIDO_API_URL", "https://api.staging.kaleidoswap.com")
|
|
27
|
+
NODE_URL = os.getenv("KALEIDO_NODE_URL", "http://localhost:3001")
|
|
28
|
+
|
|
29
|
+
# ---------------------------------------------------------------------------
|
|
30
|
+
# Logging setup (application's responsibility — the SDK never does this)
|
|
31
|
+
# ---------------------------------------------------------------------------
|
|
32
|
+
logging.basicConfig(
|
|
33
|
+
level=logging.DEBUG,
|
|
34
|
+
format="%(asctime)s [%(levelname)-8s] %(name)s — %(message)s",
|
|
35
|
+
datefmt="%H:%M:%S",
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
async def main() -> None:
|
|
40
|
+
"""Main entry point."""
|
|
41
|
+
client = KaleidoClient.create(
|
|
42
|
+
base_url=API_URL,
|
|
43
|
+
log_level=logging.DEBUG,
|
|
44
|
+
)
|
|
45
|
+
node_client = KaleidoClient.create(
|
|
46
|
+
base_url=API_URL,
|
|
47
|
+
node_url=NODE_URL,
|
|
48
|
+
log_level=logging.DEBUG,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
print(f"Maker API: {API_URL}")
|
|
52
|
+
print(f"Node URL: {NODE_URL}")
|
|
53
|
+
print("-" * 40)
|
|
54
|
+
|
|
55
|
+
print("\nFetching assets...")
|
|
56
|
+
assets = await client.maker.list_assets()
|
|
57
|
+
usdt_asset = next((asset for asset in assets.assets if asset.ticker == "USDT"), None)
|
|
58
|
+
if usdt_asset is None:
|
|
59
|
+
print("USDT asset not found in maker asset list")
|
|
60
|
+
return
|
|
61
|
+
|
|
62
|
+
protocol_ids = usdt_asset.protocol_ids or {}
|
|
63
|
+
rgb_asset_id = protocol_ids.get("RGB")
|
|
64
|
+
if rgb_asset_id is None:
|
|
65
|
+
print("USDT RGB asset id not found in protocol_ids")
|
|
66
|
+
return
|
|
67
|
+
|
|
68
|
+
print(f"Using RGB asset id for USDT: {rgb_asset_id}")
|
|
69
|
+
|
|
70
|
+
print("\nRequesting quote for USDT(RGB_LN) -> BTC(BTC_L1)...")
|
|
71
|
+
quote = await client.maker.get_quote(
|
|
72
|
+
PairQuoteRequest(
|
|
73
|
+
from_asset=SwapLegInput(
|
|
74
|
+
asset_id=rgb_asset_id,
|
|
75
|
+
layer=Layer.RGB_LN,
|
|
76
|
+
amount=1_000_000,
|
|
77
|
+
),
|
|
78
|
+
to_asset=SwapLegInput(
|
|
79
|
+
asset_id="BTC",
|
|
80
|
+
layer=Layer.BTC_L1,
|
|
81
|
+
),
|
|
82
|
+
)
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
print(f"RFQ ID: {quote.rfq_id}")
|
|
86
|
+
print(f"From: {quote.from_asset.amount} {quote.from_asset.ticker}")
|
|
87
|
+
print(f"To: {quote.to_asset.amount} {quote.to_asset.ticker}")
|
|
88
|
+
|
|
89
|
+
print("\nFetching a valid BTC address from the local node...")
|
|
90
|
+
address_response = await node_client.rln.get_address()
|
|
91
|
+
receiver_address = address_response.address
|
|
92
|
+
print(f"Receiver address: {receiver_address}")
|
|
93
|
+
|
|
94
|
+
order_request = CreateSwapOrderRequest(
|
|
95
|
+
rfq_id=quote.rfq_id,
|
|
96
|
+
from_asset=quote.from_asset,
|
|
97
|
+
to_asset=quote.to_asset,
|
|
98
|
+
receiver_address=ReceiverAddress(
|
|
99
|
+
address=receiver_address,
|
|
100
|
+
format=ReceiverAddressFormat.BTC_ADDRESS,
|
|
101
|
+
),
|
|
102
|
+
min_onchain_conf=1,
|
|
103
|
+
refund_address=receiver_address,
|
|
104
|
+
email="test@example.com",
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
print("\nCreating swap order...")
|
|
108
|
+
order = await client.maker.create_swap_order(order_request)
|
|
109
|
+
|
|
110
|
+
print("\nOrder created:")
|
|
111
|
+
print(f" Order ID: {order.id}")
|
|
112
|
+
print(f" RFQ ID: {order.rfq_id}")
|
|
113
|
+
print(f" Status: {order.status}")
|
|
114
|
+
if order.deposit_address is not None:
|
|
115
|
+
print(f" Deposit address: {order.deposit_address.address}")
|
|
116
|
+
print(f" Deposit format: {order.deposit_address.format}")
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
if __name__ == "__main__":
|
|
120
|
+
asyncio.run(main())
|