├── .github
└── workflows
│ ├── package-test.yml
│ └── publish-to-test-pypi.yml
├── .gitignore
├── LICENSE
├── README.md
├── blockfrost
├── __init__.py
├── api
│ ├── __init__.py
│ ├── cardano
│ │ ├── __init__.py
│ │ ├── accounts.py
│ │ ├── addresses.py
│ │ ├── assets.py
│ │ ├── blocks.py
│ │ ├── epochs.py
│ │ ├── ledger.py
│ │ ├── mempool.py
│ │ ├── metadata.py
│ │ ├── network.py
│ │ ├── pools.py
│ │ ├── scripts.py
│ │ ├── transactions.py
│ │ └── utils.py
│ ├── health.py
│ ├── metrics.py
│ └── nutlink.py
├── config.py
├── helpers.py
├── ipfs
│ ├── __init__.py
│ ├── add.py
│ ├── gateway.py
│ └── pins.py
└── utils.py
├── requirements.txt
├── setup.py
├── shell.nix
├── test-requirements.txt
└── tests
├── __init__.py
├── test_api.py
├── test_cardano_accounts.py
├── test_cardano_addresses.py
├── test_cardano_assets.py
├── test_cardano_blocks.py
├── test_cardano_epochs.py
├── test_cardano_ledger.py
├── test_cardano_mempool.py
├── test_cardano_metadata.py
├── test_cardano_network.py
├── test_cardano_pools.py
├── test_cardano_scripts.py
├── test_cardano_transactions.py
├── test_cardano_utils.py
├── test_health.py
├── test_helpers.py
├── test_ipfs_add.py
├── test_ipfs_gateway.py
├── test_ipfs_pins.py
├── test_metrics.py
└── test_object_mapper.py
/.github/workflows/package-test.yml:
--------------------------------------------------------------------------------
1 | name: Package Test
2 |
3 | on:
4 | - push
5 | - pull_request
6 |
7 | jobs:
8 | build:
9 |
10 | runs-on: ubuntu-latest
11 | strategy:
12 | fail-fast: false
13 | matrix:
14 | python-version: ["3.7", "3.8", "3.9", "3.10"]
15 |
16 | steps:
17 | - uses: actions/checkout@v2
18 | - name: Set up Python ${{ matrix.python-version }}
19 | uses: actions/setup-python@v2
20 | with:
21 | python-version: ${{ matrix.python-version }}
22 | - name: Install dependencies
23 | run: |
24 | python -m pip install --upgrade pip
25 | python -m pip install flake8 pytest
26 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
27 | if [ -f test-requirements.txt ]; then pip install -r test-requirements.txt; fi
28 | - name: Install package
29 | run: |
30 | python -m pip install .
31 | - name: Lint with flake8
32 | run: |
33 | # stop the build if there are Python syntax errors or undefined names
34 | flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
35 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
36 | flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
37 | - name: Test with pytest
38 | env:
39 | BLOCKFROST_PROJECT_ID_MAINNET: ${{ secrets.BLOCKFROST_PROJECT_ID_MAINNET }}
40 | run: |
41 | pytest
42 |
--------------------------------------------------------------------------------
/.github/workflows/publish-to-test-pypi.yml:
--------------------------------------------------------------------------------
1 | name: Publish Python 🐍 distributions 📦 to PyPI and TestPyPI
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | workflow_dispatch:
8 | inputs:
9 | publish_to_pypi:
10 | description: "Publish to PyPI"
11 | required: true
12 | default: "false"
13 |
14 | jobs:
15 | build-n-publish:
16 | name: Build and publish Python 🐍 distributions 📦 to PyPI and TestPyPI
17 | runs-on: ubuntu-latest
18 | steps:
19 | - uses: actions/checkout@master
20 | - name: Set up Python 3.9
21 | uses: actions/setup-python@v1
22 | with:
23 | python-version: 3.9
24 | - name: Install pypa/build
25 | run: >
26 | python -m
27 | pip install
28 | build
29 | --user
30 | - name: Build a binary wheel and a source tarball
31 | run: >
32 | python -m
33 | build
34 | --sdist
35 | --wheel
36 | --outdir dist/
37 | .
38 | - name: Publish distribution 📦 to Test PyPI
39 | uses: pypa/gh-action-pypi-publish@release/v1
40 | with:
41 | skip_existing: true
42 | user: __token__
43 | password: ${{ secrets.TESTNET_PYPI_API_TOKEN }}
44 | repository_url: https://test.pypi.org/legacy/
45 | - name: Publish distribution 📦 to PyPI
46 | if: startsWith(github.ref, 'refs/tags') || github.event.inputs.publish_to_pypi == 'true'
47 | uses: pypa/gh-action-pypi-publish@release/v1
48 | with:
49 | user: __token__
50 | password: ${{ secrets.PYPI_API_TOKEN }}
51 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
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 | pip-wheel-metadata/
24 | share/python-wheels/
25 | *.egg-info/
26 | .installed.cfg
27 | *.egg
28 | MANIFEST
29 |
30 | # PyInstaller
31 | # Usually these files are written by a python script from a template
32 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
33 | *.manifest
34 | *.spec
35 |
36 | # Installer logs
37 | pip-log.txt
38 | pip-delete-this-directory.txt
39 |
40 | # Unit test / coverage reports
41 | htmlcov/
42 | .tox/
43 | .nox/
44 | .coverage
45 | .coverage.*
46 | .cache
47 | nosetests.xml
48 | coverage.xml
49 | *.cover
50 | *.py,cover
51 | .hypothesis/
52 | .pytest_cache/
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 | target/
76 |
77 | # Jupyter Notebook
78 | .ipynb_checkpoints
79 |
80 | # IPython
81 | profile_default/
82 | ipython_config.py
83 |
84 | # pyenv
85 | .python-version
86 |
87 | # pipenv
88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
91 | # install all needed dependencies.
92 | #Pipfile.lock
93 |
94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
95 | __pypackages__/
96 |
97 | # Celery stuff
98 | celerybeat-schedule
99 | celerybeat.pid
100 |
101 | # SageMath parsed files
102 | *.sage.py
103 |
104 | # Environments
105 | .env
106 | .venv
107 | env/
108 | venv/
109 | ENV/
110 | env.bak/
111 | venv.bak/
112 |
113 | # Spyder project settings
114 | .spyderproject
115 | .spyproject
116 |
117 | # Rope project settings
118 | .ropeproject
119 |
120 | # mkdocs documentation
121 | /site
122 |
123 | # mypy
124 | .mypy_cache/
125 | .dmypy.json
126 | dmypy.json
127 |
128 | # Pyre type checker
129 | .pyre/
130 |
131 | # vscode
132 | .vscode/
133 |
134 | # JetBrains
135 | .idea/
136 | .DS_Store
137 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/blockfrost/blockfrost-python/actions/workflows/package-test.yml)
2 | [](https://pypi.org/project/blockfrost-python/)
3 | [](https://pypistats.org/packages/blockfrost-python)
4 | [](https://pypi.org/project/blockfrost-python/)
5 | [](https://github.com/blockfrost/blockfrost-python/blob/master/LICENSE)
6 | [](https://fivebinaries.com/)
7 | [](https://github.com/mathiasfrohlich)
8 |
9 |
10 |
11 | # blockfrost-python
12 |
13 |
14 |
15 |
A Python SDK for Blockfrost.io API
16 |
17 | Getting started •
18 | Installation •
19 | Usage
20 |
21 |
22 |
23 | ## Getting started
24 |
25 | To use this SDK, you first need login into [blockfrost.io](https://blockfrost.io) and create your project to retrieve
26 | your API key.
27 |
28 |
29 |
30 |
31 |
32 | ## Installation
33 |
34 | [](https://pypi.org/project/blockfrost-python/)
35 |
36 | ```console
37 | pip install blockfrost-python
38 | ```
39 |
40 |
41 |
42 | ## Usage
43 |
44 | Using the SDK is pretty straight-forward as you can see from the following examples.
45 |
46 | ### Cardano
47 |
48 | ```python
49 | from blockfrost import BlockFrostApi, ApiError, ApiUrls
50 |
51 | api = BlockFrostApi(
52 | project_id='YOUR API KEY HERE', # or export environment variable BLOCKFROST_PROJECT_ID
53 | # optional: pass base_url or export BLOCKFROST_API_URL to use testnet, defaults to ApiUrls.mainnet.value
54 | base_url=ApiUrls.testnet.value,
55 | )
56 | try:
57 | health = api.health()
58 | print(health) # prints object: HealthResponse(is_healthy=True)
59 | health = api.health(return_type='json') # Can be useful if python wrapper is behind api version
60 | print(health) # prints json: {"is_healthy":True}
61 | health = api.health(return_type='pandas')
62 | print(health) # prints Dataframe: is_healthy
63 | # 0 True
64 |
65 |
66 | account_rewards = api.account_rewards(
67 | stake_address='stake1ux3g2c9dx2nhhehyrezyxpkstartcqmu9hk63qgfkccw5rqttygt7',
68 | count=20,
69 | )
70 | print(account_rewards[0].epoch) # prints 221
71 | print(len(account_rewards)) # prints 20
72 |
73 | account_rewards = api.account_rewards(
74 | stake_address='stake1ux3g2c9dx2nhhehyrezyxpkstartcqmu9hk63qgfkccw5rqttygt7',
75 | count=20,
76 | gather_pages=True, # will collect all pages
77 | )
78 | print(account_rewards[0].epoch) # prints 221
79 | print(len(account_rewards)) # prints 57
80 |
81 | address = api.address(
82 | address='addr1qxqs59lphg8g6qndelq8xwqn60ag3aeyfcp33c2kdp46a09re5df3pzwwmyq946axfcejy5n4x0y99wqpgtp2gd0k09qsgy6pz')
83 | print(address.type) # prints 'shelley'
84 | for amount in address.amount:
85 | print(amount.unit) # prints 'lovelace'
86 |
87 | except ApiError as e:
88 | print(e)
89 | ```
90 |
91 | ### IPFS
92 |
93 | ```python
94 | from blockfrost import BlockFrostIPFS, ApiError
95 |
96 | ipfs = BlockFrostIPFS(
97 | project_id='YOUR API KEY HERE' # or export environment variable BLOCKFROST_PROJECT_ID
98 | )
99 | file_hash = None
100 | try:
101 | ipfs_object = ipfs.add('./README.md')
102 | file_hash = ipfs_object.ipfs_hash
103 | print(file_hash)
104 | except ApiError as e:
105 | print(e)
106 |
107 | try:
108 | with open('./README_downloaded.md', 'w') as file:
109 | file_data = ipfs.gateway(IPFS_path=file_hash).text
110 | file.write(file_data)
111 | except ApiError as e:
112 | print(e)
113 | ```
114 |
115 | ### Verifying Secure Webhook signature
116 |
117 | Webhooks enable Blockfrost to push real-time notifications to your application. In order to prevent malicious actor from pretending to be Blockfrost every webhook request is signed. The signature is included in a request's `Blockfrost-Signature` header. This allows you to verify that the events were sent by Blockfrost, not by a third party.
118 | To learn more about Secure Webhooks, see [Secure Webhooks Docs](https://blockfrost.dev/docs/start-building/webhooks/).
119 |
120 | You can verify the signature using `verifyWebhookSignature` function.
121 |
122 | Example:
123 |
124 | ```python
125 | # Example of Python Flask app with /webhook endpoint
126 | # for processing events sent by Blockfrost Secure Webhooks
127 | from flask import Flask, request, json
128 | from blockfrost import verify_webhook_signature, SignatureVerificationError
129 |
130 | SECRET_AUTH_TOKEN = "SECRET-WEBHOOK-AUTH-TOKEN"
131 |
132 | app = Flask(__name__)
133 |
134 | @app.route('/webhook', methods=['POST'])
135 | def webhook():
136 | if request.method == 'POST':
137 | # Validate webhook signature
138 | request_bytes = request.get_data()
139 | try:
140 | verify_webhook_signature(
141 | request_bytes, request.headers['Blockfrost-Signature'], SECRET_AUTH_TOKEN)
142 | except SignatureVerificationError as e:
143 | # for easier debugging you can access passed header and request_body values (e.header, e.request_body)
144 | print('Webhook signature is invalid.', e)
145 | return 'Invalid signature', 403
146 |
147 | # Get the payload as JSON
148 | event = request.json
149 |
150 | print('Received request id {}, webhook_id: {}'.format(
151 | event['id'], event['webhook_id']))
152 |
153 | if event['type'] == "block":
154 | # process Block event
155 | print('Received block hash {}'.format(event['payload']['hash']))
156 | elif event['type'] == "...":
157 | # truncated
158 | else:
159 | # Unexpected event type
160 | print('Unexpected event type {}'.format(event['type']))
161 |
162 | return 'Webhook received', 200
163 | else:
164 | return 'POST Method not supported', 405
165 |
166 |
167 |
168 | if __name__ == "__main__":
169 | app.run(host='0.0.0.0', port=6666)
170 | ```
171 |
172 | ## Development
173 |
174 | Install dependencies
175 |
176 | ```
177 | pip install -r requirements.txt
178 | pip install -r rest-requirements.txt
179 | ```
180 |
181 | Install package
182 |
183 | ```
184 | pip install .
185 | ```
186 |
187 | Run integration and unit tests:
188 |
189 | ```
190 | pytest
191 | ```
192 |
193 | _For integration tests you need to set env variable `BLOCKFROST_PROJECT_ID_MAINNET`_
194 |
195 | ### Release workflow
196 |
197 | To release the package create a new release via GitHub releases.
198 | This action triggers the automated release workflow that packages and uploads the distribution to PyPI.
199 |
--------------------------------------------------------------------------------
/blockfrost/__init__.py:
--------------------------------------------------------------------------------
1 | from blockfrost.api import BlockFrostApi
2 | from blockfrost.ipfs import BlockFrostIPFS
3 | from blockfrost.config import ApiUrls
4 | from blockfrost.utils import ApiError, Namespace
5 | from blockfrost.helpers import SignatureVerificationError, verify_webhook_signature
6 |
--------------------------------------------------------------------------------
/blockfrost/api/__init__.py:
--------------------------------------------------------------------------------
1 | import os
2 | import requests
3 | from dataclasses import dataclass
4 |
5 | from blockfrost.config import DEFAULT_API_VERSION
6 |
7 | from ..utils import Api, ApiUrls, request_wrapper
8 |
9 |
10 | class BlockFrostApi(Api):
11 |
12 | def __init__(self, project_id: str = None, base_url: str = None, api_version: str = None):
13 | super().__init__(
14 | project_id=project_id,
15 | base_url=base_url if base_url else os.environ.get(
16 | 'BLOCKFROST_API_URL', default=ApiUrls.mainnet.value),
17 | # if custom base_url is specified then also use specified api_version
18 | api_version=api_version if base_url else os.environ.get('BLOCKFROST_API_VERSION',
19 | default=DEFAULT_API_VERSION))
20 |
21 | @request_wrapper
22 | def root(self, **kwargs):
23 | """
24 | Root endpoint has no other function than to point end users to documentation.
25 |
26 | https://docs.blockfrost.io/#tag/Health/paths/~1/get
27 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
28 | :type return_type: str
29 | :returns RootResponse object.
30 | :rtype RootResponse
31 | :raises ApiError: If API fails
32 | :raises Exception: If the API response is somehow malformed.
33 | """
34 | return requests.get(
35 | url=f"{self.url}/",
36 | headers=self.authentication_header
37 | )
38 |
39 | from .health import \
40 | health, \
41 | clock
42 | from .metrics import \
43 | metrics, \
44 | metrics_endpoints
45 | from .nutlink import \
46 | nutlink_address, \
47 | nutlink_address_tickers, \
48 | nutlink_address_ticker, \
49 | nutlink_ticker
50 | from .cardano.accounts import \
51 | accounts, \
52 | account_rewards, \
53 | account_history, \
54 | account_delegations, \
55 | account_registrations, \
56 | account_withdrawals, \
57 | account_mirs, \
58 | account_addresses, \
59 | account_addresses_assets, \
60 | account_addresses_total
61 | from .cardano.addresses import \
62 | address, \
63 | address_extended, \
64 | address_total, \
65 | address_utxos, \
66 | address_utxos_asset, \
67 | address_transactions
68 | from .cardano.assets import \
69 | assets, \
70 | asset, \
71 | asset_history, \
72 | asset_transactions, \
73 | asset_addresses, \
74 | assets_policy
75 | from .cardano.blocks import \
76 | block_latest, \
77 | block_latest_transactions, \
78 | block, \
79 | block_slot, \
80 | block_epoch_slot, \
81 | blocks_next, \
82 | blocks_previous, \
83 | block_transactions, \
84 | blocks_addresses
85 | from .cardano.epochs import \
86 | epoch_latest, \
87 | epoch_latest_parameters, \
88 | epoch, \
89 | epochs_next, \
90 | epochs_previous, \
91 | epoch_stakes, \
92 | epoch_pool_stakes, \
93 | epoch_blocks, \
94 | epoch_pool_blocks, \
95 | epoch_protocol_parameters
96 | from .cardano.ledger import \
97 | genesis
98 | from .cardano.mempool import \
99 | mempool, \
100 | mempool_address, \
101 | mempool_tx
102 | from .cardano.metadata import \
103 | metadata_labels, \
104 | metadata_label_json, \
105 | metadata_label_cbor
106 | from .cardano.network import \
107 | network
108 | from .cardano.pools import \
109 | pools, \
110 | pools_extended, \
111 | pools_retired, \
112 | pools_retiring, \
113 | pool, \
114 | pool_history, \
115 | pool_metadata, \
116 | pool_relays, \
117 | pool_delegators, \
118 | pool_blocks, \
119 | pool_updates
120 | from .cardano.transactions import \
121 | transaction, \
122 | transaction_utxos, \
123 | transaction_stakes, \
124 | transaction_delegations, \
125 | transaction_withdrawals, \
126 | transaction_mirs, \
127 | transaction_pool_updates, \
128 | transaction_pool_retires, \
129 | transaction_metadata, \
130 | transaction_metadata_cbor, \
131 | transaction_submit, \
132 | transaction_submit_cbor, \
133 | transaction_redeemers, \
134 | transaction_evaluate, \
135 | transaction_evaluate_cbor, \
136 | transaction_evaluate_utxos
137 | from .cardano.scripts import \
138 | scripts, \
139 | script, \
140 | script_json, \
141 | script_cbor, \
142 | script_redeemers, \
143 | script_datum, \
144 | script_datum_cbor
145 | from .cardano.utils import \
146 | utils_addresses_xpub
147 |
--------------------------------------------------------------------------------
/blockfrost/api/cardano/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blockfrost/blockfrost-python/cb7418e8ce19b6761490cd14f65ebf34cd7e1527/blockfrost/api/cardano/__init__.py
--------------------------------------------------------------------------------
/blockfrost/api/cardano/accounts.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from blockfrost.utils import request_wrapper, list_request_wrapper
3 |
4 |
5 | @request_wrapper
6 | def accounts(self, stake_address: str, **kwargs):
7 | """
8 | Obtain information about a specific networkStake account.
9 |
10 | https://docs.blockfrost.io/#tag/Cardano-Accounts/paths/~1accounts~1{stake_address}/get
11 |
12 | :param stake_address: Bech32 stake address.
13 | :type stake_address: str
14 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
15 | :type return_type: str
16 | :returns object.
17 | :rtype: Namespace
18 | :raises ApiError: If API fails
19 | :raises Exception: If the API response is somehow malformed.
20 | """
21 | return requests.get(
22 | url=f"{self.url}/accounts/{stake_address}",
23 | headers=self.default_headers
24 | )
25 |
26 |
27 | @list_request_wrapper
28 | def account_rewards(self, stake_address: str, **kwargs):
29 | """
30 | Obtain information about the history of a specific account.
31 |
32 | https://docs.blockfrost.io/#tag/Cardano-Accounts/paths/~1accounts~1{stake_address}~1rewards/get
33 |
34 | :param stake_address: Bech32 stake address.
35 | :type stake_address: str
36 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
37 | :type return_type: str
38 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
39 | :type gather_pages: bool
40 | :param count: Optional. Default: 100. The number of results displayed on one page.
41 | :type count: int
42 | :param page: Optional. The page number for listing the results.
43 | :type page: int
44 | :param order: Optional. "asc" or "desc". Default: "asc".
45 | :type order: str
46 | :returns A list of objects.
47 | :rtype [Namespace]
48 | :raises ApiError: If API fails
49 | :raises Exception: If the API response is somehow malformed.
50 | """
51 | return requests.get(
52 | url=f"{self.url}/accounts/{stake_address}/rewards",
53 | params=self.query_parameters(kwargs),
54 | headers=self.default_headers
55 | )
56 |
57 |
58 | @list_request_wrapper
59 | def account_history(self, stake_address: str, **kwargs):
60 | """
61 | Obtain information about the history of a specific account.
62 |
63 | https://docs.blockfrost.io/#tag/Cardano-Accounts/paths/~1accounts~1{stake_address}~1history/get
64 |
65 | :param stake_address: Bech32 stake address.
66 | :type stake_address: str
67 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
68 | :type return_type: str
69 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
70 | :type gather_pages: bool
71 | :param count: Optional. Default: 100. The number of results displayed on one page.
72 | :type count: int
73 | :param page: Optional. The page number for listing the results.
74 | :type page: int
75 | :param order: Optional. "asc" or "desc". Default: "asc".
76 | :type order: str
77 | :returns A list of objects.
78 | :rtype [Namespace]
79 | :raises ApiError: If API fails
80 | :raises Exception: If the API response is somehow malformed.
81 | """
82 | return requests.get(
83 | url=f"{self.url}/accounts/{stake_address}/history",
84 | params=self.query_parameters(kwargs),
85 | headers=self.default_headers
86 | )
87 |
88 |
89 | @list_request_wrapper
90 | def account_delegations(self, stake_address: str, **kwargs):
91 | """
92 | Obtain information about the delegation of a specific account.
93 |
94 | https://docs.blockfrost.io/#tag/Cardano-Accounts/paths/~1accounts~1{stake_address}~1delegations/get
95 |
96 | :param stake_address: Bech32 stake address.
97 | :type stake_address: str
98 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
99 | :type return_type: str
100 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
101 | :type gather_pages: bool
102 | :param count: Optional. Default: 100. The number of results displayed on one page.
103 | :type count: int
104 | :param page: Optional. The page number for listing the results.
105 | :type page: int
106 | :param order: Optional. "asc" or "desc". Default: "asc".
107 | :type order: str
108 | :returns A list of objects.
109 | :rtype [Namespace]
110 | :raises ApiError: If API fails
111 | :raises Exception: If the API response is somehow malformed.
112 | """
113 | return requests.get(
114 | url=f"{self.url}/accounts/{stake_address}/delegations",
115 | params=self.query_parameters(kwargs),
116 | headers=self.default_headers
117 | )
118 |
119 |
120 | @list_request_wrapper
121 | def account_registrations(self, stake_address: str, **kwargs):
122 | """
123 | Obtain information about the registrations and deregistrations of a specific account.
124 |
125 | https://docs.blockfrost.io/#tag/Cardano-Accounts/paths/~1accounts~1{stake_address}~1registrations/get
126 |
127 | :param stake_address: Bech32 stake address.
128 | :type stake_address: str
129 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
130 | :type return_type: str
131 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
132 | :type gather_pages: bool
133 | :param count: Optional. Default: 100. The number of results displayed on one page.
134 | :type count: int
135 | :param page: Optional. The page number for listing the results.
136 | :type page: int
137 | :param order: Optional. "asc" or "desc". Default: "asc".
138 | :type order: str
139 | :returns A list of objects.
140 | :rtype [Namespace]
141 | :raises ApiError: If API fails
142 | :raises Exception: If the API response is somehow malformed.
143 | """
144 | return requests.get(
145 | url=f"{self.url}/accounts/{stake_address}/registrations",
146 | params=self.query_parameters(kwargs),
147 | headers=self.default_headers
148 | )
149 |
150 |
151 | @list_request_wrapper
152 | def account_withdrawals(self, stake_address: str, **kwargs):
153 | """
154 | Obtain information about the withdrawals of a specific account.
155 |
156 | https://docs.blockfrost.io/#tag/Cardano-Accounts/paths/~1accounts~1{stake_address}~1withdrawals/get
157 |
158 | :param stake_address: Bech32 stake address.
159 | :type stake_address: str
160 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
161 | :type return_type: str
162 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
163 | :type gather_pages: bool
164 | :param count: Optional. Default: 100. The number of results displayed on one page.
165 | :type count: int
166 | :param page: Optional. The page number for listing the results.
167 | :type page: int
168 | :param order: Optional. "asc" or "desc". Default: "asc".
169 | :type order: str
170 | :returns A list of objects.
171 | :rtype [Namespace]
172 | :raises ApiError: If API fails
173 | :raises Exception: If the API response is somehow malformed.
174 | """
175 | return requests.get(
176 | url=f"{self.url}/accounts/{stake_address}/withdrawals",
177 | params=self.query_parameters(kwargs),
178 | headers=self.default_headers
179 | )
180 |
181 |
182 | @list_request_wrapper
183 | def account_mirs(self, stake_address: str, **kwargs):
184 | """
185 | Obtain information about the MIRs of a specific account.
186 |
187 | https://docs.blockfrost.io/#tag/Cardano-Accounts/paths/~1accounts~1{stake_address}~1mirs/get
188 |
189 | :param stake_address: Bech32 stake address.
190 | :type stake_address: str
191 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
192 | :type return_type: str
193 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
194 | :type gather_pages: bool
195 | :param count: Optional. Default: 100. The number of results displayed on one page.
196 | :type count: int
197 | :param page: Optional. The page number for listing the results.
198 | :type page: int
199 | :param order: Optional. "asc" or "desc". Default: "asc".
200 | :type order: str
201 | :returns A list of objects.
202 | :rtype [Namespace]
203 | :raises ApiError: If API fails
204 | :raises Exception: If the API response is somehow malformed.
205 | """
206 | return requests.get(
207 | url=f"{self.url}/accounts/{stake_address}/mirs",
208 | params=self.query_parameters(kwargs),
209 | headers=self.default_headers
210 | )
211 |
212 |
213 | @list_request_wrapper
214 | def account_addresses(self, stake_address: str, **kwargs):
215 | """
216 | Obtain information about the addresses of a specific account.
217 |
218 | https://docs.blockfrost.io/#tag/Cardano-Accounts/paths/~1accounts~1{stake_address}~1addresses/get
219 |
220 | :param stake_address: Bech32 stake address.
221 | :type stake_address: str
222 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
223 | :type return_type: str
224 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
225 | :type gather_pages: bool
226 | :param count: Optional. Default: 100. The number of results displayed on one page.
227 | :type count: int
228 | :param page: Optional. The page number for listing the results.
229 | :type page: int
230 | :param order: Optional. "asc" or "desc". Default: "asc".
231 | :type order: str
232 | :returns A list of objects.
233 | :rtype [Namespace]
234 | :raises ApiError: If API fails
235 | :raises Exception: If the API response is somehow malformed.
236 | """
237 | return requests.get(
238 | url=f"{self.url}/accounts/{stake_address}/addresses",
239 | params=self.query_parameters(kwargs),
240 | headers=self.default_headers
241 | )
242 |
243 |
244 | @list_request_wrapper
245 | def account_addresses_assets(self, stake_address: str, **kwargs):
246 | """
247 | Obtain information about assets associated with addresses of a specific account.
248 |
249 | Be careful, as an account could be part of a mangled address and does not necessarily mean the addresses are owned by user as the account.
250 |
251 | https://docs.blockfrost.io/#tag/Cardano-Accounts/paths/~1accounts~1{stake_address}~1addresses~1assets/get
252 |
253 | :param stake_address: Bech32 stake address.
254 | :type stake_address: str
255 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
256 | :type return_type: str
257 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
258 | :type gather_pages: bool
259 | :param count: Optional. Default: 100. The number of results displayed on one page.
260 | :type count: int
261 | :param page: Optional. The page number for listing the results.
262 | :type page: int
263 | :param order: Optional. "asc" or "desc". Default: "asc".
264 | :type order: str
265 | :returns A list of objects.
266 | :rtype [Namespace]
267 | :raises ApiError: If API fails
268 | :raises Exception: If the API response is somehow malformed.
269 | """
270 | return requests.get(
271 | url=f"{self.url}/accounts/{stake_address}/addresses/assets",
272 | params=self.query_parameters(kwargs),
273 | headers=self.default_headers
274 | )
275 |
276 |
277 | @request_wrapper
278 | def account_addresses_total(self, stake_address: str, **kwargs):
279 | """
280 | Obtain summed details about all addresses associated with a given account.
281 |
282 | Be careful, as an account could be part of a mangled address and does not necessarily mean the addresses are owned by user as the account.
283 |
284 | https://docs.blockfrost.io/#tag/Cardano-Addresses/paths/~1accounts~1{stake_address}~1addresses~1total/get
285 |
286 | :param stake_address: Bech32 address.
287 | :type stake_address: str
288 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
289 | :type return_type: str
290 | :returns object.
291 | :rtype: Namespace
292 | :raises ApiError: If API fails
293 | :raises Exception: If the API response is somehow malformed.
294 | """
295 | return requests.get(
296 | url=f"{self.url}/accounts/{stake_address}/addresses/total",
297 | headers=self.default_headers
298 | )
299 |
--------------------------------------------------------------------------------
/blockfrost/api/cardano/addresses.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from blockfrost.utils import request_wrapper, list_request_wrapper
3 |
4 |
5 | @request_wrapper
6 | def address(self, address: str, **kwargs):
7 | """
8 | Obtain information about a specific address.
9 |
10 | https://docs.blockfrost.io/#tag/Cardano-Addresses/paths/~1addresses~1{address}/get
11 |
12 | :param address: Bech32 address.
13 | :type address: str
14 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
15 | :type return_type: str
16 | :returns object.
17 | :rtype: Namespace
18 | :raises ApiError: If API fails
19 | :raises Exception: If the API response is somehow malformed.
20 | """
21 | return requests.get(
22 | url=f"{self.url}/addresses/{address}",
23 | headers=self.default_headers
24 | )
25 |
26 |
27 | @request_wrapper
28 | def address_extended(self, address: str, **kwargs):
29 | """
30 | Obtain information about a specific address.
31 |
32 | https://docs.blockfrost.io/#tag/Cardano-Addresses/paths/~1addresses~1{address}~1extended/get
33 |
34 | :param address: Bech32 address.
35 | :type address: str
36 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
37 | :type return_type: str
38 | :returns object.
39 | :rtype: Namespace
40 | :raises ApiError: If API fails
41 | :raises Exception: If the API response is somehow malformed.
42 | """
43 | return requests.get(
44 | url=f"{self.url}/addresses/{address}/extended",
45 | headers=self.default_headers
46 | )
47 |
48 |
49 | @request_wrapper
50 | def address_total(self, address: str, **kwargs):
51 | """
52 | Obtain details about an address.
53 |
54 | https://docs.blockfrost.io/#tag/Cardano-Addresses/paths/~1addresses~1{address}~1total/get
55 |
56 | :param address: Bech32 address.
57 | :type address: str
58 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
59 | :type return_type: str
60 | :returns object.
61 | :rtype: Namespace
62 | :raises ApiError: If API fails
63 | :raises Exception: If the API response is somehow malformed.
64 | """
65 | return requests.get(
66 | url=f"{self.url}/addresses/{address}/total",
67 | headers=self.default_headers
68 | )
69 |
70 |
71 | @list_request_wrapper
72 | def address_utxos(self, address: str, **kwargs):
73 | """
74 | UTXOs of the address.
75 |
76 | https://docs.blockfrost.io/#tag/Cardano-Addresses/paths/~1addresses~1{address}~1utxos/get
77 |
78 | :param address: Bech32 address.
79 | :type address: str
80 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
81 | :type return_type: str
82 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
83 | :type gather_pages: bool
84 | :param count: Optional. Default: 100. The number of results displayed on one page.
85 | :type count: int
86 | :param page: Optional. The page number for listing the results.
87 | :type page: int
88 | :param order: Optional. "asc" or "desc". Default: "asc".
89 | :type order: str
90 | :returns A list of objects.
91 | :rtype [Namespace]
92 | :raises ApiError: If API fails
93 | :raises Exception: If the API response is somehow malformed.
94 | """
95 | return requests.get(
96 | url=f"{self.url}/addresses/{address}/utxos",
97 | params=self.query_parameters(kwargs),
98 | headers=self.default_headers
99 | )
100 |
101 |
102 | @list_request_wrapper
103 | def address_utxos_asset(self, address: str, asset: str, **kwargs):
104 | """
105 | UTXOs of the address.
106 |
107 | https://docs.blockfrost.io/#tag/Cardano-Addresses/paths/~1addresses~1{address}~1utxos~1{asset}/get
108 |
109 | :param address: Bech32 address.
110 | :type address: str
111 | :param asset: Concatenation of the policy_id and hex-encoded asset_name.
112 | :type asset: str
113 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
114 | :type return_type: str
115 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
116 | :type gather_pages: bool
117 | :param count: Optional. Default: 100. The number of results displayed on one page.
118 | :type count: int
119 | :param page: Optional. The page number for listing the results.
120 | :type page: int
121 | :param order: Optional. "asc" or "desc". Default: "asc".
122 | :type order: str
123 | :returns A list of objects.
124 | :rtype [Namespace]
125 | :raises ApiError: If API fails
126 | :raises Exception: If the API response is somehow malformed.
127 | """
128 | return requests.get(
129 | url=f"{self.url}/addresses/{address}/utxos/{asset}",
130 | params=self.query_parameters(kwargs),
131 | headers=self.default_headers
132 | )
133 |
134 |
135 | @list_request_wrapper
136 | def address_transactions(self, address: str, from_block: str = None, to_block: str = None,
137 | **kwargs):
138 | """
139 | Transactions on the address.
140 |
141 | https://docs.blockfrost.io/#tag/Cardano-Addresses/paths/~1addresses~1{address}~1transactions/get
142 |
143 | :param address: Bech32 address.
144 | :type address: str
145 | :param from: The block number and optionally also index from which (inclusive) to start search for results, concatenated using colon. Has to be lower than or equal to to parameter.
146 | :type from: str
147 | :param to: The block number and optionally also index where (inclusive) to end the search for results, concatenated using colon. Has to be higher than or equal to from parameter.
148 | :type to: str
149 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
150 | :type return_type: str
151 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
152 | :type gather_pages: bool
153 | :param count: Optional. Default: 100. The number of results displayed on one page.
154 | :type count: int
155 | :param page: Optional. The page number for listing the results.
156 | :type page: int
157 | :param order: Optional. "asc" or "desc". Default: "asc".
158 | :type order: str
159 | :returns A list of objects.
160 | :rtype [Namespace]
161 | :raises ApiError: If API fails
162 | :raises Exception: If the API response is somehow malformed.
163 | """
164 | return requests.get(
165 | url=f"{self.url}/addresses/{address}/transactions",
166 | params={
167 | 'from': from_block,
168 | 'to': to_block,
169 | **self.query_parameters(kwargs)
170 | },
171 | headers=self.default_headers
172 | )
173 |
--------------------------------------------------------------------------------
/blockfrost/api/cardano/assets.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from blockfrost.utils import request_wrapper, list_request_wrapper
3 |
4 |
5 | @list_request_wrapper
6 | def assets(self, **kwargs):
7 | """
8 | List of assets.
9 |
10 | https://docs.blockfrost.io/#tag/Cardano-Assets/paths/~1assets/get
11 |
12 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
13 | :type return_type: str
14 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
15 | :type gather_pages: bool
16 | :param count: Optional. Default: 100. The number of results displayed on one page.
17 | :type count: int
18 | :param page: Optional. The page number for listing the results.
19 | :type page: int
20 | :param order: Optional. "asc" or "desc". Default: "asc".
21 | :type order: str
22 | :returns A list of objects.
23 | :rtype [Namespace]
24 | :raises ApiError: If API fails
25 | :raises Exception: If the API response is somehow malformed.
26 | """
27 | return requests.get(
28 | url=f"{self.url}/assets",
29 | params=self.query_parameters(kwargs),
30 | headers=self.default_headers
31 | )
32 |
33 |
34 | @request_wrapper
35 | def asset(self, asset: str, **kwargs):
36 | """
37 | Information about a specific asset
38 |
39 | https://docs.blockfrost.io/#tag/Cardano-Assets/paths/~1assets~1{asset}/get
40 |
41 | :param asset: Concatenation of the policy_id and hex-encoded asset_name.
42 | :type asset: str
43 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
44 | :type return_type: str
45 | :returns object.
46 | :rtype: Namespace
47 | :raises ApiError: If API fails
48 | :raises Exception: If the API response is somehow malformed.
49 | """
50 | return requests.get(
51 | url=f"{self.url}/assets/{asset}",
52 | headers=self.default_headers
53 | )
54 |
55 |
56 | @list_request_wrapper
57 | def asset_history(self, asset: str, **kwargs):
58 | """
59 | History of a specific asset
60 |
61 | https://docs.blockfrost.io/#tag/Cardano-Assets/paths/~1assets~1{asset}~1history/get
62 |
63 | :param asset: Concatenation of the policy_id and hex-encoded asset_name.
64 | :type asset: str
65 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
66 | :type return_type: str
67 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
68 | :type gather_pages: bool
69 | :param count: Optional. Default: 100. The number of results displayed on one page.
70 | :type count: int
71 | :param page: Optional. The page number for listing the results.
72 | :type page: int
73 | :param order: Optional. "asc" or "desc". Default: "asc".
74 | :type order: str
75 | :returns A list of objects.
76 | :rtype [Namespace]
77 | :raises ApiError: If API fails
78 | :raises Exception: If the API response is somehow malformed.
79 | """
80 | return requests.get(
81 | url=f"{self.url}/assets/{asset}/history",
82 | params=self.query_parameters(kwargs),
83 | headers=self.default_headers
84 | )
85 |
86 |
87 | @list_request_wrapper
88 | def asset_transactions(self, asset: str, **kwargs):
89 | """
90 | List of a specific asset transactions
91 |
92 | https://docs.blockfrost.io/#tag/Cardano-Assets/paths/~1assets~1{asset}~1transactions/get
93 |
94 | :param asset: Concatenation of the policy_id and hex-encoded asset_name.
95 | :type asset: str
96 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
97 | :type return_type: str
98 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
99 | :type gather_pages: bool
100 | :param count: Optional. Default: 100. The number of results displayed on one page.
101 | :type count: int
102 | :param page: Optional. The page number for listing the results.
103 | :type page: int
104 | :param order: Optional. "asc" or "desc". Default: "asc".
105 | :type order: str
106 | :returns A list of objects.
107 | :rtype [Namespace]
108 | :raises ApiError: If API fails
109 | :raises Exception: If the API response is somehow malformed.
110 | """
111 | return requests.get(
112 | url=f"{self.url}/assets/{asset}/transactions",
113 | params=self.query_parameters(kwargs),
114 | headers=self.default_headers
115 | )
116 |
117 |
118 | @list_request_wrapper
119 | def asset_addresses(self, asset: str, **kwargs):
120 | """
121 | List of a addresses containing a specific asset
122 |
123 | https://docs.blockfrost.io/#tag/Cardano-Assets/paths/~1assets~1{asset}~1addresses/get
124 |
125 | :param asset: Concatenation of the policy_id and hex-encoded asset_name.
126 | :type asset: str
127 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
128 | :type return_type: str
129 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
130 | :type gather_pages: bool
131 | :param count: Optional. Default: 100. The number of results displayed on one page.
132 | :type count: int
133 | :param page: Optional. The page number for listing the results.
134 | :type page: int
135 | :param order: Optional. "asc" or "desc". Default: "asc".
136 | :type order: str
137 | :returns A list of objects.
138 | :rtype [Namespace]
139 | :raises ApiError: If API fails
140 | :raises Exception: If the API response is somehow malformed.
141 | """
142 | return requests.get(
143 | url=f"{self.url}/assets/{asset}/addresses",
144 | params=self.query_parameters(kwargs),
145 | headers=self.default_headers
146 | )
147 |
148 |
149 | @list_request_wrapper
150 | def assets_policy(self, policy_id: str, **kwargs):
151 | """
152 | List of asset minted under a specific policy
153 |
154 | https://docs.blockfrost.io/#tag/Cardano-Assets/paths/~1assets~1policy~1{policy_id}/get
155 |
156 | :param policy_id: Specific policy_id.
157 | :type policy_id: str
158 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
159 | :type return_type: str
160 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
161 | :type gather_pages: bool
162 | :param count: Optional. Default: 100. The number of results displayed on one page.
163 | :type count: int
164 | :param page: Optional. The page number for listing the results.
165 | :type page: int
166 | :param order: Optional. "asc" or "desc". Default: "asc".
167 | :type order: str
168 | :returns A list of objects.
169 | :rtype [Namespace]
170 | :raises ApiError: If API fails
171 | :raises Exception: If the API response is somehow malformed.
172 | """
173 | return requests.get(
174 | url=f"{self.url}/assets/policy/{policy_id}",
175 | params=self.query_parameters(kwargs),
176 | headers=self.default_headers
177 | )
178 |
--------------------------------------------------------------------------------
/blockfrost/api/cardano/blocks.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from blockfrost.utils import request_wrapper, list_request_wrapper
3 |
4 |
5 | @request_wrapper
6 | def block_latest(self, **kwargs):
7 | """
8 | Return the latest block available to the backends, also known as the tip of the blockchain.
9 |
10 | https://docs.blockfrost.io/#tag/Cardano-Blocks/paths/~1blocks~1latest/get
11 |
12 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
13 | :type return_type: str
14 | :returns object.
15 | :rtype: Namespace
16 | :raises ApiError: If API fails
17 | :raises Exception: If the API response is somehow malformed.
18 | """
19 | return requests.get(
20 | url=f"{self.url}/blocks/latest",
21 | headers=self.default_headers
22 | )
23 |
24 |
25 | @list_request_wrapper
26 | def block_latest_transactions(self, **kwargs):
27 | """
28 | Return the transactions within the latest block.
29 |
30 | https://docs.blockfrost.io/#tag/Cardano-Blocks/paths/~1blocks~1latest~1txs/get
31 |
32 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
33 | :type gather_pages: bool
34 | :param count: Optional. Default: 100. The number of results displayed on one page.
35 | :type count: int
36 | :param page: Optional. The page number for listing the results.
37 | :type page: int
38 | :param order: Optional. "asc" or "desc". Default: "asc".
39 | :type order: str
40 | :returns A list of str objects.
41 | :rtype [str]
42 | :raises ApiError: If API fails
43 | :raises Exception: If the API response is somehow malformed.
44 | """
45 | return requests.get(
46 | url=f"{self.url}/blocks/latest/txs",
47 | params=self.query_parameters(kwargs),
48 | headers=self.default_headers
49 | )
50 |
51 |
52 | @request_wrapper
53 | def block(self, hash_or_number: str, **kwargs):
54 | """
55 | Return the content of a requested block.
56 |
57 | https://docs.blockfrost.io/#tag/Cardano-Blocks/paths/~1blocks~1{hash_or_number}/get
58 |
59 | :param hash_or_number: Hash or number of the requested block.
60 | :type hash_or_number: str
61 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
62 | :type return_type: str
63 | :returns object.
64 | :rtype: Namespace
65 | :raises ApiError: If API fails
66 | :raises Exception: If the API response is somehow malformed.
67 | """
68 | return requests.get(
69 | url=f"{self.url}/blocks/{hash_or_number}",
70 | headers=self.default_headers
71 | )
72 |
73 |
74 | @request_wrapper
75 | def block_slot(self, slot_number: int, **kwargs):
76 | """
77 | Return the content of a requested block for a specific slot.
78 |
79 | https://docs.blockfrost.io/#tag/Cardano-Blocks/paths/~1blocks~1slot~1{slot_number}/get
80 |
81 | :param slot_number: Slot position for requested block.
82 | :type slot_number: int
83 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
84 | :type return_type: str
85 | :returns object.
86 | :rtype: Namespace
87 | :raises ApiError: If API fails
88 | :raises Exception: If the API response is somehow malformed.
89 | """
90 | return requests.get(
91 | url=f"{self.url}/blocks/slot/{slot_number}",
92 | headers=self.default_headers
93 | )
94 |
95 |
96 | @request_wrapper
97 | def block_epoch_slot(self, epoch_number: int, slot_number: int, **kwargs):
98 | """
99 | Return the content of a requested block for a specific slot in an epoch.
100 |
101 | https://docs.blockfrost.io/#tag/Cardano-Blocks/paths/~1blocks~1epoch~1{epoch_number}~1slot~1{slot_number}/get
102 |
103 | :param epoch_number: Epoch for specific epoch slot.
104 | :type epoch_number: int
105 | :param slot_number: Slot position for requested block (epoch_slot).
106 | :type slot_number: int
107 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
108 | :type return_type: str
109 | :returns object.
110 | :rtype: Namespace
111 | :raises ApiError: If API fails
112 | :raises Exception: If the API response is somehow malformed.
113 | """
114 | return requests.get(
115 | url=f"{self.url}/blocks/epoch/{epoch_number}/slot/{slot_number}",
116 | headers=self.default_headers
117 | )
118 |
119 |
120 | @list_request_wrapper
121 | def blocks_next(self, hash_or_number: str, **kwargs):
122 | """
123 | Return the list of blocks following a specific block.
124 |
125 | https://docs.blockfrost.io/#tag/Cardano-Blocks/paths/~1blocks~1{hash_or_number}~1next/get
126 |
127 | :param hash_or_number: Hash or number of the requested block.
128 | :type hash_or_number: str
129 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
130 | :type return_type: str
131 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
132 | :type gather_pages: bool
133 | :param count: Optional. Default: 100. The number of results displayed on one page.
134 | :type count: int
135 | :param page: Optional. The page number for listing the results.
136 | :type page: int
137 | :returns A list of objects.
138 | :rtype [Namespace]
139 | :raises ApiError: If API fails
140 | :raises Exception: If the API response is somehow malformed.
141 | """
142 | return requests.get(
143 | url=f"{self.url}/blocks/{hash_or_number}/next",
144 | params=self.query_parameters(kwargs),
145 | headers=self.default_headers
146 | )
147 |
148 |
149 | @list_request_wrapper
150 | def blocks_previous(self, hash_or_number: str, **kwargs):
151 | """
152 | Return the list of blocks preceding a specific block.
153 |
154 | https://docs.blockfrost.io/#tag/Cardano-Blocks/paths/~1blocks~1{hash_or_number}~1previous/get
155 |
156 | :param hash_or_number: Hash or number of the requested block.
157 | :type hash_or_number: str
158 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
159 | :type return_type: str
160 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
161 | :type gather_pages: bool
162 | :param count: Optional. Default: 100. The number of results displayed on one page.
163 | :type count: int
164 | :param page: Optional. The page number for listing the results.
165 | :type page: int
166 | :returns A list of objects.
167 | :rtype [Namespace]
168 | :raises ApiError: If API fails
169 | :raises Exception: If the API response is somehow malformed.
170 | """
171 | return requests.get(
172 | url=f"{self.url}/blocks/{hash_or_number}/previous",
173 | params=self.query_parameters(kwargs),
174 | headers=self.default_headers
175 | )
176 |
177 |
178 | @list_request_wrapper
179 | def block_transactions(self, hash_or_number: str, **kwargs):
180 | """
181 | Return the transactions within the block.
182 |
183 | https://docs.blockfrost.io/#tag/Cardano-Blocks/paths/~1blocks~1{hash_or_number}~1txs/get
184 |
185 | :param hash_or_number: Hash or number of the requested block.
186 | :type hash_or_number: str
187 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
188 | :type gather_pages: bool
189 | :param count: Optional. Default: 100. The number of results displayed on one page.
190 | :type count: int
191 | :param page: Optional. The page number for listing the results.
192 | :type page: int
193 | :param order: Optional. "asc" or "desc". Default: "asc".
194 | :type order: str
195 | :returns A list of str objects.
196 | :rtype [str]
197 | :raises ApiError: If API fails
198 | :raises Exception: If the API response is somehow malformed.
199 | """
200 | return requests.get(
201 | url=f"{self.url}/blocks/{hash_or_number}/txs",
202 | params=self.query_parameters(kwargs),
203 | headers=self.default_headers
204 | )
205 |
206 |
207 | @list_request_wrapper
208 | def blocks_addresses(self, hash_or_number: str, **kwargs):
209 | """
210 | Return list of addresses affected in the specified block with additional information, sorted by the bech32 address, ascending.
211 |
212 | https://docs.blockfrost.io/#tag/Cardano-Blocks/paths/~1blocks~1{hash_or_number}~1addresses/get
213 |
214 | :param hash_or_number: Hash or number of the requested block.
215 | :type hash_or_number: str
216 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
217 | :type return_type: str
218 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
219 | :type gather_pages: bool
220 | :param count: Optional. Default: 100. The number of results displayed on one page.
221 | :type count: int
222 | :param page: Optional. The page number for listing the results.
223 | :type page: int
224 | :returns A list of objects.
225 | :rtype [Namespace]
226 | :raises ApiError: If API fails
227 | :raises Exception: If the API response is somehow malformed.
228 | """
229 | return requests.get(
230 | url=f"{self.url}/blocks/{hash_or_number}/addresses",
231 | params=self.query_parameters(kwargs),
232 | headers=self.default_headers
233 | )
234 |
--------------------------------------------------------------------------------
/blockfrost/api/cardano/epochs.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from dataclasses import dataclass, field
3 | from blockfrost.utils import request_wrapper, list_request_wrapper
4 |
5 |
6 | @request_wrapper
7 | def epoch_latest(self, **kwargs):
8 | """
9 | Return the information about the latest, therefore current, epoch.
10 |
11 | https://docs.blockfrost.io/#tag/Cardano-Epochs/paths/~1epochs~1latest/get
12 |
13 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
14 | :type return_type: str
15 | :returns object.
16 | :rtype: Namespace
17 | :raises ApiError: If API fails
18 | :raises Exception: If the API response is somehow malformed.
19 | """
20 | return requests.get(
21 | url=f"{self.url}/epochs/latest",
22 | headers=self.default_headers
23 | )
24 |
25 |
26 | @request_wrapper
27 | def epoch_latest_parameters(self, **kwargs):
28 | """
29 | Return the protocol parameters for the latest epoch.
30 |
31 | https://docs.blockfrost.io/#tag/Cardano-Epochs/paths/~1epochs~1latest~1parameters/get
32 |
33 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
34 | :type return_type: str
35 | :returns object.
36 | :rtype: Namespace
37 | :raises ApiError: If API fails
38 | :raises Exception: If the API response is somehow malformed.
39 | """
40 | return requests.get(
41 | url=f"{self.url}/epochs/latest/parameters",
42 | headers=self.default_headers
43 | )
44 |
45 |
46 | @request_wrapper
47 | def epoch(self, number: int, **kwargs):
48 | """
49 | Return the content of the requested epoch.
50 |
51 | https://docs.blockfrost.io/#tag/Cardano-Epochs/paths/~1epochs~1{number}/get
52 |
53 | :param number: Number of the epoch.
54 | :type number: int
55 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
56 | :type return_type: str
57 | :returns object.
58 | :rtype: Namespace
59 | :raises ApiError: If API fails
60 | :raises Exception: If the API response is somehow malformed.
61 | """
62 | return requests.get(
63 | url=f"{self.url}/epochs/{number}",
64 | headers=self.default_headers
65 | )
66 |
67 |
68 | @list_request_wrapper
69 | def epochs_next(self, number: int, **kwargs):
70 | """
71 | Return the list of epochs following a specific epoch.
72 |
73 | https://docs.blockfrost.io/#tag/Cardano-Epochs/paths/~1epochs~1{number}~1next/get
74 |
75 | :param number: Number of the epoch.
76 | :type number: int
77 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
78 | :type return_type: str
79 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
80 | :type gather_pages: bool
81 | :param count: Optional. Default: 100. The number of results displayed on one page.
82 | :type count: int
83 | :param page: Optional. The page number for listing the results.
84 | :type page: int
85 | :returns A list of objects.
86 | :rtype [Namespace]
87 | :raises ApiError: If API fails
88 | :raises Exception: If the API response is somehow malformed.
89 | """
90 | return requests.get(
91 | url=f"{self.url}/epochs/{number}/next",
92 | params=self.query_parameters(kwargs),
93 | headers=self.default_headers
94 | )
95 |
96 |
97 | @list_request_wrapper
98 | def epochs_previous(self, number: int, **kwargs):
99 | """
100 | Return the list of epochs preceding a specific epoch.
101 |
102 | https://docs.blockfrost.io/#tag/Cardano-Epochs/paths/~1epochs~1{number}~1previous/get
103 |
104 | :param number: Number of the epoch.
105 | :type number: int
106 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
107 | :type return_type: str
108 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
109 | :type gather_pages: bool
110 | :param count: Optional. Default: 100. The number of results displayed on one page.
111 | :type count: int
112 | :param page: Optional. The page number for listing the results.
113 | :type page: int
114 | :returns A list of objects.
115 | :rtype [Namespace]
116 | :raises ApiError: If API fails
117 | :raises Exception: If the API response is somehow malformed.
118 | """
119 | return requests.get(
120 | url=f"{self.url}/epochs/{number}/previous",
121 | params=self.query_parameters(kwargs),
122 | headers=self.default_headers
123 | )
124 |
125 |
126 | @list_request_wrapper
127 | def epoch_stakes(self, number: int, **kwargs):
128 | """
129 | Return the active stake distribution for the specified epoch.
130 |
131 | https://docs.blockfrost.io/#tag/Cardano-Epochs/paths/~1epochs~1{number}~1stakes/get
132 |
133 | :param number: Number of the epoch.
134 | :type number: int
135 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
136 | :type return_type: str
137 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
138 | :type gather_pages: bool
139 | :param count: Optional. Default: 100. The number of results displayed on one page.
140 | :type count: int
141 | :param page: Optional. The page number for listing the results.
142 | :type page: int
143 | :returns A list of objects.
144 | :rtype [Namespace]
145 | :raises ApiError: If API fails
146 | :raises Exception: If the API response is somehow malformed.
147 | """
148 | return requests.get(
149 | url=f"{self.url}/epochs/{number}/stakes",
150 | params=self.query_parameters(kwargs),
151 | headers=self.default_headers
152 | )
153 |
154 |
155 | @list_request_wrapper
156 | def epoch_pool_stakes(self, number: int, pool_id: str, **kwargs):
157 | """
158 | Return the active stake distribution for the epoch specified by stake pool.
159 |
160 | https://docs.blockfrost.io/#tag/Cardano-Epochs/paths/~1epochs~1{number}~1stakes~1{pool_id}/get
161 |
162 | :param number: Number of the epoch.
163 | :type number: int
164 | :param pool_id: Stake pool ID to filter.
165 | :type pool_id: int
166 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
167 | :type return_type: str
168 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
169 | :type gather_pages: bool
170 | :param count: Optional. Default: 100. The number of results displayed on one page.
171 | :type count: int
172 | :param page: Optional. The page number for listing the results.
173 | :type page: int
174 | :returns A list of objects.
175 | :rtype [Namespace]
176 | :raises ApiError: If API fails
177 | :raises Exception: If the API response is somehow malformed.
178 | """
179 | return requests.get(
180 | url=f"{self.url}/epochs/{number}/stakes/{pool_id}",
181 | params=self.query_parameters(kwargs),
182 | headers=self.default_headers
183 | )
184 |
185 |
186 | @list_request_wrapper
187 | def epoch_blocks(self, number: int, **kwargs):
188 | """
189 | Return the blocks minted for the epoch specified.
190 |
191 | https://docs.blockfrost.io/#tag/Cardano-Epochs/paths/~1epochs~1{number}~1blocks/get
192 |
193 | :param number: Number of the epoch.
194 | :type number: int
195 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
196 | :type gather_pages: bool
197 | :param count: Optional. Default: 100. The number of results displayed on one page.
198 | :type count: int
199 | :param page: Optional. The page number for listing the results.
200 | :type page: int
201 | :param order: Optional. "asc" or "desc". Default: "asc".
202 | :type order: str
203 | :returns A list of str objects.
204 | :rtype [str]
205 | :raises ApiError: If API fails
206 | :raises Exception: If the API response is somehow malformed.
207 | """
208 | return requests.get(
209 | url=f"{self.url}/epochs/{number}/blocks",
210 | params=self.query_parameters(kwargs),
211 | headers=self.default_headers
212 | )
213 |
214 |
215 | @list_request_wrapper
216 | def epoch_pool_blocks(self, number: int, pool_id: str, **kwargs):
217 | """
218 | Return the block minted for the epoch specified by stake pool.
219 |
220 | https://docs.blockfrost.io/#tag/Cardano-Epochs/paths/~1epochs~1{number}~1blocks~1{pool_id}/get
221 |
222 | :param number: Number of the epoch.
223 | :type number: int
224 | :param pool_id: Stake pool ID to filter.
225 | :type pool_id: int
226 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
227 | :type gather_pages: bool
228 | :param count: Optional. Default: 100. The number of results displayed on one page.
229 | :type count: int
230 | :param page: Optional. The page number for listing the results.
231 | :type page: int
232 | :param order: Optional. "asc" or "desc". Default: "asc".
233 | :type order: str
234 | :returns A list of str objects.
235 | :rtype [str]
236 | :raises ApiError: If API fails
237 | :raises Exception: If the API response is somehow malformed.
238 | """
239 | return requests.get(
240 | url=f"{self.url}/epochs/{number}/blocks/{pool_id}",
241 | params=self.query_parameters(kwargs),
242 | headers=self.default_headers
243 | )
244 |
245 |
246 | @request_wrapper
247 | def epoch_protocol_parameters(self, number: int, **kwargs):
248 | """
249 | Return the protocol parameters for the epoch specified.
250 |
251 | https://docs.blockfrost.io/#tag/Cardano-Epochs/paths/~1epochs~1{number}~1parameters/get
252 |
253 | :param number: Number of the epoch.
254 | :type number: int
255 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
256 | :type return_type: str
257 | :returns object.
258 | :rtype: Namespace
259 | :raises ApiError: If API fails
260 | :raises Exception: If the API response is somehow malformed.
261 | """
262 | return requests.get(
263 | url=f"{self.url}/epochs/{number}/parameters",
264 | headers=self.default_headers
265 | )
266 |
--------------------------------------------------------------------------------
/blockfrost/api/cardano/ledger.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from blockfrost.utils import request_wrapper
3 |
4 |
5 | @request_wrapper
6 | def genesis(self, **kwargs):
7 | """
8 | Return the information about blockchain genesis.
9 |
10 | https://docs.blockfrost.io/#tag/Cardano-Ledger/paths/~1genesis/get
11 |
12 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
13 | :type return_type: str
14 | :returns object.
15 | :rtype: Namespace
16 | :raises ApiError: If API fails
17 | :raises Exception: If the API response is somehow malformed.
18 | """
19 | return requests.get(
20 | url=f"{self.url}/genesis",
21 | headers=self.default_headers
22 | )
23 |
--------------------------------------------------------------------------------
/blockfrost/api/cardano/mempool.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from blockfrost.utils import list_request_wrapper
3 |
4 |
5 | @list_request_wrapper
6 | def mempool(self, **kwargs):
7 | """
8 | Obtains transactions that are currently stored in Blockfrost mempool, waiting to be included in a newly minted block.
9 | Returns only transactions submitted via Blockfrost.io.
10 |
11 | https://docs.blockfrost.io/#tag/Cardano-Mempool/paths/~1mempool/get
12 |
13 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
14 | :type return_type: str
15 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
16 | :type gather_pages: bool
17 | :param count: Optional. Default: 100. The number of results displayed on one page.
18 | :type count: int
19 | :param page: Optional. The page number for listing the results.
20 | :type page: int
21 | :returns A list of objects.
22 | :rtype [Namespace]
23 | :raises ApiError: If API fails
24 | :raises Exception: If the API response is somehow malformed.
25 | """
26 | return requests.get(
27 | url=f"{self.url}/mempool",
28 | params=self.query_parameters(kwargs),
29 | headers=self.default_headers
30 | )
31 |
32 | @list_request_wrapper
33 | def mempool_tx(self, hash: str, **kwargs):
34 | """
35 | Obtains mempool transaction
36 |
37 | https://docs.blockfrost.io/#tag/Cardano-Mempool/paths/~1mempool~1%7Bhash%7D/get
38 |
39 | :param hash: Hash of the requested transaction.
40 | :type hash: str
41 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
42 | :type return_type: str
43 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
44 | :type gather_pages: bool
45 | :param count: Optional. Default: 100. The number of results displayed on one page.
46 | :type count: int
47 | :param page: Optional. The page number for listing the results.
48 | :type page: int
49 | :returns A list of objects.
50 | :rtype [Namespace]
51 | :raises ApiError: If API fails
52 | :raises Exception: If the API response is somehow malformed.
53 | """
54 | return requests.get(
55 | url=f"{self.url}/mempool/{hash}",
56 | params=self.query_parameters(kwargs),
57 | headers=self.default_headers
58 | )
59 |
60 | @list_request_wrapper
61 | def mempool_address(self, address: str, **kwargs):
62 | """
63 | Obtains list of mempool transactions where at least one of the transaction inputs or outputs belongs to the address (paginated).
64 | Shows only transactions submitted via Blockfrost.io.
65 |
66 | https://docs.blockfrost.io/#tag/Cardano-Mempool/paths/~1mempool~1addresses~1%7Baddress%7D/get
67 |
68 | :param address: Bech32 address.
69 | :type address: str
70 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
71 | :type return_type: str
72 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
73 | :type gather_pages: bool
74 | :param count: Optional. Default: 100. The number of results displayed on one page.
75 | :type count: int
76 | :param page: Optional. The page number for listing the results.
77 | :type page: int
78 | :returns A list of objects.
79 | :rtype [Namespace]
80 | :raises ApiError: If API fails
81 | :raises Exception: If the API response is somehow malformed.
82 | """
83 | return requests.get(
84 | url=f"{self.url}/mempool/addresses/{address}",
85 | params=self.query_parameters(kwargs),
86 | headers=self.default_headers
87 | )
88 |
89 |
--------------------------------------------------------------------------------
/blockfrost/api/cardano/metadata.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from blockfrost.utils import list_request_wrapper
3 |
4 |
5 | @list_request_wrapper
6 | def metadata_labels(self, **kwargs):
7 | """
8 | List of all used transaction metadata labels.
9 |
10 | https://docs.blockfrost.io/#tag/Cardano-Metadata/paths/~1metadata~1txs~1labels/get
11 |
12 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
13 | :type return_type: str
14 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
15 | :type gather_pages: bool
16 | :param count: Optional. Default: 100. The number of results displayed on one page.
17 | :type count: int
18 | :param page: Optional. The page number for listing the results.
19 | :type page: int
20 | :param order: Optional. "asc" or "desc". Default: "asc".
21 | :type order: str
22 | :returns A list of objects.
23 | :rtype [Namespace]
24 | :raises ApiError: If API fails
25 | :raises Exception: If the API response is somehow malformed.
26 | """
27 | return requests.get(
28 | url=f"{self.url}/metadata/txs/labels",
29 | params=self.query_parameters(kwargs),
30 | headers=self.default_headers
31 | )
32 |
33 |
34 | @list_request_wrapper
35 | def metadata_label_json(self, label: str, **kwargs):
36 | """
37 | Transaction metadata per label.
38 |
39 | https://docs.blockfrost.io/#tag/Cardano-Metadata/paths/~1metadata~1txs~1labels~1{label}/get
40 |
41 | :param label: Metadata label
42 | :type label: str
43 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
44 | :type return_type: str
45 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
46 | :type gather_pages: bool
47 | :param count: Optional. Default: 100. The number of results displayed on one page.
48 | :type count: int
49 | :param page: Optional. The page number for listing the results.
50 | :type page: int
51 | :param order: Optional. "asc" or "desc". Default: "asc".
52 | :type order: str
53 | :returns A list of objects.
54 | :rtype [Namespace]
55 | :raises ApiError: If API fails
56 | :raises Exception: If the API response is somehow malformed.
57 | """
58 | return requests.get(
59 | url=f"{self.url}/metadata/txs/labels/{label}",
60 | params=self.query_parameters(kwargs),
61 | headers=self.default_headers
62 | )
63 |
64 |
65 | @list_request_wrapper
66 | def metadata_label_cbor(self, label: str, **kwargs):
67 | """
68 | Transaction metadata per label.
69 |
70 | https://docs.blockfrost.io/#tag/Cardano-Metadata/paths/~1metadata~1txs~1labels~1{label}~1cbor/get
71 |
72 | :param label: Metadata label
73 | :type label: str
74 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
75 | :type return_type: str
76 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
77 | :type gather_pages: bool
78 | :param count: Optional. Default: 100. The number of results displayed on one page.
79 | :type count: int
80 | :param page: Optional. The page number for listing the results.
81 | :type page: int
82 | :param order: Optional. "asc" or "desc". Default: "asc".
83 | :type order: str
84 | :returns A list of objects.
85 | :rtype [Namespace]
86 | :raises ApiError: If API fails
87 | :raises Exception: If the API response is somehow malformed.
88 | """
89 | return requests.get(
90 | url=f"{self.url}/metadata/txs/labels/{label}/cbor",
91 | params=self.query_parameters(kwargs),
92 | headers=self.default_headers
93 | )
94 |
--------------------------------------------------------------------------------
/blockfrost/api/cardano/network.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from blockfrost.utils import request_wrapper
3 |
4 |
5 | @request_wrapper
6 | def network(self, **kwargs):
7 | """
8 | Return detailed network information.
9 |
10 | https://docs.blockfrost.io/#tag/Cardano-Network/paths/~1network/get
11 |
12 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
13 | :type return_type: str
14 | :returns object.
15 | :rtype: Namespace
16 | :raises ApiError: If API fails
17 | :raises Exception: If the API response is somehow malformed.
18 | """
19 | return requests.get(
20 | url=f"{self.url}/network",
21 | headers=self.default_headers
22 | )
23 |
--------------------------------------------------------------------------------
/blockfrost/api/cardano/pools.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from blockfrost.utils import request_wrapper, list_request_wrapper
3 |
4 |
5 | @list_request_wrapper
6 | def pools(self, **kwargs):
7 | """
8 | List of registered stake pools.
9 |
10 | https://docs.blockfrost.io/#tag/Cardano-Pools/paths/~1pools/get
11 |
12 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
13 | :type gather_pages: bool
14 | :param count: Optional. Default: 100. The number of results displayed on one page.
15 | :type count: int
16 | :param page: Optional. The page number for listing the results.
17 | :type page: int
18 | :param order: Optional. "asc" or "desc". Default: "asc".
19 | :type order: str
20 | :returns A list of str objects.
21 | :rtype [str]
22 | :raises ApiError: If API fails
23 | :raises Exception: If the API response is somehow malformed.
24 | """
25 | return requests.get(
26 | url=f"{self.url}/pools",
27 | params=self.query_parameters(kwargs),
28 | headers=self.default_headers
29 | )
30 |
31 |
32 | @list_request_wrapper
33 | def pools_extended(self, **kwargs):
34 | """
35 | List of registered stake pools with additional information.
36 |
37 | https://docs.blockfrost.io/#tag/Cardano-Pools/paths/~1pools~1extended/get
38 |
39 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
40 | :type gather_pages: bool
41 | :param count: Optional. Default: 100. The number of results displayed on one page.
42 | :type count: int
43 | :param page: Optional. The page number for listing the results.
44 | :type page: int
45 | :param order: Optional. "asc" or "desc". Default: "asc".
46 | :type order: str
47 | :returns A list of objects.
48 | :rtype [Namespace]
49 | :raises ApiError: If API fails
50 | :raises Exception: If the API response is somehow malformed.
51 | """
52 | return requests.get(
53 | url=f"{self.url}/pools/extended",
54 | params=self.query_parameters(kwargs),
55 | headers=self.default_headers
56 | )
57 |
58 |
59 | @list_request_wrapper
60 | def pools_retired(self, **kwargs):
61 | """
62 | List of already retired pools.
63 |
64 | https://docs.blockfrost.io/#tag/Cardano-Pools/paths/~1pools~1retired/get
65 |
66 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
67 | :type gather_pages: bool
68 | :param count: Optional. Default: 100. The number of results displayed on one page.
69 | :type count: int
70 | :param page: Optional. The page number for listing the results.
71 | :type page: int
72 | :param order: Optional. "asc" or "desc". Default: "asc".
73 | :type order: str
74 | :returns A list of objects.
75 | :rtype [Namespace]
76 | :raises ApiError: If API fails
77 | :raises Exception: If the API response is somehow malformed.
78 | """
79 | return requests.get(
80 | url=f"{self.url}/pools/retired",
81 | params=self.query_parameters(kwargs),
82 | headers=self.default_headers
83 | )
84 |
85 |
86 | @list_request_wrapper
87 | def pools_retiring(self, **kwargs):
88 | """
89 | List of stake pools retiring in the upcoming epochs
90 |
91 | https://docs.blockfrost.io/#tag/Cardano-Pools/paths/~1pools~1retiring/get
92 |
93 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
94 | :type gather_pages: bool
95 | :param count: Optional. Default: 100. The number of results displayed on one page.
96 | :type count: int
97 | :param page: Optional. The page number for listing the results.
98 | :type page: int
99 | :param order: Optional. "asc" or "desc". Default: "asc".
100 | :type order: str
101 | :returns A list of objects.
102 | :rtype [Namespace]
103 | :raises ApiError: If API fails
104 | :raises Exception: If the API response is somehow malformed.
105 | """
106 | return requests.get(
107 | url=f"{self.url}/pools/retiring",
108 | params=self.query_parameters(kwargs),
109 | headers=self.default_headers
110 | )
111 |
112 |
113 | @request_wrapper
114 | def pool(self, pool_id: str, **kwargs):
115 | """
116 | Pool information.
117 |
118 | https://docs.blockfrost.io/#tag/Cardano-Pools/paths/~1pools~1{pool_id}/get
119 |
120 | :param pool_id: Bech32 or hexadecimal pool ID.
121 | :type pool_id: str
122 | :returns object.
123 | :rtype: Namespace
124 | :raises ApiError: If API fails
125 | :raises Exception: If the API response is somehow malformed.
126 | """
127 | return requests.get(
128 | url=f"{self.url}/pools/{pool_id}",
129 | headers=self.default_headers
130 | )
131 |
132 |
133 | @list_request_wrapper
134 | def pool_history(self, pool_id: str, **kwargs):
135 | """
136 | History of stake pool parameters over epochs.
137 |
138 | https://docs.blockfrost.io/#tag/Cardano-Pools/paths/~1pools~1{pool_id}~1history/get
139 |
140 | :param pool_id: Bech32 or hexadecimal pool ID.
141 | :type pool_id: str
142 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
143 | :type gather_pages: bool
144 | :param count: Optional. Default: 100. The number of results displayed on one page.
145 | :type count: int
146 | :param page: Optional. The page number for listing the results.
147 | :type page: int
148 | :param order: Optional. "asc" or "desc". Default: "asc".
149 | :type order: str
150 | :returns A list of objects.
151 | :rtype [Namespace]
152 | :raises ApiError: If API fails
153 | :raises Exception: If the API response is somehow malformed.
154 | """
155 | return requests.get(
156 | url=f"{self.url}/pools/{pool_id}/history",
157 | params=self.query_parameters(kwargs),
158 | headers=self.default_headers
159 | )
160 |
161 |
162 | @request_wrapper
163 | def pool_metadata(self, pool_id: str, **kwargs):
164 | """
165 | Stake pool registration metadata.
166 |
167 | https://docs.blockfrost.io/#tag/Cardano-Pools/paths/~1pools~1{pool_id}~1metadata/get
168 |
169 | :param pool_id: Bech32 or hexadecimal pool ID.
170 | :type pool_id: str
171 | :returns object.
172 | :rtype: Namespace
173 | :raises ApiError: If API fails
174 | :raises Exception: If the API response is somehow malformed.
175 | """
176 | return requests.get(
177 | url=f"{self.url}/pools/{pool_id}/metadata",
178 | headers=self.default_headers
179 | )
180 |
181 |
182 | @list_request_wrapper
183 | def pool_relays(self, pool_id: str, **kwargs):
184 | """
185 | Relays of a stake pool.
186 |
187 | https://docs.blockfrost.io/#tag/Cardano-Pools/paths/~1pools~1{pool_id}~1relays/get
188 |
189 | :param pool_id: Bech32 or hexadecimal pool ID.
190 | :type pool_id: str
191 | :returns A list of objects.
192 | :rtype [Namespace]
193 | :raises ApiError: If API fails
194 | :raises Exception: If the API response is somehow malformed.
195 | """
196 | return requests.get(
197 | url=f"{self.url}/pools/{pool_id}/relays",
198 | headers=self.default_headers
199 | )
200 |
201 |
202 | @list_request_wrapper
203 | def pool_delegators(self, pool_id: str, **kwargs):
204 | """
205 | List of current stake pools delegators.
206 |
207 | https://docs.blockfrost.io/#tag/Cardano-Pools/paths/~1pools~1{pool_id}~1delegators/get
208 |
209 | :param pool_id: Bech32 or hexadecimal pool ID.
210 | :type pool_id: str
211 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
212 | :type gather_pages: bool
213 | :param count: Optional. Default: 100. The number of results displayed on one page.
214 | :type count: int
215 | :param page: Optional. The page number for listing the results.
216 | :type page: int
217 | :param order: Optional. "asc" or "desc". Default: "asc".
218 | :type order: str
219 | :returns A list of objects.
220 | :rtype [Namespace]
221 | :raises ApiError: If API fails
222 | :raises Exception: If the API response is somehow malformed.
223 | """
224 | return requests.get(
225 | url=f"{self.url}/pools/{pool_id}/delegators",
226 | params=self.query_parameters(kwargs),
227 | headers=self.default_headers
228 | )
229 |
230 |
231 | @list_request_wrapper
232 | def pool_blocks(self, pool_id: str, **kwargs):
233 | """
234 | List of stake pools blocks.
235 |
236 | https://docs.blockfrost.io/#tag/Cardano-Pools/paths/~1pools~1{pool_id}~1blocks/get
237 |
238 | :param pool_id: Bech32 or hexadecimal pool ID.
239 | :type pool_id: str
240 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
241 | :type gather_pages: bool
242 | :param count: Optional. Default: 100. The number of results displayed on one page.
243 | :type count: int
244 | :param page: Optional. The page number for listing the results.
245 | :type page: int
246 | :param order: Optional. "asc" or "desc". Default: "asc".
247 | :type order: str
248 | :returns A list of str objects.
249 | :rtype [str]
250 | :raises ApiError: If API fails
251 | :raises Exception: If the API response is somehow malformed.
252 | """
253 | return requests.get(
254 | url=f"{self.url}/pools/{pool_id}/blocks",
255 | params=self.query_parameters(kwargs),
256 | headers=self.default_headers
257 | )
258 |
259 |
260 | @list_request_wrapper
261 | def pool_updates(self, pool_id: str, **kwargs):
262 | """
263 | List of certificate updates to the stake pool.
264 |
265 | https://docs.blockfrost.io/#tag/Cardano-Pools/paths/~1pools~1{pool_id}~1updates/get
266 |
267 | :param pool_id: Bech32 or hexadecimal pool ID.
268 | :type pool_id: str
269 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
270 | :type gather_pages: bool
271 | :param count: Optional. Default: 100. The number of results displayed on one page.
272 | :type count: int
273 | :param page: Optional. The page number for listing the results.
274 | :type page: int
275 | :param order: Optional. "asc" or "desc". Default: "asc".
276 | :type order: str
277 | :returns A list of objects.
278 | :rtype [Namespace]
279 | :raises ApiError: If API fails
280 | :raises Exception: If the API response is somehow malformed.
281 | """
282 | return requests.get(
283 | url=f"{self.url}/pools/{pool_id}/updates",
284 | params=self.query_parameters(kwargs),
285 | headers=self.default_headers
286 | )
287 |
--------------------------------------------------------------------------------
/blockfrost/api/cardano/scripts.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from blockfrost.utils import request_wrapper, list_request_wrapper
3 |
4 |
5 | @list_request_wrapper
6 | def scripts(self, **kwargs):
7 | """
8 | List of scripts.
9 |
10 | https://docs.blockfrost.io/#tag/Cardano-Scripts/paths/~1scripts/get
11 |
12 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
13 | :type return_type: str
14 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
15 | :type gather_pages: bool
16 | :param count: Optional. Default: 100. The number of results displayed on one page.
17 | :type count: int
18 | :param page: Optional. The page number for listing the results.
19 | :type page: int
20 | :param order: Optional. "asc" or "desc". Default: "asc".
21 | :type order: str
22 | :returns A list of objects.
23 | :rtype [Namespace]
24 | :raises ApiError: If API fails
25 | :raises Exception: If the API response is somehow malformed.
26 | """
27 | return requests.get(
28 | url=f"{self.url}/scripts",
29 | params=self.query_parameters(kwargs),
30 | headers=self.default_headers
31 | )
32 |
33 |
34 | @request_wrapper
35 | def script(self, script_hash: str, **kwargs):
36 | """
37 | Information about a specific script.
38 |
39 | https://docs.blockfrost.io/#tag/Cardano-Scripts/paths/~1scripts~1{script_hash}/get
40 |
41 | :param script_hash: Hash of the script.
42 | :type script_hash: str
43 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
44 | :type return_type: str
45 | :returns object.
46 | :rtype: Namespace
47 | :raises ApiError: If API fails
48 | :raises Exception: If the API response is somehow malformed.
49 | """
50 | return requests.get(
51 | url=f"{self.url}/scripts/{script_hash}",
52 | headers=self.default_headers
53 | )
54 |
55 |
56 | @request_wrapper
57 | def script_json(self, script_hash: str, **kwargs):
58 | """
59 | JSON representation of a timelock script.
60 |
61 | https://docs.blockfrost.io/#tag/Cardano-Scripts/paths/~1scripts~1{script_hash}~1json/get
62 |
63 | :param script_hash: Hash of the script.
64 | :type script_hash: str
65 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
66 | :type return_type: str
67 | :returns object.
68 | :rtype: Namespace
69 | :raises ApiError: If API fails
70 | :raises Exception: If the API response is somehow malformed.
71 | """
72 | return requests.get(
73 | url=f"{self.url}/scripts/{script_hash}/json",
74 | headers=self.default_headers
75 | )
76 |
77 |
78 | @request_wrapper
79 | def script_cbor(self, script_hash: str, **kwargs):
80 | """
81 | CBOR representation of a plutus script
82 |
83 | https://docs.blockfrost.io/#tag/Cardano-Scripts/paths/~1scripts~1{script_hash}~1cbor/get
84 |
85 | :param script_hash: Hash of the script.
86 | :type script_hash: str
87 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
88 | :type return_type: str
89 | :returns object.
90 | :rtype: Namespace
91 | :raises ApiError: If API fails
92 | :raises Exception: If the API response is somehow malformed.
93 | """
94 | return requests.get(
95 | url=f"{self.url}/scripts/{script_hash}/cbor",
96 | headers=self.default_headers
97 | )
98 |
99 |
100 | @list_request_wrapper
101 | def script_redeemers(self, script_hash: str, **kwargs):
102 | """
103 | List of redeemers of a specific script.
104 |
105 | https://docs.blockfrost.io/#tag/Cardano-Scripts/paths/~1scripts~1{script_hash}~1redeemers/get
106 |
107 | :param script_hash: Hash of the script.
108 | :type script_hash: str
109 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
110 | :type return_type: str
111 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
112 | :type gather_pages: bool
113 | :param count: Optional. Default: 100. The number of results displayed on one page.
114 | :type count: int
115 | :param page: Optional. The page number for listing the results.
116 | :type page: int
117 | :param order: Optional. "asc" or "desc". Default: "asc".
118 | :type order: str
119 | :returns A list of objects.
120 | :rtype [Namespace]
121 | :raises ApiError: If API fails
122 | :raises Exception: If the API response is somehow malformed.
123 | """
124 | return requests.get(
125 | url=f"{self.url}/scripts/{script_hash}/redeemers",
126 | params=self.query_parameters(kwargs),
127 | headers=self.default_headers
128 | )
129 |
130 |
131 | @request_wrapper
132 | def script_datum(self, datum_hash: str, **kwargs):
133 | """
134 | Query JSON value of a datum by its hash.
135 |
136 | https://docs.blockfrost.io/#tag/Cardano-Scripts/paths/~1scripts~1datum~1{datum_hash}/get
137 |
138 | :param datum_hash: Hash of the datum.
139 | :type datum_hash: str
140 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
141 | :type return_type: str
142 | :returns object.
143 | :rtype: Namespace
144 | :raises ApiError: If API fails
145 | :raises Exception: If the API response is somehow malformed.
146 | """
147 | return requests.get(
148 | url=f"{self.url}/scripts/datum/{datum_hash}",
149 | headers=self.default_headers
150 | )
151 |
152 | @request_wrapper
153 | def script_datum_cbor(self, datum_hash: str, **kwargs):
154 | """
155 | Query CBOR value of a datum by its hash.
156 |
157 | https://docs.blockfrost.io/#tag/Cardano-Scripts/paths/~1scripts~1datum~1{datum_hash}~1cbor/get
158 |
159 | :param datum_hash: Hash of the datum.
160 | :type datum_hash: str
161 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
162 | :type return_type: str
163 | :returns object.
164 | :rtype: Namespace
165 | :raises ApiError: If API fails
166 | :raises Exception: If the API response is somehow malformed.
167 | """
168 | return requests.get(
169 | url=f"{self.url}/scripts/datum/{datum_hash}/cbor",
170 | headers=self.default_headers
171 | )
172 |
--------------------------------------------------------------------------------
/blockfrost/api/cardano/utils.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from blockfrost.utils import request_wrapper, list_request_wrapper
3 |
4 |
5 | @list_request_wrapper
6 | def utils_addresses_xpub(self, xpub: str, role: int, index: int, **kwargs):
7 | """
8 | Derive Shelley address from an xpub
9 |
10 | https://docs.blockfrost.io/#tag/Cardano-Utilities/paths/~1utils~1addresses~1xpub~1{xpub}~1{role}~1{index}/get
11 |
12 | :param xpub: Hex xpub.
13 | :type xpub: str
14 | :param role: Account role.
15 | :type role: int
16 | :param index: Address index.
17 | :type index: int
18 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
19 | :type return_type: str
20 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
21 | :type gather_pages: bool
22 | :param count: Optional. Default: 100. The number of results displayed on one page.
23 | :type count: int
24 | :param page: Optional. The page number for listing the results.
25 | :type page: int
26 | :param order: Optional. "asc" or "desc". Default: "asc".
27 | :type order: str
28 | :returns A list of objects.
29 | :rtype [Namespace]
30 | :raises ApiError: If API fails
31 | :raises Exception: If the API response is somehow malformed.
32 | """
33 | return requests.get(
34 | url=f"{self.url}/utils/addresses/xpub/{xpub}/{role}/{index}",
35 | params=self.query_parameters(kwargs),
36 | headers=self.default_headers
37 | )
38 |
--------------------------------------------------------------------------------
/blockfrost/api/health.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from ..utils import request_wrapper
3 |
4 |
5 | @request_wrapper
6 | def health(self, **kwargs):
7 | """
8 | Return backend status as a boolean. Your application should handle situations when backend for the given chain is unavailable.
9 |
10 | https://docs.blockfrost.io/#tag/Health/paths/~1health/get
11 |
12 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
13 | :type return_type: str
14 | :returns HealthResponse object.
15 | :rtype HealthResponse
16 | :raises ApiError: If API fails
17 | :raises Exception: If the API response is somehow malformed.
18 | """
19 | return requests.get(
20 | url=f"{self.url}/health",
21 | headers=self.default_headers
22 | )
23 |
24 |
25 | @request_wrapper
26 | def clock(self, **kwargs):
27 | """
28 | This endpoint provides the current UNIX time. Your application might use this to verify if the client clock is not out of sync.
29 |
30 | https://docs.blockfrost.io/#tag/Health/paths/~1health~1clock/get
31 |
32 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
33 | :type return_type: str
34 | :returns ClockResponse object.
35 | :rtype ClockResponse
36 | :raises ApiError: If API fails
37 | :raises Exception: If the API response is somehow malformed.
38 | """
39 | return requests.get(
40 | url=f"{self.url}/health/clock",
41 | headers=self.default_headers
42 | )
43 |
--------------------------------------------------------------------------------
/blockfrost/api/metrics.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from dataclasses import dataclass
3 | from ..utils import list_request_wrapper
4 |
5 |
6 | @list_request_wrapper
7 | def metrics(self, **kwargs):
8 | """
9 | History of your Blockfrost usage metrics in the past 30 days.
10 |
11 | https://docs.blockfrost.io/#tag/Metrics/paths/~1metrics~1/get
12 |
13 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
14 | :type return_type: str
15 | :returns A list of objects.
16 | :rtype [Namespace]
17 | :raises ApiError: If API fails
18 | :raises Exception: If the API response is somehow malformed.
19 | """
20 | return requests.get(
21 | url=f"{self.url}/metrics",
22 | headers=self.default_headers
23 | )
24 |
25 |
26 | @list_request_wrapper
27 | def metrics_endpoints(self, **kwargs):
28 | """
29 | History of your Blockfrost usage metrics per endpoint in the past 30 days.
30 |
31 | https://docs.blockfrost.io/#tag/Metrics/paths/~1metrics~1endpoints/get
32 |
33 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
34 | :type return_type: str
35 | :returns A list of objects.
36 | :rtype [Namespace]
37 | :raises ApiError: If API fails
38 | :raises Exception: If the API response is somehow malformed.
39 | """
40 | return requests.get(
41 | url=f"{self.url}/metrics/endpoints",
42 | headers=self.default_headers
43 | )
44 |
--------------------------------------------------------------------------------
/blockfrost/api/nutlink.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from dataclasses import dataclass
3 | from ..utils import request_wrapper, list_request_wrapper
4 |
5 |
6 | @request_wrapper
7 | def nutlink_address(self, address: str, **kwargs):
8 | """
9 | List metadata about specific address
10 |
11 | https://docs.blockfrost.io/#tag/Nut.link
12 |
13 | :param address: Address of a metadata oracle.
14 | :type address: str
15 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
16 | :type return_type: str
17 | :returns NutlinkAddressResponse object.
18 | :rtype NutlinkAddressResponse
19 | :raises ApiError: If API fails
20 | :raises Exception: If the API response is somehow malformed.
21 | """
22 | return requests.get(
23 | url=f"{self.url}/nutlink/{address}",
24 | headers=self.default_headers
25 | )
26 |
27 |
28 | @list_request_wrapper
29 | def nutlink_address_tickers(self, address: str, **kwargs):
30 | """
31 | List tickers for a specific metadata oracle
32 |
33 | https://docs.blockfrost.io/#tag/Nut.link/paths/~1nutlink~1{address}~1tickers/get
34 |
35 | :param address: Address of a metadata oracle.
36 | :type address: str
37 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
38 | :type return_type: str
39 | :param gather_pages: Optional. Default: 100. Will collect all pages into one return
40 | :type gather_pages: bool
41 | :param count: Optional. Default: 1. The number of results displayed on one page.
42 | :type count: int
43 | :param page: Optional. The page number for listing the results.
44 | :type page: int
45 | :param order: Optional. "asc" or "desc". Default: "asc".
46 | :type order: str
47 | :returns A list of NutlinkAddressTickersResponse objects.
48 | :rtype [NutlinkAddressTickersResponse]
49 | :raises ApiError: If API fails
50 | :raises Exception: If the API response is somehow malformed.
51 | """
52 | return requests.get(
53 | url=f"{self.url}/nutlink/{address}/tickers",
54 | params=self.query_parameters(kwargs),
55 | headers=self.default_headers
56 | )
57 |
58 |
59 | @list_request_wrapper
60 | def nutlink_address_ticker(self, address: str, ticker: str, **kwargs):
61 | """
62 | List of records of a specific ticker
63 |
64 | https://docs.blockfrost.io/#tag/Nut.link/paths/~1nutlink~1{address}~1tickers~1{ticker}/get
65 |
66 | :param address: Address of a metadata oracle.
67 | :type address: str
68 | :param ticker: Ticker for the pool record.
69 | :type ticker: str
70 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
71 | :type return_type: str
72 | :param gather_pages: Optional. Default: 100. Will collect all pages into one return
73 | :type gather_pages: bool
74 | :param count: Optional. Default: 1. The number of results displayed on one page.
75 | :type count: int
76 | :param page: Optional. The page number for listing the results.
77 | :type page: int
78 | :param order: Optional. "asc" or "desc". Default: "asc".
79 | :type order: str
80 | :returns A list of NutlinkAddressTickerResponse objects.
81 | :rtype [NutlinkAddressTickerResponse]
82 | :raises ApiError: If API fails
83 | :raises Exception: If the API response is somehow malformed.
84 | """
85 | return requests.get(
86 | url=f"{self.url}/nutlink/{address}/tickers/{ticker}",
87 | params=self.query_parameters(kwargs),
88 | headers=self.default_headers
89 | )
90 |
91 |
92 | @list_request_wrapper
93 | def nutlink_ticker(self, ticker: str, **kwargs):
94 | """
95 | List of records of a specific ticker
96 |
97 | https://docs.blockfrost.io/#tag/Nut.link/paths/~1nutlink~1tickers~1{ticker}/get
98 |
99 | :param ticker: Ticker for the pool record.
100 | :type ticker: str
101 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
102 | :type return_type: str
103 | :param gather_pages: Optional. Default: 100. Will collect all pages into one return
104 | :type gather_pages: bool
105 | :param count: Optional. Default: 1. The number of results displayed on one page.
106 | :type count: int
107 | :param page: Optional. The page number for listing the results.
108 | :type page: int
109 | :param order: Optional. "asc" or "desc". Default: "asc".
110 | :type order: str
111 | :returns A list of NutlinkTickerResponse objects.
112 | :rtype [NutlinkTickerResponse]
113 | :raises ApiError: If API fails
114 | :raises Exception: If the API response is somehow malformed.
115 | """
116 | return requests.get(
117 | url=f"{self.url}/nutlink/tickers/{ticker}",
118 | params=self.query_parameters(kwargs),
119 | headers=self.default_headers
120 | )
121 |
--------------------------------------------------------------------------------
/blockfrost/config.py:
--------------------------------------------------------------------------------
1 | from enum import Enum
2 | try:
3 | from importlib.metadata import version
4 | except ImportError: # for Python<3.8
5 | from importlib_metadata import version
6 |
7 | class ApiUrls(Enum):
8 | mainnet = 'https://cardano-mainnet.blockfrost.io/api'
9 | preprod = 'https://cardano-preprod.blockfrost.io/api'
10 | preview = 'https://cardano-preview.blockfrost.io/api'
11 | testnet = 'https://cardano-testnet.blockfrost.io/api'
12 | ipfs = 'https://ipfs.blockfrost.io/api'
13 |
14 |
15 | DEFAULT_API_VERSION = 'v0'
16 | DEFAULT_ORDER = 'asc'
17 | DEFAULT_PAGINATION_PAGE_COUNT = 1
18 | DEFAULT_PAGINATION_PAGE_ITEMS_COUNT = 100
19 |
20 | ADDRESS_GAP_LIMIT = 20
21 |
22 | package_name = 'blockfrost-python'
23 | version = version(package_name)
24 | USER_AGENT = f'{package_name} {version}'
25 |
--------------------------------------------------------------------------------
/blockfrost/helpers.py:
--------------------------------------------------------------------------------
1 | import hmac
2 | import hashlib
3 | import time
4 |
5 |
6 | class SignatureVerificationError(Exception):
7 | def __init__(self, message, header, request_body):
8 | self.message = message
9 | self.header = header
10 | self.request_body = request_body
11 | super().__init__(self.message)
12 |
13 |
14 | def get_unix_timestamp():
15 | return int(time.time())
16 |
17 |
18 | def verify_webhook_signature(request_body, signature_header, secret, timestamp_tolerance_seconds=600):
19 | # Parse signature header
20 | # Example of Blockfrost-Signature header: t=1648550558,v1=162381a59040c97d9b323cdfec02facdfce0968490ec1732f5d938334c1eed4e,v1=...)
21 | tokens = signature_header.split(',')
22 | timestamp = None
23 | signatures = []
24 | for token in tokens:
25 | key, value = token.split('=')
26 | if key == 't':
27 | timestamp = value
28 | elif key == 'v1':
29 | signatures.append(value)
30 | else:
31 | print('Cannot parse part of the Blockfrost-Signature header, key "{}" is not supported by this version of Blockfrost SDK. Please upgrade.'.format(key))
32 |
33 | if timestamp is None or timestamp.isnumeric() is False or len(tokens) < 2:
34 | # timestamp and at least one signature must be present
35 | raise SignatureVerificationError(
36 | 'Invalid signature header format.', signature_header, request_body)
37 |
38 | if len(signatures) == 0:
39 | # There are no signatures that this version of SDK supports
40 | raise SignatureVerificationError(
41 | 'No signatures with supported version scheme.', signature_header, request_body)
42 |
43 | has_valid_signature = False
44 | for signature in signatures:
45 | # Recreate signature by concatenating the timestamp with the payload (all in bytes),
46 | # then compute HMAC using sha256 and provided secret (webhook auth token)
47 | signature_payload = timestamp.encode() + b"." + request_body
48 | local_signature = hmac.new(
49 | secret.encode(), signature_payload, hashlib.sha256).hexdigest()
50 |
51 | # computed signature should match at least one signature parsed from a signature header
52 | if (hmac.compare_digest(signature, local_signature)):
53 | has_valid_signature = True
54 | break
55 |
56 | if has_valid_signature == False:
57 | raise SignatureVerificationError(
58 | 'No signature matches the expected signature for the payload.', signature_header, request_body)
59 |
60 | current_timestamp = get_unix_timestamp()
61 |
62 | if (current_timestamp - int(timestamp) > timestamp_tolerance_seconds):
63 | # Event is older than timestamp_tolerance_seconds
64 | raise SignatureVerificationError(
65 | 'Signature\'s timestamp is outside of the time tolerance.', signature_header, request_body)
66 | else:
67 | # Successfully validate the signature only if it is within timestamp_tolerance_seconds tolerance
68 | return True
69 |
--------------------------------------------------------------------------------
/blockfrost/ipfs/__init__.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from blockfrost.config import DEFAULT_API_VERSION
4 | from ..utils import Api, ApiUrls
5 |
6 |
7 | class BlockFrostIPFS(Api):
8 |
9 | def __init__(self, project_id: str = None, base_url: str = None, api_version: str = None):
10 | super().__init__(
11 | project_id=project_id,
12 | base_url=base_url if base_url else os.environ.get(
13 | 'BLOCKFROST_IPFS_URL', default=ApiUrls.ipfs.value),
14 | api_version=api_version if base_url else os.environ.get('BLOCKFROST_API_VERSION',
15 | default=DEFAULT_API_VERSION))
16 |
17 | from .add import add
18 | from .gateway import gateway
19 | from .pins import \
20 | pin_object, \
21 | pined_list, \
22 | pined_object, \
23 | pined_object_remove
24 |
--------------------------------------------------------------------------------
/blockfrost/ipfs/add.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from dataclasses import dataclass
3 | from ..utils import request_wrapper
4 |
5 |
6 | @request_wrapper
7 | def add(self, file_path: str, **kwargs):
8 | """
9 | Add a file or directory to IPFS
10 |
11 | You need to `/ipfs/pin/add` an object to avoid it being garbage collected.
12 | This usage is being counted in your user account quota.
13 |
14 | https://docs.blockfrost.io/#tag/IPFS-Add/paths/~1ipfs~1add/post
15 |
16 | :param file_path: Path to file.
17 | :type file_path: str
18 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
19 | :type return_type: str
20 | :returns IPFSObject object.
21 | :rtype IPFSObject
22 | :raises ApiError: If API fails
23 | :raises Exception: If the API response is somehow malformed.
24 | """
25 | with open(file_path, 'rb') as file:
26 | return requests.post(
27 | url=f"{self.url}/ipfs/add",
28 | headers=self.default_headers,
29 | files={'file': file},
30 | )
31 |
--------------------------------------------------------------------------------
/blockfrost/ipfs/gateway.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from ..utils import simple_request_wrapper
3 |
4 |
5 | @simple_request_wrapper
6 | def gateway(self, IPFS_path: str, **kwargs):
7 | """
8 | Retrieve an object from the IFPS gateway (useful if you do not want to rely on a public gateway, such as ipfs.blockfrost.dev).
9 |
10 | https://docs.blockfrost.io/#tag/IPFS-Gateway
11 |
12 | :param IPFS_path: Path to the IPFS object.
13 | :type IPFS_path: str
14 | :returns file text.
15 | :rtype data
16 | :raises ApiError: If API fails
17 | :raises Exception: If the API response is somehow malformed.
18 | """
19 |
20 | response = requests.get(
21 | url=f"{self.url}/ipfs/gateway/{IPFS_path}",
22 | headers=self.default_headers,
23 | )
24 | return response
25 |
--------------------------------------------------------------------------------
/blockfrost/ipfs/pins.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from dataclasses import dataclass
3 | from ..utils import request_wrapper, list_request_wrapper
4 |
5 |
6 | @request_wrapper
7 | def pin_object(self, IPFS_path: str, **kwargs):
8 | """
9 | Pinned objects are counted in your user storage quota.
10 |
11 | https://docs.blockfrost.io/#tag/IPFS-Pins
12 |
13 | :param IPFS_path: Path to the IPFS object.
14 | :type IPFS_path: str
15 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
16 | :type return_type: str
17 | :returns object.
18 | :rtype: Namespace
19 | :raises ApiError: If API fails
20 | :raises Exception: If the API response is somehow malformed.
21 | """
22 | return requests.post(
23 | url=f"{self.url}/ipfs/pin/add/{IPFS_path}",
24 | headers=self.default_headers,
25 | )
26 |
27 |
28 | @list_request_wrapper
29 | def pined_list(self, **kwargs):
30 | """
31 | List objects pinned to local storage
32 |
33 | https://docs.blockfrost.io/#tag/IPFS-Pins/paths/~1ipfs~1pin~1list~1/get
34 |
35 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
36 | :type return_type: str
37 | :param gather_pages: Optional. Default: false. Will collect all pages into one return
38 | :type gather_pages: bool
39 | :param count: Optional. Default: 100. The number of results displayed on one page.
40 | :type count: int
41 | :param page: Optional. The page number for listing the results.
42 | :type page: int
43 | :param order: Optional. "asc" or "desc". Default: "asc".
44 | :type order: str
45 | :returns A list of objects.
46 | :rtype [Namespace]
47 | :raises ApiError: If API fails
48 | :raises Exception: If the API response is somehow malformed.
49 | """
50 | return requests.get(
51 | url=f"{self.url}/ipfs/pin/list",
52 | params=self.query_parameters(kwargs),
53 | headers=self.default_headers,
54 | )
55 |
56 |
57 | @request_wrapper
58 | def pined_object(self, IPFS_path: str, **kwargs):
59 | """
60 | List objects pinned to local storage
61 |
62 | https://docs.blockfrost.io/#tag/IPFS-Pins/paths/~1ipfs~1pin~1list~1{IPFS_path}/get
63 |
64 | :param IPFS_path: Path to the IPFS object.
65 | :type IPFS_path: str
66 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
67 | :type return_type: str
68 | :returns object.
69 | :rtype: Namespace
70 | :raises ApiError: If API fails
71 | :raises Exception: If the API response is somehow malformed.
72 | """
73 | return requests.get(
74 | url=f"{self.url}/ipfs/pin/list/{IPFS_path}",
75 | headers=self.default_headers,
76 | )
77 |
78 |
79 | @request_wrapper
80 | def pined_object_remove(self, IPFS_path: str, **kwargs):
81 | """
82 | Remove pinned objects from local storage
83 |
84 | https://docs.blockfrost.io/#tag/IPFS-Pins/paths/~1ipfs~1pin~1remove~1{IPFS_path}/post
85 |
86 | :param IPFS_path: Path to the IPFS object.
87 | :type IPFS_path: str
88 | :param return_type: Optional. "object", "json" or "pandas". Default: "object".
89 | :type return_type: str
90 | :returns object.
91 | :rtype: Namespace
92 | :raises ApiError: If API fails
93 | :raises Exception: If the API response is somehow malformed.
94 | """
95 | return requests.post(
96 | url=f"{self.url}/ipfs/pin/remove/{IPFS_path}",
97 | headers=self.default_headers,
98 | )
99 |
--------------------------------------------------------------------------------
/blockfrost/utils.py:
--------------------------------------------------------------------------------
1 | import os
2 | import json
3 |
4 | from requests import Response
5 | from functools import wraps
6 |
7 | from .config import ApiUrls, USER_AGENT, DEFAULT_API_VERSION, DEFAULT_PAGINATION_PAGE_ITEMS_COUNT
8 | from types import SimpleNamespace
9 |
10 |
11 | class ApiError(Exception):
12 |
13 | def __init__(self, response: Response):
14 | try:
15 | # assume Response json
16 | response_json = response.json()
17 | super().__init__(response_json)
18 | self.status_code = response_json['status_code']
19 | self.error = response_json['error']
20 | self.message = response_json['message']
21 | except Exception:
22 | super().__init__(response)
23 | self.status_code = response.status_code
24 | self.error = None
25 | self.message = None
26 |
27 |
28 | class Namespace(SimpleNamespace):
29 | def to_dict(self):
30 | return self.__dict__
31 |
32 | def to_json(self):
33 | return json.dumps(self.to_dict())
34 |
35 |
36 | def convert_json_to_object(json_response):
37 | return json.loads(json.dumps(json_response), object_hook=lambda d: Namespace(**d))
38 |
39 |
40 | def convert_json_to_pandas(json_response):
41 | try:
42 | import pandas as pd
43 | return pd.json_normalize(json_response)
44 | except ImportError as error:
45 | raise ImportError(
46 | "To use \"return_type='pandas'\" you must pip install pandas")
47 |
48 |
49 | def simple_request_wrapper(func):
50 | @wraps(func)
51 | def error_wrapper(*args, **kwargs):
52 | request_response: Response = func(*args, **kwargs)
53 | if request_response.status_code != 200:
54 | raise ApiError(request_response)
55 | else:
56 | return request_response
57 |
58 | return error_wrapper
59 |
60 |
61 | def request_wrapper(func):
62 | @wraps(func)
63 | def error_wrapper(*args, **kwargs):
64 | request_response: Response = func(*args, **kwargs)
65 | if request_response.status_code != 200:
66 | raise ApiError(request_response)
67 | else:
68 | if 'return_type' in kwargs:
69 | if kwargs['return_type'] == 'object':
70 | return convert_json_to_object(request_response.json())
71 | elif kwargs['return_type'] == 'pandas':
72 | return convert_json_to_pandas(request_response.json())
73 | elif kwargs['return_type'] == 'json':
74 | return request_response.json()
75 | else:
76 | return convert_json_to_object(request_response.json())
77 |
78 | return error_wrapper
79 |
80 |
81 | def list_request_wrapper(func):
82 | @wraps(func)
83 | def pagination(*args, **kwargs):
84 | def recursive_append(json_list, *args, **kwargs):
85 | request_response: Response = func(*args, **kwargs)
86 | if request_response.status_code != 200:
87 | raise ApiError(request_response)
88 | json_list.extend(request_response.json())
89 | if 'count' not in kwargs:
90 | expected_result_length = DEFAULT_PAGINATION_PAGE_ITEMS_COUNT
91 | else:
92 | expected_result_length = kwargs['count']
93 | if len(request_response.json()) == expected_result_length:
94 | if 'page' not in kwargs:
95 | kwargs['page'] = 2
96 | else:
97 | kwargs['page'] = kwargs['page'] + 1
98 | recursive_append(json_list, *args, **kwargs)
99 | else:
100 | return json_list
101 |
102 | if 'gather_pages' in kwargs and kwargs['gather_pages'] is True:
103 | json_list = []
104 | recursive_append(json_list, *args, **kwargs)
105 | request_json = json_list
106 | else:
107 | request_response: Response = func(*args, **kwargs)
108 | if request_response.status_code != 200:
109 | raise ApiError(request_response)
110 | request_json = request_response.json()
111 | if 'return_type' in kwargs:
112 | if kwargs['return_type'] == 'object':
113 | return convert_json_to_object(request_json)
114 | elif kwargs['return_type'] == 'pandas':
115 | return convert_json_to_pandas(request_json)
116 | elif kwargs['return_type'] == 'json':
117 | return request_json
118 | else:
119 | return convert_json_to_object(request_json)
120 |
121 | return pagination
122 |
123 |
124 | class Api:
125 |
126 | def __init__(
127 | self,
128 | project_id: str = None,
129 | base_url: str = None,
130 | api_version: str = None,
131 | ):
132 | self.project_id = project_id if project_id else os.environ.get(
133 | 'BLOCKFROST_PROJECT_ID')
134 | self.api_version = api_version if api_version else os.environ.get('BLOCKFROST_API_VERSION',
135 | default=DEFAULT_API_VERSION)
136 | self.base_url = base_url
137 |
138 | @property
139 | def url(self):
140 | return f"{self.base_url}/{self.api_version}" if self.api_version else f"{self.base_url}"
141 |
142 | @property
143 | def authentication_header(self):
144 | return {
145 | 'project_id': self.project_id
146 | }
147 |
148 | @property
149 | def user_agent_header(self):
150 | return {
151 | 'User-Agent': USER_AGENT
152 | }
153 |
154 | @property
155 | def default_headers(self):
156 | return {**self.authentication_header, **self.user_agent_header}
157 |
158 | @staticmethod
159 | def query_parameters(kwargs: dict):
160 | """
161 | count
162 | integer <= 100
163 | Default: 100
164 | The number of results displayed on one page.
165 |
166 | page
167 | integer
168 | Default: 1
169 | The page number for listing the results.
170 |
171 | order
172 | string
173 | Default: "asc"
174 | Enum: "asc" "desc"
175 | The ordering of items from the point of view of the blockchain, not the page listing itself. By default, we return oldest first, newest last.
176 | """
177 | return {
178 | "count": kwargs.get('count', None),
179 | "page": kwargs.get('page', None),
180 | "order": kwargs.get('order', None),
181 | }
182 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | requests
2 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | import pathlib
3 | from setuptools import setup, find_packages
4 |
5 | HERE = pathlib.Path(__file__).parent
6 |
7 | long_description = (HERE / 'README.md').read_text(encoding='utf-8')
8 |
9 | setup(
10 | name='blockfrost-python',
11 | version='0.6.0',
12 | description='The official Python SDK for Blockfrost API v0.1.37',
13 | long_description=long_description,
14 | long_description_content_type='text/markdown',
15 | url='https://github.com/blockfrost/blockfrost-python',
16 | # Author details
17 | author='blockfrost.io',
18 | author_email='contact@blockfrost.io',
19 | ghostwriter='https://github.com/mathiasfrohlich',
20 | license='Apache-2.0',
21 | keywords='blockfrost blockchain cardano ipfs',
22 | packages=find_packages(exclude=['tests', 'tests.*']),
23 | python_requires='>=3.7, <4',
24 | requires=[
25 | "importlib_metadata",
26 | ],
27 | install_requires=[
28 | "requests",
29 | ],
30 | tests_require=[
31 | "pytest",
32 | "mock",
33 | "requests-mock",
34 | "pandas",
35 | ],
36 |
37 | classifiers=[ # Optional
38 | # How mature is this project? Common values are
39 | # 3 - Alpha
40 | # 4 - Beta
41 | # 5 - Production/Stable
42 | 'Development Status :: 4 - Beta',
43 |
44 | 'Intended Audience :: Developers',
45 |
46 | 'Topic :: Software Development :: Build Tools',
47 |
48 | 'License :: OSI Approved :: Apache Software License',
49 |
50 | 'Programming Language :: Python :: 3',
51 | 'Programming Language :: Python :: 3.7',
52 | 'Programming Language :: Python :: 3.8',
53 | 'Programming Language :: Python :: 3.9',
54 | 'Programming Language :: Python :: 3.10',
55 | 'Programming Language :: Python :: 3 :: Only',
56 | ],
57 | )
58 |
--------------------------------------------------------------------------------
/shell.nix:
--------------------------------------------------------------------------------
1 | { pkgs ? import {} }:
2 | pkgs.mkShell {
3 | buildInputs = [
4 | (pkgs.python3.withPackages (ps: [
5 | ps.requests
6 | # tests
7 | ps.setuptools
8 | ps.pytest
9 | ps.mock
10 | ps.requests-mock
11 | ps.pandas
12 | ])
13 | )
14 | ];
15 |
16 | shellHook = ''
17 | echo
18 | echo '# blockfrost-python development shell'
19 | echo
20 | echo '## to run unit tests, use'
21 | echo 'pytest'
22 | echo
23 | echo '## to run integration tests, use'
24 | echo 'export BLOCKFROST_PROJECT_ID_MAINNET=mainnet..'
25 | echo 'pytest'
26 | '';
27 | }
28 |
--------------------------------------------------------------------------------
/test-requirements.txt:
--------------------------------------------------------------------------------
1 | pytest
2 | mock
3 | requests-mock
4 | pandas
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blockfrost/blockfrost-python/cb7418e8ce19b6761490cd14f65ebf34cd7e1527/tests/__init__.py
--------------------------------------------------------------------------------
/tests/test_api.py:
--------------------------------------------------------------------------------
1 | import os
2 | from blockfrost import BlockFrostApi, ApiError
3 | from blockfrost.utils import convert_json_to_object
4 |
5 |
6 | def test_root(requests_mock):
7 | api = BlockFrostApi()
8 | mock_data = {
9 | "url": "https://blockfrost.io/",
10 | "version": "0.1.0"
11 | }
12 | requests_mock.get(api.url + '/', json=mock_data)
13 | assert api.root() == convert_json_to_object(mock_data)
14 |
15 |
16 | def test_integration_root():
17 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
18 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
19 | assert api.root()
20 |
21 |
22 | def test_integration_root():
23 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
24 | assert True
25 |
--------------------------------------------------------------------------------
/tests/test_cardano_accounts.py:
--------------------------------------------------------------------------------
1 | import os
2 | from blockfrost import BlockFrostApi, ApiError
3 | from blockfrost.utils import convert_json_to_object
4 |
5 | stake_address = 'stake1ux3g2c9dx2nhhehyrezyxpkstartcqmu9hk63qgfkccw5rqttygt7'
6 |
7 |
8 | def test_accounts(requests_mock):
9 | api = BlockFrostApi()
10 | mock_data = {
11 | "stake_address": stake_address,
12 | "active": True,
13 | "active_epoch": 412,
14 | "controlled_amount": "619154618165",
15 | "rewards_sum": "319154618165",
16 | "withdrawals_sum": "12125369253",
17 | "reserves_sum": "319154618165",
18 | "treasury_sum": "12000000",
19 | "withdrawable_amount": "319154618165",
20 | "pool_id": "pool1pu5jlj4q9w9jlxeu370a3c9myx47md5j5m2str0naunn2q3lkdy"
21 | }
22 | requests_mock.get(f"{api.url}/accounts/{stake_address}", json=mock_data)
23 | assert api.accounts(stake_address=stake_address) == convert_json_to_object(mock_data)
24 |
25 |
26 | def test_integration_accounts():
27 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
28 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
29 | assert api.accounts(stake_address=stake_address)
30 |
31 |
32 | def test_account_rewards(requests_mock):
33 | api = BlockFrostApi()
34 | mock_data = [
35 | {
36 | "epoch": 215,
37 | "amount": "12695385",
38 | "pool_id": "pool1pu5jlj4q9w9jlxeu370a3c9myx47md5j5m2str0naunn2q3lkdy",
39 | "type": "member"
40 | },
41 | {
42 | "epoch": 216,
43 | "amount": "3586329",
44 | "pool_id": "pool1pu5jlj4q9w9jlxeu370a3c9myx47md5j5m2str0naunn2q3lkdy",
45 | "type": "member"
46 | },
47 | {
48 | "epoch": 217,
49 | "amount": "1",
50 | "pool_id": "pool1pu5jlj4q9w9jlxeu370a3c9myx47md5j5m2str0naunn2q3lkdy",
51 | "type": "member"
52 | },
53 | {
54 | "epoch": 217,
55 | "amount": "1337",
56 | "pool_id": "pool1cytwr0n7eas6du2h2xshl8ypa1yqr18f0erlhhjcuczysiunjcs",
57 | "type": "leader"
58 | },
59 | {
60 | "epoch": 218,
61 | "amount": "1395265",
62 | "pool_id": "pool1pu5jlj4q9w9jlxeu370a3c9myx47md5j5m2str0naunn2q3lkdy",
63 | "type": "member"
64 | },
65 | {
66 | "epoch": 218,
67 | "amount": "500000000",
68 | "pool_id": "pool1cytwr0n7eas6du2h2xshl8ypa1yqr18f0erlhhjcuczysiunjcs",
69 | "type": "pool_deposit_refund"
70 | }
71 | ]
72 | requests_mock.get(f"{api.url}/accounts/{stake_address}/rewards", json=mock_data)
73 | assert api.account_rewards(stake_address=stake_address) == convert_json_to_object(mock_data)
74 |
75 |
76 | def test_integration_account_rewards():
77 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
78 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
79 | assert api.account_rewards(stake_address=stake_address)
80 |
81 |
82 | def test_account_history(requests_mock):
83 | api = BlockFrostApi()
84 | mock_data = [
85 | {
86 | "active_epoch": 210,
87 | "amount": "12695385",
88 | "pool_id": "pool1pu5jlj4q9w9jlxeu370a3c9myx47md5j5m2str0naunn2q3lkdy"
89 | },
90 | {
91 | "active_epoch": 211,
92 | "amount": "22695385",
93 | "pool_id": "pool1pu5jlj4q9w9jlxeu370a3c9myx47md5j5m2str0naunn2q3lkdy"
94 | }
95 | ]
96 | requests_mock.get(f"{api.url}/accounts/{stake_address}/history", json=mock_data)
97 | assert api.account_history(stake_address=stake_address) == convert_json_to_object(mock_data)
98 |
99 |
100 | def test_integration_account_history():
101 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
102 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
103 | assert api.account_history(stake_address=stake_address)
104 |
105 |
106 | def test_account_delegations(requests_mock):
107 | api = BlockFrostApi()
108 | mock_data = [
109 | {
110 | "active_epoch": 210,
111 | "tx_hash": "2dd15e0ef6e6a17841cb9541c27724072ce4d4b79b91e58432fbaa32d9572531",
112 | "amount": "12695385",
113 | "pool_id": "pool1pu5jlj4q9w9jlxeu370a3c9myx47md5j5m2str0naunn2q3lkdy"
114 | },
115 | {
116 | "active_epoch": 242,
117 | "tx_hash": "1a0570af966fb355a7160e4f82d5a80b8681b7955f5d44bec0dde628516157f0",
118 | "amount": "12691385",
119 | "pool_id": "pool1kchver88u3kygsak8wgll7htr8uxn5v35lfrsyy842nkscrzyvj"
120 | }
121 | ]
122 | requests_mock.get(f"{api.url}/accounts/{stake_address}/delegations", json=mock_data)
123 | assert api.account_delegations(stake_address=stake_address) == convert_json_to_object(mock_data)
124 |
125 |
126 | def test_integration_account_delegations():
127 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
128 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
129 | assert api.account_delegations(stake_address=stake_address)
130 |
131 |
132 | def test_account_registrations(requests_mock):
133 | api = BlockFrostApi()
134 | mock_data = [
135 | {
136 | "tx_hash": "2dd15e0ef6e6a17841cb9541c27724072ce4d4b79b91e58432fbaa32d9572531",
137 | "action": "registered"
138 | },
139 | {
140 | "tx_hash": "1a0570af966fb355a7160e4f82d5a80b8681b7955f5d44bec0dde628516157f0",
141 | "action": "deregistered"
142 | }
143 | ]
144 | requests_mock.get(f"{api.url}/accounts/{stake_address}/registrations", json=mock_data)
145 | assert api.account_registrations(stake_address=stake_address) == convert_json_to_object(mock_data)
146 |
147 |
148 | def test_integration_account_registrations():
149 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
150 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
151 | assert api.account_registrations(stake_address=stake_address)
152 |
153 |
154 | def test_account_withdrawals(requests_mock):
155 | api = BlockFrostApi()
156 | mock_data = [
157 | {
158 | "tx_hash": "48a9625c841eea0dd2bb6cf551eabe6523b7290c9ce34be74eedef2dd8f7ecc5",
159 | "amount": "454541212442"
160 | },
161 | {
162 | "tx_hash": "4230b0cbccf6f449f0847d8ad1d634a7a49df60d8c142bb8cc2dbc8ca03d9e34",
163 | "amount": "97846969"
164 | }
165 | ]
166 | requests_mock.get(f"{api.url}/accounts/{stake_address}/withdrawals", json=mock_data)
167 | assert api.account_withdrawals(stake_address=stake_address) == convert_json_to_object(mock_data)
168 |
169 |
170 | def test_integration_account_withdrawals():
171 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
172 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
173 | assert api.account_withdrawals(stake_address=stake_address)
174 |
175 |
176 | def test_account_mirs(requests_mock):
177 | api = BlockFrostApi()
178 | mock_data = [
179 | {
180 | "tx_hash": "69705bba1d687a816ff5a04ec0c358a1f1ef075ab7f9c6cc2763e792581cec6d",
181 | "amount": "2193707473"
182 | },
183 | {
184 | "tx_hash": "baaa77b63d4d7d2bb3ab02c9b85978c2092c336dede7f59e31ad65452d510c13",
185 | "amount": "14520198574"
186 | }
187 | ]
188 | requests_mock.get(f"{api.url}/accounts/{stake_address}/mirs", json=mock_data)
189 | assert api.account_mirs(stake_address=stake_address) == convert_json_to_object(mock_data)
190 |
191 |
192 | def test_integration_account_mirs():
193 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
194 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
195 | assert api.account_mirs(stake_address=stake_address)
196 |
197 |
198 | def test_account_addresses(requests_mock):
199 | api = BlockFrostApi()
200 | mock_data = [
201 | {
202 | "address": "addr1qx2kd28nq8ac5prwg32hhvudlwggpgfp8utlyqxu6wqgz62f79qsdmm5dsknt9ecr5w468r9ey0fxwkdrwh08ly3tu9sy0f4qd"
203 | },
204 | {
205 | "address": "addr1qys3czp8s9thc6u2fqed9yq3h24nyw28uk0m6mkgn9dkckjf79qsdmm5dsknt9ecr5w468r9ey0fxwkdrwh08ly3tu9suth4w4"
206 | },
207 | {
208 | "address": "addr1q8j55h253zcvl326sk5qdt2n8z7eghzspe0ekxgncr796s2f79qsdmm5dsknt9ecr5w468r9ey0fxwkdrwh08ly3tu9sjmd35m"
209 | },
210 | {
211 | "address": "addr1q8f7gxrprank3drhx8k5grlux7ene0nlwun8y9thu8mc3yjf79qsdmm5dsknt9ecr5w468r9ey0fxwkdrwh08ly3tu9sls6vnt"
212 | }
213 | ]
214 | requests_mock.get(f"{api.url}/accounts/{stake_address}/addresses", json=mock_data)
215 | assert api.account_addresses(stake_address=stake_address) == convert_json_to_object(mock_data)
216 |
217 |
218 | def test_integration_account_addresses():
219 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
220 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
221 | assert api.account_addresses(stake_address=stake_address)
222 |
223 |
224 | def test_account_addresses_assets(requests_mock):
225 | api = BlockFrostApi()
226 | mock_data = [
227 | {
228 | "unit": "d5e6bf0500378d4f0da4e8dde6becec7621cd8cbf5cbb9b87013d4cc537061636542756433343132",
229 | "quantity": "1"
230 | },
231 | {
232 | "unit": "b0d07d45fe9514f80213f4020e5a61241458be626841cde717cb38a76e7574636f696e",
233 | "quantity": "125"
234 | }
235 | ]
236 | requests_mock.get(f"{api.url}/accounts/{stake_address}/addresses/assets", json=mock_data)
237 | assert api.account_addresses_assets(stake_address=stake_address) == convert_json_to_object(mock_data)
238 |
239 |
240 | def test_integration_account_addresses_assets():
241 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
242 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
243 | assert api.account_addresses_assets(stake_address=stake_address) == []
244 |
245 |
246 | def test_account_addresses_total(requests_mock):
247 | api = BlockFrostApi()
248 | mock_data = {
249 | "stake_address": "stake1u9l5q5jwgelgagzyt6nuaasefgmn8pd25c8e9qpeprq0tdcp0e3uk",
250 | "received_sum": [
251 | {
252 | "unit": "lovelace",
253 | "quantity": "42000000"
254 | },
255 | {
256 | "unit": "b0d07d45fe9514f80213f4020e5a61241458be626841cde717cb38a76e7574636f696e",
257 | "quantity": "12"
258 | }
259 | ],
260 | "sent_sum": [
261 | {
262 | "unit": "lovelace",
263 | "quantity": "42000000"
264 | },
265 | {
266 | "unit": "b0d07d45fe9514f80213f4020e5a61241458be626841cde717cb38a76e7574636f696e",
267 | "quantity": "12"
268 | }
269 | ],
270 | "tx_count": 12
271 | }
272 | requests_mock.get(f"{api.url}/accounts/{stake_address}/addresses/total", json=mock_data)
273 | assert api.account_addresses_total(stake_address=stake_address) == convert_json_to_object(mock_data)
274 |
275 |
276 | def test_integration_account_addresses_total():
277 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
278 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
279 | assert api.account_addresses_total(stake_address=stake_address)
280 |
--------------------------------------------------------------------------------
/tests/test_cardano_addresses.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from blockfrost import BlockFrostApi, ApiError
4 | from blockfrost.utils import convert_json_to_object
5 |
6 | address = 'addr1qxk49ptelk7uda7acrczz30a7fu778sax5aapa38nhmve3eu7yzv8ay6qvmlywtgvt7exaxt783dxuzv03qal7muda5srnx35s'
7 | stake_address = 'stake1ux3g2c9dx2nhhehyrezyxpkstartcqmu9hk63qgfkccw5rqttygt7'
8 | asset = 'f4988f549728dc76b58d7677849443caf6e5385dc67e6c25f6aa901e506978656c54696c653235'
9 |
10 |
11 | def test_address(requests_mock):
12 | api = BlockFrostApi()
13 | mock_data = {
14 | "address": address,
15 | "amount": [
16 | {
17 | "unit": "lovelace",
18 | "quantity": "42000000"
19 | },
20 | {
21 | "unit": "b0d07d45fe9514f80213f4020e5a61241458be626841cde717cb38a76e7574636f696e",
22 | "quantity": "12"
23 | }
24 | ],
25 | "stake_address": stake_address,
26 | "type": "shelley",
27 | "script": False,
28 | }
29 | requests_mock.get(f"{api.url}/addresses/{address}", json=mock_data)
30 | assert api.address(address=address) == convert_json_to_object(mock_data)
31 |
32 |
33 | def test_integration_address():
34 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
35 | api = BlockFrostApi(project_id=os.getenv(
36 | 'BLOCKFROST_PROJECT_ID_MAINNET'))
37 | assert api.address(address=address)
38 |
39 |
40 | def test_address_extended(requests_mock):
41 | api = BlockFrostApi()
42 | mock_data = {
43 | "address": address,
44 | "amount": [
45 | {
46 | "unit": "lovelace",
47 | "quantity": "42000000",
48 | "decimals": 6,
49 | "has_nft_onchain_metadata": None
50 | },
51 | {
52 | "unit": "b0d07d45fe9514f80213f4020e5a61241458be626841cde717cb38a76e7574636f696e",
53 | "quantity": "12",
54 | "decimals": None,
55 | "has_nft_onchain_metadata": True
56 | }
57 | ],
58 | "stake_address": "stake1ux3g2c9dx2nhhehyrezyxpkstartcqmu9hk63qgfkccw5rqttygt7",
59 | "type": "shelley",
60 | "script": False
61 | }
62 | requests_mock.get(
63 | f"{api.url}/addresses/{address}/extended", json=mock_data)
64 | assert api.address_extended(
65 | address=address) == convert_json_to_object(mock_data)
66 |
67 |
68 | def test_integration_address_extended():
69 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
70 | api = BlockFrostApi(project_id=os.getenv(
71 | 'BLOCKFROST_PROJECT_ID_MAINNET'))
72 | assert api.address_extended(address=address)
73 |
74 |
75 | def test_address_total(requests_mock):
76 | api = BlockFrostApi()
77 | mock_data = {
78 | "address": address,
79 | "received_sum": [
80 | {
81 | "unit": "lovelace",
82 | "quantity": "42000000"
83 | },
84 | {
85 | "unit": "b0d07d45fe9514f80213f4020e5a61241458be626841cde717cb38a76e7574636f696e",
86 | "quantity": "12"
87 | }
88 | ],
89 | "sent_sum": [
90 | {
91 | "unit": "lovelace",
92 | "quantity": "42000000"
93 | },
94 | {
95 | "unit": "b0d07d45fe9514f80213f4020e5a61241458be626841cde717cb38a76e7574636f696e",
96 | "quantity": "12"
97 | }
98 | ],
99 | "tx_count": 12
100 | }
101 | requests_mock.get(f"{api.url}/addresses/{address}/total", json=mock_data)
102 | assert api.address_total(
103 | address=address) == convert_json_to_object(mock_data)
104 |
105 |
106 | def test_integration_address_total():
107 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
108 | api = BlockFrostApi(project_id=os.getenv(
109 | 'BLOCKFROST_PROJECT_ID_MAINNET'))
110 | assert api.address_total(address=address)
111 |
112 |
113 | def test_address_utxos(requests_mock):
114 | api = BlockFrostApi()
115 | mock_data = [
116 | {
117 | "tx_hash": "39a7a284c2a0948189dc45dec670211cd4d72f7b66c5726c08d9b3df11e44d58",
118 | "tx_index": 1,
119 | "output_index": 0,
120 | "amount": [
121 | {
122 | "unit": "lovelace",
123 | "quantity": "42000000"
124 | }
125 | ],
126 | "block": "7eb8e27d18686c7db9a18f8bbcfe34e3fed6e047afaa2d969904d15e934847e6",
127 | "data_hash": "9e478573ab81ea7a8e31891ce0648b81229f408d596a3483e6f4f9b92d3cf710"
128 | },
129 | {
130 | "tx_hash": "4c4e67bafa15e742c13c592b65c8f74c769cd7d9af04c848099672d1ba391b49",
131 | "tx_index": 1,
132 | "output_index": 0,
133 | "amount": [
134 | {
135 | "unit": "lovelace",
136 | "quantity": "729235000"
137 | }
138 | ],
139 | "block": "953f1b80eb7c11a7ffcd67cbd4fde66e824a451aca5a4065725e5174b81685b7",
140 | "data_hash": None
141 | },
142 | {
143 | "tx_hash": "768c63e27a1c816a83dc7b07e78af673b2400de8849ea7e7b734ae1333d100d2",
144 | "tx_index": 1,
145 | "output_index": 1,
146 | "amount": [
147 | {
148 | "unit": "lovelace",
149 | "quantity": "42000000"
150 | },
151 | {
152 | "unit": "b0d07d45fe9514f80213f4020e5a61241458be626841cde717cb38a76e7574636f696e",
153 | "quantity": "12"
154 | }
155 | ],
156 | "block": "5c571f83fe6c784d3fbc223792627ccf0eea96773100f9aedecf8b1eda4544d7",
157 | "data_hash": None
158 | }
159 | ]
160 | requests_mock.get(f"{api.url}/addresses/{address}/utxos", json=mock_data)
161 | assert api.address_utxos(
162 | address=address) == convert_json_to_object(mock_data)
163 |
164 |
165 | def test_integration_address_utxos():
166 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
167 | api = BlockFrostApi(project_id=os.getenv(
168 | 'BLOCKFROST_PROJECT_ID_MAINNET'))
169 | assert api.address_utxos(address=address) == []
170 |
171 |
172 | def test_address_utxos_asset(requests_mock):
173 | api = BlockFrostApi()
174 | mock_data = [
175 | {
176 | "tx_hash": "39a7a284c2a0948189dc45dec670211cd4d72f7b66c5726c08d9b3df11e44d58",
177 | "output_index": 0,
178 | "amount": [
179 | {
180 | "unit": "lovelace",
181 | "quantity": "42000000"
182 | }
183 | ],
184 | "block": "7eb8e27d18686c7db9a18f8bbcfe34e3fed6e047afaa2d969904d15e934847e6",
185 | "data_hash": "9e478573ab81ea7a8e31891ce0648b81229f408d596a3483e6f4f9b92d3cf710"
186 | },
187 | {
188 | "tx_hash": "4c4e67bafa15e742c13c592b65c8f74c769cd7d9af04c848099672d1ba391b49",
189 | "output_index": 0,
190 | "amount": [
191 | {
192 | "unit": "lovelace",
193 | "quantity": "729235000"
194 | }
195 | ],
196 | "block": "953f1b80eb7c11a7ffcd67cbd4fde66e824a451aca5a4065725e5174b81685b7",
197 | "data_hash": None
198 | },
199 | {
200 | "tx_hash": "768c63e27a1c816a83dc7b07e78af673b2400de8849ea7e7b734ae1333d100d2",
201 | "output_index": 1,
202 | "amount": [
203 | {
204 | "unit": "lovelace",
205 | "quantity": "42000000"
206 | },
207 | {
208 | "unit": "b0d07d45fe9514f80213f4020e5a61241458be626841cde717cb38a76e7574636f696e",
209 | "quantity": "12"
210 | }
211 | ],
212 | "block": "5c571f83fe6c784d3fbc223792627ccf0eea96773100f9aedecf8b1eda4544d7",
213 | "data_hash": None
214 | }
215 | ]
216 | requests_mock.get(
217 | f"{api.url}/addresses/{address}/utxos/{asset}", json=mock_data)
218 | assert api.address_utxos_asset(
219 | address=address, asset=asset) == convert_json_to_object(mock_data)
220 |
221 |
222 | def test_integration_address_utxos_asset():
223 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
224 | api = BlockFrostApi(project_id=os.getenv(
225 | 'BLOCKFROST_PROJECT_ID_MAINNET'))
226 | assert api.address_utxos_asset(address=address, asset=asset) == []
227 |
228 |
229 | def test_address_transactions(requests_mock):
230 | api = BlockFrostApi()
231 | mock_data = [
232 | {
233 | "tx_hash": "8788591983aa73981fc92d6cddbbe643959f5a784e84b8bee0db15823f575a5b",
234 | "tx_index": 6,
235 | "block_height": 69,
236 | "block_time": 1635505891
237 | },
238 | {
239 | "tx_hash": "52e748c4dec58b687b90b0b40d383b9fe1f24c1a833b7395cdf07dd67859f46f",
240 | "tx_index": 9,
241 | "block_height": 4547,
242 | "block_time": 1635505987
243 | },
244 | {
245 | "tx_hash": "e8073fd5318ff43eca18a852527166aa8008bee9ee9e891f585612b7e4ba700b",
246 | "tx_index": 0,
247 | "block_height": 564654,
248 | "block_time": 1834505492
249 | }
250 | ]
251 | requests_mock.get(
252 | f"{api.url}/addresses/{address}/transactions", json=mock_data)
253 | assert api.address_transactions(
254 | address=address) == convert_json_to_object(mock_data)
255 |
256 |
257 | def test_integration_address_transactions():
258 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
259 | api = BlockFrostApi(project_id=os.getenv(
260 | 'BLOCKFROST_PROJECT_ID_MAINNET'))
261 | assert api.address_transactions(address=address)
262 |
--------------------------------------------------------------------------------
/tests/test_cardano_assets.py:
--------------------------------------------------------------------------------
1 | import os
2 | from blockfrost import BlockFrostApi, ApiError
3 | from blockfrost.utils import convert_json_to_object
4 |
5 | asset = '00000002df633853f6a47465c9496721d2d5b1291b8398016c0e87ae6e7574636f696e'
6 | policy_id = '00000002df633853f6a47465c9496721d2d5b1291b8398016c0e87ae'
7 |
8 |
9 | def test_assets(requests_mock):
10 | api = BlockFrostApi()
11 | mock_data = [
12 | {
13 | "asset": "b0d07d45fe9514f80213f4020e5a61241458be626841cde717cb38a76e7574636f696e",
14 | "quantity": "1"
15 | },
16 | {
17 | "asset": "b0d07d45fe9514f80213f4020e5a61241458be626841cde717cb38a76e75d",
18 | "quantity": "100000"
19 | },
20 | {
21 | "asset": "6804edf9712d2b619edb6ac86861fe93a730693183a262b165fcc1ba1bc99cad",
22 | "quantity": "18605647"
23 | }
24 | ]
25 | requests_mock.get(f"{api.url}/assets", json=mock_data)
26 | assert api.assets() == convert_json_to_object(mock_data)
27 |
28 |
29 | def test_integration_assets():
30 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
31 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
32 | assert api.assets()
33 |
34 |
35 | def test_asset(requests_mock):
36 | api = BlockFrostApi()
37 | mock_data = {
38 | "asset": asset,
39 | "policy_id": policy_id,
40 | "asset_name": "6e7574636f696e",
41 | "fingerprint": "asset1pkpwyknlvul7az0xx8czhl60pyel45rpje4z8w",
42 | "quantity": "12000",
43 | "initial_mint_tx_hash": "6804edf9712d2b619edb6ac86861fe93a730693183a262b165fcc1ba1bc99cad",
44 | "mint_or_burn_count": 1,
45 | "onchain_metadata": {
46 | "name": "My NFT token",
47 | "image": "ipfs://ipfs/QmfKyJ4tuvHowwKQCbCHj4L5T3fSj8cjs7Aau8V7BWv226"
48 | },
49 | "metadata": {
50 | "name": "nutcoin",
51 | "description": "The Nut Coin",
52 | "ticker": "nutc",
53 | "url": "https://www.stakenuts.com/",
54 | "logo": "iVBORw0KGgoAAAANSUhEUgAAADAAAAAoCAYAAAC4h3lxAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QA/wD/AP+gvaeTAAAAB3RJTUUH5QITCDUPjqwFHwAAB9xJREFUWMPVWXtsU9cZ/8499/r6dZ3E9rUdO7ZDEgglFWO8KaOsJW0pCLRKrN1AqqYVkqoqrYo0ja7bpElru1WairStFKY9WzaE1E1tx+jokKqwtqFNyhKahEJJyJNgJ37E9r1+3HvO/sFR4vhx7SBtfH/F3/l93/f7ne/4PBxEKYU72dj/ZfH772v1TU+HtqbTaX8wOO01GPQpRVH7JEm+vGHDuq6z7/8jUSoHKtaBKkEUFUXdajDy1hUrmrs6zn/wWS7m7pZVjMUirKGUTnzc+e9xLcTrPPVfZzDz06Sc2lyQGEIyAPzT7Xa+dvE/3e+XLaCxoflHsVj8MAAYs74aa/WHoenwvpkZKeFy2Z5NJlOPUkqXZccFwSSrKjlyffjLH+TL6XTUGTGL/6hklD3ldIrj2M5MRmkLBMcvaRLQ1Nj88sxM/HCBfMP+eu/OYGDqe6l0WmpoqJ/88upgrU7HrQNA/cFg6MlkKiLlBtVUO40cx54BgHvLIT/HJLvdeqh/4NKxogKWN7fsCoUi7xTLxLJ4vLq6ak//wKVOrdXtttrTDMPsqJA8AAAwDErdu3VL3alTf5ma9eWCpoKhn5dKpCiqJxicPucQPVu0FHaInn35yHMcKwPAa4SQ3QCwFgDWUko3qSr5vqqSgTypuEg4Mo/zvA74/Y0rZSnZU8akSHV17k2fXfy0txjI5224kEym1s/1EUI7LBbztweHrkzkizn49LP6U6feepFSeggAQK/n04SQZ8bGrxdeQjZrbRvGzLH5hcibRqOhPplMfS1fIY5jz4xPDBdcGggho2h3z9sOLRazdG3wqp9SMgUlzGZ17SSEPsRx7J8CwfGu3PF57WhqqjfN/VxVJUxKUrIdITAXKpDJKFscosdfaFy0u+/K9aXTmXe0kAcAmA5Nng5Hbj6Tj/wCAYFAcN7uEY3GXGazMSHLqVVFapgBoMPna9yqhRAAgCTJMa3YUjZPgNFkSlWYx5eUkx+0tKx83V3rF+cVYJjruWCe133DIXqMmrNrFSDabRcWkywYmG5XFOW6aHcfb9324CoAgMmbo9MIoXkneCajiAihV/c/8eSiBSw4BxyiZxQA6m7H7FBKT2CMn2MY5jFFUX6ZO+5w2j8aHZ7YH40FByrJD5DnHGAY5uTtIA8AgBDaR4F2Yxb3WizCgmtA4ObUPSazodduqz3Suu0hf0U1cjvgdNSJ1dWWveFwdDUAtAiC2Uopdcdi8c9Zlh3GmDGl05mtAKAvo47EcdwThJCjqqpWFxALlNITomg73tff21GRAJez7iVK4WGGYfoJIQduBsbm7UrLm1ueCoUiv65kpiilw1ZbzcFoZOYoIcRTAn6eYZgXJm+Oni+Vd3YJbdyweSch9HlK6SpVVfcyDDq7Yf3m2XPBIXraKyV/a4b9UkLawbLsZgB4rwR8CyGkw13r+5fX27BckwBAEJ47oKpk8+DgUIdod7fV1vqOAMDrlZLPmqKoB+rrvXIgOP6w0WjYy3Ls5RL4bUk52bVm9fqnCk7M3CXU2ND8+MxM7BcIIftiyRYyntcdHh0bmr0wfmXl6p2SJB2KRmP3l4j7zejYUFtRAQAAgslm1Bv4nyGEDpYiIwjmjw0G/RjP866JiclNqqqWfKLq9fyZkdHBBXcnl9O71GDgD8bj0ncRQqZ8sRgzL9yYHH2pqICsOUTPLgA4CXNeZFmzWIS/YhYfjUZmvqPjuceSckrz25pS2h2cmlhbaBwhzr6kfsnL8Xhif55YYFl23Y3Jkdl7EVMoUSA4/q6qqNsBIPd11e52u45FwtG3CSH7yiEPAGC1Vt9dXGBmanDoygFLlbAjtzZCCMyC6VeaOpA1l9N7l1kwtauKaozHE28YTQaQpeR7+TqjxXheR0fHhhgt2CX1S3clEtKC16HL5djYe+niBU0CcmYA2W21/Qih5ZqDcoxlMZ24MaJJAABA87IVJ8Lh6N65Pr1B/+LIyLUfAhRZQvnM6ah7ZDHkAQB0vK6/HHxNTc2ruT5Zkldn/y5LACFk+2LIAwAwCGl6yGSt88KHXbmrBCHkqEgAz+vWLFZALJb4qNwYhFDhCSknkSwnQ4sVgDFeWg7+gQe2r1tAmkGTFQlACHWVg89nhJA9ot3dphV/eeCLp/Pw6K5IQP0S39uLFXCLwDG7zf1cKZxD9LSlUunHc/12u/2t2Vzl/rzu8zb8PZlM7bwdQgDgPK/nX2nddt+53//ht3LW2dS0fF0iLj2vquojuQFmwXRucPBKa8UCmpe1iOFwpAsAfLdJBFBKwVIlXJ2JxqKCxbwyHkvoCkAlv9/71U+7Oq+UJWDZ0hViJBL1cRynbNq0sSeeiPl6ei4NqIqq6TSmlB7X6bjuTEY5pgWfzwxGPZhMpt39/b3vzvWXFGCzulZjjM/DrauDwcAr8bjcgzGjZUuVBMH8k2uDX7wCAFDr8n2LEPI7SqmhTP6SzVbz6MDlz0/nDpT8EmOM22HOvUeWU2wp8iyLgRL6hk7Hrc2SBwC4MTlykmXZRozxn00mbVcphNA5jJmV+chr6oDd5l6jN/A/TqfSuwEAGITGMIsvGo3GTwTB3Dc2NjGSxdZYq4VIOOoNBANnKE0XPXE3brjHOTQ08k2MmVZOxzVJCbkFIQSCYEphzPaFQuGzTpfjb319PZ8UFXin/5OvrHPg/9HueAH/BSUqOuNZm4fyAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDIxLTAyLTE5VDA4OjUyOjI1KzAwOjAwCmFGlgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyMS0wMi0xOVQwODo1MjoyMyswMDowMBjsyxAAAAAASUVORK5CYII=",
55 | "decimals": 6
56 | }
57 | }
58 | requests_mock.get(f"{api.url}/assets/{asset}", json=mock_data)
59 | assert api.asset(asset=asset) == convert_json_to_object(mock_data)
60 |
61 |
62 | def test_integration_asset():
63 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
64 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
65 | assert api.asset(asset=asset)
66 |
67 |
68 | def test_asset_history(requests_mock):
69 | api = BlockFrostApi()
70 | mock_data = [
71 | {
72 | "tx_hash": "2dd15e0ef6e6a17841cb9541c27724072ce4d4b79b91e58432fbaa32d9572531",
73 | "amount": "10",
74 | "action": "minted"
75 | },
76 | {
77 | "tx_hash": "9c190bc1ac88b2ab0c05a82d7de8b71b67a9316377e865748a89d4426c0d3005",
78 | "amount": "5",
79 | "action": "burned"
80 | },
81 | {
82 | "tx_hash": "1a0570af966fb355a7160e4f82d5a80b8681b7955f5d44bec0dde628516157f0",
83 | "amount": "5",
84 | "action": "burned"
85 | }
86 | ]
87 | requests_mock.get(f"{api.url}/assets/{asset}/history", json=mock_data)
88 | assert api.asset_history(asset=asset) == convert_json_to_object(mock_data)
89 |
90 |
91 | def test_integration_asset_history():
92 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
93 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
94 | assert api.asset_history(asset=asset)
95 |
96 |
97 | def test_asset_transactions(requests_mock):
98 | api = BlockFrostApi()
99 | mock_data = [
100 | {
101 | "tx_hash": "8788591983aa73981fc92d6cddbbe643959f5a784e84b8bee0db15823f575a5b",
102 | "tx_index": 6,
103 | "block_height": 69,
104 | "block_time": 1635505891
105 | },
106 | {
107 | "tx_hash": "52e748c4dec58b687b90b0b40d383b9fe1f24c1a833b7395cdf07dd67859f46f",
108 | "tx_index": 9,
109 | "block_height": 4547,
110 | "block_time": 1635505987
111 | },
112 | {
113 | "tx_hash": "e8073fd5318ff43eca18a852527166aa8008bee9ee9e891f585612b7e4ba700b",
114 | "tx_index": 0,
115 | "block_height": 564654,
116 | "block_time": 1834505492
117 | }
118 | ]
119 | requests_mock.get(f"{api.url}/assets/{asset}/transactions", json=mock_data)
120 | assert api.asset_transactions(asset=asset) == convert_json_to_object(mock_data)
121 |
122 |
123 | def test_integration_asset_transactions():
124 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
125 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
126 | assert api.asset_transactions(asset=asset)
127 |
128 |
129 | def test_asset_addresses(requests_mock):
130 | api = BlockFrostApi()
131 | mock_data = [
132 | {
133 | "address": "addr1qxqs59lphg8g6qndelq8xwqn60ag3aeyfcp33c2kdp46a09re5df3pzwwmyq946axfcejy5n4x0y99wqpgtp2gd0k09qsgy6pz",
134 | "quantity": "1"
135 | },
136 | {
137 | "address": "addr1qyhr4exrgavdcn3qhfcc9f939fzsch2re5ry9cwvcdyh4x4re5df3pzwwmyq946axfcejy5n4x0y99wqpgtp2gd0k09qdpvhza",
138 | "quantity": "100000"
139 | },
140 | {
141 | "address": "addr1q8zup8m9ue3p98kxlxl9q8rnyan8hw3ul282tsl9s326dfj088lvedv4zckcj24arcpasr0gua4c5gq4zw2rpcpjk2lq8cmd9l",
142 | "quantity": "18605647"
143 | }
144 | ]
145 | requests_mock.get(f"{api.url}/assets/{asset}/addresses", json=mock_data)
146 | assert api.asset_addresses(asset=asset) == convert_json_to_object(mock_data)
147 |
148 |
149 | def test_integration_asset_addresses():
150 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
151 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
152 | assert api.asset_addresses(asset=asset)
153 |
154 |
155 | def test_assets_policy(requests_mock):
156 | api = BlockFrostApi()
157 | mock_data = [
158 | {
159 | "asset": "b0d07d45fe9514f80213f4020e5a61241458be626841cde717cb38a76e7574636f696e",
160 | "quantity": "1"
161 | },
162 | {
163 | "asset": "b0d07d45fe9514f80213f4020e5a61241458be626841cde717cb38a766e",
164 | "quantity": "100000"
165 | },
166 | {
167 | "asset": "b0d07d45fe9514f80213f4020e5a61241458be626841cde717cb574636f696e",
168 | "quantity": "18605647"
169 | }
170 | ]
171 | requests_mock.get(f"{api.url}/assets/policy/{policy_id}", json=mock_data)
172 | assert api.assets_policy(policy_id=policy_id) == convert_json_to_object(mock_data)
173 |
174 |
175 | def test_integration_assets_policy():
176 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
177 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
178 | assert api.assets_policy(policy_id=policy_id)
179 |
--------------------------------------------------------------------------------
/tests/test_cardano_blocks.py:
--------------------------------------------------------------------------------
1 | import os
2 | from blockfrost import BlockFrostApi, ApiError
3 | from blockfrost.utils import convert_json_to_object
4 |
5 | # hash = '4ea1ba291e8eef538635a53e59fddba7810d1679631cc3aed7c8e6c4091a516a'
6 | hash = '796b28e192f1c9040e3749feb1bd2b35ce9a262976c7db95b43a3d3c417d37d4'
7 | slot_number = 46138897
8 | epoch_number = 304
9 |
10 |
11 | def test_block_latest(requests_mock):
12 | api = BlockFrostApi()
13 | mock_data = {
14 | "time": 1641338934,
15 | "height": 15243593,
16 | "hash": hash,
17 | "slot": slot_number,
18 | "epoch": epoch_number,
19 | "epoch_slot": 12,
20 | "slot_leader": "pool1pu5jlj4q9w9jlxeu370a3c9myx47md5j5m2str0naunn2qnikdy",
21 | "size": 3,
22 | "tx_count": 1,
23 | "output": "128314491794",
24 | "fees": "592661",
25 | "block_vrf": "vrf_vk1wf2k6lhujezqcfe00l6zetxpnmh9n6mwhpmhm0dvfh3fxgmdnrfqkms8ty",
26 | "previous_block": "43ebccb3ac72c7cebd0d9b755a4b08412c9f5dcb81b8a0ad1e3c197d29d47b05",
27 | "next_block": "8367f026cf4b03e116ff8ee5daf149b55ba5a6ec6dec04803b8dc317721d15fa",
28 | "confirmations": 4698
29 | }
30 | requests_mock.get(f"{api.url}/blocks/latest", json=mock_data)
31 | assert api.block_latest() == convert_json_to_object(mock_data)
32 |
33 |
34 | def test_integration_block_latest():
35 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
36 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
37 | assert api.block_latest()
38 |
39 |
40 | def test_block_latest_transactions(requests_mock):
41 | api = BlockFrostApi()
42 | mock_data = [
43 | "8788591983aa73981fc92d6cddbbe643959f5a784e84b8bee0db15823f575a5b",
44 | "4eef6bb7755d8afbeac526b799f3e32a624691d166657e9d862aaeb66682c036",
45 | "52e748c4dec58b687b90b0b40d383b9fe1f24c1a833b7395cdf07dd67859f46f",
46 | "e8073fd5318ff43eca18a852527166aa8008bee9ee9e891f585612b7e4ba700b"
47 | ]
48 | requests_mock.get(f"{api.url}/blocks/latest/txs", json=mock_data)
49 | assert api.block_latest_transactions() == convert_json_to_object(mock_data)
50 |
51 |
52 | def test_integration_block_latest_transactions():
53 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
54 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
55 | assert (api.block_latest_transactions() or
56 | api.block_latest_transactions() == [])
57 |
58 |
59 | def test_block(requests_mock):
60 | api = BlockFrostApi()
61 | mock_data = {
62 | "time": 1641338934,
63 | "height": 15243593,
64 | "hash": hash,
65 | "slot": slot_number,
66 | "epoch": epoch_number,
67 | "epoch_slot": 12,
68 | "slot_leader": "pool1pu5jlj4q9w9jlxeu370a3c9myx47md5j5m2str0naunn2qnikdy",
69 | "size": 3,
70 | "tx_count": 1,
71 | "output": "128314491794",
72 | "fees": "592661",
73 | "block_vrf": "vrf_vk1wf2k6lhujezqcfe00l6zetxpnmh9n6mwhpmhm0dvfh3fxgmdnrfqkms8ty",
74 | "previous_block": "43ebccb3ac72c7cebd0d9b755a4b08412c9f5dcb81b8a0ad1e3c197d29d47b05",
75 | "next_block": "8367f026cf4b03e116ff8ee5daf149b55ba5a6ec6dec04803b8dc317721d15fa",
76 | "confirmations": 4698
77 | }
78 | requests_mock.get(f"{api.url}/blocks/{hash}", json=mock_data)
79 | assert api.block(hash_or_number=hash) == convert_json_to_object(mock_data)
80 |
81 |
82 | def test_integration_block():
83 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
84 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
85 | assert api.block(hash_or_number=hash)
86 |
87 |
88 | def test_block_slot(requests_mock):
89 | api = BlockFrostApi()
90 | mock_data = {
91 | "time": 1641338934,
92 | "height": 15243593,
93 | "hash": hash,
94 | "slot": slot_number,
95 | "epoch": epoch_number,
96 | "epoch_slot": 12,
97 | "slot_leader": "pool1pu5jlj4q9w9jlxeu370a3c9myx47md5j5m2str0naunn2qnikdy",
98 | "size": 3,
99 | "tx_count": 1,
100 | "output": "128314491794",
101 | "fees": "592661",
102 | "block_vrf": "vrf_vk1wf2k6lhujezqcfe00l6zetxpnmh9n6mwhpmhm0dvfh3fxgmdnrfqkms8ty",
103 | "previous_block": "43ebccb3ac72c7cebd0d9b755a4b08412c9f5dcb81b8a0ad1e3c197d29d47b05",
104 | "next_block": "8367f026cf4b03e116ff8ee5daf149b55ba5a6ec6dec04803b8dc317721d15fa",
105 | "confirmations": 4698
106 | }
107 | requests_mock.get(f"{api.url}/blocks/slot/{slot_number}", json=mock_data)
108 | assert api.block_slot(slot_number=slot_number) == convert_json_to_object(mock_data)
109 |
110 |
111 | def test_integration_block_slot():
112 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
113 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
114 | assert api.block_slot(slot_number=slot_number)
115 |
116 |
117 | def test_block_epoch_slot(requests_mock):
118 | api = BlockFrostApi()
119 | mock_data = {
120 | "time": 1641338934,
121 | "height": 15243593,
122 | "hash": hash,
123 | "slot": slot_number,
124 | "epoch": epoch_number,
125 | "epoch_slot": 12,
126 | "slot_leader": "pool1pu5jlj4q9w9jlxeu370a3c9myx47md5j5m2str0naunn2qnikdy",
127 | "size": 3,
128 | "tx_count": 1,
129 | "output": "128314491794",
130 | "fees": "592661",
131 | "block_vrf": "vrf_vk1wf2k6lhujezqcfe00l6zetxpnmh9n6mwhpmhm0dvfh3fxgmdnrfqkms8ty",
132 | "previous_block": "43ebccb3ac72c7cebd0d9b755a4b08412c9f5dcb81b8a0ad1e3c197d29d47b05",
133 | "next_block": "8367f026cf4b03e116ff8ee5daf149b55ba5a6ec6dec04803b8dc317721d15fa",
134 | "confirmations": 4698
135 | }
136 | requests_mock.get(f"{api.url}/blocks/epoch/{epoch_number}/slot/{slot_number}", json=mock_data)
137 | assert api.block_epoch_slot(epoch_number=epoch_number, slot_number=slot_number) == convert_json_to_object(mock_data)
138 |
139 |
140 | def test_integration_block_epoch_slot():
141 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
142 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
143 | assert api.block_epoch_slot(epoch_number=epoch_number, slot_number=174097)
144 |
145 |
146 | def test_blocks_next(requests_mock):
147 | api = BlockFrostApi()
148 | mock_data = [
149 | {
150 | "time": 1641338934,
151 | "height": 15243593,
152 | "hash": hash,
153 | "slot": slot_number,
154 | "epoch": epoch_number,
155 | "epoch_slot": 12,
156 | "slot_leader": "pool1pu5jlj4q9w9jlxeu370a3c9myx47md5j5m2str0naunn2qnikdy",
157 | "size": 3,
158 | "tx_count": 1,
159 | "output": "128314491794",
160 | "fees": "592661",
161 | "block_vrf": "vrf_vk1wf2k6lhujezqcfe00l6zetxpnmh9n6mwhpmhm0dvfh3fxgmdnrfqkms8ty",
162 | "previous_block": "43ebccb3ac72c7cebd0d9b755a4b08412c9f5dcb81b8a0ad1e3c197d29d47b05",
163 | "next_block": "8367f026cf4b03e116ff8ee5daf149b55ba5a6ec6dec04803b8dc317721d15fa",
164 | "confirmations": 4698
165 | }
166 | ]
167 | requests_mock.get(f"{api.url}/blocks/{hash}/next", json=mock_data)
168 | assert api.blocks_next(hash_or_number=hash) == convert_json_to_object(mock_data)
169 |
170 |
171 | def test_integration_blocks_next():
172 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
173 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
174 | assert api.blocks_next(hash_or_number=hash)
175 |
176 |
177 | def test_blocks_previous(requests_mock):
178 | api = BlockFrostApi()
179 | mock_data = [
180 | {
181 | "time": 1641338934,
182 | "height": 15243593,
183 | "hash": hash,
184 | "slot": slot_number,
185 | "epoch": epoch_number,
186 | "epoch_slot": 12,
187 | "slot_leader": "pool1pu5jlj4q9w9jlxeu370a3c9myx47md5j5m2str0naunn2qnikdy",
188 | "size": 3,
189 | "tx_count": 1,
190 | "output": "128314491794",
191 | "fees": "592661",
192 | "block_vrf": "vrf_vk1wf2k6lhujezqcfe00l6zetxpnmh9n6mwhpmhm0dvfh3fxgmdnrfqkms8ty",
193 | "previous_block": "43ebccb3ac72c7cebd0d9b755a4b08412c9f5dcb81b8a0ad1e3c197d29d47b05",
194 | "next_block": "8367f026cf4b03e116ff8ee5daf149b55ba5a6ec6dec04803b8dc317721d15fa",
195 | "confirmations": 4698
196 | }
197 | ]
198 | requests_mock.get(f"{api.url}/blocks/{hash}/previous", json=mock_data)
199 | assert api.blocks_previous(hash_or_number=hash) == convert_json_to_object(mock_data)
200 |
201 |
202 | def test_integration_blocks_previous():
203 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
204 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
205 | assert api.blocks_previous(hash_or_number=hash)
206 |
207 |
208 | def test_block_transactions(requests_mock):
209 | api = BlockFrostApi()
210 | mock_data = [
211 | "8788591983aa73981fc92d6cddbbe643959f5a784e84b8bee0db15823f575a5b",
212 | "4eef6bb7755d8afbeac526b799f3e32a624691d166657e9d862aaeb66682c036",
213 | "52e748c4dec58b687b90b0b40d383b9fe1f24c1a833b7395cdf07dd67859f46f",
214 | "e8073fd5318ff43eca18a852527166aa8008bee9ee9e891f585612b7e4ba700b"
215 | ]
216 | requests_mock.get(f"{api.url}/blocks/{hash}/txs", json=mock_data)
217 | assert api.block_transactions(hash_or_number=hash) == convert_json_to_object(mock_data)
218 |
219 |
220 | def test_integration_block_transactions():
221 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
222 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
223 | assert api.block_transactions(hash_or_number=hash)
224 |
225 |
226 | def test_blocks_blocks_addresses(requests_mock):
227 | api = BlockFrostApi()
228 | mock_data = [
229 | {
230 | "address": "addr1q9ld26v2lv8wvrxxmvg90pn8n8n5k6tdst06q2s856rwmvnueldzuuqmnsye359fqrk8hwvenjnqultn7djtrlft7jnq7dy7wv",
231 | "transactions": [
232 | {
233 | "tx_hash": "1a0570af966fb355a7160e4f82d5a80b8681b7955f5d44bec0dce628516157f0"
234 | }
235 | ]
236 | },
237 | {
238 | "address": "addr1qxqs59lphg8g6qndelq8xwqn60ag3aeyfcp33c2kdp46a09re5df3pzwwmyq946axfcejy5n4x0y99wqpgtp2gd0k09qsgy6pz",
239 | "transactions": [
240 | {
241 | "tx_hash": "1a0570af966fb355a7160e4f82d5a80b8681b7955f5d44bec0dce628516157d0"
242 | }
243 | ]
244 | }
245 | ]
246 | requests_mock.get(f"{api.url}/blocks/{hash}/addresses", json=mock_data)
247 | assert api.blocks_addresses(hash_or_number=hash) == convert_json_to_object(mock_data)
248 |
249 |
250 | def test_integration_blocks_addresses():
251 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
252 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
253 | assert api.blocks_addresses(hash_or_number=hash)
254 |
--------------------------------------------------------------------------------
/tests/test_cardano_epochs.py:
--------------------------------------------------------------------------------
1 | import os
2 | from blockfrost import BlockFrostApi, ApiError
3 | from blockfrost.utils import convert_json_to_object
4 |
5 | epoch = 225
6 | pool_id = 'pool1pu5jlj4q9w9jlxeu370a3c9myx47md5j5m2str0naunn2q3lkdy'
7 |
8 |
9 | def test_epoch_latest(requests_mock):
10 | api = BlockFrostApi()
11 | mock_data = {
12 | "epoch": epoch,
13 | "start_time": 1603403091,
14 | "end_time": 1603835086,
15 | "first_block_time": 1603403092,
16 | "last_block_time": 1603835084,
17 | "block_count": 21298,
18 | "tx_count": 17856,
19 | "output": "7849943934049314",
20 | "fees": "4203312194",
21 | "active_stake": "784953934049314"
22 | }
23 | requests_mock.get(f"{api.url}/epochs/latest", json=mock_data)
24 | assert api.epoch_latest() == convert_json_to_object(mock_data)
25 |
26 |
27 | def test_integration_epoch_latest():
28 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
29 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
30 | assert api.epoch_latest()
31 |
32 |
33 | def test_epoch_latest_parameters(requests_mock):
34 | api = BlockFrostApi()
35 | mock_data = {
36 | "epoch": epoch,
37 | "min_fee_a": 44,
38 | "min_fee_b": 155381,
39 | "max_block_size": 65536,
40 | "max_tx_size": 16384,
41 | "max_block_header_size": 1100,
42 | "key_deposit": "2000000",
43 | "pool_deposit": "500000000",
44 | "e_max": 18,
45 | "n_opt": 150,
46 | "a0": 0.3,
47 | "rho": 0.003,
48 | "tau": 0.2,
49 | "decentralisation_param": 0.5,
50 | "extra_entropy": None,
51 | "protocol_major_ver": 2,
52 | "protocol_minor_ver": 0,
53 | "min_utxo": "1000000",
54 | "min_pool_cost": "340000000",
55 | "nonce": "1a3be38bcbb7911969283716ad7aa550250226b76a61fc51cc9a9a35d9276d81",
56 | "price_mem": 0.0577,
57 | "price_step": 0.0000721,
58 | "max_tx_ex_mem": "10000000",
59 | "max_tx_ex_steps": "10000000000",
60 | "max_block_ex_mem": "50000000",
61 | "max_block_ex_steps": "40000000000",
62 | "max_val_size": "5000",
63 | "collateral_percent": 150,
64 | "max_collateral_inputs": 3,
65 | "coins_per_utxo_word": "34482"
66 | }
67 | requests_mock.get(f"{api.url}/epochs/latest/parameters", json=mock_data)
68 | assert api.epoch_latest_parameters() == convert_json_to_object(mock_data)
69 |
70 |
71 | def test_integration_epoch_latest_parameters():
72 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
73 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
74 | assert api.epoch_latest_parameters()
75 |
76 |
77 | def test_epoch(requests_mock):
78 | api = BlockFrostApi()
79 | mock_data = {
80 | "epoch": epoch,
81 | "start_time": 1603403091,
82 | "end_time": 1603835086,
83 | "first_block_time": 1603403092,
84 | "last_block_time": 1603835084,
85 | "block_count": 21298,
86 | "tx_count": 17856,
87 | "output": "7849943934049314",
88 | "fees": "4203312194",
89 | "active_stake": "784953934049314"
90 | }
91 | requests_mock.get(f"{api.url}/epochs/{epoch}", json=mock_data)
92 | assert api.epoch(number=epoch) == convert_json_to_object(mock_data)
93 |
94 |
95 | def test_integration_epoch():
96 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
97 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
98 | assert api.epoch(number=epoch)
99 |
100 |
101 | def test_epochs_next(requests_mock):
102 | api = BlockFrostApi()
103 | mock_data = [
104 | {
105 | "epoch": 225,
106 | "start_time": 1603403091,
107 | "end_time": 1603835086,
108 | "first_block_time": 1603403092,
109 | "last_block_time": 1603835084,
110 | "block_count": 21298,
111 | "tx_count": 17856,
112 | "output": "7849943934049314",
113 | "fees": "4203312194",
114 | "active_stake": "784953934049314"
115 | }
116 | ]
117 | requests_mock.get(f"{api.url}/epochs/{epoch}/next", json=mock_data)
118 | assert api.epochs_next(number=epoch) == convert_json_to_object(mock_data)
119 |
120 |
121 | def test_integration_epochs_next():
122 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
123 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
124 | assert api.epochs_next(number=epoch)
125 |
126 |
127 | def test_epochs_previous(requests_mock):
128 | api = BlockFrostApi()
129 | mock_data = [
130 | {
131 | "epoch": 225,
132 | "start_time": 1603403091,
133 | "end_time": 1603835086,
134 | "first_block_time": 1603403092,
135 | "last_block_time": 1603835084,
136 | "block_count": 21298,
137 | "tx_count": 17856,
138 | "output": "7849943934049314",
139 | "fees": "4203312194",
140 | "active_stake": "784953934049314"
141 | }
142 | ]
143 | requests_mock.get(f"{api.url}/epochs/{epoch}/previous", json=mock_data)
144 | assert api.epochs_previous(number=epoch) == convert_json_to_object(mock_data)
145 |
146 |
147 | def test_integration_epochs_previous():
148 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
149 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
150 | assert api.epochs_previous(number=epoch)
151 |
152 |
153 | def test_epoch_stakes(requests_mock):
154 | api = BlockFrostApi()
155 | mock_data = [
156 | {
157 | "stake_address": "stake1u9l5q5jwgelgagzyt6nuaasefgmn8pd25c8e9qpeprq0tdcp0e3uk",
158 | "pool_id": pool_id,
159 | "amount": "4440295078"
160 | }
161 | ]
162 | requests_mock.get(f"{api.url}/epochs/{epoch}/stakes", json=mock_data)
163 | assert api.epoch_stakes(number=epoch) == convert_json_to_object(mock_data)
164 |
165 |
166 | def test_integration_epoch_stakes():
167 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
168 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
169 | assert api.epoch_stakes(number=epoch)
170 |
171 |
172 | def test_epoch_pool_stakes(requests_mock):
173 | api = BlockFrostApi()
174 | mock_data = [
175 | {
176 | "stake_address": "stake1u9l5q5jwgelgagzyt6nuaasefgmn8pd25c8e9qpeprq0tdcp0e3uk",
177 | "amount": "4440295078"
178 | }
179 | ]
180 | requests_mock.get(f"{api.url}/epochs/{epoch}/stakes/{pool_id}", json=mock_data)
181 | assert api.epoch_pool_stakes(number=epoch, pool_id=pool_id) == convert_json_to_object(mock_data)
182 |
183 |
184 | def test_integration_epoch_pool_stakes():
185 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
186 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
187 | assert api.epoch_pool_stakes(number=epoch, pool_id=pool_id)
188 |
189 |
190 | def test_epoch_blocks(requests_mock):
191 | api = BlockFrostApi()
192 | mock_data = [
193 | "d0fa315687e99ccdc96b14cc2ea74a767405d64427b648c470731a9b69e4606e",
194 | "38bc6efb92a830a0ed22a64f979d120d26483fd3c811f6622a8c62175f530878",
195 | "f3258fcd8b975c061b4fcdcfcbb438807134d6961ec278c200151274893b6b7d"
196 | ]
197 | requests_mock.get(f"{api.url}/epochs/{epoch}/blocks", json=mock_data)
198 | assert api.epoch_blocks(number=epoch) == convert_json_to_object(mock_data)
199 |
200 |
201 | def test_integration_epoch_blocks():
202 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
203 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
204 | assert api.epoch_blocks(number=epoch)
205 |
206 |
207 | def test_epoch_pool_blocks(requests_mock):
208 | api = BlockFrostApi()
209 | mock_data = [
210 | "d0fa315687e99ccdc96b14cc2ea74a767405d64427b648c470731a9b69e4606e",
211 | "38bc6efb92a830a0ed22a64f979d120d26483fd3c811f6622a8c62175f530878",
212 | "f3258fcd8b975c061b4fcdcfcbb438807134d6961ec278c200151274893b6b7d"
213 | ]
214 | requests_mock.get(f"{api.url}/epochs/{epoch}/blocks/{pool_id}", json=mock_data)
215 | assert api.epoch_pool_blocks(number=epoch, pool_id=pool_id) == convert_json_to_object(mock_data)
216 |
217 |
218 | def test_integration_epoch_pool_blocks():
219 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
220 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
221 | assert api.epoch_pool_blocks(number=epoch, pool_id=pool_id)
222 |
223 |
224 | def test_epoch_latest_parameters(requests_mock):
225 | api = BlockFrostApi()
226 | mock_data = {
227 | "epoch": epoch,
228 | "min_fee_a": 44,
229 | "min_fee_b": 155381,
230 | "max_block_size": 65536,
231 | "max_tx_size": 16384,
232 | "max_block_header_size": 1100,
233 | "key_deposit": "2000000",
234 | "pool_deposit": "500000000",
235 | "e_max": 18,
236 | "n_opt": 150,
237 | "a0": 0.3,
238 | "rho": 0.003,
239 | "tau": 0.2,
240 | "decentralisation_param": 0.5,
241 | "extra_entropy": None,
242 | "protocol_major_ver": 2,
243 | "protocol_minor_ver": 0,
244 | "min_utxo": "1000000",
245 | "min_pool_cost": "340000000",
246 | "nonce": "1a3be38bcbb7911969283716ad7aa550250226b76a61fc51cc9a9a35d9276d81",
247 | "price_mem": 0.001,
248 | "price_step": 0.01,
249 | "max_tx_ex_mem": "11000000000",
250 | "max_tx_ex_steps": "11000000000",
251 | "max_block_ex_mem": "110000000000",
252 | "max_block_ex_steps": "110000000000",
253 | "max_val_size": "5000",
254 | "collateral_percent": 1.5,
255 | "max_collateral_inputs": 6,
256 | "coins_per_utxo_word": "34482"
257 | }
258 | requests_mock.get(f"{api.url}/epochs/{epoch}/parameters", json=mock_data)
259 | assert api.epoch_protocol_parameters(number=epoch) == convert_json_to_object(mock_data)
260 |
261 |
262 | def test_integration_epoch_latest_parameters():
263 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
264 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
265 | assert api.epoch_protocol_parameters(number=epoch)
266 |
--------------------------------------------------------------------------------
/tests/test_cardano_ledger.py:
--------------------------------------------------------------------------------
1 | import os
2 | from blockfrost import BlockFrostApi, ApiError
3 | from blockfrost.utils import convert_json_to_object
4 |
5 |
6 |
7 | def test_genesis(requests_mock):
8 | api = BlockFrostApi()
9 | mock_data = {
10 | "active_slots_coefficient": 0.05,
11 | "update_quorum": 5,
12 | "max_lovelace_supply": "45000000000000000",
13 | "network_magic": 764824073,
14 | "epoch_length": 432000,
15 | "system_start": 1506203091,
16 | "slots_per_kes_period": 129600,
17 | "slot_length": 1,
18 | "max_kes_evolutions": 62,
19 | "security_param": 2160
20 | }
21 | requests_mock.get(f"{api.url}/genesis", json=mock_data)
22 | assert api.genesis() == convert_json_to_object(mock_data)
23 |
24 |
25 | def test_integration_genesis():
26 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
27 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
28 | assert api.genesis()
29 |
--------------------------------------------------------------------------------
/tests/test_cardano_mempool.py:
--------------------------------------------------------------------------------
1 | import os
2 | from blockfrost import BlockFrostApi
3 | from blockfrost.utils import convert_json_to_object
4 |
5 |
6 | def test_mempool(requests_mock):
7 | api = BlockFrostApi()
8 | mock_data = [
9 | {
10 | "tx_hash": "6a3511c5418edb5659c925c3287bf891fb641b67cb81380de4d4b2e21bf9ca20"
11 | },
12 | {
13 | "tx_hash": "9006fe580833f1a49126f698a4378473c413747486c4d43f9c8e0053b434f60c"
14 | },
15 | {
16 | "tx_hash": "b4ccc2ef8a381f15e68c7ad654a5789f5e31fd7f6467060663e204849f9b8247"
17 | },
18 | {
19 | "tx_hash": "f9e07beb51a459f8dbf02d5d68793ecabda5514bcbdfe95137a3fc1826479fb7"
20 | },
21 | {
22 | "tx_hash": "adcb286ccb45d7c4d43827a632c32781c86122410b38d7f39b40c06ef55a792b"
23 | }
24 | ]
25 | requests_mock.get(f"{api.url}/mempool", json=mock_data)
26 | assert api.mempool() == convert_json_to_object(mock_data)
27 |
28 |
29 | def test_integration_mempool():
30 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
31 | api = BlockFrostApi(project_id=os.getenv(
32 | 'BLOCKFROST_PROJECT_ID_MAINNET'))
33 | assert api.mempool()
34 |
35 |
36 | def test_mempool_tx(requests_mock):
37 | api = BlockFrostApi()
38 | hash = '7f9abe0b87064b6b39ec51f0f8ae976f586273c3ac123362ff550d94690d2881'
39 | mock_data = [
40 | {
41 | "tx": {
42 | "hash": "7f9abe0b87064b6b39ec51f0f8ae976f586273c3ac123362ff550d94690d2881",
43 | "output_amount": [
44 | {
45 | "unit": "lovelace",
46 | "quantity": "4597809591"
47 | }
48 | ],
49 | "fees": "168493",
50 | "deposit": "0",
51 | "size": 293,
52 | "invalid_before": None,
53 | "invalid_hereafter": "32304188",
54 | "utxo_count": 3,
55 | "withdrawal_count": 0,
56 | "mir_cert_count": 0,
57 | "delegation_count": 0,
58 | "stake_cert_count": 0,
59 | "pool_update_count": 0,
60 | "pool_retire_count": 0,
61 | "asset_mint_or_burn_count": 0,
62 | "redeemer_count": 0,
63 | "valid_contract": True
64 | },
65 | "inputs": [
66 | {
67 | "address": "addr_test1qq7ee7hjrux0zhptjpvt3rfp9rw0xfgkxwpussw8am5qwx24v0taaqmfkr2w88wfaqr6e5yz8nx42hdwulu6tw25dnuqgxnk57",
68 | "tx_hash": "9c5c73008491e4ce07b2c868624ae8af5ea53e5d071723f700554c576400397b",
69 | "output_index": 1,
70 | "collateral": False,
71 | "reference": False
72 | }
73 | ],
74 | "outputs": [
75 | {
76 | "address": "addr_test1qru6ah9weaq77re5jkjv65fgteppd3y7m5ezar4x7nyav5csg06mvtj45v4nhstgf92qghdz3rrf9x5f0h9ac8n48zrs7tv53q",
77 | "amount": [
78 | {
79 | "unit": "lovelace",
80 | "quantity": "50000000"
81 | }
82 | ],
83 | "output_index": 0,
84 | "data_hash": None,
85 | "inline_datum": None,
86 | "collateral": False,
87 | "reference_script_hash": None
88 | },
89 | {
90 | "address": "addr_test1qq7ee7hjrux0zhptjpvt3rfp9rw0xfgkxwpussw8am5qwx24v0taaqmfkr2w88wfaqr6e5yz8nx42hdwulu6tw25dnuqgxnk57",
91 | "amount": [
92 | {
93 | "unit": "lovelace",
94 | "quantity": "4547809591"
95 | }
96 | ],
97 | "output_index": 1,
98 | "data_hash": None,
99 | "inline_datum": None,
100 | "collateral": False,
101 | "reference_script_hash": None
102 | }
103 | ]
104 | }
105 | ]
106 | requests_mock.get(f"{api.url}/mempool/{hash}", json=mock_data)
107 | assert api.mempool_tx(hash) == convert_json_to_object(mock_data)
108 |
109 |
110 | # def test_integration_mempool():
111 | # if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
112 | # api = BlockFrostApi(project_id=os.getenv(
113 | # 'BLOCKFROST_PROJECT_ID_MAINNET'))
114 | # assert api.mempool_tx()
115 |
116 | def test_mempool_address(requests_mock):
117 | address = 'addr1qyptln5t5s0mastzc9rksn6wdqp9ynt67ahw0nhzukar5keu7yzv8ay6qvmlywtgvt7exaxt783dxuzv03qal7muda5sl42hg6'
118 | api = BlockFrostApi()
119 | mock_data = [
120 | {
121 | "tx_hash": "6a3511c5418edb5659c925c3287bf891fb641b67cb81380de4d4b2e21bf9ca20"
122 | }
123 | ]
124 | requests_mock.get(
125 | f"{api.url}/mempool/addresses/{address}", json=mock_data)
126 | assert api.mempool_address(address) == convert_json_to_object(mock_data)
127 |
128 |
129 | # def test_integration_mempool_address():
130 | # if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
131 | # api = BlockFrostApi(project_id=os.getenv(
132 | # 'BLOCKFROST_PROJECT_ID_MAINNET'))
133 | # assert api.mempool_address()
134 |
--------------------------------------------------------------------------------
/tests/test_cardano_metadata.py:
--------------------------------------------------------------------------------
1 | import os
2 | from blockfrost import BlockFrostApi, ApiError
3 | from blockfrost.utils import convert_json_to_object
4 |
5 |
6 | label = "1990"
7 |
8 |
9 | def test_metadata_labels(requests_mock):
10 | api = BlockFrostApi()
11 | mock_data = [
12 | {
13 | "label": "1990",
14 | "cip10": None,
15 | "count": "1"
16 | },
17 | {
18 | "label": "1967",
19 | "cip10": "nut.link metadata oracles registry",
20 | "count": "3"
21 | },
22 | {
23 | "label": "1968",
24 | "cip10": "nut.link metadata oracles data points",
25 | "count": "16321"
26 | }
27 | ]
28 | requests_mock.get(f"{api.url}/metadata/txs/labels", json=mock_data)
29 | assert api.metadata_labels() == convert_json_to_object(mock_data)
30 |
31 |
32 | def test_integration_metadata_labels():
33 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
34 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
35 | assert api.metadata_labels()
36 |
37 |
38 | def test_metadata_label_json(requests_mock):
39 | api = BlockFrostApi()
40 | mock_data = [
41 | {
42 | "tx_hash": "257d75c8ddb0434e9b63e29ebb6241add2b835a307aa33aedba2effe09ed4ec8",
43 | "json_metadata": {
44 | "ADAUSD": [
45 | {
46 | "value": "0.10409800535729975",
47 | "source": "ergoOracles"
48 | }
49 | ]
50 | }
51 | },
52 | {
53 | "tx_hash": "e865f2cc01ca7381cf98dcdc4de07a5e8674b8ea16e6a18e3ed60c186fde2b9c",
54 | "json_metadata": {
55 | "ADAUSD": [
56 | {
57 | "value": "0.15409850555139935",
58 | "source": "ergoOracles"
59 | }
60 | ]
61 | }
62 | },
63 | {
64 | "tx_hash": "4237501da3cfdd53ade91e8911e764bd0699d88fd43b12f44a1f459b89bc91be",
65 | "json_metadata": None
66 | }
67 | ]
68 | requests_mock.get(f"{api.url}/metadata/txs/labels/{label}", json=mock_data)
69 | assert api.metadata_label_json(label=label) == convert_json_to_object(mock_data)
70 |
71 |
72 | def test_integration_metadata_label_json():
73 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
74 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
75 | assert api.metadata_label_json(label=label)
76 |
77 |
78 | def test_metadata_label_cbor(requests_mock):
79 | api = BlockFrostApi()
80 | mock_data = [
81 | {
82 | "tx_hash": "257d75c8ddb0434e9b63e29ebb6241add2b835a307aa33aedba2effe09ed4ec8",
83 | "cbor_metadata": None,
84 | "metadata": None
85 | },
86 | {
87 | "tx_hash": "e865f2cc01ca7381cf98dcdc4de07a5e8674b8ea16e6a18e3ed60c186fde2b9c",
88 | "cbor_metadata": None,
89 | "metadata": None
90 | },
91 | {
92 | "tx_hash": "4237501da3cfdd53ade91e8911e764bd0699d88fd43b12f44a1f459b89bc91be",
93 | "cbor_metadata": "\\xa100a16b436f6d62696e6174696f6e8601010101010c",
94 | "metadata": "a100a16b436f6d62696e6174696f6e8601010101010c"
95 | }
96 | ]
97 | requests_mock.get(f"{api.url}/metadata/txs/labels/{label}/cbor", json=mock_data)
98 | assert api.metadata_label_cbor(label=label) == convert_json_to_object(mock_data)
99 |
100 |
101 | def test_integration_metadata_label_cbor():
102 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
103 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
104 | assert api.metadata_label_cbor(label=label)
105 |
--------------------------------------------------------------------------------
/tests/test_cardano_network.py:
--------------------------------------------------------------------------------
1 | import os
2 | from blockfrost import BlockFrostApi, ApiError
3 | from blockfrost.utils import convert_json_to_object
4 |
5 |
6 | def test_network(requests_mock):
7 | api = BlockFrostApi()
8 | mock_data = {
9 | "supply": {
10 | "max": "45000000000000000",
11 | "total": "32890715183299160",
12 | "circulating": "32412601976210393",
13 | "locked": "125006953355",
14 | "treasury": "98635632000000",
15 | "reserves": "46635632000000"
16 | },
17 | "stake": {
18 | "live": "23204950463991654",
19 | "active": "22210233523456321"
20 | }
21 | }
22 | requests_mock.get(f"{api.url}/network", json=mock_data)
23 | assert api.network() == convert_json_to_object(mock_data)
24 |
25 |
26 | def test_integration_network():
27 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
28 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
29 | assert api.network()
30 |
--------------------------------------------------------------------------------
/tests/test_cardano_pools.py:
--------------------------------------------------------------------------------
1 | import os
2 | from blockfrost import BlockFrostApi, ApiError
3 | from blockfrost.utils import convert_json_to_object
4 |
5 | pool_id = 'pool1pu5jlj4q9w9jlxeu370a3c9myx47md5j5m2str0naunn2q3lkdy'
6 |
7 |
8 | def test_pools(requests_mock):
9 | api = BlockFrostApi()
10 | mock_data = [
11 | "pool1pu5jlj4q9w9jlxeu370a3c9myx47md5j5m2str0naunn2q3lkdy",
12 | "pool1hn7hlwrschqykupwwrtdfkvt2u4uaxvsgxyh6z63703p2knj288",
13 | "pool1ztjyjfsh432eqetadf82uwuxklh28xc85zcphpwq6mmezavzad2"
14 | ]
15 | requests_mock.get(f"{api.url}/pools", json=mock_data)
16 | assert api.pools() == convert_json_to_object(mock_data)
17 |
18 |
19 | def test_integration_pools():
20 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
21 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
22 | assert api.pools()
23 |
24 |
25 | def test_pools_extended(requests_mock):
26 | api = BlockFrostApi()
27 | mock_data = [
28 | {
29 | "pool_id": "pool19u64770wqp6s95gkajc8udheske5e6ljmpq33awxk326zjaza0q",
30 | "active_stake": "1541200000",
31 | "live_stake": "1541400000"
32 | },
33 | {
34 | "pool_id": "pool1dvla4zq98hpvacv20snndupjrqhuc79zl6gjap565nku6et5zdx",
35 | "active_stake": "22200000",
36 | "live_stake": "48955550"
37 | },
38 | {
39 | "pool_id": "pool1wvccajt4eugjtf3k0ja3exjqdj7t8egsujwhcw4tzj4rzsxzw5w",
40 | "active_stake": "9989541215",
41 | "live_stake": "168445464878"
42 | }
43 | ]
44 | requests_mock.get(f"{api.url}/pools/extended", json=mock_data)
45 | assert api.pools_extended() == convert_json_to_object(mock_data)
46 |
47 |
48 | def test_integration_pools_extended():
49 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
50 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
51 | assert api.pools_extended()
52 |
53 |
54 | def test_pools_retired(requests_mock):
55 | api = BlockFrostApi()
56 | mock_data = [
57 | {
58 | "pool_id": "pool19u64770wqp6s95gkajc8udheske5e6ljmpq33awxk326zjaza0q",
59 | "epoch": 225
60 | },
61 | {
62 | "pool_id": "pool1dvla4zq98hpvacv20snndupjrqhuc79zl6gjap565nku6et5zdx",
63 | "epoch": 215
64 | },
65 | {
66 | "pool_id": "pool1wvccajt4eugjtf3k0ja3exjqdj7t8egsujwhcw4tzj4rzsxzw5w",
67 | "epoch": 231
68 | }
69 | ]
70 | requests_mock.get(f"{api.url}/pools/retired", json=mock_data)
71 | assert api.pools_retired() == convert_json_to_object(mock_data)
72 |
73 |
74 | def test_integration_pools_retired():
75 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
76 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
77 | assert api.pools_retired()
78 |
79 |
80 | def test_pools_retiring(requests_mock):
81 | api = BlockFrostApi()
82 | mock_data = [
83 | {
84 | "pool_id": "pool19u64770wqp6s95gkajc8udheske5e6ljmpq33awxk326zjaza0q",
85 | "epoch": 225
86 | },
87 | {
88 | "pool_id": "pool1dvla4zq98hpvacv20snndupjrqhuc79zl6gjap565nku6et5zdx",
89 | "epoch": 215
90 | },
91 | {
92 | "pool_id": "pool1wvccajt4eugjtf3k0ja3exjqdj7t8egsujwhcw4tzj4rzsxzw5w",
93 | "epoch": 231
94 | }
95 | ]
96 | requests_mock.get(f"{api.url}/pools/retiring", json=mock_data)
97 | assert api.pools_retiring() == convert_json_to_object(mock_data)
98 |
99 |
100 | def test_integration_pools_retiring():
101 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
102 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
103 | assert api.pools_retiring()
104 |
105 |
106 | def test_pool(requests_mock):
107 | api = BlockFrostApi()
108 | mock_data = {
109 | "pool_id": pool_id,
110 | "hex": "0f292fcaa02b8b2f9b3c8f9fd8e0bb21abedb692a6d5058df3ef2735",
111 | "vrf_key": "0b5245f9934ec2151116fb8ec00f35fd00e0aa3b075c4ed12cce440f999d8233",
112 | "blocks_minted": 69,
113 | "blocks_epoch": 4,
114 | "live_stake": "6900000000",
115 | "live_size": 0.42,
116 | "live_saturation": 0.93,
117 | "live_delegators": 127,
118 | "active_stake": "4200000000",
119 | "active_size": 0.43,
120 | "declared_pledge": "5000000000",
121 | "live_pledge": "5000000001",
122 | "margin_cost": 0.05,
123 | "fixed_cost": "340000000",
124 | "reward_account": "stake1uxkptsa4lkr55jleztw43t37vgdn88l6ghclfwuxld2eykgpgvg3f",
125 | "owners": [
126 | "stake1u98nnlkvkk23vtvf9273uq7cph5ww6u2yq2389psuqet90sv4xv9v"
127 | ],
128 | "registration": [
129 | "9f83e5484f543e05b52e99988272a31da373f3aab4c064c76db96643a355d9dc",
130 | "7ce3b8c433bf401a190d58c8c483d8e3564dfd29ae8633c8b1b3e6c814403e95",
131 | "3e6e1200ce92977c3fe5996bd4d7d7e192bcb7e231bc762f9f240c76766535b9"
132 | ],
133 | "retirement": [
134 | "252f622976d39e646815db75a77289cf16df4ad2b287dd8e3a889ce14c13d1a8"
135 | ]
136 | }
137 | requests_mock.get(f"{api.url}/pools/{pool_id}", json=mock_data)
138 | assert api.pool(pool_id=pool_id) == convert_json_to_object(mock_data)
139 |
140 |
141 | def test_integration_pool():
142 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
143 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
144 | assert api.pool(pool_id=pool_id)
145 |
146 |
147 | def test_pool_history(requests_mock):
148 | api = BlockFrostApi()
149 | mock_data = [
150 | {
151 | "epoch": 233,
152 | "blocks": 22,
153 | "active_stake": "20485965693569",
154 | "active_size": 1.2345,
155 | "delegators_count": 115,
156 | "rewards": "206936253674159",
157 | "fees": "1290968354"
158 | }
159 | ]
160 | requests_mock.get(f"{api.url}/pools/{pool_id}/history", json=mock_data)
161 | assert api.pool_history(pool_id=pool_id) == convert_json_to_object(mock_data)
162 |
163 |
164 | def test_integration_pool_history():
165 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
166 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
167 | assert api.pool_history(pool_id=pool_id)
168 |
169 |
170 | def test_pool_metadata(requests_mock):
171 | api = BlockFrostApi()
172 | mock_data = {
173 | "pool_id": pool_id,
174 | "hex": "0f292fcaa02b8b2f9b3c8f9fd8e0bb21abedb692a6d5058df3ef2735",
175 | "url": "https://stakenuts.com/mainnet.json",
176 | "hash": "47c0c68cb57f4a5b4a87bad896fc274678e7aea98e200fa14a1cb40c0cab1d8c",
177 | "ticker": "NUTS",
178 | "name": "Stake Nuts",
179 | "description": "The best pool ever",
180 | "homepage": "https://stakentus.com/"
181 | }
182 | requests_mock.get(f"{api.url}/pools/{pool_id}/metadata", json=mock_data)
183 | assert api.pool_metadata(pool_id=pool_id) == convert_json_to_object(mock_data)
184 |
185 |
186 | def test_integration_pool_metadata():
187 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
188 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
189 | assert api.pool_metadata(pool_id=pool_id)
190 |
191 |
192 | def test_pool_relays(requests_mock):
193 | api = BlockFrostApi()
194 | mock_data = [
195 | {
196 | "ipv4": "4.4.4.4",
197 | "ipv6": "https://stakenuts.com/mainnet.json",
198 | "dns": "relay1.stakenuts.com",
199 | "dns_srv": "_relays._tcp.relays.stakenuts.com",
200 | "port": 3001
201 | }
202 | ]
203 | requests_mock.get(f"{api.url}/pools/{pool_id}/relays", json=mock_data)
204 | assert api.pool_relays(pool_id=pool_id) == convert_json_to_object(mock_data)
205 |
206 |
207 | def test_integration_pool_relays():
208 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
209 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
210 | assert api.pool_relays(pool_id=pool_id)
211 |
212 |
213 | def test_pool_delegators(requests_mock):
214 | api = BlockFrostApi()
215 | mock_data = [
216 | {
217 | "address": "stake1ux4vspfvwuus9uwyp5p3f0ky7a30jq5j80jxse0fr7pa56sgn8kha",
218 | "live_stake": "1137959159981411"
219 | },
220 | {
221 | "address": "stake1uylayej7esmarzd4mk4aru37zh9yz0luj3g9fsvgpfaxulq564r5u",
222 | "live_stake": "16958865648"
223 | },
224 | {
225 | "address": "stake1u8lr2pnrgf8f7vrs9lt79hc3sxm8s2w4rwvgpncks3axx6q93d4ck",
226 | "live_stake": "18605647"
227 | }
228 | ]
229 | requests_mock.get(f"{api.url}/pools/{pool_id}/delegators", json=mock_data)
230 | assert api.pool_delegators(pool_id=pool_id) == convert_json_to_object(mock_data)
231 |
232 |
233 | def test_integration_pool_delegators():
234 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
235 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
236 | assert api.pool_delegators(pool_id=pool_id)
237 |
238 |
239 | def test_pool_blocks(requests_mock):
240 | api = BlockFrostApi()
241 | mock_data = [
242 | "d8982ca42cfe76b747cc681d35d671050a9e41e9cfe26573eb214e94fe6ff21d",
243 | "026436c539e2ce84c7f77ffe669f4e4bbbb3b9c53512e5857dcba8bb0b4e9a8c",
244 | "bcc8487f419b8c668a18ea2120822a05df6dfe1de1f0fac3feba88cf760f303c",
245 | "86bf7b4a274e0f8ec9816171667c1b4a0cfc661dc21563f271acea9482b62df7"
246 | ]
247 | requests_mock.get(f"{api.url}/pools/{pool_id}/blocks", json=mock_data)
248 | assert api.pool_blocks(pool_id=pool_id) == convert_json_to_object(mock_data)
249 |
250 |
251 | def test_integration_pool_blocks():
252 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
253 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
254 | assert api.pool_blocks(pool_id=pool_id)
255 |
256 |
257 | def test_pool_updates(requests_mock):
258 | api = BlockFrostApi()
259 | mock_data = [
260 | {
261 | "tx_hash": "6804edf9712d2b619edb6ac86861fe93a730693183a262b165fcc1ba1bc99cad",
262 | "cert_index": 0,
263 | "action": "registered"
264 | },
265 | {
266 | "tx_hash": "9c190bc1ac88b2ab0c05a82d7de8b71b67a9316377e865748a89d4426c0d3005",
267 | "cert_index": 0,
268 | "action": "deregistered"
269 | },
270 | {
271 | "tx_hash": "e14a75b0eb2625de7055f1f580d70426311b78e0d36dd695a6bdc96c7b3d80e0",
272 | "cert_index": 1,
273 | "action": "registered"
274 | }
275 | ]
276 | requests_mock.get(f"{api.url}/pools/{pool_id}/updates", json=mock_data)
277 | assert api.pool_updates(pool_id=pool_id) == convert_json_to_object(mock_data)
278 |
279 |
280 | def test_integration_pool_updates():
281 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
282 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
283 | assert api.pool_updates(pool_id=pool_id)
284 |
--------------------------------------------------------------------------------
/tests/test_cardano_scripts.py:
--------------------------------------------------------------------------------
1 | import os, json
2 | from blockfrost import BlockFrostApi, ApiError
3 | from blockfrost.utils import convert_json_to_object
4 |
5 | script_hash = "65c197d565e88a20885e535f93755682444d3c02fd44dd70883fe89e"
6 | datum_hash = "923918e403bf43c34b4ef6b48eb2ee04babed17320d8d1b9ff9ad086e86f44ec"
7 |
8 |
9 | def test_scripts(requests_mock):
10 | api = BlockFrostApi()
11 | mock_data = [
12 | {
13 | "script_hash": script_hash
14 | },
15 | {
16 | "script_hash": "e1457a0c47dfb7a2f6b8fbb059bdceab163c05d34f195b87b9f2b30e"
17 | },
18 | {
19 | "script_hash": "a6e63c0ff05c96943d1cc30bf53112ffff0f34b45986021ca058ec54"
20 | }
21 | ]
22 | requests_mock.get(f"{api.url}/scripts", json=mock_data)
23 | assert api.scripts() == convert_json_to_object(mock_data)
24 |
25 |
26 | def test_integration_scripts():
27 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
28 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
29 | assert api.scripts()
30 |
31 |
32 | def test_script(requests_mock):
33 | api = BlockFrostApi()
34 | mock_data = {
35 | "script_hash": "13a3efd825703a352a8f71f4e2758d08c28c564e8dfcce9f77776ad1",
36 | "type": "plutus",
37 | "serialised_size": 3119
38 | }
39 | requests_mock.get(f"{api.url}/scripts/{script_hash}", json=mock_data)
40 | assert api.script(script_hash=script_hash) == convert_json_to_object(mock_data)
41 |
42 |
43 | def test_integration_script():
44 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
45 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
46 | assert api.script(script_hash=script_hash)
47 |
48 |
49 | def test_script_json(requests_mock):
50 | api = BlockFrostApi()
51 | mock_data = {
52 | "json": {
53 | "type": "atLeast",
54 | "scripts": [
55 | {
56 | "type": "sig",
57 | "keyHash": "654891a4db2ea44b5263f4079a33efa0358ba90769e3d8f86a4a0f81"
58 | },
59 | {
60 | "type": "sig",
61 | "keyHash": "8685ad48f9bebb8fdb6447abbe140645e0bf743ff98da62e63e2147f"
62 | },
63 | {
64 | "type": "sig",
65 | "keyHash": "cb0f3b3f91693374ff7ce1d473cf6e721c7bab52b0737f04164e5a2d"
66 | }
67 | ],
68 | "required": 2
69 | }
70 | }
71 | requests_mock.get(f"{api.url}/scripts/{script_hash}/json", json=mock_data)
72 | assert api.script_json(script_hash=script_hash) == convert_json_to_object(mock_data)
73 |
74 |
75 | def test_integration_script_json():
76 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
77 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
78 | assert api.script_json(script_hash=script_hash)
79 |
80 |
81 | def test_script_cbor(requests_mock):
82 | api = BlockFrostApi()
83 | mock_data = {
84 | "cbor": "4e4d01000033222220051200120011"
85 | }
86 | requests_mock.get(f"{api.url}/scripts/{script_hash}/cbor", json=mock_data)
87 | assert api.script_cbor(script_hash=script_hash) == convert_json_to_object(mock_data)
88 |
89 |
90 | def test_integration_script_cbor():
91 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
92 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
93 | assert api.script_cbor(script_hash=script_hash)
94 |
95 |
96 | def test_script_redeemers(requests_mock):
97 | api = BlockFrostApi()
98 | mock_data = [
99 | {
100 | "tx_hash": "1a0570af966fb355a7160e4f82d5a80b8681b7955f5d44bec0dce628516157f0",
101 | "tx_index": 0,
102 | "purpose": "spend",
103 | "unit_mem": "1700",
104 | "unit_steps": "476468",
105 | "fee": "172033"
106 | }
107 | ]
108 | requests_mock.get(f"{api.url}/scripts/{script_hash}/redeemers", json=mock_data)
109 | assert api.script_redeemers(script_hash=script_hash) == convert_json_to_object(mock_data)
110 |
111 |
112 | def test_integration_script_redeemers():
113 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
114 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
115 | assert api.script_redeemers(script_hash=script_hash) == []
116 |
117 |
118 | def test_script_datum(requests_mock):
119 | api = BlockFrostApi()
120 | mock_data = {
121 | "json_value": {
122 | "int": 42
123 | }
124 | }
125 | requests_mock.get(f"{api.url}/scripts/datum/{datum_hash}", json=mock_data)
126 | assert api.script_datum(datum_hash=datum_hash) == convert_json_to_object(mock_data)
127 |
128 |
129 | def test_integration_script_datum():
130 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
131 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
132 | assert api.script_datum(datum_hash=datum_hash)
133 |
134 | def test_script_datum_cbor(requests_mock):
135 | api = BlockFrostApi()
136 | mock_data = {
137 | "cbor": "4e4d01000033222220051200120011"
138 | }
139 | requests_mock.get(f"{api.url}/scripts/datum/{datum_hash}/cbor", json=mock_data)
140 | assert api.script_datum_cbor(datum_hash=datum_hash) == convert_json_to_object(mock_data)
141 |
142 |
143 | def test_integration_script_datum_cbor():
144 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
145 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
146 | assert api.script_datum_cbor(datum_hash=datum_hash)
147 |
--------------------------------------------------------------------------------
/tests/test_cardano_utils.py:
--------------------------------------------------------------------------------
1 | import os, json
2 | from blockfrost import BlockFrostApi, ApiError
3 | from blockfrost.utils import convert_json_to_object
4 |
5 | hash = "8f55e18a94e4c0951e5b8bd8910b2cb20aa4d742b1608fda3a06793d39fb07b1"
6 | xpub = "d507c8f866691bd96e131334c355188b1a1d0b2fa0ab11545075aab332d77d9eb19657ad13ee581b56b0f8d744d66ca356b93d42fe176b3de007d53e9c4c4e7a"
7 | role = 0
8 | index = 0
9 |
10 |
11 | def test_utils_addresses_xpub(requests_mock):
12 | api = BlockFrostApi()
13 | mock_data = [
14 | {
15 | "xpub": "d507c8f866691bd96e131334c355188b1a1d0b2fa0ab11545075aab332d77d9eb19657ad13ee581b56b0f8d744d66ca356b93d42fe176b3de007d53e9c4c4e7a",
16 | "role": 0,
17 | "index": 0,
18 | "address": "addr1q90sqnljxky88s0jsnps48jd872p7znzwym0jpzqnax6qs5nfrlkaatu28n0qzmqh7f2cpksxhpc9jefx3wrl0a2wu8q5amen7"
19 | }
20 | ]
21 | requests_mock.get(f"{api.url}/utils/addresses/xpub/{xpub}/{role}/{index}", json=mock_data)
22 | assert api.utils_addresses_xpub(xpub, role, index) == convert_json_to_object(mock_data)
23 |
24 |
25 | def test_integration_utils_addresses_xpub():
26 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
27 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
28 | assert api.utils_addresses_xpub(xpub, role, index)
29 |
30 |
31 | def test_utils_transaction_evaluate(requests_mock):
32 | api = BlockFrostApi()
33 | mock_data = hash
34 | requests_mock.post(f"{api.url}/utils/txs/evaluate", json=mock_data)
35 | assert api.transaction_evaluate(file_path="./README.md") == convert_json_to_object(mock_data)
36 |
--------------------------------------------------------------------------------
/tests/test_health.py:
--------------------------------------------------------------------------------
1 | import os
2 | from blockfrost import BlockFrostApi, ApiError
3 | from blockfrost.utils import convert_json_to_object
4 |
5 |
6 | def test_health(requests_mock):
7 | api = BlockFrostApi()
8 | mock_data = {
9 | "is_healthy": True
10 | }
11 | requests_mock.get(api.url + '/health', json=mock_data)
12 | assert api.health() == convert_json_to_object(mock_data)
13 |
14 |
15 | def test_integration_health():
16 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
17 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
18 | assert api.health()
19 |
20 |
21 | def test_clock(requests_mock):
22 | api = BlockFrostApi()
23 | mock_data = {
24 | "server_time": 1603400958947
25 | }
26 | requests_mock.get(api.url + '/health/clock', json=mock_data)
27 | assert api.clock() == convert_json_to_object(mock_data)
28 |
29 |
30 | def test_integration_clock():
31 | if os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'):
32 | api = BlockFrostApi(project_id=os.getenv('BLOCKFROST_PROJECT_ID_MAINNET'))
33 | assert api.clock()
34 |
--------------------------------------------------------------------------------
/tests/test_helpers.py:
--------------------------------------------------------------------------------
1 | import os
2 | import mock
3 | import pytest
4 | from blockfrost import SignatureVerificationError, verify_webhook_signature
5 |
6 | request_body = b'{"id":"47668401-c3a4-42d4-bac1-ad46515924a3","webhook_id":"cf68eb9c-635f-415e-a5a8-6233638f28d7","created":1650013856,"type":"block","payload":{"time":1650013853,"height":7126256,"hash":"f49521b67b440e5030adf124aee8f88881b7682ba07acf06c2781405b0f806a4","slot":58447562,"epoch":332,"epoch_slot":386762,"slot_leader":"pool1njjr0zn7uvydjy8067nprgwlyxqnznp9wgllfnag24nycgkda25","size":34617,"tx_count":13,"output":"13403118309871","fees":"4986390","block_vrf":"vrf_vk197w95j9alkwt8l4g7xkccknhn4pqwx65c5saxnn5ej3cpmps72msgpw69d","previous_block":"9e3f5bfc9f0be44cf6e14db9ed5f1efb6b637baff0ea1740bb6711786c724915","next_block":null,"confirmations":0}}'
7 | success_fixtures_list = [
8 | {
9 | 'description': 'valid signature',
10 | 'request_body': request_body,
11 | 'signature_header': 't=1650013856,v1=f4c3bb2a8b0c8e21fa7d5fdada2ee87c9c6f6b0b159cc22e483146917e195c3e',
12 | 'secret': '59a1eb46-96f4-4f0b-8a03-b4d26e70593a',
13 | 'current_timestamp_mock': 1650013856 + 1,
14 | 'result': True
15 | },
16 | {
17 | 'description': '2 signatures, one valid and one invalid',
18 | 'request_body': request_body,
19 | 'signature_header': 't=1650013856,v1=abc,v1=f4c3bb2a8b0c8e21fa7d5fdada2ee87c9c6f6b0b159cc22e483146917e195c3e',
20 | 'secret': '59a1eb46-96f4-4f0b-8a03-b4d26e70593a',
21 | 'current_timestamp_mock': 1650013856 + 1,
22 | 'result': True
23 | }
24 | ]
25 |
26 | error_fixtures_list = [
27 | {
28 | 'description': 'throws due to invalid header fromat',
29 | 'request_body': request_body,
30 | 'signature_header': 'v1=f4c3bb2a8b0c8e21fa7d5fdada2ee87c9c6f6b0b159cc22e483146917e195c3e',
31 | 'secret': '59a1eb46-96f4-4f0b-8a03-b4d26e70593a',
32 | 'current_timestamp_mock': 1650013856 + 1,
33 | 'result_error': 'Invalid signature header format.'
34 | },
35 | {
36 | 'description': 'throws due to sig version not supported by this sdk',
37 | 'request_body': request_body,
38 | 'signature_header': 't=1650013856,v42=abc',
39 | 'secret': '59a1eb46-96f4-4f0b-8a03-b4d26e70593a',
40 | 'current_timestamp_mock': 1650013856 + 1,
41 | 'result_error': 'No signatures with supported version scheme.'
42 | },
43 | {
44 | 'description': 'throws due to no signature match',
45 | 'request_body': request_body,
46 | 'signature_header': 't=1650013856,v1=abc',
47 | 'secret': '59a1eb46-96f4-4f0b-8a03-b4d26e70593a',
48 | 'current_timestamp_mock': 1650013856 + 1,
49 | 'result_error': 'No signature matches the expected signature for the payload.'
50 | },
51 | {
52 | 'description': 'throws due to timestamp out of tolerance zone',
53 | 'request_body': request_body,
54 | 'signature_header': 't=1650013856,v1=f4c3bb2a8b0c8e21fa7d5fdada2ee87c9c6f6b0b159cc22e483146917e195c3e',
55 | 'secret': '59a1eb46-96f4-4f0b-8a03-b4d26e70593a',
56 | 'current_timestamp_mock': 1650013856 + 7200,
57 | 'result_error': 'Signature\'s timestamp is outside of the time tolerance.'
58 | }
59 | ]
60 |
61 |
62 | @pytest.mark.parametrize("fixture", success_fixtures_list)
63 | def test_verify_webhook_signature(fixture):
64 | with mock.patch('blockfrost.helpers.get_unix_timestamp', return_value=fixture['current_timestamp_mock']):
65 | res = verify_webhook_signature(
66 | fixture['request_body'], fixture['signature_header'], fixture['secret'])
67 | assert res == fixture['result']
68 |
69 |
70 | @pytest.mark.parametrize("fixture", error_fixtures_list)
71 | def test_verify_webhook_signature_fails(fixture):
72 | with mock.patch('blockfrost.helpers.get_unix_timestamp', return_value=fixture['current_timestamp_mock']):
73 | with pytest.raises(SignatureVerificationError) as e_info:
74 | verify_webhook_signature(
75 | fixture['request_body'], fixture['signature_header'], fixture['secret'])
76 | assert str(e_info.value) == fixture['result_error']
77 | assert e_info.value.header == fixture['signature_header']
78 | assert e_info.value.request_body == fixture['request_body']
79 |
--------------------------------------------------------------------------------
/tests/test_ipfs_add.py:
--------------------------------------------------------------------------------
1 | from blockfrost import BlockFrostIPFS, ApiError
2 | from blockfrost.utils import convert_json_to_object
3 |
4 | file_path = "README.md"
5 |
6 |
7 | def test_add(requests_mock):
8 | ipfs = BlockFrostIPFS()
9 | mock_data = {
10 | "name": file_path,
11 | "ipfs_hash": "QmZbHqiCxKEVX7QfijzJTkZiSi3WEVTcvANgNAWzDYgZDr",
12 | "size": 125297
13 | }
14 | requests_mock.post(f"{ipfs.url}/ipfs/add", json=mock_data)
15 | assert ipfs.add(file_path=file_path) == convert_json_to_object(mock_data)
16 |
--------------------------------------------------------------------------------
/tests/test_ipfs_gateway.py:
--------------------------------------------------------------------------------
1 | from blockfrost import BlockFrostIPFS, ApiError
2 | from blockfrost.utils import convert_json_to_object
3 |
4 | IPFS_path = "QmZbHqiCxKEVX7QfijzJTkZiSi3WEVTcvANgNAWzDYgZDr"
5 |
6 |
7 | def test_gateway(requests_mock):
8 | ipfs = BlockFrostIPFS()
9 | mock_data = "data"
10 | requests_mock.get(f"{ipfs.url}/ipfs/gateway/{IPFS_path}", text=mock_data)
11 | assert ipfs.gateway(IPFS_path=IPFS_path).text == convert_json_to_object(mock_data)
12 |
--------------------------------------------------------------------------------
/tests/test_ipfs_pins.py:
--------------------------------------------------------------------------------
1 | from blockfrost import BlockFrostIPFS, ApiError
2 | from blockfrost.utils import convert_json_to_object
3 |
4 | IPFS_path = "QmZbHqiCxKEVX7QfijzJTkZiSi3WEVTcvANgNAWzDYgZDr"
5 |
6 |
7 | def test_pin_object(requests_mock):
8 | ipfs = BlockFrostIPFS()
9 | mock_data = {
10 | "ipfs_hash": IPFS_path,
11 | "state": "queued"
12 | }
13 | requests_mock.post(f"{ipfs.url}/ipfs/pin/add/{IPFS_path}", json=mock_data)
14 | assert ipfs.pin_object(IPFS_path=IPFS_path) == convert_json_to_object(mock_data)
15 |
16 |
17 | def test_pined_list(requests_mock):
18 | ipfs = BlockFrostIPFS()
19 | mock_data = [
20 | {
21 | "time_created": 1615551024,
22 | "time_pinned": 1615551024,
23 | "ipfs_hash": IPFS_path,
24 | "size": 1615551024,
25 | "state": "pinned"
26 | }
27 | ]
28 | requests_mock.get(f"{ipfs.url}/ipfs/pin/list", json=mock_data)
29 | assert ipfs.pined_list() == convert_json_to_object(mock_data)
30 |
31 |
32 | def test_pined_object(requests_mock):
33 | ipfs = BlockFrostIPFS()
34 | mock_data = {
35 | "time_created": 1615551024,
36 | "time_pinned": 1615551024,
37 | "ipfs_hash": IPFS_path,
38 | "size": 1615551024,
39 | "state": "pinned"
40 | }
41 | requests_mock.get(f"{ipfs.url}/ipfs/pin/list/{IPFS_path}", json=mock_data)
42 | assert ipfs.pined_object(IPFS_path=IPFS_path) == convert_json_to_object(mock_data)
43 |
44 |
45 | def test_pined_object_remove(requests_mock):
46 | ipfs = BlockFrostIPFS()
47 | mock_data = {
48 | "ipfs_hash": IPFS_path,
49 | "state": "unpinned"
50 | }
51 | requests_mock.post(f"{ipfs.url}/ipfs/pin/remove/{IPFS_path}", json=mock_data)
52 | assert ipfs.pined_object_remove(IPFS_path=IPFS_path) == convert_json_to_object(mock_data)
53 |
--------------------------------------------------------------------------------
/tests/test_metrics.py:
--------------------------------------------------------------------------------
1 | from blockfrost import BlockFrostApi, ApiError
2 | from blockfrost.utils import convert_json_to_object
3 |
4 |
5 | def test_metrics(requests_mock):
6 | api = BlockFrostApi()
7 | mock_data = [
8 | {
9 | "time": 1612543884,
10 | "calls": 42
11 | },
12 | {
13 | "time": 1614523884,
14 | "calls": 6942
15 | }
16 | ]
17 |
18 | requests_mock.get(api.url + '/metrics', json=mock_data)
19 | assert api.metrics() == convert_json_to_object(mock_data)
20 |
21 |
22 | def test_metrics_endpoints(requests_mock):
23 | api = BlockFrostApi()
24 | mock_data = [
25 | {
26 | "time": 1612543814,
27 | "calls": 182,
28 | "endpoint": "block"
29 | },
30 | {
31 | "time": 1612543814,
32 | "calls": 42,
33 | "endpoint": "epoch"
34 | },
35 | ]
36 |
37 | requests_mock.get(api.url + '/metrics/endpoints', json=mock_data)
38 | assert api.metrics_endpoints() == convert_json_to_object(mock_data)
39 |
--------------------------------------------------------------------------------
/tests/test_object_mapper.py:
--------------------------------------------------------------------------------
1 | import pandas as pd
2 | from pandas._testing import assert_frame_equal
3 | from blockfrost import BlockFrostApi, ApiError
4 | from blockfrost.utils import convert_json_to_object
5 |
6 | api = BlockFrostApi()
7 |
8 | mock_data = {
9 | "is_healthy": True
10 | }
11 |
12 |
13 | def test_default_mapper(requests_mock):
14 | requests_mock.get(api.url + '/health', json=mock_data)
15 | assert api.health() == convert_json_to_object(mock_data)
16 |
17 |
18 | def test_object_mapper(requests_mock):
19 | requests_mock.get(api.url + '/health', json=mock_data)
20 | assert api.health(return_type="object") == convert_json_to_object(mock_data)
21 |
22 |
23 | def test_json_mapper(requests_mock):
24 | requests_mock.get(api.url + '/health', json=mock_data)
25 | assert api.health(return_type="json") == mock_data
26 |
27 |
28 | def test_pandas_mapper(requests_mock):
29 | requests_mock.get(api.url + '/health', json=mock_data)
30 | mock_pandas = pd.json_normalize(mock_data)
31 | assert_frame_equal(api.health(return_type="pandas"), mock_pandas)
32 |
--------------------------------------------------------------------------------