morpho-blue-py 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.
- morpho_blue_py-0.1.0/.github/dependabot.yml +10 -0
- morpho_blue_py-0.1.0/.github/workflows/ci.yml +46 -0
- morpho_blue_py-0.1.0/.github/workflows/docs.yml +27 -0
- morpho_blue_py-0.1.0/.gitignore +218 -0
- morpho_blue_py-0.1.0/CHANGELOG.md +29 -0
- morpho_blue_py-0.1.0/CONTRIBUTING.md +56 -0
- morpho_blue_py-0.1.0/LICENSE +21 -0
- morpho_blue_py-0.1.0/PKG-INFO +189 -0
- morpho_blue_py-0.1.0/README.md +149 -0
- morpho_blue_py-0.1.0/docs/api.md +3 -0
- morpho_blue_py-0.1.0/docs/index.md +1 -0
- morpho_blue_py-0.1.0/examples/async_usage.py +29 -0
- morpho_blue_py-0.1.0/examples/top_markets.py +35 -0
- morpho_blue_py-0.1.0/examples/vaults_and_positions.py +29 -0
- morpho_blue_py-0.1.0/mkdocs.yml +44 -0
- morpho_blue_py-0.1.0/pyproject.toml +87 -0
- morpho_blue_py-0.1.0/src/morpho_blue/__init__.py +47 -0
- morpho_blue_py-0.1.0/src/morpho_blue/_common.py +166 -0
- morpho_blue_py-0.1.0/src/morpho_blue/async_client.py +377 -0
- morpho_blue_py-0.1.0/src/morpho_blue/client.py +375 -0
- morpho_blue_py-0.1.0/src/morpho_blue/exceptions.py +51 -0
- morpho_blue_py-0.1.0/src/morpho_blue/export.py +82 -0
- morpho_blue_py-0.1.0/src/morpho_blue/models.py +330 -0
- morpho_blue_py-0.1.0/src/morpho_blue/py.typed +0 -0
- morpho_blue_py-0.1.0/src/morpho_blue/queries.py +172 -0
- morpho_blue_py-0.1.0/tests/__init__.py +0 -0
- morpho_blue_py-0.1.0/tests/fixtures.py +209 -0
- morpho_blue_py-0.1.0/tests/test_async_client.py +51 -0
- morpho_blue_py-0.1.0/tests/test_client.py +121 -0
- morpho_blue_py-0.1.0/tests/test_export.py +43 -0
- morpho_blue_py-0.1.0/tests/test_integration.py +24 -0
- morpho_blue_py-0.1.0/tests/test_models.py +101 -0
- morpho_blue_py-0.1.0/tests/test_pagination.py +52 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
# Static checks run once on a single modern interpreter. mypy targets 3.10
|
|
10
|
+
# (its config floor); ruff is interpreter-independent.
|
|
11
|
+
lint:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
15
|
+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
|
16
|
+
with:
|
|
17
|
+
python-version: "3.12"
|
|
18
|
+
- name: Install
|
|
19
|
+
run: |
|
|
20
|
+
python -m pip install --upgrade pip
|
|
21
|
+
pip install -e ".[dev]"
|
|
22
|
+
- name: Ruff
|
|
23
|
+
run: ruff check .
|
|
24
|
+
- name: Mypy (strict)
|
|
25
|
+
run: mypy
|
|
26
|
+
|
|
27
|
+
# Runtime tests run on every supported interpreter, including 3.9, to verify
|
|
28
|
+
# true 3.9 compatibility (requires-python >= 3.9).
|
|
29
|
+
test:
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
strategy:
|
|
32
|
+
fail-fast: false
|
|
33
|
+
matrix:
|
|
34
|
+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
|
35
|
+
steps:
|
|
36
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
37
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
38
|
+
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
|
39
|
+
with:
|
|
40
|
+
python-version: ${{ matrix.python-version }}
|
|
41
|
+
- name: Install
|
|
42
|
+
run: |
|
|
43
|
+
python -m pip install --upgrade pip
|
|
44
|
+
pip install -e ".[dev]"
|
|
45
|
+
- name: Pytest
|
|
46
|
+
run: pytest -q
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: Docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
build-deploy:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
16
|
+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
|
17
|
+
with:
|
|
18
|
+
python-version: "3.12"
|
|
19
|
+
- name: Install
|
|
20
|
+
run: |
|
|
21
|
+
python -m pip install --upgrade pip
|
|
22
|
+
pip install -e . mkdocs-material "mkdocstrings[python]"
|
|
23
|
+
- name: Build
|
|
24
|
+
run: mkdocs build
|
|
25
|
+
- name: Deploy to GitHub Pages
|
|
26
|
+
if: github.ref == 'refs/heads/main'
|
|
27
|
+
run: mkdocs gh-deploy --force
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py.cover
|
|
50
|
+
.hypothesis/
|
|
51
|
+
.pytest_cache/
|
|
52
|
+
cover/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Django stuff:
|
|
59
|
+
*.log
|
|
60
|
+
local_settings.py
|
|
61
|
+
db.sqlite3
|
|
62
|
+
db.sqlite3-journal
|
|
63
|
+
|
|
64
|
+
# Flask stuff:
|
|
65
|
+
instance/
|
|
66
|
+
.webassets-cache
|
|
67
|
+
|
|
68
|
+
# Scrapy stuff:
|
|
69
|
+
.scrapy
|
|
70
|
+
|
|
71
|
+
# Sphinx documentation
|
|
72
|
+
docs/_build/
|
|
73
|
+
|
|
74
|
+
# PyBuilder
|
|
75
|
+
.pybuilder/
|
|
76
|
+
target/
|
|
77
|
+
|
|
78
|
+
# Jupyter Notebook
|
|
79
|
+
.ipynb_checkpoints
|
|
80
|
+
|
|
81
|
+
# IPython
|
|
82
|
+
profile_default/
|
|
83
|
+
ipython_config.py
|
|
84
|
+
|
|
85
|
+
# pyenv
|
|
86
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
87
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
88
|
+
# .python-version
|
|
89
|
+
|
|
90
|
+
# pipenv
|
|
91
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
92
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
93
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
94
|
+
# install all needed dependencies.
|
|
95
|
+
# Pipfile.lock
|
|
96
|
+
|
|
97
|
+
# UV
|
|
98
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
99
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
100
|
+
# commonly ignored for libraries.
|
|
101
|
+
# uv.lock
|
|
102
|
+
|
|
103
|
+
# poetry
|
|
104
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
105
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
106
|
+
# commonly ignored for libraries.
|
|
107
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
108
|
+
# poetry.lock
|
|
109
|
+
# poetry.toml
|
|
110
|
+
|
|
111
|
+
# pdm
|
|
112
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
113
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
114
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
115
|
+
# pdm.lock
|
|
116
|
+
# pdm.toml
|
|
117
|
+
.pdm-python
|
|
118
|
+
.pdm-build/
|
|
119
|
+
|
|
120
|
+
# pixi
|
|
121
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
122
|
+
# pixi.lock
|
|
123
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
124
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
125
|
+
.pixi
|
|
126
|
+
|
|
127
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
128
|
+
__pypackages__/
|
|
129
|
+
|
|
130
|
+
# Celery stuff
|
|
131
|
+
celerybeat-schedule
|
|
132
|
+
celerybeat.pid
|
|
133
|
+
|
|
134
|
+
# Redis
|
|
135
|
+
*.rdb
|
|
136
|
+
*.aof
|
|
137
|
+
*.pid
|
|
138
|
+
|
|
139
|
+
# RabbitMQ
|
|
140
|
+
mnesia/
|
|
141
|
+
rabbitmq/
|
|
142
|
+
rabbitmq-data/
|
|
143
|
+
|
|
144
|
+
# ActiveMQ
|
|
145
|
+
activemq-data/
|
|
146
|
+
|
|
147
|
+
# SageMath parsed files
|
|
148
|
+
*.sage.py
|
|
149
|
+
|
|
150
|
+
# Environments
|
|
151
|
+
.env
|
|
152
|
+
.envrc
|
|
153
|
+
.venv
|
|
154
|
+
env/
|
|
155
|
+
venv/
|
|
156
|
+
ENV/
|
|
157
|
+
env.bak/
|
|
158
|
+
venv.bak/
|
|
159
|
+
|
|
160
|
+
# Spyder project settings
|
|
161
|
+
.spyderproject
|
|
162
|
+
.spyproject
|
|
163
|
+
|
|
164
|
+
# Rope project settings
|
|
165
|
+
.ropeproject
|
|
166
|
+
|
|
167
|
+
# mkdocs documentation
|
|
168
|
+
/site
|
|
169
|
+
|
|
170
|
+
# mypy
|
|
171
|
+
.mypy_cache/
|
|
172
|
+
.dmypy.json
|
|
173
|
+
dmypy.json
|
|
174
|
+
|
|
175
|
+
# Pyre type checker
|
|
176
|
+
.pyre/
|
|
177
|
+
|
|
178
|
+
# pytype static type analyzer
|
|
179
|
+
.pytype/
|
|
180
|
+
|
|
181
|
+
# Cython debug symbols
|
|
182
|
+
cython_debug/
|
|
183
|
+
|
|
184
|
+
# PyCharm
|
|
185
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
186
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
187
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
188
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
189
|
+
# .idea/
|
|
190
|
+
|
|
191
|
+
# Abstra
|
|
192
|
+
# Abstra is an AI-powered process automation framework.
|
|
193
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
194
|
+
# Learn more at https://abstra.io/docs
|
|
195
|
+
.abstra/
|
|
196
|
+
|
|
197
|
+
# Visual Studio Code
|
|
198
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
199
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
200
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
201
|
+
# you could uncomment the following to ignore the entire vscode folder
|
|
202
|
+
# .vscode/
|
|
203
|
+
# Temporary file for partial code execution
|
|
204
|
+
tempCodeRunnerFile.py
|
|
205
|
+
|
|
206
|
+
# Ruff stuff:
|
|
207
|
+
.ruff_cache/
|
|
208
|
+
|
|
209
|
+
# PyPI configuration file
|
|
210
|
+
.pypirc
|
|
211
|
+
|
|
212
|
+
# Marimo
|
|
213
|
+
marimo/_static/
|
|
214
|
+
marimo/_lsp/
|
|
215
|
+
__marimo__/
|
|
216
|
+
|
|
217
|
+
# Streamlit
|
|
218
|
+
.streamlit/secrets.toml
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format is based on
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
|
|
5
|
+
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.1.0]
|
|
10
|
+
|
|
11
|
+
Initial release.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- Synchronous `MorphoClient` and asynchronous `AsyncMorphoClient` over `httpx`.
|
|
16
|
+
- Typed pydantic v2 models for the Morpho Blue GraphQL schema (`Market`,
|
|
17
|
+
`MarketState`, `Vault`, `VaultState`, `VaultAllocation`, `MarketPosition`,
|
|
18
|
+
`VaultPosition`, `User`, `Asset`, `Chain`, `PageInfo`, …); ships `py.typed`.
|
|
19
|
+
- Helper methods: `top_markets_by_supply_apy`, `top_vaults_by_apy`,
|
|
20
|
+
`get_market`, `get_vault`, `get_user`, and `iter_markets` (automatic
|
|
21
|
+
pagination via `skip`).
|
|
22
|
+
- Multi-chain support through the `chain_id` parameter.
|
|
23
|
+
- Optional pandas export helpers (`morpho_blue.export`) behind the `pandas`
|
|
24
|
+
extra.
|
|
25
|
+
- Examples, quickstart README, and a GitHub Actions CI matrix across Python
|
|
26
|
+
3.9–3.13.
|
|
27
|
+
|
|
28
|
+
[Unreleased]: https://github.com/robertruben98/morpho-blue-py/compare/v0.1.0...HEAD
|
|
29
|
+
[0.1.0]: https://github.com/robertruben98/morpho-blue-py/releases/tag/v0.1.0
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in improving **morpho-blue-py**! This guide covers the
|
|
4
|
+
local setup and the checks your change needs to pass.
|
|
5
|
+
|
|
6
|
+
## Development setup
|
|
7
|
+
|
|
8
|
+
The project uses [uv](https://docs.astral.sh/uv/), but plain `pip` works too.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
# with uv (recommended)
|
|
12
|
+
uv venv --python 3.9
|
|
13
|
+
uv pip install -e ".[dev]"
|
|
14
|
+
|
|
15
|
+
# or with pip
|
|
16
|
+
python -m venv .venv && source .venv/bin/activate
|
|
17
|
+
python -m pip install --upgrade pip
|
|
18
|
+
pip install -e ".[dev]"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
We target **Python 3.9+**, so develop against 3.9 when in doubt. Runtime-evaluated
|
|
22
|
+
type annotations (e.g. inside pydantic models) must avoid PEP 604 `X | None` —
|
|
23
|
+
use `typing.Optional`/`typing.Union` instead.
|
|
24
|
+
|
|
25
|
+
## Quality gates
|
|
26
|
+
|
|
27
|
+
All of these must be green before a PR can merge; CI runs them on Python
|
|
28
|
+
3.9–3.13.
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
ruff check . # lint
|
|
32
|
+
mypy # type-check (strict)
|
|
33
|
+
pytest # unit tests (no network)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Unit tests must not hit the network — they use `respx` with realistic GraphQL
|
|
37
|
+
fixtures (see `tests/fixtures.py`). The single live test is marked `integration`
|
|
38
|
+
and deselected by default; run it explicitly with:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pytest -m integration
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Workflow
|
|
45
|
+
|
|
46
|
+
1. Branch off `main`.
|
|
47
|
+
2. Follow test-driven development: add a failing test, then the implementation.
|
|
48
|
+
3. Keep public APIs documented with Google-style docstrings and pydantic
|
|
49
|
+
`Field(description=...)`.
|
|
50
|
+
4. Update `CHANGELOG.md` under `[Unreleased]`.
|
|
51
|
+
5. Open a pull request; ensure CI is green.
|
|
52
|
+
|
|
53
|
+
## Reporting issues
|
|
54
|
+
|
|
55
|
+
Please file bugs and feature requests at
|
|
56
|
+
<https://github.com/robertruben98/morpho-blue-py/issues>.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Robert Ruben
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: morpho-blue-py
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Typed Python client for the Morpho Blue GraphQL API (lending markets, vaults, and positions analytics).
|
|
5
|
+
Project-URL: Homepage, https://github.com/robertruben98/morpho-blue-py
|
|
6
|
+
Project-URL: Repository, https://github.com/robertruben98/morpho-blue-py
|
|
7
|
+
Project-URL: Documentation, https://docs.morpho.org/tools/offchain/api/get-started/
|
|
8
|
+
Project-URL: Issues, https://github.com/robertruben98/morpho-blue-py/issues
|
|
9
|
+
Author: Robert Ruben
|
|
10
|
+
License: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: defi,ethereum,graphql,lending,morpho,morpho-blue
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
23
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
24
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
25
|
+
Classifier: Typing :: Typed
|
|
26
|
+
Requires-Python: >=3.9
|
|
27
|
+
Requires-Dist: httpx>=0.24
|
|
28
|
+
Requires-Dist: pydantic>=2.0
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: mypy>=1.8; extra == 'dev'
|
|
31
|
+
Requires-Dist: pandas-stubs; extra == 'dev'
|
|
32
|
+
Requires-Dist: pandas>=1.3; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
|
|
34
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
35
|
+
Requires-Dist: respx>=0.20; extra == 'dev'
|
|
36
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
37
|
+
Provides-Extra: pandas
|
|
38
|
+
Requires-Dist: pandas>=1.3; extra == 'pandas'
|
|
39
|
+
Description-Content-Type: text/markdown
|
|
40
|
+
|
|
41
|
+
# morpho-blue-py
|
|
42
|
+
|
|
43
|
+
[](https://github.com/robertruben98/morpho-blue-py/actions/workflows/ci.yml)
|
|
44
|
+
[](https://pypi.org/project/morpho-blue-py/)
|
|
45
|
+
[](https://robertruben98.github.io/morpho-blue-py/)
|
|
46
|
+
[](https://pypi.org/project/morpho-blue-py/)
|
|
47
|
+
[](https://opensource.org/licenses/MIT)
|
|
48
|
+
|
|
49
|
+
A typed Python client for the [Morpho Blue GraphQL API](https://docs.morpho.org/tools/offchain/api/get-started/) —
|
|
50
|
+
lending markets, MetaMorpho vaults, and user positions analytics.
|
|
51
|
+
|
|
52
|
+
- Sync (`MorphoClient`) and async (`AsyncMorphoClient`) clients built on `httpx`.
|
|
53
|
+
- Fully typed [pydantic v2](https://docs.pydantic.dev/) models (ships `py.typed`).
|
|
54
|
+
- Helper methods: top markets by APY, market/vault lookups, wallet positions.
|
|
55
|
+
- Automatic pagination and multi-chain support.
|
|
56
|
+
- Optional `pandas` export.
|
|
57
|
+
|
|
58
|
+
The API is public and read-only — no API key required.
|
|
59
|
+
|
|
60
|
+
## Install
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install morpho-blue-py
|
|
64
|
+
# with pandas export helpers:
|
|
65
|
+
pip install "morpho-blue-py[pandas]"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Quickstart — list the largest markets and their supply APY
|
|
69
|
+
|
|
70
|
+
`supply_apy` / `borrow_apy` are returned as **decimal fractions** (e.g. `0.0366`
|
|
71
|
+
means 3.66%), so format them with `:.2%`. We list the biggest Ethereum markets
|
|
72
|
+
by deposits and skip ones at 100% utilization — a fully-utilized market reports a
|
|
73
|
+
distorted instantaneous rate that can read as thousands of percent.
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
from morpho_blue import MorphoClient
|
|
77
|
+
|
|
78
|
+
with MorphoClient() as client:
|
|
79
|
+
markets = client.get_markets(
|
|
80
|
+
chain_id=1,
|
|
81
|
+
first=5,
|
|
82
|
+
order_by="supply_assets_usd",
|
|
83
|
+
where={"utilization_lte": 0.99},
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
for market in markets:
|
|
87
|
+
loan = market.loan_asset.symbol if market.loan_asset else "?"
|
|
88
|
+
apy = market.state.supply_apy if market.state else None
|
|
89
|
+
print(f"{loan:8} supply APY: {apy:.2%}" if apy is not None else loan)
|
|
90
|
+
# USDC supply APY: 3.66%
|
|
91
|
+
# USDT supply APY: 3.16%
|
|
92
|
+
# WETH supply APY: 1.62%
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Markets
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
from morpho_blue import MorphoClient
|
|
99
|
+
|
|
100
|
+
with MorphoClient() as client:
|
|
101
|
+
# A page of markets on Ethereum (chainId 1), sorted by USD supply.
|
|
102
|
+
markets = client.get_markets(chain_id=1, first=20, order_by="supply_assets_usd")
|
|
103
|
+
|
|
104
|
+
# A single market by its unique key (marketId) — note: the Morpho schema's
|
|
105
|
+
# unique key is `marketId`, NOT `uniqueKey`.
|
|
106
|
+
market = client.get_market(
|
|
107
|
+
"0x8eaf7b29f02ba8d8c1d7aeb587403dcb16e2e943e4e2f5f94b0963c2386406c9",
|
|
108
|
+
chain_id=1,
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
# All markets across pages (auto-paginated via skip).
|
|
112
|
+
everything = client.iter_markets(chain_id=1, page_size=100)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Vaults (MetaMorpho)
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
with MorphoClient() as client:
|
|
119
|
+
vaults = client.top_vaults_by_apy(chain_id=1, limit=10)
|
|
120
|
+
vault = client.get_vault("0xBEEF01735c132Ada46AA9aA4c54623cAA92A64CB", chain_id=1)
|
|
121
|
+
if vault.state:
|
|
122
|
+
print(vault.name, vault.state.net_apy, vault.state.total_assets_usd)
|
|
123
|
+
for alloc in vault.state.allocation:
|
|
124
|
+
print(alloc.market.market_id, alloc.supply_assets_usd)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Wallet positions
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
with MorphoClient() as client:
|
|
131
|
+
user = client.get_user("0x47E2D28169738039755586743E2dfCF3bd643f86", chain_id=1)
|
|
132
|
+
for pos in user.market_positions:
|
|
133
|
+
if pos.state:
|
|
134
|
+
print(pos.market.market_id, pos.state.supply_assets, pos.state.borrow_assets)
|
|
135
|
+
for vpos in user.vault_positions:
|
|
136
|
+
print(vpos.vault.symbol, vpos.state.assets if vpos.state else None)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Async
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
import asyncio
|
|
143
|
+
from morpho_blue import AsyncMorphoClient
|
|
144
|
+
|
|
145
|
+
async def main() -> None:
|
|
146
|
+
async with AsyncMorphoClient() as client:
|
|
147
|
+
markets = await client.top_markets_by_supply_apy(chain_id=1, limit=5)
|
|
148
|
+
print([m.loan_asset.symbol for m in markets if m.loan_asset])
|
|
149
|
+
|
|
150
|
+
asyncio.run(main())
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## pandas export
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
from morpho_blue import MorphoClient
|
|
157
|
+
from morpho_blue.export import markets_to_dataframe
|
|
158
|
+
|
|
159
|
+
with MorphoClient() as client:
|
|
160
|
+
df = markets_to_dataframe(client.get_markets(chain_id=1, first=50))
|
|
161
|
+
print(df[["loan_asset_symbol", "supply_apy", "supply_assets_usd"]])
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Multi-chain
|
|
165
|
+
|
|
166
|
+
Every method takes an optional `chain_id`. Supported chains include Ethereum (1),
|
|
167
|
+
Base (8453), Arbitrum (42161), Polygon (137), Optimism (10), Unichain (130), and more.
|
|
168
|
+
Omit `chain_id` to query across all chains the API exposes.
|
|
169
|
+
|
|
170
|
+
## Custom endpoint
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
MorphoClient(endpoint="https://blue-api.morpho.org/graphql") # default
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Development
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
uv venv --python 3.9
|
|
180
|
+
uv pip install -e ".[dev]"
|
|
181
|
+
ruff check .
|
|
182
|
+
mypy
|
|
183
|
+
pytest # unit tests (no network)
|
|
184
|
+
pytest -m integration # hits the live endpoint
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## License
|
|
188
|
+
|
|
189
|
+
MIT
|