├── .coveragerc ├── .flake8 ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── dependabot.yml ├── donate_addr.png ├── logo.png └── workflows │ ├── main.yml │ └── publish.yml ├── .gitignore ├── .readthedocs.yaml ├── CHANGELOG.md ├── LICENSE ├── Makefile ├── README.md ├── docs ├── Makefile ├── make.bat ├── requirements.txt └── source │ ├── api │ ├── pycardano.address.rst │ ├── pycardano.backend.base.rst │ ├── pycardano.certificate.rst │ ├── pycardano.cip.rst │ ├── pycardano.coinselection.rst │ ├── pycardano.crypto.rst │ ├── pycardano.exception.rst │ ├── pycardano.governance.rst │ ├── pycardano.hash.rst │ ├── pycardano.key.rst │ ├── pycardano.metadata.rst │ ├── pycardano.nativescript.rst │ ├── pycardano.network.rst │ ├── pycardano.plutus.rst │ ├── pycardano.poolparams.rst │ ├── pycardano.serialization.rst │ ├── pycardano.transaction.rst │ ├── pycardano.utils.rst │ └── pycardano.witness.rst │ ├── conf.py │ ├── guides │ ├── address.rst │ ├── instance_creation.rst │ ├── plutus.rst │ ├── serialization.rst │ └── transaction.rst │ ├── index.rst │ └── tutorial.rst ├── ensure_pure_cbor2.sh ├── examples ├── delegator_loyalty_rewards.py ├── full_stack │ ├── README.md │ ├── demo.gif │ ├── poetry.lock │ ├── pyproject.toml │ ├── sequence_diagram.svg │ ├── sequence_diagram.txt │ ├── server.py │ ├── static │ │ ├── App.js │ │ └── style.css │ └── templates │ │ └── index.html ├── more_examples │ ├── .env-example │ ├── .gitignore │ ├── 01_address.py │ ├── 02_query_address.py │ ├── 03_distribute.py │ ├── 04_consolidate.py │ ├── 05_mint_asset.py │ ├── 06_query_receive_address.py │ ├── 07_mint_nfts.py │ ├── 08_burn_nfts.py │ ├── 09_sign_document_data.py │ ├── 10_verify_document.py │ ├── 11_verify_fake_document.py │ ├── 12_transaction_chaining.py │ ├── README.md │ └── keys │ │ └── .gitkeep ├── native_token.py ├── plutus │ └── forty_two │ │ ├── README.md │ │ ├── forty_two.py │ │ ├── fortytwo.plutus │ │ └── fortytwoV2.plutus ├── raw_multi_asset_transaction.py ├── raw_transaction.py ├── tx_builder.py └── tx_builder_with_metadata.py ├── integration-test ├── README.md ├── __init__.py ├── bootstrap.sh ├── configs │ ├── local-alonzo │ │ ├── alonzo-genesis.json │ │ ├── byron-genesis.json │ │ ├── byron │ │ │ ├── delegate.cert │ │ │ └── delegate.key │ │ ├── config.json │ │ ├── conway-genesis.json │ │ ├── shelley-genesis.json │ │ ├── shelley │ │ │ ├── kes.skey │ │ │ ├── kes.vkey │ │ │ ├── node.cert │ │ │ ├── operator.counter │ │ │ ├── operator.skey │ │ │ ├── operator.vkey │ │ │ ├── utxo-keys │ │ │ │ ├── payment.addr │ │ │ │ ├── utxo1.skey │ │ │ │ └── utxo1.vkey │ │ │ ├── vrf.skey │ │ │ └── vrf.vkey │ │ └── topology.json │ ├── local-chang │ │ ├── alonzo-genesis.json │ │ ├── byron-genesis.json │ │ ├── byron │ │ │ ├── delegate.cert │ │ │ └── delegate.key │ │ ├── config.json │ │ ├── conway-genesis.json │ │ ├── shelley-genesis.json │ │ ├── shelley │ │ │ ├── kes.skey │ │ │ ├── kes.vkey │ │ │ ├── node.cert │ │ │ ├── operator.counter │ │ │ ├── operator.skey │ │ │ ├── operator.vkey │ │ │ ├── utxo-keys │ │ │ │ ├── payment.addr │ │ │ │ ├── utxo1.skey │ │ │ │ └── utxo1.vkey │ │ │ ├── vrf.skey │ │ │ └── vrf.vkey │ │ └── topology.json │ ├── local-vasil │ │ ├── alonzo-genesis.json │ │ ├── byron-genesis.json │ │ ├── byron │ │ │ ├── delegate.cert │ │ │ └── delegate.key │ │ ├── config.json │ │ ├── conway-genesis.json │ │ ├── shelley-genesis.json │ │ ├── shelley │ │ │ ├── kes.skey │ │ │ ├── kes.vkey │ │ │ ├── node.cert │ │ │ ├── operator.counter │ │ │ ├── operator.skey │ │ │ ├── operator.vkey │ │ │ ├── utxo-keys │ │ │ │ ├── payment.addr │ │ │ │ ├── utxo1.skey │ │ │ │ └── utxo1.vkey │ │ │ ├── vrf.skey │ │ │ └── vrf.vkey │ │ └── topology.json │ ├── mainnet │ │ ├── alonzo-genesis.json │ │ ├── byron-genesis.json │ │ ├── config.json │ │ ├── shelley-genesis.json │ │ └── topology.json │ └── testnet │ │ ├── alonzo-genesis.json │ │ ├── byron-genesis.json │ │ ├── config.json │ │ ├── shelley-genesis.json │ │ └── topology.json ├── docker-compose-chang.yml ├── docker-compose.yml ├── keys │ ├── extended.skey │ └── pool │ │ ├── cold.counter │ │ ├── cold.skey │ │ ├── cold.vkey │ │ ├── delegation.cert │ │ ├── full.addr │ │ ├── kes.skey │ │ ├── kes.vkey │ │ ├── node.cert │ │ ├── payment.addr │ │ ├── payment.skey │ │ ├── payment.vkey │ │ ├── pool-registration.cert │ │ ├── pool.id │ │ ├── pool_registration_tx.signed │ │ ├── stake.addr │ │ ├── stake.cert │ │ ├── stake.skey │ │ ├── stake.vkey │ │ ├── topology.json │ │ ├── vrf.skey │ │ └── vrf.vkey ├── plutus_scripts │ ├── always_succeeds.plutus │ ├── fortytwo.plutus │ ├── fortytwoV2.plutus │ ├── helloworldV3.plutus │ ├── pass_certifying_and_rewarding.plutus │ └── unroll.plutus ├── run_node.sh ├── run_pool.sh ├── run_tests.sh └── test │ ├── __init__.py │ ├── base.py │ ├── test_cardano_cli.py │ ├── test_certificate.py │ ├── test_certificate_script.py │ ├── test_governance.py │ ├── test_min_utxo.py │ ├── test_mint.py │ ├── test_ogmios.py │ ├── test_plutus.py │ └── test_zero_empty_asset.py ├── poetry.lock ├── pycardano ├── __init__.py ├── address.py ├── backend │ ├── __init__.py │ ├── base.py │ ├── blockfrost.py │ ├── cardano_cli.py │ ├── kupo.py │ ├── ogmios_v5.py │ └── ogmios_v6.py ├── certificate.py ├── cip │ ├── __init__.py │ ├── cip14.py │ └── cip8.py ├── coinselection.py ├── crypto │ ├── __init__.py │ ├── bech32.py │ └── bip32.py ├── exception.py ├── governance.py ├── hash.py ├── key.py ├── logging.py ├── metadata.py ├── nativescript.py ├── network.py ├── plutus.py ├── pool_params.py ├── serialization.py ├── transaction.py ├── txbuilder.py ├── types.py ├── utils.py └── witness.py ├── pyproject.toml └── test ├── __init__.py ├── conftest.py ├── pycardano ├── __init__.py ├── backend │ ├── __init__.py │ ├── conftest.py │ ├── test_blockfrost.py │ ├── test_cardano_cli.py │ └── test_ogmios_v5.py ├── crypto │ ├── __init__.py │ └── test_bip32.py ├── test_address.py ├── test_certificate.py ├── test_cip14.py ├── test_cip8.py ├── test_coinselection.py ├── test_governance.py ├── test_key.py ├── test_metadata.py ├── test_nativescript.py ├── test_network.py ├── test_plutus.py ├── test_pool_params.py ├── test_serialization.py ├── test_transaction.py ├── test_txbuilder.py ├── test_types.py ├── test_util.py └── util.py └── resources ├── haskell └── PlutusData │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── cabal.project │ ├── hie.yaml │ ├── plutus-data.cabal │ ├── plutus-data.cbor │ ├── plutus-data.json │ └── src │ └── PlutusData.hs └── keys ├── cold.skey ├── cold.vkey ├── payment.skey ├── payment.vkey ├── staking.skey └── staking.vkey /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | branch = True 3 | omit = 4 | pycardano/crypto/bech32.py 5 | 6 | [report] 7 | # Regexes for lines to exclude from consideration 8 | exclude_lines = 9 | # Have to re-enable the standard pragma 10 | pragma: no cover 11 | 12 | # Don't complain about missing debug-only code: 13 | def __repr__ 14 | if self\.debug 15 | 16 | # Don't complain if tests don't hit defensive assertion code: 17 | raise AssertionError 18 | raise NotImplementedError 19 | 20 | # Don't complain if non-runnable code isn't run: 21 | if 0: 22 | if __name__ == .__main__.: 23 | 24 | ignore_errors = True 25 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = D203, E126, W503, E203 3 | exclude = 4 | .git, 5 | __pycache__, 6 | docs/source/conf.py, 7 | build, 8 | 9 | max-line-length = 120 -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [cffls] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior. e.g. A python script. 15 | 16 | **Logs** 17 | If applicable, add logs to help explain your problem. 18 | 19 | **Expected behavior** 20 | A clear and concise description of what you expected to happen. 21 | 22 | **Environment and software version (please complete the following information):** 23 | - OS: [e.g. Ubuntu 20.04.3 LTS, Mac OS 12.1] 24 | - PyCardano Version [e.g. 0.1.1] 25 | 26 | 27 | **Additional context** 28 | Add any other context about the problem here. 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "pip" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | open-pull-requests-limit: 0 -------------------------------------------------------------------------------- /.github/donate_addr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Python-Cardano/pycardano/7d63d0e1da1b0e64cd2b9d389ed4f9e2e5c076ae/.github/donate_addr.png -------------------------------------------------------------------------------- /.github/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Python-Cardano/pycardano/7d63d0e1da1b0e64cd2b9d389ed4f9e2e5c076ae/.github/logo.png -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: "**" 6 | pull_request: 7 | branches: ["main", "chang"] 8 | types: [opened, reopened, edited, synchronize] 9 | 10 | jobs: 11 | build: 12 | 13 | runs-on: ${{ matrix.os }} 14 | strategy: 15 | matrix: 16 | os: [ubuntu-latest, macos-latest] 17 | python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] 18 | 19 | steps: 20 | - uses: actions/checkout@v4 21 | - name: Install poetry 22 | run: pipx install poetry 23 | - name: Set up Python ${{ matrix.python-version }} 24 | uses: actions/setup-python@v5 25 | with: 26 | python-version: ${{ matrix.python-version }} 27 | cache: 'poetry' 28 | - name: Install dependencies 29 | run: | 30 | poetry install 31 | - name: Ensure pure cbor2 is installed 32 | run: | 33 | make ensure-pure-cbor2 34 | - name: Run unit tests 35 | run: | 36 | poetry run pytest --doctest-modules --ignore=examples --cov=pycardano --cov-config=.coveragerc --cov-report=xml 37 | - name: "Upload coverage to Codecov" 38 | if: ${{ matrix.python-version == '3.11' }} 39 | uses: codecov/codecov-action@v4 40 | with: 41 | fail_ci_if_error: false 42 | token: ${{ secrets.CODECOV_TOKEN || '' }} 43 | - name: Run static analyses 44 | if: ${{ matrix.python-version == '3.11' }} 45 | run: | 46 | make qa 47 | 48 | continuous-integration: 49 | runs-on: ${{ matrix.os }} 50 | strategy: 51 | matrix: 52 | os: [ubuntu-latest] 53 | python-version: ['3.11'] 54 | 55 | steps: 56 | - uses: actions/checkout@v4 57 | - name: Install poetry 58 | run: pipx install poetry 59 | - name: Set up Python ${{ matrix.python-version }} 60 | uses: actions/setup-python@v5 61 | with: 62 | python-version: ${{ matrix.python-version }} 63 | cache: 'poetry' 64 | 65 | - name: Setup docker-compose 66 | uses: KengoTODA/actions-setup-docker-compose@v1.2.2 67 | with: 68 | version: '2.14.2' 69 | 70 | - name: Run integration tests 71 | run: | 72 | cd integration-test && ./run_tests.sh 73 | 74 | - name: "Upload coverage to Codecov" 75 | if: ${{ matrix.python-version == '3.11' }} 76 | uses: codecov/codecov-action@v4 77 | with: 78 | fail_ci_if_error: false 79 | token: ${{ secrets.CODECOV_TOKEN || '' }} 80 | 81 | - name: Dump docker logs 82 | if: failure() 83 | run: | 84 | cd integration-test && docker compose logs --no-color > integration-test.log 85 | 86 | - name: Upload integration-test.log 87 | if: failure() 88 | uses: actions/upload-artifact@v4 89 | with: 90 | name: integration-test.log 91 | path: integration-test/integration-test.log -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: publish 2 | on: 3 | push: 4 | tags: 5 | - "v[0-9]+.[0-9]+.[0-9]+" # Push events to matching *, i.e. 1.0, 20.15.10 6 | 7 | jobs: 8 | publish: 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | python-version: ['3.13'] 13 | os: [ubuntu-latest] 14 | runs-on: ${{ matrix.os }} 15 | steps: 16 | - uses: actions/checkout@v3 17 | - name: Install poetry 18 | run: pipx install poetry 19 | - name: Set up Python ${{ matrix.python-version }} 20 | uses: actions/setup-python@v5 21 | with: 22 | python-version: ${{ matrix.python-version }} 23 | cache: 'poetry' 24 | - name: Install dependencies 25 | run: | 26 | poetry install 27 | - name: Ensure pure cbor2 is installed 28 | run: | 29 | make ensure-pure-cbor2 30 | - name: Lint with flake8 31 | run: | 32 | poetry run flake8 pycardano 33 | - name: Run unit tests 34 | run: | 35 | poetry run pytest --doctest-modules --ignore=examples --cov=pycardano --cov-config=.coveragerc --cov-report=xml 36 | - name: poetry-check 37 | run: | 38 | poetry check 39 | - name: poetry-publish 40 | run: | 41 | poetry publish --build --username __token__ --password ${{ secrets.PYPI_TOKEN }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | .coverage 3 | cov_html 4 | docs/build 5 | dist 6 | .mypy_cache 7 | coverage.xml 8 | .cbor2_version 9 | 10 | # IDE 11 | .idea 12 | .code 13 | /integration-test/.env 14 | /integration-test/tmp_configs/* 15 | /integration-test/.coverage* -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Set the version of Python and other tools you might need 9 | build: 10 | os: ubuntu-20.04 11 | tools: 12 | python: "3.9" 13 | # You can also specify other tool versions: 14 | # nodejs: "16" 15 | # rust: "1.55" 16 | # golang: "1.17" 17 | 18 | # Build documentation in the docs/ directory with Sphinx 19 | sphinx: 20 | configuration: docs/source/conf.py 21 | 22 | # If using Sphinx, optionally build your docs in additional formats such as PDF 23 | # formats: 24 | # - pdf 25 | 26 | # Optionally declare the Python requirements required to build your docs 27 | python: 28 | install: 29 | - requirements: docs/requirements.txt 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 cffls 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: cov cov-html clean clean-test clean-pyc clean-build qa format test test-single help docs 2 | .DEFAULT_GOAL := help 3 | 4 | define BROWSER_PYSCRIPT 5 | import os, webbrowser, sys 6 | 7 | from urllib.request import pathname2url 8 | 9 | webbrowser.open("file://" + pathname2url(os.path.abspath(sys.argv[1]))) 10 | endef 11 | export BROWSER_PYSCRIPT 12 | 13 | define PRINT_HELP_PYSCRIPT 14 | import re, sys 15 | 16 | for line in sys.stdin: 17 | match = re.match(r'^([a-zA-Z_-]+):.*?## (.*)$$', line) 18 | if match: 19 | target, help = match.groups() 20 | print("%-20s %s" % (target, help)) 21 | endef 22 | export PRINT_HELP_PYSCRIPT 23 | 24 | BROWSER := poetry run python -c "$$BROWSER_PYSCRIPT" 25 | 26 | ensure-pure-cbor2: ## ensures cbor2 is installed with pure Python implementation 27 | @poetry run python -c "from importlib.metadata import version; \ 28 | print(version('cbor2'))" > .cbor2_version 29 | @poetry run python -c "import cbor2, inspect; \ 30 | print('Checking cbor2 implementation...'); \ 31 | decoder_path = inspect.getfile(cbor2.CBORDecoder); \ 32 | using_c_ext = decoder_path.endswith('.so'); \ 33 | print(f'Implementation path: {decoder_path}'); \ 34 | print(f'Using C extension: {using_c_ext}'); \ 35 | exit(1 if using_c_ext else 0)" || \ 36 | (echo "Reinstalling cbor2 with pure Python implementation..." && \ 37 | poetry run pip uninstall -y cbor2 && \ 38 | CBOR2_BUILD_C_EXTENSION=0 poetry run pip install --no-binary cbor2 "cbor2==$$(cat .cbor2_version)" --force-reinstall && \ 39 | rm .cbor2_version) 40 | 41 | help: 42 | @python -c "$$PRINT_HELP_PYSCRIPT" < $(MAKEFILE_LIST) 43 | 44 | cov: ensure-pure-cbor2 ## check code coverage 45 | poetry run pytest -n 4 --cov pycardano 46 | 47 | cov-html: cov ## check code coverage and generate an html report 48 | poetry run coverage html -d cov_html 49 | $(BROWSER) cov_html/index.html 50 | 51 | 52 | clean: clean-build clean-pyc clean-test ## remove all build, test, coverage and Python artifacts 53 | 54 | clean-build: ## remove build artifacts 55 | rm -fr build/ 56 | rm -fr dist/ 57 | rm -fr .eggs/ 58 | find . -name '*.egg-info' -exec rm -fr {} + 59 | find . -name '*.egg' -exec rm -f {} + 60 | 61 | clean-pyc: ## remove Python file artifacts 62 | find . -name '*.pyc' -exec rm -f {} + 63 | find . -name '*.pyo' -exec rm -f {} + 64 | find . -name '*~' -exec rm -f {} + 65 | find . -name '__pycache__' -exec rm -fr {} + 66 | 67 | clean-test: ## remove test and coverage artifacts 68 | rm -f .coverage 69 | rm -fr cov_html/ 70 | rm -fr .pytest_cache 71 | 72 | test: ensure-pure-cbor2 ## runs tests 73 | poetry run pytest -vv -n 4 74 | 75 | test-integration: ## runs integration tests 76 | cd integration-test && ./run_tests.sh 77 | 78 | test-single: ## runs tests with "single" markers 79 | poetry run pytest -s -vv -m single 80 | 81 | qa: ensure-pure-cbor2 ## runs static analyses 82 | poetry run flake8 pycardano 83 | poetry run mypy --install-types --non-interactive pycardano 84 | poetry run black --check . 85 | 86 | format: ## runs code style and formatter 87 | poetry run isort . 88 | poetry run black . 89 | 90 | docs: ## build the documentation 91 | poetry export --dev --without-hashes > docs/requirements.txt 92 | rm -r -f docs/build 93 | poetry run sphinx-build docs/source docs/build/html 94 | $(BROWSER) docs/build/html/index.html 95 | 96 | release: clean qa test format ensure-pure-cbor2 ## build dist version and release to pypi 97 | poetry build 98 | poetry publish -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.https://www.sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/source/api/pycardano.address.rst: -------------------------------------------------------------------------------- 1 | Address 2 | ======================== 3 | 4 | .. automodule:: pycardano.address 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/api/pycardano.backend.base.rst: -------------------------------------------------------------------------------- 1 | Backend 2 | ============================= 3 | 4 | .. automodule:: pycardano.backend.base 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | .. automodule:: pycardano.backend.blockfrost 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | 14 | .. automodule:: pycardano.backend.ogmios_v6 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: 18 | 19 | .. automodule:: pycardano.backend.ogmios_v5 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | -------------------------------------------------------------------------------- /docs/source/api/pycardano.certificate.rst: -------------------------------------------------------------------------------- 1 | Certificate 2 | ============================== 3 | 4 | .. automodule:: pycardano.certificate 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/api/pycardano.cip.rst: -------------------------------------------------------------------------------- 1 | CIP 2 | ===================== 3 | 4 | Implementation of Cardano Improvement Proposals (CIPs) 5 | 6 | .. automodule:: pycardano.cip.cip8 7 | :members: 8 | :undoc-members: 9 | :show-inheritance: 10 | 11 | .. automodule:: pycardano.cip.cip14 12 | :members: 13 | :undoc-members: 14 | :show-inheritance: 15 | -------------------------------------------------------------------------------- /docs/source/api/pycardano.coinselection.rst: -------------------------------------------------------------------------------- 1 | Coin selection 2 | ============================== 3 | 4 | .. automodule:: pycardano.coinselection 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/api/pycardano.crypto.rst: -------------------------------------------------------------------------------- 1 | Crypto 2 | ============================= 3 | A module that contains cryptographic functions. 4 | 5 | .. automodule:: pycardano.crypto.bip32 6 | :members: 7 | :undoc-members: 8 | :show-inheritance: 9 | -------------------------------------------------------------------------------- /docs/source/api/pycardano.exception.rst: -------------------------------------------------------------------------------- 1 | Exception 2 | ========================== 3 | 4 | .. automodule:: pycardano.exception 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/api/pycardano.governance.rst: -------------------------------------------------------------------------------- 1 | Governance 2 | ============================== 3 | 4 | .. automodule:: pycardano.governance 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/api/pycardano.hash.rst: -------------------------------------------------------------------------------- 1 | Hash 2 | ===================== 3 | 4 | .. automodule:: pycardano.hash 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/api/pycardano.key.rst: -------------------------------------------------------------------------------- 1 | Key 2 | ==================== 3 | 4 | .. automodule:: pycardano.key 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/api/pycardano.metadata.rst: -------------------------------------------------------------------------------- 1 | Metadata 2 | ==================== 3 | 4 | .. automodule:: pycardano.metadata 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/api/pycardano.nativescript.rst: -------------------------------------------------------------------------------- 1 | Native Script 2 | ==================== 3 | 4 | .. automodule:: pycardano.nativescript 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/api/pycardano.network.rst: -------------------------------------------------------------------------------- 1 | Network 2 | ======================== 3 | 4 | .. automodule:: pycardano.network 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/api/pycardano.plutus.rst: -------------------------------------------------------------------------------- 1 | Plutus 2 | ======================== 3 | 4 | .. automodule:: pycardano.plutus 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/api/pycardano.poolparams.rst: -------------------------------------------------------------------------------- 1 | Pool parameters 2 | ======================== 3 | 4 | .. automodule:: pycardano.pool_params 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/api/pycardano.serialization.rst: -------------------------------------------------------------------------------- 1 | Serialization 2 | ============================== 3 | 4 | .. automodule:: pycardano.serialization 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/api/pycardano.transaction.rst: -------------------------------------------------------------------------------- 1 | Transaction 2 | ============================ 3 | 4 | .. automodule:: pycardano.transaction 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | .. automodule:: pycardano.txbuilder 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | -------------------------------------------------------------------------------- /docs/source/api/pycardano.utils.rst: -------------------------------------------------------------------------------- 1 | Utils 2 | ====================== 3 | 4 | .. automodule:: pycardano.utils 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/api/pycardano.witness.rst: -------------------------------------------------------------------------------- 1 | Witness 2 | ======================== 3 | 4 | .. automodule:: pycardano.witness 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | import os 14 | import sys 15 | 16 | sys.path.insert(0, os.path.abspath("../")) 17 | # For readthedocs whose working dir is at docs/source 18 | sys.path.insert(0, os.path.abspath("../../")) 19 | 20 | 21 | # -- Project information ----------------------------------------------------- 22 | 23 | project = "PyCardano" 24 | copyright = "2023, Jerry" 25 | author = "Jerry" 26 | 27 | 28 | # -- General configuration --------------------------------------------------- 29 | 30 | # Add any Sphinx extension module names here, as strings. They can be 31 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 32 | # ones. 33 | extensions = [ 34 | "sphinx.ext.autodoc", 35 | "sphinx.ext.autosectionlabel", 36 | "sphinx.ext.napoleon", 37 | "sphinx_rtd_theme", 38 | "sphinx_copybutton", 39 | ] 40 | 41 | master_doc = "index" 42 | 43 | napoleon_google_docstring = True 44 | napoleon_include_init_with_doc = False 45 | 46 | copybutton_prompt_text = r">>> |\.\.\. |\$ |In \[\d*\]: | {2,5}\.\.\.: | {5,8}: " 47 | copybutton_prompt_is_regexp = True 48 | 49 | autodoc_member_order = "bysource" 50 | 51 | # Add any paths that contain templates here, relative to this directory. 52 | templates_path = ["_templates"] 53 | 54 | # List of patterns, relative to source directory, that match files and 55 | # directories to ignore when looking for source files. 56 | # This pattern also affects html_static_path and html_extra_path. 57 | exclude_patterns = [] 58 | 59 | pygments_style = "sphinx" 60 | highlight_language = "python" 61 | todo_include_todos = False 62 | 63 | 64 | # -- Options for HTML output ------------------------------------------------- 65 | 66 | # The theme to use for HTML and HTML Help pages. See the documentation for 67 | # a list of builtin themes. 68 | # 69 | html_theme = "sphinx_rtd_theme" 70 | 71 | # Add any paths that contain custom static files (such as style sheets) here, 72 | # relative to this directory. They are copied after the builtin static files, 73 | # so a file named "default.css" will overwrite the builtin "default.css". 74 | html_static_path = ["_static"] 75 | -------------------------------------------------------------------------------- /docs/source/guides/serialization.rst: -------------------------------------------------------------------------------- 1 | ============= 2 | Serialization 3 | ============= 4 | 5 | 6 | Cardano uses Concise Binary Object Representation (`CBOR `_) to 7 | store on-chain data. Reading and writing data from/to blockchain requires serialization and deserialization of CBOR 8 | binaries. 9 | 10 | A core feature PyCardano provides is serialization. It can serialize Python objects into CBOR bytes and deserialize 11 | CBOR bytes back to Python objects. Most Classes in PyCardano are child class of 12 | `CBORSerializable <../api/pycardano.serialization.html#pycardano.serialization.CBORSerializable>`_, which provides two 13 | CBOR-related methods. `to_cbor <../api/pycardano.serialization.html#pycardano.serialization.CBORSerializable.to_cbor>`_ 14 | generates CBOR bytes from an instance, and 15 | `from_cbor <../api/pycardano.serialization.html#pycardano.serialization.CBORSerializable.from_cbor>`_ restore an instance. 16 | 17 | Examples:: 18 | 19 | >>> from pycardano import (TransactionBody, 20 | ... TransactionInput, 21 | ... TransactionId, 22 | ... TransactionOutput) 23 | >>> 24 | >>> tx_id_hex = "732bfd67e66be8e8288349fcaaa2294973ef6271cc189a239bb431275401b8e5" 25 | >>> tx_in = TransactionInput(TransactionId(bytes.fromhex(tx_id_hex)), 0) 26 | >>> addr = Address.decode( 27 | ... "addr_test1vrm9x2zsux7va6w892g38tvchnzahvcd9tykqf3ygnmwtaqyfg52x" 28 | ... ) 29 | >>> output1 = TransactionOutput(addr, 100000000000) 30 | >>> output2 = TransactionOutput(addr, 799999834103) 31 | >>> fee = 165897 32 | >>> tx_body = TransactionBody( 33 | ... inputs=[tx_in], 34 | ... outputs=[output1, output2], 35 | ... fee=fee 36 | ... ) 37 | >>> cbor_hex = tx_body.to_cbor_hex() 38 | a50081825820732bfd67e66be8e8288349fcaaa2294973ef6271cc189a239bb431275401b8e500018282581d60f6532850e1bccee9c72a9113ad98bcc5dbb30d2ac960262444f6e5f41b000000174876e80082581d60f6532850e1bccee9c72a9113ad98bcc5dbb30d2ac960262444f6e5f41b000000ba43b4b7f7021a000288090d800e80 39 | 40 | >>> restored_tx_body = TransactionBody.from_cbor(cbor_hex) 41 | >>> assert tx_body == restored_tx_body 42 | 43 | >>> restored_tx_body 44 | {'auxiliary_data_hash': None, 45 | 'certificates': None, 46 | 'collateral': [], 47 | 'fee': 165897, 48 | 'inputs': [{'index': 0, 49 | 'transaction_id': TransactionId(hex='732bfd67e66be8e8288349fcaaa2294973ef6271cc189a239bb431275401b8e5')}], 50 | 'mint': None, 51 | 'network_id': None, 52 | 'outputs': [{'address': addr_test1vrm9x2zsux7va6w892g38tvchnzahvcd9tykqf3ygnmwtaqyfg52x, 53 | 'amount': 100000000000, 54 | 'datum_hash': None}, 55 | {'address': addr_test1vrm9x2zsux7va6w892g38tvchnzahvcd9tykqf3ygnmwtaqyfg52x, 56 | 'amount': 799999834103, 57 | 'datum_hash': None}], 58 | 'required_signers': [], 59 | 'script_data_hash': None, 60 | 'ttl': None, 61 | 'update': None, 62 | 'validity_start': None, 63 | 'withdraws': None} 64 | 65 | ---------- 66 | Plutus Data 67 | ---------- 68 | 69 | Note that Plutus datums, passed to `smart contracts <./plutus.html>`_ follow slightly specific rules to `from_cbor`, outlined in the `plutus documentation <./plutus.html#...>`_. -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. PyCardano documentation master file, created by 2 | sphinx-quickstart on Wed Dec 29 20:36:02 2021. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | PyCardano 7 | ===================================== 8 | 9 | PyCardano is a standalone Cardano client written in Python. The library is able to create and sign transactions 10 | without depending on third-party Cardano serialization tools, such as cardano-cli and cardano-serialization-lib, 11 | making it a light-weight library that is easy and fast to set up in all kinds of environments. 12 | 13 | .. toctree:: 14 | :maxdepth: 1 15 | :caption: Get Started 16 | 17 | tutorial 18 | 19 | .. toctree:: 20 | :maxdepth: 1 21 | :caption: Usage Guides 22 | 23 | guides/address 24 | guides/serialization 25 | guides/instance_creation 26 | guides/transaction 27 | guides/plutus 28 | 29 | 30 | .. toctree:: 31 | :maxdepth: 1 32 | :caption: API Reference 33 | 34 | api/pycardano.address 35 | api/pycardano.backend.base 36 | api/pycardano.certificate 37 | api/pycardano.cip 38 | api/pycardano.crypto 39 | api/pycardano.coinselection 40 | api/pycardano.exception 41 | api/pycardano.governance 42 | api/pycardano.hash 43 | api/pycardano.key 44 | api/pycardano.metadata 45 | api/pycardano.nativescript 46 | api/pycardano.network 47 | api/pycardano.plutus 48 | api/pycardano.poolparams 49 | api/pycardano.serialization 50 | api/pycardano.transaction 51 | api/pycardano.utils 52 | api/pycardano.witness 53 | 54 | 55 | Links 56 | ================== 57 | 58 | * :ref:`genindex` 59 | * :ref:`modindex` 60 | * :ref:`search` 61 | * `Github Home Page `_ 62 | * `More usage examples on Github `_ 63 | 64 | -------------------------------------------------------------------------------- /docs/source/tutorial.rst: -------------------------------------------------------------------------------- 1 | ========== 2 | Quickstart 3 | ========== 4 | 5 | ------------ 6 | Installation 7 | ------------ 8 | 9 | PyCardano could be installed using ``pip`` as follows: 10 | 11 | .. code-block:: shell 12 | 13 | $ pip install pycardano 14 | 15 | 16 | --------------- 17 | Using PyCardano 18 | --------------- 19 | 20 | Create a payment key and a payment address:: 21 | 22 | >>> from pycardano import Address, Network, PaymentSigningKey, PaymentVerificationKey 23 | 24 | >>> payment_signing_key = PaymentSigningKey.generate() 25 | >>> payment_signing_key.save("payment.skey") 26 | >>> payment_verification_key = PaymentVerificationKey.from_signing_key(payment_signing_key) 27 | >>> payment_verification_key.save("payment.vkey") 28 | 29 | >>> network = Network.TESTNET 30 | >>> address = Address(payment_part=payment_verification_key.hash(), network=network) 31 | >>> address 32 | 'addr_test1vr2p8st5t5cxqglyjky7vk98k7jtfhdpvhl4e97cezuhn0cqcexl7' 33 | 34 | 35 | .. warning:: 36 | 37 | Your address generated by the python code above will be different from the one shown. 38 | Please use the address you generated. Anything sent to the address above will be lost. 39 | 40 | 41 | Fund the address with some tADA (test ADA) through the 42 | `faucet `_ here. 43 | 44 | With the address and key created above, you can now create and sign transactions, and submit the 45 | transaction to Cardano network. `Transaction usage guide `_ provides detailed steps about 46 | transaction creation and signing. -------------------------------------------------------------------------------- /ensure_pure_cbor2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Script to ensure cbor2 is installed with pure Python implementation 3 | 4 | set -e 5 | 6 | # Check if poetry is available, otherwise use python directly 7 | if command -v poetry &> /dev/null; then 8 | PYTHON="poetry run python" 9 | else 10 | PYTHON="python" 11 | fi 12 | 13 | echo "Checking cbor2 version..." 14 | $PYTHON -c "from importlib.metadata import version; print(version('cbor2'))" > .cbor2_version 15 | CBOR2_VERSION=$(cat .cbor2_version) 16 | echo "Found cbor2 version: $CBOR2_VERSION" 17 | 18 | echo "Checking cbor2 implementation..." 19 | $PYTHON -c " 20 | import cbor2, inspect, sys 21 | decoder_path = inspect.getfile(cbor2.CBORDecoder) 22 | using_c_ext = decoder_path.endswith('.so') 23 | print(f'Implementation path: {decoder_path}') 24 | print(f'Using C extension: {using_c_ext}') 25 | sys.exit(1 if using_c_ext else 0) 26 | " 27 | 28 | if [ $? -ne 0 ]; then 29 | echo "Reinstalling cbor2 with pure Python implementation..." 30 | $PYTHON -m pip uninstall -y cbor2 31 | CBOR2_BUILD_C_EXTENSION=0 $PYTHON -m pip install --no-binary cbor2 "cbor2==$CBOR2_VERSION" --force-reinstall 32 | echo "Successfully reinstalled cbor2 with pure Python implementation" 33 | else 34 | echo "Already using pure Python implementation of cbor2" 35 | fi 36 | 37 | # Clean up 38 | rm -f .cbor2_version -------------------------------------------------------------------------------- /examples/delegator_loyalty_rewards.py: -------------------------------------------------------------------------------- 1 | """A script that sends loyalty rewards (based on certain rules) to a pool's delegators in one transaction 2 | An example transaction generated by this script on mainnet: 3 | https://cardanoscan.io/transaction/c1b58dd4f2f4ee8656cc7962eefa8552877c4aa23d0699c02b885363d592a961 4 | """ 5 | 6 | from blockfrost import ApiUrls, BlockFrostApi 7 | 8 | from pycardano import * 9 | 10 | # ======= Modify variables below ======== 11 | 12 | network = Network.MAINNET 13 | 14 | BLOCK_FROST_PROJECT_ID = "your_project_id" 15 | 16 | POOL_ID = "your_pool_id" 17 | 18 | POOL_TICKER = "your_pool_ticker" 19 | 20 | # An address where any changes will be returned to 21 | CHANGE_ADDRESS = "your_change_address" 22 | 23 | # If you want to exclude any address (e.g. your own address), include those in the variable below 24 | EXCLUDE_ADDRESSES = [] 25 | 26 | # The payment key used to generate sender address 27 | PAYMENT_KEY_PATH = "payment.skey" 28 | 29 | # ======= Modify variables above ======== 30 | 31 | 32 | # Read keys to memory 33 | # Assume there is a payment.skey file sitting in current directory 34 | psk = PaymentSigningKey.load(PAYMENT_KEY_PATH) 35 | pvk = PaymentVerificationKey.from_signing_key(psk) 36 | 37 | # Derive an address from payment verification key 38 | input_address = Address(pvk.hash(), network=network) 39 | print( 40 | f"ADA will be distributed from this address: {input_address}, make sure there are enough ADA in it." 41 | ) 42 | 43 | # Create a BlockFrost chain context 44 | context = BlockFrostChainContext(BLOCK_FROST_PROJECT_ID, base_url=ApiUrls.mainnet.value) 45 | 46 | api = BlockFrostApi(BLOCK_FROST_PROJECT_ID, ApiUrls.mainnet.value) 47 | 48 | delegators = api.pool_delegators(POOL_ID, gather_pages=True) 49 | 50 | to_send_50 = [] 51 | to_send_10 = [] 52 | 53 | for delegator in delegators: 54 | if delegator.address not in EXCLUDE_ADDRESSES: 55 | if int(delegator.live_stake) >= 100000000000: 56 | to_send_50.append(delegator) 57 | elif int(delegator.live_stake) >= 10000000000: 58 | to_send_10.append(delegator) 59 | 60 | builder = TransactionBuilder(context) 61 | 62 | builder.add_input_address(input_address) 63 | 64 | # ======= Business logic starts ======== 65 | 66 | # Send 50 ADA to delegators with 100K+ ADA 67 | for d in to_send_50: 68 | to_send_addr = api.account_addresses(d.address)[0].address 69 | builder.add_output(TransactionOutput.from_primitive([to_send_addr, 50000000])) 70 | 71 | # Send 10 ADA to delegators with 10K+ ADA 72 | for d in to_send_10: 73 | to_send_addr = api.account_addresses(d.address)[0].address 74 | builder.add_output(TransactionOutput.from_primitive([to_send_addr, 10000000])) 75 | 76 | # ======= Business logic ends ======== 77 | 78 | auxiliary_data = AuxiliaryData( 79 | AlonzoMetadata( 80 | metadata=Metadata( 81 | { 82 | 674: { 83 | "Title": f"Loyalty rewards for stake pool [{POOL_TICKER}] delegators", 84 | "Rules": {"100K+": "50 ADA", "10K+": "10 ADA"}, 85 | "Notes": "Created with https://github.com/Python-Cardano/pycardano.", 86 | } 87 | } 88 | ) 89 | ) 90 | ) 91 | 92 | builder.auxiliary_data = auxiliary_data 93 | 94 | # Create final signed transaction 95 | signed_tx = builder.build_and_sign( 96 | [psk], change_address=Address.from_primitive(CHANGE_ADDRESS) 97 | ) 98 | 99 | # Submit signed transaction to the network 100 | print(signed_tx) 101 | 102 | print("#### Transaction id ####") 103 | print(signed_tx.id) 104 | context.submit_tx(signed_tx) 105 | print("Transaction successfully submitted!") 106 | -------------------------------------------------------------------------------- /examples/full_stack/README.md: -------------------------------------------------------------------------------- 1 | ## Full stack demo 2 | 3 | This is a full stack demo on transaction creation with PyCardano and transaction signing with 4 | [Nami](https://namiwallet.io/) wallet. 5 | 6 | The backend is hosted by a simple [flask](https://flask.palletsprojects.com/en/2.0.x/) application. 7 | The frontend is rendered using [React](https://reactjs.org/). 8 | 9 | This webapp allows users to send ADA to multiple addresses, which is currently not possible with only Nami wallet. 10 | 11 | #### Note 12 | This is a simple demo built in a few hours. It is not fully tested and some designs could be inefficient. 13 | 14 | The DApp (on testnet) is now hosted on replit: https://pycardano.cffls.repl.co/ 15 | 16 | ### Steps 17 | 18 | 1. Install dependencies 19 | 20 | ```shell 21 | $ poetry install 22 | ``` 23 | 24 | 2. Modify BlockFrost project ID in `server.py` 25 | 26 | 3. Start flask app 27 | 28 | ```shell 29 | $ export BLOCKFROST_ID="your_blockfrost_project_id" 30 | $ export FLASK_APP=server 31 | $ poetry run flask run 32 | ``` 33 | 34 | 4. Open a browser that has Nami wallet extension installed, go to 35 | 36 | ```http://127.0.0.1:5000/``` 37 | 38 | 39 | 5. Connect the wallet by clicking "Connect wallet" button. 40 | 41 | 6. Paste multiple Cardano addresses and specify the amount of ADA to send for each one. 42 | 43 | 7. When you are done with adding addresses, click "Submit Tx" button, and Nami will prompt a signing window. 44 | 45 | 8. Sign the transaction and you are all set. You should be able to see the transaction soon in the blockchain explorer. 46 | 47 | 48 | ### Demo 49 | 50 | ![Alt Text](demo.gif) 51 | 52 | The transaction submitted in the demo could be found 53 | [here](https://explorer.cardano-testnet.iohkdev.io/en/transaction?id=79476c8b257f36cf6f560d4e43b40bf853ee5c2a87e8fd6f09ab722675efcb6e). 54 | 55 | ### Sequence Diagram 56 | 57 | ![Alt Text](sequence_diagram.svg) -------------------------------------------------------------------------------- /examples/full_stack/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Python-Cardano/pycardano/7d63d0e1da1b0e64cd2b9d389ed4f9e2e5c076ae/examples/full_stack/demo.gif -------------------------------------------------------------------------------- /examples/full_stack/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "backend" 3 | version = "0.1.0" 4 | description = "" 5 | authors = ["Your Name "] 6 | 7 | [tool.poetry.dependencies] 8 | python = "^3.8.1" 9 | Flask = "^2.0.3" 10 | pycardano = "^0.12.0" 11 | 12 | [tool.poetry.dev-dependencies] 13 | 14 | [build-system] 15 | requires = ["poetry-core>=1.0.0"] 16 | build-backend = "poetry.core.masonry.api" 17 | -------------------------------------------------------------------------------- /examples/full_stack/sequence_diagram.txt: -------------------------------------------------------------------------------- 1 | title Sequence Diagram 2 | 3 | participant User 4 | 5 | participant WebApp 6 | 7 | participant Nami 8 | 9 | participant PyCardano 10 | 11 | participant BlockFrost 12 | 13 | 14 | User->WebApp: Type in output addresses and amount to send 15 | note over User, WebApp: User click "**Submit Tx**" button 16 | WebApp->Nami: getUsedAddresses() getChangeAddress() 17 | Nami-->>WebApp: Return sender addresses and change address 18 | WebApp->PyCardano: build_tx(senderAddress, changeAddress) 19 | PyCardano-->>WebApp: unsignedTx 20 | WebApp->Nami: signTx(unsignedTx) 21 | note over User, Nami: Nami pops tx signing window; user signs tx 22 | Nami-->>WebApp: witness 23 | WebApp->PyCardano: submit_tx(unsignedTx, witnesses) 24 | note over PyCardano: Compose a signed Tx using unsignedTx and witnesses 25 | PyCardano->BlockFrost: submitTx(signedTx) 26 | BlockFrost-->>PyCardano: OK 200 27 | PyCardano-->>WebApp: Tx ID 28 | WebApp-->>User: Notify user with Tx ID -------------------------------------------------------------------------------- /examples/full_stack/server.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from flask import Flask, render_template, request 4 | 5 | from pycardano import ( 6 | Address, 7 | Asset, 8 | BlockFrostChainContext, 9 | MultiAsset, 10 | Network, 11 | Transaction, 12 | TransactionBuilder, 13 | TransactionOutput, 14 | TransactionWitnessSet, 15 | Value, 16 | ) 17 | 18 | app = Flask(__name__) 19 | 20 | block_forst_project_id = os.environ.get("BLOCKFROST_ID") 21 | 22 | # Use BlockFrostChainContext for simplicity. You can also implement your own chain context. 23 | chain_context = BlockFrostChainContext( 24 | block_forst_project_id, base_url="https://cardano-preview.blockfrost.io/api" 25 | ) 26 | 27 | 28 | def build_transaction(data): 29 | input_addresses = [ 30 | Address.from_primitive(bytes.fromhex(sender)) for sender in data["senders"] 31 | ] 32 | change_address = Address.from_primitive(bytes.fromhex(data["change_address"])) 33 | transaction_outputs = [ 34 | TransactionOutput.from_primitive([address, int(amount) * 1000000]) 35 | for address, amount in data["recipients"] 36 | ] 37 | 38 | print(f"Input addresses: {input_addresses}") 39 | print(f"Transaction outputs: {transaction_outputs}") 40 | print(f"Change address: {change_address}") 41 | 42 | builder = TransactionBuilder(chain_context) 43 | for input_address in input_addresses: 44 | builder.add_input_address(input_address) 45 | for transaction_output in transaction_outputs: 46 | builder.add_output(transaction_output) 47 | 48 | tx_body = builder.build(change_address=change_address) 49 | 50 | return Transaction(tx_body, TransactionWitnessSet()) 51 | 52 | 53 | def compose_tx_and_witness(data): 54 | tx = Transaction.from_cbor(data["tx"]) 55 | witness = TransactionWitnessSet.from_cbor(data["witness"]) 56 | tx.transaction_witness_set = witness 57 | return tx 58 | 59 | 60 | @app.route("/") 61 | def home_page(): 62 | return render_template("index.html") 63 | 64 | 65 | @app.route("/build_tx", methods=["POST"]) 66 | def build_tx(): 67 | tx = build_transaction(request.json) 68 | cbor_hex = tx.to_cbor_hex() 69 | print(cbor_hex) 70 | return {"tx": cbor_hex} 71 | 72 | 73 | @app.route("/submit_tx", methods=["POST"]) 74 | def submit_tx(): 75 | tx = compose_tx_and_witness(request.json) 76 | tx_id = tx.transaction_body.hash().hex() 77 | print(f"Transaction: \n {tx}") 78 | print(f"Transaction cbor: {tx.to_cbor_hex()}") 79 | print(f"Transaction ID: {tx_id}") 80 | chain_context.submit_tx(tx) 81 | return {"tx_id": tx_id} 82 | -------------------------------------------------------------------------------- /examples/full_stack/static/style.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | height: 100%; 3 | color: #61DAFB; 4 | background: #2D2D2D; 5 | } 6 | 7 | h1 { 8 | margin: 100px 0 15px 0; 9 | } 10 | 11 | #main { 12 | width: 1000px; 13 | margin: 0 auto; 14 | text-align: left; 15 | } 16 | 17 | button { 18 | color: #2D2D2D; 19 | } 20 | 21 | ul { 22 | list-style: none; 23 | } 24 | 25 | ul>li:hover { 26 | background-color: #F5F5F5; 27 | } 28 | 29 | .form-inline .form-control { 30 | #width: 100%; 31 | #margin-left: 80px; 32 | } 33 | 34 | .done { 35 | color: red; 36 | text-decoration: line-through; 37 | } 38 | 39 | .undone { 40 | color: #2D2D2D; 41 | } 42 | 43 | .icon { 44 | margin: 6px 10px 6px 0; 45 | } -------------------------------------------------------------------------------- /examples/full_stack/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | PyCardano Demo 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /examples/more_examples/.env-example: -------------------------------------------------------------------------------- 1 | network="testnet" 2 | wallet_mnemonic="select calm scorpion mask furnace nerve fade slam bid suggest avoid remove half depend turn little midnight fossil submit cart sick glance inner slide" 3 | blockfrost_api_key="preprod...." -------------------------------------------------------------------------------- /examples/more_examples/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | /keys/* 3 | !keys/.gitkeep 4 | tempfile.pdf 5 | tempfile_copy.pdf -------------------------------------------------------------------------------- /examples/more_examples/01_address.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from blockfrost import ApiError, ApiUrls, BlockFrostApi, BlockFrostIPFS 4 | from dotenv import load_dotenv 5 | 6 | from pycardano import * 7 | 8 | load_dotenv() 9 | network = os.getenv("network") 10 | wallet_mnemonic = os.getenv("wallet_mnemonic") 11 | 12 | 13 | if network == "testnet": 14 | base_url = ApiUrls.preprod.value 15 | cardano_network = Network.TESTNET 16 | else: 17 | base_url = ApiUrls.mainnet.value 18 | cardano_network = Network.MAINNET 19 | 20 | 21 | new_wallet = crypto.bip32.HDWallet.from_mnemonic(wallet_mnemonic) 22 | payment_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/0/0") 23 | staking_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/2/0") 24 | payment_skey = ExtendedSigningKey.from_hdwallet(payment_key) 25 | staking_skey = ExtendedSigningKey.from_hdwallet(staking_key) 26 | 27 | 28 | print("Enterprise address (only payment):") 29 | print("Payment Derivation path: m/1852'/1815'/0'/0/0") 30 | 31 | enterprise_address = Address( 32 | payment_part=payment_skey.to_verification_key().hash(), network=cardano_network 33 | ) 34 | print(enterprise_address) 35 | 36 | print(" ") 37 | print("Staking enabled address:") 38 | print("Payment Derivation path: m/1852'/1815'/0'/0/0") 39 | print("Staking Derivation path: m/1852'/1815'/0'/2/0") 40 | 41 | staking_enabled_address = Address( 42 | payment_part=payment_skey.to_verification_key().hash(), 43 | staking_part=staking_skey.to_verification_key().hash(), 44 | network=cardano_network, 45 | ) 46 | print(staking_enabled_address) 47 | 48 | print(" ") 49 | next_step = input("Press Enter to continue...") 50 | print(" ") 51 | 52 | for i in range(5): 53 | derivation_path = f"m/1852'/1815'/0'/0/{i}" 54 | 55 | payment_key = new_wallet.derive_from_path(derivation_path) 56 | payment_skey = ExtendedSigningKey.from_hdwallet(payment_key) 57 | 58 | enterprise_address = Address( 59 | payment_part=payment_skey.to_verification_key().hash(), network=cardano_network 60 | ) 61 | print(f"Address {derivation_path}: {enterprise_address}") 62 | 63 | print(" ") 64 | next_step = input("Press Enter to continue...") 65 | print(" ") 66 | 67 | for i in range(5): 68 | derivation_path = f"m/1852'/1815'/0'/0/{i}" 69 | 70 | payment_key = new_wallet.derive_from_path(derivation_path) 71 | payment_skey = ExtendedSigningKey.from_hdwallet(payment_key) 72 | 73 | staking_enabled_address = Address( 74 | payment_part=payment_skey.to_verification_key().hash(), 75 | staking_part=staking_skey.to_verification_key().hash(), 76 | network=cardano_network, 77 | ) 78 | print(f"Address {derivation_path}: {staking_enabled_address}") 79 | -------------------------------------------------------------------------------- /examples/more_examples/02_query_address.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | from blockfrost import ApiError, ApiUrls, BlockFrostApi, BlockFrostIPFS 5 | from dotenv import load_dotenv 6 | 7 | from pycardano import * 8 | 9 | load_dotenv() 10 | network = os.getenv("network") 11 | wallet_mnemonic = os.getenv("wallet_mnemonic") 12 | blockfrost_api_key = os.getenv("blockfrost_api_key") 13 | 14 | 15 | if network == "testnet": 16 | base_url = ApiUrls.preprod.value 17 | cardano_network = Network.TESTNET 18 | else: 19 | base_url = ApiUrls.mainnet.value 20 | cardano_network = Network.MAINNET 21 | 22 | 23 | new_wallet = crypto.bip32.HDWallet.from_mnemonic(wallet_mnemonic) 24 | payment_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/0/0") 25 | staking_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/2/0") 26 | payment_skey = ExtendedSigningKey.from_hdwallet(payment_key) 27 | staking_skey = ExtendedSigningKey.from_hdwallet(staking_key) 28 | 29 | 30 | main_address = Address( 31 | payment_part=payment_skey.to_verification_key().hash(), 32 | staking_part=staking_skey.to_verification_key().hash(), 33 | network=cardano_network, 34 | ) 35 | 36 | print(" ") 37 | print(f"Derived address: {main_address}") 38 | print(" ") 39 | 40 | api = BlockFrostApi(project_id=blockfrost_api_key, base_url=base_url) 41 | 42 | try: 43 | utxos = api.address_utxos(main_address) 44 | except Exception as e: 45 | if e.status_code == 404: 46 | print("Address does not have any UTXOs. ") 47 | if network == "testnet": 48 | print( 49 | "Request tADA from the faucet: https://docs.cardano.org/cardano-testnets/tools/faucet/" 50 | ) 51 | else: 52 | print(e.message) 53 | sys.exit(1) 54 | 55 | print(f"hash \t\t\t\t\t\t\t\t\t amount") 56 | print( 57 | "--------------------------------------------------------------------------------------" 58 | ) 59 | 60 | for utxo in utxos: 61 | tokens = "" 62 | for token in utxo.amount: 63 | if token.unit != "lovelace": 64 | tokens += f"{token.quantity} {token.unit} + " 65 | print( 66 | f"{utxo.tx_hash}#{utxo.tx_index} \t {int(utxo.amount[0].quantity)/1000000} ADA [{tokens}]" 67 | ) 68 | -------------------------------------------------------------------------------- /examples/more_examples/03_distribute.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | from blockfrost import ApiError, ApiUrls, BlockFrostApi, BlockFrostIPFS 5 | from dotenv import load_dotenv 6 | 7 | from pycardano import * 8 | 9 | load_dotenv() 10 | network = os.getenv("network") 11 | wallet_mnemonic = os.getenv("wallet_mnemonic") 12 | blockfrost_api_key = os.getenv("blockfrost_api_key") 13 | 14 | 15 | if network == "testnet": 16 | base_url = ApiUrls.preprod.value 17 | cardano_network = Network.TESTNET 18 | else: 19 | base_url = ApiUrls.mainnet.value 20 | cardano_network = Network.MAINNET 21 | 22 | 23 | new_wallet = crypto.bip32.HDWallet.from_mnemonic(wallet_mnemonic) 24 | payment_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/0/0") 25 | staking_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/2/0") 26 | payment_skey = ExtendedSigningKey.from_hdwallet(payment_key) 27 | staking_skey = ExtendedSigningKey.from_hdwallet(staking_key) 28 | 29 | 30 | main_address = Address( 31 | payment_part=payment_skey.to_verification_key().hash(), 32 | staking_part=staking_skey.to_verification_key().hash(), 33 | network=cardano_network, 34 | ) 35 | 36 | print(" ") 37 | print(f"Derived address: {main_address}") 38 | print(" ") 39 | 40 | api = BlockFrostApi(project_id=blockfrost_api_key, base_url=base_url) 41 | 42 | try: 43 | utxos = api.address_utxos(main_address) 44 | except Exception as e: 45 | if e.status_code == 404: 46 | print("Address does not have any UTXOs. ") 47 | if network == "testnet": 48 | print( 49 | "Request tADA from the faucet: https://docs.cardano.org/cardano-testnets/tools/faucet/" 50 | ) 51 | else: 52 | print(e.message) 53 | sys.exit(1) 54 | 55 | 56 | cardano = BlockFrostChainContext(project_id=blockfrost_api_key, base_url=base_url) 57 | 58 | builder = TransactionBuilder(cardano) 59 | 60 | for i in range(20): 61 | output = TransactionOutput(main_address, Value(4000000)) 62 | builder.add_output(output) 63 | 64 | builder.add_input_address(main_address) 65 | signed_tx = builder.build_and_sign([payment_skey], change_address=main_address) 66 | result = cardano.submit_tx(signed_tx.to_cbor()) 67 | print(f"Number of inputs: \t {len(signed_tx.transaction_body.inputs)}") 68 | print(f"Number of outputs: \t {len(signed_tx.transaction_body.outputs)}") 69 | print(f"Fee: \t\t\t {signed_tx.transaction_body.fee/1000000} ADA") 70 | print(f"Transaction submitted! ID: {result}") 71 | -------------------------------------------------------------------------------- /examples/more_examples/04_consolidate.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | from blockfrost import ApiError, ApiUrls, BlockFrostApi, BlockFrostIPFS 5 | from dotenv import load_dotenv 6 | 7 | from pycardano import * 8 | 9 | load_dotenv() 10 | network = os.getenv("network") 11 | wallet_mnemonic = os.getenv("wallet_mnemonic") 12 | blockfrost_api_key = os.getenv("blockfrost_api_key") 13 | 14 | 15 | if network == "testnet": 16 | base_url = ApiUrls.preprod.value 17 | cardano_network = Network.TESTNET 18 | else: 19 | base_url = ApiUrls.mainnet.value 20 | cardano_network = Network.MAINNET 21 | 22 | 23 | new_wallet = crypto.bip32.HDWallet.from_mnemonic(wallet_mnemonic) 24 | payment_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/0/0") 25 | staking_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/2/0") 26 | payment_skey = ExtendedSigningKey.from_hdwallet(payment_key) 27 | staking_skey = ExtendedSigningKey.from_hdwallet(staking_key) 28 | 29 | 30 | main_address = Address( 31 | payment_part=payment_skey.to_verification_key().hash(), 32 | staking_part=staking_skey.to_verification_key().hash(), 33 | network=cardano_network, 34 | ) 35 | 36 | print(" ") 37 | print(f"Derived address: {main_address}") 38 | print(" ") 39 | 40 | api = BlockFrostApi(project_id=blockfrost_api_key, base_url=base_url) 41 | 42 | try: 43 | utxos = api.address_utxos(main_address) 44 | except Exception as e: 45 | if e.status_code == 404: 46 | print("Address does not have any UTXOs. ") 47 | if network == "testnet": 48 | print( 49 | "Request tADA from the faucet: https://docs.cardano.org/cardano-testnets/tools/faucet/" 50 | ) 51 | else: 52 | print(e.message) 53 | sys.exit(1) 54 | 55 | 56 | cardano = BlockFrostChainContext(project_id=blockfrost_api_key, base_url=base_url) 57 | 58 | builder = TransactionBuilder(cardano) 59 | 60 | inputs = [] 61 | 62 | total_ada_used = 0 63 | 64 | for utxo in utxos: 65 | input = TransactionInput.from_primitive([utxo.tx_hash, utxo.tx_index]) 66 | inputs.append(input) 67 | builder.add_input(input) 68 | total_ada_used += int(utxo.amount[0].quantity) 69 | 70 | output = TransactionOutput(main_address, Value(total_ada_used)) 71 | 72 | tx_body = TransactionBody(inputs=inputs, outputs=[output], fee=100000) 73 | 74 | signature = payment_skey.sign(tx_body.hash()) 75 | vk = PaymentVerificationKey.from_signing_key(payment_skey) 76 | vk_witnesses = [VerificationKeyWitness(vk, signature)] 77 | signed_tx = Transaction(tx_body, TransactionWitnessSet(vkey_witnesses=vk_witnesses)) 78 | 79 | calculated_fee = fee(cardano, len(signed_tx.to_cbor())) 80 | 81 | 82 | total_ada_available = total_ada_used - calculated_fee 83 | output = TransactionOutput(main_address, Value(total_ada_available)) 84 | 85 | tx_body = TransactionBody(inputs=inputs, outputs=[output], fee=calculated_fee) 86 | 87 | signature = payment_skey.sign(tx_body.hash()) 88 | vk = PaymentVerificationKey.from_signing_key(payment_skey) 89 | vk_witnesses = [VerificationKeyWitness(vk, signature)] 90 | signed_tx = Transaction(tx_body, TransactionWitnessSet(vkey_witnesses=vk_witnesses)) 91 | 92 | try: 93 | result = cardano.submit_tx(signed_tx.to_cbor()) 94 | print(f"Number of inputs: \t {len(signed_tx.transaction_body.inputs)}") 95 | print(f"Number of outputs: \t {len(signed_tx.transaction_body.outputs)}") 96 | print(f"Fee: \t\t\t {signed_tx.transaction_body.fee/1000000} ADA") 97 | print(f"Transaction submitted! ID: {result}") 98 | except Exception as e: 99 | if "BadInputsUTxO" in str(e): 100 | print("Trying to spend an input that doesn't exist (or no longer exist).") 101 | elif "ValueNotConservedUTxO" in str(e): 102 | print( 103 | "Transaction not correctly balanced. Inputs and outputs (+fee) don't match." 104 | ) 105 | else: 106 | print(e) 107 | -------------------------------------------------------------------------------- /examples/more_examples/06_query_receive_address.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | from blockfrost import ApiError, ApiUrls, BlockFrostApi, BlockFrostIPFS 5 | from dotenv import load_dotenv 6 | 7 | from pycardano import * 8 | 9 | load_dotenv() 10 | network = os.getenv("network") 11 | wallet_mnemonic = os.getenv("wallet_mnemonic") 12 | blockfrost_api_key = os.getenv("blockfrost_api_key") 13 | 14 | 15 | if network == "testnet": 16 | base_url = ApiUrls.preprod.value 17 | cardano_network = Network.TESTNET 18 | else: 19 | base_url = ApiUrls.mainnet.value 20 | cardano_network = Network.MAINNET 21 | 22 | 23 | new_wallet = crypto.bip32.HDWallet.from_mnemonic(wallet_mnemonic) 24 | payment_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/0/1") 25 | staking_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/2/0") 26 | payment_skey = ExtendedSigningKey.from_hdwallet(payment_key) 27 | staking_skey = ExtendedSigningKey.from_hdwallet(staking_key) 28 | 29 | 30 | main_address = Address( 31 | payment_part=payment_skey.to_verification_key().hash(), 32 | staking_part=staking_skey.to_verification_key().hash(), 33 | network=cardano_network, 34 | ) 35 | 36 | print(" ") 37 | print(f"Derived address: {main_address}") 38 | print(" ") 39 | 40 | api = BlockFrostApi(project_id=blockfrost_api_key, base_url=base_url) 41 | 42 | try: 43 | utxos = api.address_utxos(main_address) 44 | except Exception as e: 45 | if e.status_code == 404: 46 | print("Address does not have any UTXOs. ") 47 | if network == "testnet": 48 | print( 49 | "Request tADA from the faucet: https://docs.cardano.org/cardano-testnets/tools/faucet/" 50 | ) 51 | else: 52 | print(e.message) 53 | sys.exit(1) 54 | 55 | print(f"hash \t\t\t\t\t\t\t\t\t amount") 56 | print( 57 | "--------------------------------------------------------------------------------------" 58 | ) 59 | for utxo in utxos: 60 | tokens = "" 61 | for token in utxo.amount: 62 | if token.unit != "lovelace": 63 | tokens += f"{token.quantity} {token.unit} + " 64 | print( 65 | f"{utxo.tx_hash}#{utxo.tx_index} \t {int(utxo.amount[0].quantity)/1000000} ADA [{tokens}]" 66 | ) 67 | -------------------------------------------------------------------------------- /examples/more_examples/09_sign_document_data.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | import random 4 | import sys 5 | import urllib.request 6 | from hashlib import sha256 7 | from os.path import exists 8 | 9 | from blockfrost import ApiError, ApiUrls, BlockFrostApi, BlockFrostIPFS 10 | from dotenv import load_dotenv 11 | from reportlab.pdfgen import canvas 12 | 13 | from pycardano import * 14 | 15 | 16 | def split_into_64chars(string): 17 | return [string[i : i + 64] for i in range(0, len(string), 64)] 18 | 19 | 20 | load_dotenv() 21 | network = os.getenv("network") 22 | wallet_mnemonic = os.getenv("wallet_mnemonic") 23 | blockfrost_api_key = os.getenv("blockfrost_api_key") 24 | 25 | 26 | filename = "tempfile.pdf" 27 | pdf = canvas.Canvas(filename) 28 | pdf.drawString(100, 750, "Hello, this is an example PDF!") 29 | 30 | pdf.save() 31 | 32 | 33 | h256 = sha256() 34 | h256.update(open(filename, "rb").read()) 35 | document_hash = h256.hexdigest() 36 | 37 | 38 | if network == "testnet": 39 | base_url = ApiUrls.preprod.value 40 | cardano_network = Network.TESTNET 41 | else: 42 | base_url = ApiUrls.mainnet.value 43 | cardano_network = Network.MAINNET 44 | 45 | 46 | new_wallet = crypto.bip32.HDWallet.from_mnemonic(wallet_mnemonic) 47 | payment_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/0/0") 48 | staking_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/2/0") 49 | payment_skey = ExtendedSigningKey.from_hdwallet(payment_key) 50 | staking_skey = ExtendedSigningKey.from_hdwallet(staking_key) 51 | 52 | 53 | main_address = Address( 54 | payment_part=payment_skey.to_verification_key().hash(), 55 | staking_part=staking_skey.to_verification_key().hash(), 56 | network=cardano_network, 57 | ) 58 | 59 | 60 | print(" ") 61 | print(f"Derived address: {main_address}") 62 | print(" ") 63 | 64 | payload = {"document_hash": document_hash} 65 | 66 | payload = str(payload) 67 | 68 | result = cip8.sign( 69 | message=payload, 70 | signing_key=payment_skey, 71 | network=cardano_network, 72 | attach_cose_key=True, 73 | ) 74 | 75 | 76 | metadata = { 77 | 1787: { 78 | document_hash: { 79 | "signature": split_into_64chars(result["signature"]), 80 | } 81 | } 82 | } 83 | 84 | 85 | api = BlockFrostApi(project_id=blockfrost_api_key, base_url=base_url) 86 | 87 | try: 88 | utxos = api.address_utxos(main_address) 89 | except Exception as e: 90 | if e.status_code == 404: 91 | print("Address does not have any UTXOs. ") 92 | if network == "testnet": 93 | print( 94 | "Request tADA from the faucet: https://docs.cardano.org/cardano-testnets/tools/faucet/" 95 | ) 96 | else: 97 | print(e.message) 98 | sys.exit(1) 99 | 100 | 101 | cardano = BlockFrostChainContext(project_id=blockfrost_api_key, base_url=base_url) 102 | 103 | builder = TransactionBuilder(cardano) 104 | 105 | 106 | auxiliary_data = AuxiliaryData(AlonzoMetadata(metadata=Metadata(metadata))) 107 | builder.auxiliary_data = auxiliary_data 108 | 109 | 110 | builder.add_input_address(main_address) 111 | signed_tx = builder.build_and_sign([payment_skey], change_address=main_address) 112 | result = cardano.submit_tx(signed_tx.to_cbor()) 113 | 114 | print(f"Number of inputs: \t {len(signed_tx.transaction_body.inputs)}") 115 | print(f"Number of outputs: \t {len(signed_tx.transaction_body.outputs)}") 116 | print(f"Fee: \t\t\t {signed_tx.transaction_body.fee/1000000} ADA") 117 | print(f"Transaction submitted! ID: {result}") 118 | -------------------------------------------------------------------------------- /examples/more_examples/10_verify_document.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | import random 4 | import sys 5 | import urllib.request 6 | from hashlib import sha256 7 | from os.path import exists 8 | 9 | from blockfrost import ApiError, ApiUrls, BlockFrostApi, BlockFrostIPFS 10 | from dotenv import load_dotenv 11 | 12 | from pycardano import * 13 | 14 | 15 | def split_into_64chars(string): 16 | return [string[i : i + 64] for i in range(0, len(string), 64)] 17 | 18 | 19 | load_dotenv() 20 | network = os.getenv("network") 21 | wallet_mnemonic = os.getenv("wallet_mnemonic") 22 | blockfrost_api_key = os.getenv("blockfrost_api_key") 23 | 24 | 25 | if network == "testnet": 26 | base_url = ApiUrls.preprod.value 27 | cardano_network = Network.TESTNET 28 | else: 29 | base_url = ApiUrls.mainnet.value 30 | cardano_network = Network.MAINNET 31 | 32 | 33 | new_wallet = crypto.bip32.HDWallet.from_mnemonic(wallet_mnemonic) 34 | payment_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/0/0") 35 | staking_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/2/0") 36 | payment_skey = ExtendedSigningKey.from_hdwallet(payment_key) 37 | staking_skey = ExtendedSigningKey.from_hdwallet(staking_key) 38 | 39 | 40 | main_address = Address( 41 | payment_part=payment_skey.to_verification_key().hash(), 42 | staking_part=staking_skey.to_verification_key().hash(), 43 | network=cardano_network, 44 | ) 45 | 46 | 47 | prefix = "a401010327200621" 48 | jsonkey = json.loads(payment_skey.to_verification_key().to_non_extended().to_json()) 49 | 50 | 51 | api = BlockFrostApi(project_id=blockfrost_api_key, base_url=base_url) 52 | cardano = BlockFrostChainContext(project_id=blockfrost_api_key, base_url=base_url) 53 | 54 | # get commandline arguments 55 | 56 | transaction_id = sys.argv[1] 57 | document_hash = sys.argv[2] 58 | 59 | 60 | onchain_metadata = api.transaction_metadata(transaction_id) 61 | 62 | if onchain_metadata is None: 63 | print("No metadata onchain.") 64 | sys.exit(1) 65 | 66 | 67 | if "1787" in onchain_metadata[0].label: 68 | print("This transaction has a 1787 metadata label onchain.") 69 | 70 | result = onchain_metadata[0].json_metadata 71 | 72 | if document_hash in str(result): 73 | print("Document hash found onchain.") 74 | 75 | if getattr(result, document_hash).signature: 76 | print("Signature found onchain.") 77 | signature = getattr(result, document_hash).signature 78 | 79 | public_key = f"{prefix}{jsonkey['cborHex']}" 80 | 81 | signed_message = { 82 | "signature": "".join(signature), 83 | "key": public_key, 84 | } 85 | 86 | result = cip8.verify(signed_message=signed_message, attach_cose_key=True) 87 | 88 | if result["verified"]: 89 | print( 90 | "This signature is verified correctly, this document was signed by this wallet/identity." 91 | ) 92 | print("Original payload:") 93 | print(result["message"]) 94 | else: 95 | print("This signature is NOT correct!") 96 | else: 97 | print("This transaction does not have a signatuer attribute") 98 | else: 99 | print(f"Document hash ({document_hash}) was not found in this transaction.") 100 | else: 101 | print("This transaction DOES NOT have a 1787 metadata label.") 102 | -------------------------------------------------------------------------------- /examples/more_examples/11_verify_fake_document.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | import random 4 | import sys 5 | import urllib.request 6 | from hashlib import sha256 7 | from os.path import exists 8 | 9 | from blockfrost import ApiError, ApiUrls, BlockFrostApi, BlockFrostIPFS 10 | from dotenv import load_dotenv 11 | from reportlab.pdfgen import canvas 12 | 13 | from pycardano import * 14 | 15 | 16 | def split_into_64chars(string): 17 | return [string[i : i + 64] for i in range(0, len(string), 64)] 18 | 19 | 20 | load_dotenv() 21 | network = os.getenv("network") 22 | wallet_mnemonic = os.getenv("wallet_mnemonic") 23 | blockfrost_api_key = os.getenv("blockfrost_api_key") 24 | 25 | 26 | if network == "testnet": 27 | base_url = ApiUrls.preprod.value 28 | cardano_network = Network.TESTNET 29 | else: 30 | base_url = ApiUrls.mainnet.value 31 | cardano_network = Network.MAINNET 32 | 33 | 34 | filename = "tempfile_copy.pdf" 35 | pdf = canvas.Canvas(filename) 36 | pdf.drawString(100, 750, "Hello, this is a copy of the example PDF!") 37 | 38 | pdf.save() 39 | 40 | h256 = sha256() 41 | h256.update(open(filename, "rb").read()) 42 | document_hash = h256.hexdigest() 43 | 44 | print(f"Trying to verify document with hash: {document_hash}") 45 | 46 | new_wallet = crypto.bip32.HDWallet.from_mnemonic(wallet_mnemonic) 47 | payment_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/0/0") 48 | staking_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/2/0") 49 | payment_skey = ExtendedSigningKey.from_hdwallet(payment_key) 50 | staking_skey = ExtendedSigningKey.from_hdwallet(staking_key) 51 | 52 | 53 | main_address = Address( 54 | payment_part=payment_skey.to_verification_key().hash(), 55 | staking_part=staking_skey.to_verification_key().hash(), 56 | network=cardano_network, 57 | ) 58 | 59 | 60 | prefix = "a401010327200621" 61 | jsonkey = json.loads(payment_skey.to_verification_key().to_non_extended().to_json()) 62 | 63 | 64 | api = BlockFrostApi(project_id=blockfrost_api_key, base_url=base_url) 65 | cardano = BlockFrostChainContext(project_id=blockfrost_api_key, base_url=base_url) 66 | 67 | # get commandline arguments 68 | 69 | transaction_id = sys.argv[1] 70 | 71 | 72 | onchain_metadata = api.transaction_metadata(transaction_id) 73 | 74 | if onchain_metadata is None: 75 | print("No metadata onchain.") 76 | sys.exit(1) 77 | 78 | 79 | if "1787" in onchain_metadata[0].label: 80 | print("This transaction has a 1787 metadata label onchain.") 81 | 82 | result = onchain_metadata[0].json_metadata 83 | 84 | if document_hash in str(result): 85 | print("Document hash found onchain.") 86 | 87 | if getattr(result, document_hash).signature: 88 | print("Signature found onchain.") 89 | signature = getattr(result, document_hash).signature 90 | 91 | public_key = f"{prefix}{jsonkey['cborHex']}" 92 | 93 | signed_message = { 94 | "signature": "".join(signature), 95 | "key": public_key, 96 | } 97 | 98 | result = cip8.verify(signed_message=signed_message, attach_cose_key=True) 99 | 100 | if result["verified"]: 101 | print("This signature is verified correctly!") 102 | if result["message"] == document_hash: 103 | print("TargetHash matches as well! ") 104 | else: 105 | print("This signature is NOT correct!") 106 | else: 107 | print("This transaction does not have a signatuer attribute") 108 | else: 109 | print( 110 | f"Document hash ({document_hash}) was not found in this transaction. Possible corruption." 111 | ) 112 | else: 113 | print("This transaction DOES NOT have a 1787 metadata label.") 114 | -------------------------------------------------------------------------------- /examples/more_examples/README.md: -------------------------------------------------------------------------------- 1 | ## Introduction into Cardano using PyCardano 2 | 3 | - [x] Derive addresses 4 | - [x] Query address balance 5 | - [x] Create transaction with multiple outputs 6 | - [x] Consolidate all inputs back into 1 utxo 7 | - [x] Mint a fungible asset within a policy and send it to an external address 8 | - [x] Query the receiver address 9 | - [x] Minting 5 NFT's with metadata (player characters in this example) 10 | - [x] Burning NFT's 11 | - [x] Downloading a document from a URL and signing it with CIP8 12 | - [x] Verify a valid CIP8 signature 13 | - [x] Verify an invalid CIP8 signature 14 | - [x] Example of transaction chaining with manually building and signing a transaction (instead of TransactionBuilder) 15 | 16 | 17 | ## How to use 18 | - Clone repo 19 | - rename .env-example to .env 20 | - update values in .env 21 | - play around! -------------------------------------------------------------------------------- /examples/more_examples/keys/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Python-Cardano/pycardano/7d63d0e1da1b0e64cd2b9d389ed4f9e2e5c076ae/examples/more_examples/keys/.gitkeep -------------------------------------------------------------------------------- /examples/plutus/forty_two/forty_two.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | Off-chain code of taker and giver in fortytwo. 4 | 5 | """ 6 | 7 | import os 8 | 9 | import cbor2 10 | from blockfrost import ApiUrls 11 | from retry import retry 12 | 13 | from pycardano import * 14 | 15 | NETWORK = Network.TESTNET 16 | 17 | 18 | def get_env_val(key): 19 | val = os.environ.get(key) 20 | if not val: 21 | raise Exception(f"Environment variable {key} is not set!") 22 | return val 23 | 24 | 25 | payment_skey = PaymentSigningKey.load(get_env_val("PAYMENT_KEY_PATH")) 26 | payment_vkey = PaymentVerificationKey.from_signing_key(payment_skey) 27 | 28 | chain_context = BlockFrostChainContext( 29 | project_id=get_env_val("BLOCKFROST_ID"), 30 | base_url=ApiUrls.preprod.value, 31 | ) 32 | 33 | 34 | @retry(delay=20) 35 | def wait_for_tx(tx_id): 36 | chain_context.api.transaction(tx_id) 37 | print(f"Transaction {tx_id} has been successfully included in the blockchain.") 38 | 39 | 40 | def submit_tx(tx): 41 | print("############### Transaction created ###############") 42 | print(tx) 43 | print(tx.to_cbor_hex()) 44 | print("############### Submitting transaction ###############") 45 | chain_context.submit_tx(tx) 46 | wait_for_tx(str(tx.id)) 47 | 48 | 49 | with open("fortytwoV2.plutus", "r") as f: 50 | script_hex = f.read() 51 | forty_two_script = PlutusV2Script(cbor2.loads(bytes.fromhex(script_hex))) 52 | 53 | 54 | script_hash = plutus_script_hash(forty_two_script) 55 | 56 | script_address = Address(script_hash, network=NETWORK) 57 | 58 | giver_address = Address(payment_vkey.hash(), network=NETWORK) 59 | 60 | builder = TransactionBuilder(chain_context) 61 | builder.add_input_address(giver_address) 62 | builder.add_output(TransactionOutput(giver_address, 50000000, script=forty_two_script)) 63 | 64 | signed_tx = builder.build_and_sign([payment_skey], giver_address) 65 | 66 | print("############### Transaction created ###############") 67 | print(signed_tx) 68 | print("############### Submitting transaction ###############") 69 | submit_tx(signed_tx) 70 | 71 | 72 | # ----------- Send ADA to the script address --------------- 73 | 74 | builder = TransactionBuilder(chain_context) 75 | builder.add_input_address(giver_address) 76 | datum = 42 77 | builder.add_output(TransactionOutput(script_address, 50000000, datum=datum)) 78 | 79 | signed_tx = builder.build_and_sign([payment_skey], giver_address) 80 | 81 | print("############### Transaction created ###############") 82 | print(signed_tx) 83 | print("############### Submitting transaction ###############") 84 | submit_tx(signed_tx) 85 | 86 | # ----------- Taker take --------------- 87 | 88 | redeemer = Redeemer(42) 89 | 90 | utxo_to_spend = None 91 | 92 | # Spend the utxo with datum 42 sitting at the script address 93 | for utxo in chain_context.utxos(script_address): 94 | print(utxo) 95 | if utxo.output.datum: 96 | utxo_to_spend = utxo 97 | break 98 | 99 | # Find the reference script utxo 100 | reference_script_utxo = None 101 | for utxo in chain_context.utxos(giver_address): 102 | if utxo.output.script and utxo.output.script == forty_two_script: 103 | reference_script_utxo = utxo 104 | break 105 | 106 | taker_address = Address(payment_vkey.hash(), network=NETWORK) 107 | 108 | builder = TransactionBuilder(chain_context) 109 | 110 | builder.add_script_input(utxo_to_spend, script=reference_script_utxo, redeemer=redeemer) 111 | take_output = TransactionOutput(taker_address, 25123456) 112 | builder.add_output(take_output) 113 | 114 | signed_tx = builder.build_and_sign([payment_skey], taker_address) 115 | 116 | print("############### Transaction created ###############") 117 | print(signed_tx) 118 | print("############### Submitting transaction ###############") 119 | submit_tx(signed_tx) 120 | -------------------------------------------------------------------------------- /examples/plutus/forty_two/fortytwo.plutus: -------------------------------------------------------------------------------- 1 | 59082459082101000033232332233223232333222323332223233333333222222223233322232333322223232332232333222323332223232332233223232333332222233223322332233223322332222223232533530313330063333573466e1cd55ce9baa0054800081248c98d4c120cd5ce0260248238231bad0043333573466e1cd55cea8012400046601264646464646464646464646666ae68cdc39aab9d500a480008cccccccccc05ccd40948c8c8cccd5cd19b8735573aa004900011980e981c1aba15002302a357426ae8940088c98d4c160cd5ce02e02c82b82b09aab9e5001137540026ae854028cd4094098d5d0a804999aa8163ae502b35742a010666aa058eb940acd5d0a80399a8128209aba15006335025335505204a75a6ae854014c8c8c8cccd5cd19b8735573aa0049000119a80f9919191999ab9a3370e6aae7540092000233502733504075a6ae854008c114d5d09aba25002232635305c3357380c00ba0b60b426aae7940044dd50009aba150023232323333573466e1cd55cea80124000466a04a66a080eb4d5d0a80118229aba135744a004464c6a60b866ae7018017416c1684d55cf280089baa001357426ae8940088c98d4c160cd5ce02e02c82b82b09aab9e5001137540026ae854010cd4095d71aba15003335025335505275c40026ae854008c0dcd5d09aba2500223263530543357380b00aa0a60a426ae8940044d5d1280089aba25001135744a00226ae8940044d5d1280089aba25001135744a00226aae7940044dd50009aba150023232323333573466e1d400520062301c3039357426aae79400c8cccd5cd19b875002480108c06cc10cd5d09aab9e500423333573466e1d400d20022301b302e357426aae7940148cccd5cd19b875004480008c078dd71aba135573ca00c464c6a609e66ae7014c14013813413012c1284d55cea80089baa001357426ae8940088c98d4c120cd5ce026024823823082409931a982399ab9c49010350543500048046135573ca00226ea80048848cc00400c0088004888888888848cccccccccc00402c02802402001c01801401000c00880048848cc00400c008800448848cc00400c0084800448848cc00400c0084800448848cc00400c00848004848888c010014848888c00c014848888c008014848888c004014800448c88c008dd6000990009aa81a911999aab9f0012500e233500d30043574200460066ae880080cc8c8c8c8cccd5cd19b8735573aa006900011998039919191999ab9a3370e6aae754009200023300d303135742a00466a02605a6ae84d5d1280111931a981b99ab9c03b038036035135573ca00226ea8004d5d0a801999aa805bae500a35742a00466a01eeb8d5d09aba25002232635303333573806e06806406226ae8940044d55cf280089baa00122212333001004003002200122123300100300220011335500175ceb44488c88c008dd5800990009aa81791191999aab9f0022500923350083355031300635573aa004600a6aae794008c010d5d100181709aba10011122002122122330010040031200112232323333573466e1d400520002350083005357426aae79400c8cccd5cd19b87500248008940208c98d4c0a8cd5ce01701581481401389aab9d500113754002242446004006224400224002464646666ae68cdc39aab9d5002480008cc018c01cd5d0a8011bad357426ae8940088c98d4c090cd5ce01401281181109aab9e50011375400244246600200600440024646666ae68cdc39aab9d5001480008dd71aba135573ca004464c6a604066ae7009008407c0784dd500089119191999ab9a3370ea00290021280391999ab9a3370ea004900111a80518031aba135573ca00846666ae68cdc3a801a40004a014464c6a604666ae7009c09008808408007c4d55cea80089baa00112122230030041122200211222001120012323333573466e1d40052002200623333573466e1d400920002006232635301b33573803e03803403203026aae74dd50008910010910009000919191919191999ab9a3370ea0029006100591999ab9a3370ea0049005100691999ab9a3370ea00690041198059bae35742a00a6eb4d5d09aba2500523333573466e1d4011200623300d375c6ae85401cdd71aba135744a00e46666ae68cdc3a802a400846602460286ae854024dd71aba135744a01246666ae68cdc3a8032400446028602a6ae84d55cf280591999ab9a3370ea00e900011809980b1aba135573ca018464c6a604066ae7009008407c07807407006c0680640604d55cea80209aab9e5003135573ca00426aae7940044dd500090911111118038041109111111198030048041091111111802804091111110020911111100191091111111980100480411091111111980080480410009191919191999ab9a3370ea002900111998041bad35742a0086eb4d5d0a8019bad357426ae89400c8cccd5cd19b875002480008c028c02cd5d09aab9e5006232635301133573802a02402001e01c26aae75400c4d5d1280089aab9e5001137540024244600400644424466600200a0080064002464646666ae68cdc3a800a40044600c6eb8d5d09aab9e500323333573466e1d4009200023008375c6ae84d55cf280211931a980599ab9c00f00c00a009008135573aa00226ea80048488c00800c8488c00400c800444888c8c8cccd5cd19b8735573aa0049000119aa80598031aba150023005357426ae8940088c98d4c020cd5ce00600480380309aab9e5001137540029309000900088910919800801801089000a4903505431001123230010012233003300200200133322222253353004333573466e1c00920540060051006133573892010e77726f6e672072656465656d65720000512200212200120011 -------------------------------------------------------------------------------- /examples/plutus/forty_two/fortytwoV2.plutus: -------------------------------------------------------------------------------- 1 | 58775875010000323232322225335323253350021001100933320015007003332001500648150ccc8005401800ccc8005401520541004132632498cd5ce2491d496e636f727265637420646174756d2e2045787065637465642034322e0000412001123750002244666ae68cdd780100089100100189100081 -------------------------------------------------------------------------------- /examples/raw_multi_asset_transaction.py: -------------------------------------------------------------------------------- 1 | """An example that demonstrates low-level construction of a transaction that involves multi-asset.""" 2 | 3 | from pycardano import ( 4 | Address, 5 | PaymentSigningKey, 6 | PaymentVerificationKey, 7 | Transaction, 8 | TransactionBody, 9 | TransactionInput, 10 | TransactionOutput, 11 | TransactionWitnessSet, 12 | Value, 13 | VerificationKeyWitness, 14 | ) 15 | 16 | # Define a transaction input 17 | tx_id_hex = "732bfd67e66be8e8288349fcaaa2294973ef6271cc189a239bb431275401b8e5" 18 | tx_in = TransactionInput.from_primitive([tx_id_hex, 0]) 19 | 20 | # Define an output address 21 | addr = Address.decode("addr_test1vrm9x2zsux7va6w892g38tvchnzahvcd9tykqf3ygnmwtaqyfg52x") 22 | 23 | # Define two transaction outputs, both to the same address, but one with multi-assets. 24 | output1 = TransactionOutput(addr, 100000000000) 25 | 26 | # Output2 will send ADA along with multi-assets 27 | policy_id = b"1" * 28 # A dummy policy ID 28 | multi_asset = Value.from_primitive( 29 | [ 30 | 2, # Amount of ADA (in lovelace) to send 31 | { 32 | policy_id: { 33 | b"Token1": 100, # Send 100 Token1 under `policy_id` 34 | b"Token2": 200, # Send 200 Token2 under `policy_id` 35 | } 36 | }, 37 | ] 38 | ) 39 | output2 = TransactionOutput(addr, multi_asset) 40 | 41 | # Create a transaction body from inputs and outputs 42 | tx_body = TransactionBody(inputs=[tx_in], outputs=[output1, output2], fee=165897) 43 | 44 | # Create signing key from a secret json file 45 | sk = PaymentSigningKey.from_json( 46 | """{ 47 | "type": "GenesisUTxOSigningKey_ed25519", 48 | "description": "Genesis Initial UTxO Signing Key", 49 | "cborHex": "5820093be5cd3987d0c9fd8854ef908f7746b69e2d73320db6dc0f780d81585b84c2" 50 | }""" 51 | ) 52 | 53 | # Derive a verification key from the signing key 54 | vk = PaymentVerificationKey.from_signing_key(sk) 55 | 56 | # Sign the transaction body hash 57 | signature = sk.sign(tx_body.hash()) 58 | 59 | # Add verification key and the signature to the witness set 60 | vk_witnesses = [VerificationKeyWitness(vk, signature)] 61 | 62 | # Create final signed transaction 63 | signed_tx = Transaction(tx_body, TransactionWitnessSet(vkey_witnesses=vk_witnesses)) 64 | -------------------------------------------------------------------------------- /examples/raw_transaction.py: -------------------------------------------------------------------------------- 1 | """An example that demonstrates low-level construction of a transaction.""" 2 | 3 | from pycardano import ( 4 | PaymentSigningKey, 5 | PaymentVerificationKey, 6 | Transaction, 7 | TransactionBody, 8 | TransactionInput, 9 | TransactionOutput, 10 | TransactionWitnessSet, 11 | VerificationKeyWitness, 12 | ) 13 | 14 | # Define a transaction input 15 | tx_id = "732bfd67e66be8e8288349fcaaa2294973ef6271cc189a239bb431275401b8e5" 16 | tx_in = TransactionInput.from_primitive([tx_id, 0]) 17 | 18 | # Define an output address 19 | addr = "addr_test1vrm9x2zsux7va6w892g38tvchnzahvcd9tykqf3ygnmwtaqyfg52x" 20 | 21 | # Define two transaction outputs, both to the same address, but with different amount. 22 | output1 = TransactionOutput.from_primitive([addr, 100000000000]) 23 | output2 = TransactionOutput.from_primitive([addr, 799999834103]) 24 | 25 | # Create a transaction body from inputs and outputs 26 | tx_body = TransactionBody(inputs=[tx_in], outputs=[output1, output2], fee=165897) 27 | 28 | # Create signing key from a secret json file 29 | sk = PaymentSigningKey.from_json( 30 | """{ 31 | "type": "GenesisUTxOSigningKey_ed25519", 32 | "description": "Genesis Initial UTxO Signing Key", 33 | "cborHex": "5820093be5cd3987d0c9fd8854ef908f7746b69e2d73320db6dc0f780d81585b84c2" 34 | }""" 35 | ) 36 | 37 | # Derive a verification key from the signing key 38 | vk = PaymentVerificationKey.from_signing_key(sk) 39 | 40 | # Sign the transaction body hash 41 | signature = sk.sign(tx_body.hash()) 42 | 43 | # Add verification key and the signature to the witness set 44 | vk_witnesses = [VerificationKeyWitness(vk, signature)] 45 | 46 | # Create final signed transaction 47 | signed_tx = Transaction(tx_body, TransactionWitnessSet(vkey_witnesses=vk_witnesses)) 48 | -------------------------------------------------------------------------------- /examples/tx_builder.py: -------------------------------------------------------------------------------- 1 | """Build a transaction using transaction builder""" 2 | 3 | from blockfrost import ApiUrls 4 | 5 | from pycardano import * 6 | 7 | # Use testnet 8 | network = Network.TESTNET 9 | 10 | # Read keys to memory 11 | # Assume there is a payment.skey file sitting in current directory 12 | psk = PaymentSigningKey.load("payment.skey") 13 | # Assume there is a stake.skey file sitting in current directory 14 | ssk = StakeSigningKey.load("stake.skey") 15 | 16 | pvk = PaymentVerificationKey.from_signing_key(psk) 17 | svk = StakeVerificationKey.from_signing_key(ssk) 18 | 19 | # Derive an address from payment verification key and stake verification key 20 | address = Address(pvk.hash(), svk.hash(), network) 21 | 22 | # Create a BlockFrost chain context. In this example, we will use preprod network. 23 | context = BlockFrostChainContext( 24 | "your_blockfrost_project_id", base_url=ApiUrls.preprod.value 25 | ) 26 | 27 | # Create a transaction builder 28 | builder = TransactionBuilder(context) 29 | 30 | # Tell the builder that transaction input will come from a specific address, assuming that there are some ADA and native 31 | # assets sitting at this address. "add_input_address" could be called multiple times with different address. 32 | builder.add_input_address(address) 33 | 34 | # Get all UTxOs currently sitting at this address 35 | utxos = context.utxos(address) 36 | 37 | # We can also tell the builder to include a specific UTxO in the transaction. 38 | # Similarly, "add_input" could be called multiple times. 39 | builder.add_input(utxos[0]) 40 | 41 | # Send 1.5 ADA and a native asset (CHOC) in quantity of 2000 to an address. 42 | builder.add_output( 43 | TransactionOutput( 44 | Address.from_primitive( 45 | "addr_test1vrm9x2zsux7va6w892g38tvchnzahvcd9tykqf3ygnmwtaqyfg52x" 46 | ), 47 | Value.from_primitive( 48 | [ 49 | 1500000, 50 | { 51 | bytes.fromhex( 52 | "57fca08abbaddee36da742a839f7d83a7e1d2419f1507fcbf3916522" # Policy ID 53 | ): { 54 | b"CHOC": 2000 # Asset name and amount 55 | } 56 | }, 57 | ] 58 | ), 59 | ) 60 | ) 61 | 62 | # We can add multiple outputs, similar to what we can do with inputs. 63 | # Send 2 ADA and a native asset (CHOC) in quantity of 200 to ourselves 64 | builder.add_output( 65 | TransactionOutput( 66 | address, 67 | Value.from_primitive( 68 | [ 69 | 2000000, 70 | { 71 | bytes.fromhex( 72 | "57fca08abbaddee36da742a839f7d83a7e1d2419f1507fcbf3916522" # Policy ID 73 | ): { 74 | b"CHOC": 200 # Asset name and amount 75 | } 76 | }, 77 | ] 78 | ), 79 | ) 80 | ) 81 | 82 | # Create final signed transaction 83 | signed_tx = builder.build_and_sign([psk], change_address=address) 84 | 85 | # Submit signed transaction to the network 86 | context.submit_tx(signed_tx) 87 | -------------------------------------------------------------------------------- /examples/tx_builder_with_metadata.py: -------------------------------------------------------------------------------- 1 | from blockfrost import ApiUrls 2 | 3 | from pycardano import ( 4 | Address, 5 | AlonzoMetadata, 6 | AuxiliaryData, 7 | BlockFrostChainContext, 8 | Metadata, 9 | Network, 10 | PaymentSigningKey, 11 | PaymentVerificationKey, 12 | TransactionBuilder, 13 | TransactionOutput, 14 | ) 15 | 16 | # Use testnet 17 | network = Network.TESTNET 18 | 19 | # Read keys to memory 20 | # Assume there is a payment.skey file sitting in current directory 21 | payment_signing_key = PaymentSigningKey.load("payment.skey") 22 | payment_verification_key = PaymentVerificationKey.from_signing_key(payment_signing_key) 23 | 24 | from_address = Address(payment_verification_key.hash(), network=network) 25 | 26 | # Create a BlockFrost chain context. In this example, we will use preprod network. 27 | context = BlockFrostChainContext( 28 | "your_blockfrost_project_id", base_url=ApiUrls.preprod.value 29 | ) 30 | 31 | # Metadata that follows the CIP-20 standard. More info here https://cips.cardano.org/cip/CIP-20/ 32 | metadata = { 33 | 674: { 34 | "msg": [ 35 | "Invoice-No: 1234567890", 36 | "Customer-No: 555-1234", 37 | "P.S.: i will shop again at your store :-)", 38 | ] 39 | } 40 | } 41 | 42 | # Place metadata in AuxiliaryData, the format acceptable by a transaction. 43 | auxiliary_data = AuxiliaryData(AlonzoMetadata(metadata=Metadata(metadata))) 44 | # Set transaction metadata 45 | builder.auxiliary_data = auxiliary_data 46 | # Create a transaction builder 47 | builder = TransactionBuilder(context) 48 | # Set your address 49 | builder.add_input_address(from_address) 50 | # Recipient address 51 | to_address = "cardano_address_you_want_to_send_ada_to" 52 | # Add output and sign transaction 53 | builder.add_output(TransactionOutput.from_primitive([to_address, 100000000000])) 54 | signed_tx = builder.build_and_sign([payment_signing_key], change_address=from_address) 55 | # Send transaction 56 | context.submit_tx(signed_tx) 57 | -------------------------------------------------------------------------------- /integration-test/README.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | Runtime environments for integration tests. 4 | 5 | `docker-compose.yml` kicks off two components, [cardano-node](https://github.com/input-output-hk/cardano-node) and 6 | [ogmios](https://github.com/CardanoSolutions/ogmios), which are necessary to run deterministic integration tests. 7 | 8 | Good things about a customizable and deterministic ledger: 9 | 10 | * Deterministic UTxO set and deterministic actors (isolation). 11 | * Deterministic fees. 12 | * Flexible configurations. 13 | * Reproducible. 14 | 15 | To achieve a relatively good degree of determinism, we use a local cardano node that runs as a single 16 | BFT node in the network. The node will produce all blocks and the environment/ledger is isolated. 17 | 18 | ## Instructions 19 | 20 | ### Pre-requisites 21 | 22 | * Install [Docker](https://www.docker.com/) 23 | 24 | ### Launch containers 25 | 26 | Bootstrap config files for a single BFT node: 27 | 28 | `./bootstrap.sh local-alonzo` 29 | 30 | 31 | Compose docker services (node + ogmios): 32 | 33 | `docker-compose up -d` 34 | 35 | 36 | Clean up docker containers and volumes when done with testing: 37 | 38 | `docker-compose down` 39 | 40 | 41 | ### Test 42 | 43 | Current, all integration tests could be kicked off by running: 44 | 45 | `./run_tests.sh` -------------------------------------------------------------------------------- /integration-test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Python-Cardano/pycardano/7d63d0e1da1b0e64cd2b9d389ed4f9e2e5c076ae/integration-test/__init__.py -------------------------------------------------------------------------------- /integration-test/bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | if [ "$#" -ne 1 ] || [ "$1" = "-h" ]; then 6 | echo "Bootstrap network configs and environment variables." 7 | echo "Usage: $0 [network] (e.g. local-alonzo, testnet, mainnet)" 8 | exit 0 9 | fi 10 | 11 | if [ -d "./tmp_configs" ]; then 12 | echo "Removing tmp_configs" 13 | rm -rf ./tmp_configs 14 | fi 15 | 16 | echo "Copying configs to tmp_configs" 17 | cp -r configs tmp_configs 18 | 19 | NETWORK=$1 20 | 21 | echo "Bootstrapping network: $NETWORK" 22 | 23 | if [ "$NETWORK" = "local-alonzo" ] || [ "$NETWORK" = "local-vasil" ] || [ "$NETWORK" = "local-chang" ]; then 24 | echo "Updating byron startTime to present in local mode, $NETWORK era" 25 | jq -M ".startTime = ($(date +%s) + 60)" configs/"$NETWORK"/byron-genesis.json > \ 26 | tmp_configs/"$NETWORK"/byron-genesis.json 27 | fi 28 | 29 | echo "NETWORK=$NETWORK" >.env 30 | NETWORK_MAGIC=$(jq .networkMagic tmp_configs/"$NETWORK"/shelley-genesis.json) 31 | echo "Found network magic: $NETWORK_MAGIC" 32 | echo "NETWORK_MAGIC=$NETWORK_MAGIC" >>.env 33 | echo "Done" 34 | -------------------------------------------------------------------------------- /integration-test/configs/local-alonzo/byron-genesis.json: -------------------------------------------------------------------------------- 1 | { "bootStakeholders": 2 | { "b733bf8070781d30a0c8d5ca66392188f78c6604b631629cd055f402": 1 } 3 | , "heavyDelegation": 4 | { "b733bf8070781d30a0c8d5ca66392188f78c6604b631629cd055f402": 5 | { "omega": 0 6 | , "issuerPk": 7 | "ckPV1Ypq8uRkxwoDj93p7cCm4G+uB9R8SGGOKyc6KyIR8NDVVwu1FS3AwSoUjra02uiF5AlAUXUvVqZvnT8nCw==" 8 | , "delegatePk": 9 | "MYL9xuLMepgsQxRtqOu57nJw16pMWel79j0APRV1NSqH3ZUeBu+p7XaNoVCzw7yemMb4vwLiRDcMnnqHXztFVA==" 10 | , "cert": 11 | "643985a3022fedf3d9aaee8ab18d35e0cdc894beb5edb502ca47c37cce678741dd502fba0c2b8ee38513e0a75f6ee2dcc0f05d5b3c1d7ce72cc1c22a8a910909" 12 | } } 13 | , "startTime": 1640212228 14 | , "nonAvvmBalances": 15 | { "2657WMsDfac6ef4bngGRU7FmksmW8QRfAifshdj4XyDxPeVT4DbPeoiUgzRdKjYYF": 16 | "10020000000" } 17 | , "blockVersionData": 18 | { "scriptVersion": 0 19 | , "slotDuration": "1000" 20 | , "maxBlockSize": "2000000" 21 | , "maxHeaderSize": "2000000" 22 | , "maxTxSize": "4096" 23 | , "maxProposalSize": "700" 24 | , "mpcThd": "20000000000000" 25 | , "heavyDelThd": "300000000000" 26 | , "updateVoteThd": "1000000000000" 27 | , "updateProposalThd": "100000000000000" 28 | , "updateImplicit": "10000" 29 | , "softforkRule": 30 | { "initThd": "900000000000000" 31 | , "minThd": "600000000000000" 32 | , "thdDecrement": "50000000000000" 33 | } 34 | , "txFeePolicy": 35 | { "summand": "155381000000000" , "multiplier": "43946000000" } 36 | , "unlockStakeEpoch": "18446744073709551615" 37 | } 38 | , "protocolConsts": { "k": 10 , "protocolMagic": 42 } 39 | , "avvmDistr": {} 40 | } -------------------------------------------------------------------------------- /integration-test/configs/local-alonzo/byron/delegate.cert: -------------------------------------------------------------------------------- 1 | { "omega": 0 2 | , "issuerPk": 3 | "ckPV1Ypq8uRkxwoDj93p7cCm4G+uB9R8SGGOKyc6KyIR8NDVVwu1FS3AwSoUjra02uiF5AlAUXUvVqZvnT8nCw==" 4 | , "delegatePk": 5 | "MYL9xuLMepgsQxRtqOu57nJw16pMWel79j0APRV1NSqH3ZUeBu+p7XaNoVCzw7yemMb4vwLiRDcMnnqHXztFVA==" 6 | , "cert": 7 | "643985a3022fedf3d9aaee8ab18d35e0cdc894beb5edb502ca47c37cce678741dd502fba0c2b8ee38513e0a75f6ee2dcc0f05d5b3c1d7ce72cc1c22a8a910909" 8 | } -------------------------------------------------------------------------------- /integration-test/configs/local-alonzo/byron/delegate.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Python-Cardano/pycardano/7d63d0e1da1b0e64cd2b9d389ed4f9e2e5c076ae/integration-test/configs/local-alonzo/byron/delegate.key -------------------------------------------------------------------------------- /integration-test/configs/local-alonzo/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "ByronGenesisFile": "byron-genesis.json", 3 | "ShelleyGenesisFile": "shelley-genesis.json", 4 | "AlonzoGenesisFile": "alonzo-genesis.json", 5 | "ConwayGenesisFile": "conway-genesis.json", 6 | "SocketPath": "db/node.socket", 7 | "MaxConcurrencyBulkSync": 1, 8 | "MaxConcurrencyDeadline": 2, 9 | "Protocol": "Cardano", 10 | "PBftSignatureThreshold": 0.6, 11 | "RequiresNetworkMagic": "RequiresMagic", 12 | "LastKnownBlockVersion-Major": 5, 13 | "LastKnownBlockVersion-Minor": 0, 14 | "LastKnownBlockVersion-Alt": 0, 15 | "ApplicationName": "cardano-sl", 16 | "ApplicationVersion": 1, 17 | "TurnOnLogging": true, 18 | "TurnOnLogMetrics": true, 19 | "minSeverity": "Debug", 20 | "TracingVerbosity": "NormalVerbosity", 21 | "setupBackends": [ 22 | "KatipBK" 23 | ], 24 | "defaultBackends": [ 25 | "KatipBK" 26 | ], 27 | "setupScribes": [ 28 | { 29 | "scKind": "FileSK", 30 | "scName": "logs/mainnet.log", 31 | "scFormat": "ScText" 32 | }, 33 | { 34 | "scKind": "StdoutSK", 35 | "scName": "stdout", 36 | "scFormat": "ScText" 37 | } 38 | ], 39 | "defaultScribes": [ 40 | [ 41 | "FileSK", 42 | "logs/mainnet.log" 43 | ], 44 | [ 45 | "StdoutSK", 46 | "stdout" 47 | ] 48 | ], 49 | "rotation": { 50 | "rpLogLimitBytes": 5000000, 51 | "rpKeepFilesNum": 3, 52 | "rpMaxAgeHours": 24 53 | }, 54 | "TraceBlockFetchClient": false, 55 | "TraceBlockFetchDecisions": false, 56 | "TraceBlockFetchProtocol": false, 57 | "TraceBlockFetchProtocolSerialised": false, 58 | "TraceBlockFetchServer": false, 59 | "TraceBlockchainTime": false, 60 | "TraceChainDb": true, 61 | "TraceChainSyncClient": false, 62 | "TraceChainSyncBlockServer": false, 63 | "TraceChainSyncHeaderServer": false, 64 | "TraceChainSyncProtocol": false, 65 | "TraceDNSResolver": true, 66 | "TraceDNSSubscription": true, 67 | "TraceErrorPolicy": true, 68 | "TraceLocalErrorPolicy": true, 69 | "TraceForge": true, 70 | "TraceHandshake": false, 71 | "TraceIpSubscription": true, 72 | "TraceLocalChainSyncProtocol": false, 73 | "TraceLocalHandshake": false, 74 | "TraceLocalTxSubmissionProtocol": false, 75 | "TraceLocalTxSubmissionServer": false, 76 | "TraceMempool": true, 77 | "TraceMux": false, 78 | "TraceTxInbound": false, 79 | "TraceTxOutbound": false, 80 | "TraceTxSubmissionProtocol": false, 81 | "options": { 82 | "mapBackends": { 83 | "cardano.node.metrics": [ 84 | "EKGViewBK" 85 | ] 86 | }, 87 | "mapScribes": { 88 | "cardano.node.metrics": [ 89 | "FileSK::logs/mainnet.log" 90 | ] 91 | }, 92 | "mapSeverity": { 93 | "cardano.node.ChainDB": "Notice", 94 | "cardano.node.DnsSubscription": "Debug" 95 | } 96 | }, 97 | "EnableLogMetrics": false, 98 | "EnableLogging": true, 99 | "TestShelleyHardForkAtEpoch": 0, 100 | "TestAllegraHardForkAtEpoch": 0, 101 | "TestMaryHardForkAtEpoch": 0, 102 | "TestAlonzoHardForkAtEpoch": 0, 103 | "EnableDevelopmentHardForkEras": true, 104 | "ExperimentalProtocolsEnabled": true 105 | } -------------------------------------------------------------------------------- /integration-test/configs/local-alonzo/conway-genesis.json: -------------------------------------------------------------------------------- 1 | { 2 | "poolVotingThresholds": { 3 | "committeeNormal": 0.51, 4 | "committeeNoConfidence": 0.51, 5 | "hardForkInitiation": 0.51, 6 | "motionNoConfidence": 0.51, 7 | "ppSecurityGroup": 0.51 8 | }, 9 | "dRepVotingThresholds": { 10 | "motionNoConfidence": 0.51, 11 | "committeeNormal": 0.51, 12 | "committeeNoConfidence": 0.51, 13 | "updateToConstitution": 0.51, 14 | "hardForkInitiation": 0.51, 15 | "ppNetworkGroup": 0.51, 16 | "ppEconomicGroup": 0.51, 17 | "ppTechnicalGroup": 0.51, 18 | "ppGovGroup": 0.51, 19 | "treasuryWithdrawal": 0.51 20 | }, 21 | "committeeMinSize": 0, 22 | "committeeMaxTermLength": 200, 23 | "govActionLifetime": 10, 24 | "govActionDeposit": 1000000000, 25 | "dRepDeposit": 2000000, 26 | "dRepActivity": 20, 27 | "constitution": { 28 | "anchor": { 29 | "url": "", 30 | "dataHash": "0000000000000000000000000000000000000000000000000000000000000000" 31 | } 32 | }, 33 | "committee": { 34 | "members": { 35 | 36 | }, 37 | "quorum": 0 38 | } 39 | } -------------------------------------------------------------------------------- /integration-test/configs/local-alonzo/shelley-genesis.json: -------------------------------------------------------------------------------- 1 | { 2 | "maxLovelaceSupply": 1000000000000, 3 | "securityParam": 1000000000, 4 | "slotsPerKESPeriod": 1000000000, 5 | "updateQuorum": 2, 6 | "activeSlotsCoeff": 0.5, 7 | "protocolParams": { 8 | "minUTxOValue": 1000000, 9 | "eMax": 18, 10 | "extraEntropy": { 11 | "tag": "NeutralNonce" 12 | }, 13 | "minFeeB": 155381, 14 | "tau": 0.1, 15 | "maxBlockBodySize": 65536, 16 | "minPoolCost": 0, 17 | "minFeeA": 44, 18 | "maxTxSize": 16384, 19 | "nOpt": 100, 20 | "maxBlockHeaderSize": 1100, 21 | "keyDeposit": 1000000, 22 | "protocolVersion": { 23 | "minor": 0, 24 | "major": 5 25 | }, 26 | "poolDeposit": 1000000, 27 | "a0": 0.0, 28 | "rho": 0.1, 29 | "decentralisationParam": 0.1 30 | }, 31 | "networkMagic": 42, 32 | "initialFunds": { 33 | "60d413c1745d306023e49589e658a7b7a4b4dda165ff5c97d8c8b979bf": 900000000000 34 | }, 35 | "maxKESEvolutions": 60000000, 36 | "networkId": "Testnet", 37 | "genDelegs": { 38 | "37c2ef3cfb83c1004fcc21c75f42fee8013ac994afde92c1af419d1c": { 39 | "delegate": "5bd3a54bf30412243d4616c145c79467322164b81aa577814b74a520", 40 | "vrf": "fb66920eb17f426d4f513535be0eed59859a0e83963860090bb6db571f8a5b55" 41 | } 42 | }, 43 | "slotLength": 1, 44 | "systemStart": "2021-12-21T03:17:14.803874404Z", 45 | "staking": { 46 | "pools": {}, 47 | "stake": {} 48 | }, 49 | "epochLength": 2 50 | } -------------------------------------------------------------------------------- /integration-test/configs/local-alonzo/shelley/kes.skey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "KesSigningKey_ed25519_kes_2^6", 3 | "description": "KES Signing Key", 4 | "cborHex": "59026051c2b5536d23bbd7ff92aa8b58a011fb57b669183b7083961ae979a7b2ad1fbcbf1ee580c9e39567b88562b370cdccd27cababc4812a2ce1a7a0c7369274cf5f18f3e4796482babf0ea8d4e97157d6221bb6448da0cf3f173bbc1b13e708e40c25559347cc225b6d916bf611bc133d265482d0c503e94493456bb607ce34fd7b51a13e8908d9d85582edbed89e0fd2a0fb34d45480cef5b277dbb46b23322ea191760cafdf5c2f3bc5307f2128c121e5f8f54fdf6ca2925c034fc11dcc933855b595493e629e717a1b2ced715dfac5bf42838928edd19c287d55c1ef04ecf31070fe52ab805cf813e752f001353ac637f8f3f76db4b8c0e12f8552335182af76683b819debaa623a730e12f2f7d9f63190c835e8211bdf86d2bf244e8ad114328621535a63fd1a1497389356220e818e5d2f530f50494401b7ee027172ca72093645465b2c83e0dcd1d9c4a81b6871849601a8706d95e3c58a4c0841fdfb214b0bb82ec1e18ba7bea9e4f3eb9a0abbb39e57a9ab96799379ca8cadeb2e1a8df84b3e0e7ca0af3d6665a12029f6cefe4d309c5b3fad5bec4ca7812d5bede426b6fff6f37da99a286cd837b327b35b645ca5bfabf0935ea87cbd29b3ce2b7b80f83f386a474c69f86f553e35069f40b04f9a6bb6a13b583c0a911126c8aed1301b4014e0ea8229d5dcce81a56836f5bb286bd28c1ee5c69fd358c16a4fdbd5b6e9b0ed1ef766dcf6c56c7a845104309c92a2013bd5a7c8354fb8a866b61b23e014a07a78ed5b69469f4121c97bce50864d8555b91e3c2d812f4760a6318750c7b71fccbc8bab1c54c0be28f60c97cc8e33cbd8da235e4ca9344c48f13d81a37459" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-alonzo/shelley/kes.vkey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "KesVerificationKey_ed25519_kes_2^6", 3 | "description": "KES Verification Key", 4 | "cborHex": "58206e59b21f538b5fdbe50df62f793488f8783e19d261d3fd59a700d2c41963cec2" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-alonzo/shelley/node.cert: -------------------------------------------------------------------------------- 1 | { 2 | "type": "NodeOperationalCertificate", 3 | "description": "", 4 | "cborHex": "828458206e59b21f538b5fdbe50df62f793488f8783e19d261d3fd59a700d2c41963cec201005840853403f4d2e63e027b26f59c45ce81c74b1dfd708dc561b5ede5204262253451b7560f1c75425d3ee08fd4d933392f7fe3f1017efb3c8ee565a5493a061a270d582091934010118a86e2628e8188413cfa3eeac1237f3f699ebe16892f41671ccf3f" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-alonzo/shelley/operator.counter: -------------------------------------------------------------------------------- 1 | { 2 | "type": "NodeOperationalCertificateIssueCounter", 3 | "description": "Next certificate issue number: 2", 4 | "cborHex": "8202582091934010118a86e2628e8188413cfa3eeac1237f3f699ebe16892f41671ccf3f" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-alonzo/shelley/operator.skey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "GenesisDelegateSigningKey_ed25519", 3 | "description": "Genesis delegate operator key", 4 | "cborHex": "5820351111fb3058c30c976b57f1b13e0e333243126768eae52133294cfe1481e943" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-alonzo/shelley/operator.vkey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "GenesisDelegateVerificationKey_ed25519", 3 | "description": "Genesis delegate operator key", 4 | "cborHex": "582091934010118a86e2628e8188413cfa3eeac1237f3f699ebe16892f41671ccf3f" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-alonzo/shelley/utxo-keys/payment.addr: -------------------------------------------------------------------------------- 1 | addr_test1vr2p8st5t5cxqglyjky7vk98k7jtfhdpvhl4e97cezuhn0cqcexl7 -------------------------------------------------------------------------------- /integration-test/configs/local-alonzo/shelley/utxo-keys/utxo1.skey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "GenesisUTxOSigningKey_ed25519", 3 | "description": "Genesis Initial UTxO Signing Key", 4 | "cborHex": "5820093be5cd3987d0c9fd8854ef908f7746b69e2d73320db6dc0f780d81585b84c2" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-alonzo/shelley/utxo-keys/utxo1.vkey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "GenesisUTxOVerificationKey_ed25519", 3 | "description": "Genesis Initial UTxO Verification Key", 4 | "cborHex": "58208be8339e9f3addfa6810d59e2f072f85e64d4c024c087e0d24f8317c6544f62f" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-alonzo/shelley/vrf.skey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "VrfSigningKey_PraosVRF", 3 | "description": "VRF Signing Key", 4 | "cborHex": "5840b504af084d200455b08e72f0d278cf23bd9f2acddf834755d007e87536e19d1158cc502328977455f71db641249286ce07c11de5cb1f7429db0584eca3cabb7e" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-alonzo/shelley/vrf.vkey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "VrfVerificationKey_PraosVRF", 3 | "description": "VRF Verification Key", 4 | "cborHex": "582058cc502328977455f71db641249286ce07c11de5cb1f7429db0584eca3cabb7e" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-alonzo/topology.json: -------------------------------------------------------------------------------- 1 | { 2 | "Producers": [ 3 | { 4 | "addr": "172.20.0.102", 5 | "port": 3000, 6 | "valency": 1 7 | } 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /integration-test/configs/local-chang/byron-genesis.json: -------------------------------------------------------------------------------- 1 | { "bootStakeholders": 2 | { "b733bf8070781d30a0c8d5ca66392188f78c6604b631629cd055f402": 1 } 3 | , "heavyDelegation": 4 | { "b733bf8070781d30a0c8d5ca66392188f78c6604b631629cd055f402": 5 | { "omega": 0 6 | , "issuerPk": 7 | "ckPV1Ypq8uRkxwoDj93p7cCm4G+uB9R8SGGOKyc6KyIR8NDVVwu1FS3AwSoUjra02uiF5AlAUXUvVqZvnT8nCw==" 8 | , "delegatePk": 9 | "MYL9xuLMepgsQxRtqOu57nJw16pMWel79j0APRV1NSqH3ZUeBu+p7XaNoVCzw7yemMb4vwLiRDcMnnqHXztFVA==" 10 | , "cert": 11 | "643985a3022fedf3d9aaee8ab18d35e0cdc894beb5edb502ca47c37cce678741dd502fba0c2b8ee38513e0a75f6ee2dcc0f05d5b3c1d7ce72cc1c22a8a910909" 12 | } } 13 | , "startTime": 1640212228 14 | , "nonAvvmBalances": 15 | { "2657WMsDfac6ef4bngGRU7FmksmW8QRfAifshdj4XyDxPeVT4DbPeoiUgzRdKjYYF": 16 | "10020000000" } 17 | , "blockVersionData": 18 | { "scriptVersion": 0 19 | , "slotDuration": "1000" 20 | , "maxBlockSize": "2000000" 21 | , "maxHeaderSize": "2000000" 22 | , "maxTxSize": "4096" 23 | , "maxProposalSize": "700" 24 | , "mpcThd": "20000000000000" 25 | , "heavyDelThd": "300000000000" 26 | , "updateVoteThd": "1000000000000" 27 | , "updateProposalThd": "100000000000000" 28 | , "updateImplicit": "10000" 29 | , "softforkRule": 30 | { "initThd": "900000000000000" 31 | , "minThd": "600000000000000" 32 | , "thdDecrement": "50000000000000" 33 | } 34 | , "txFeePolicy": 35 | { "summand": "155381000000000" , "multiplier": "43946000000" } 36 | , "unlockStakeEpoch": "18446744073709551615" 37 | } 38 | , "protocolConsts": { "k": 10 , "protocolMagic": 42 } 39 | , "avvmDistr": {} 40 | } -------------------------------------------------------------------------------- /integration-test/configs/local-chang/byron/delegate.cert: -------------------------------------------------------------------------------- 1 | { "omega": 0 2 | , "issuerPk": 3 | "ckPV1Ypq8uRkxwoDj93p7cCm4G+uB9R8SGGOKyc6KyIR8NDVVwu1FS3AwSoUjra02uiF5AlAUXUvVqZvnT8nCw==" 4 | , "delegatePk": 5 | "MYL9xuLMepgsQxRtqOu57nJw16pMWel79j0APRV1NSqH3ZUeBu+p7XaNoVCzw7yemMb4vwLiRDcMnnqHXztFVA==" 6 | , "cert": 7 | "643985a3022fedf3d9aaee8ab18d35e0cdc894beb5edb502ca47c37cce678741dd502fba0c2b8ee38513e0a75f6ee2dcc0f05d5b3c1d7ce72cc1c22a8a910909" 8 | } -------------------------------------------------------------------------------- /integration-test/configs/local-chang/byron/delegate.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Python-Cardano/pycardano/7d63d0e1da1b0e64cd2b9d389ed4f9e2e5c076ae/integration-test/configs/local-chang/byron/delegate.key -------------------------------------------------------------------------------- /integration-test/configs/local-chang/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "ByronGenesisFile": "./byron-genesis.json", 3 | "ShelleyGenesisFile": "./shelley-genesis.json", 4 | "AlonzoGenesisFile": "./alonzo-genesis.json", 5 | "ConwayGenesisFile": "./conway-genesis.json", 6 | "SocketPath": "db/node.socket", 7 | "Protocol": "Cardano", 8 | "PBftSignatureThreshold": 0.6, 9 | "RequiresNetworkMagic": "RequiresMagic", 10 | "LastKnownBlockVersion-Alt": 0, 11 | "LastKnownBlockVersion-Major": 3, 12 | "LastKnownBlockVersion-Minor": 1, 13 | "ApplicationName": "cardano-sl", 14 | "MinNodeVersion": "9.0", 15 | "ApplicationVersion": 1, 16 | "TurnOnLogging": true, 17 | "TurnOnLogMetrics": true, 18 | "minSeverity": "Debug", 19 | "TracingVerbosity": "NormalVerbosity", 20 | "setupBackends": [ 21 | "KatipBK" 22 | ], 23 | "defaultBackends": [ 24 | "KatipBK" 25 | ], 26 | "setupScribes": [ 27 | { 28 | "scKind": "FileSK", 29 | "scName": "logs/mainnet.log", 30 | "scFormat": "ScText" 31 | }, 32 | { 33 | "scKind": "StdoutSK", 34 | "scName": "stdout", 35 | "scFormat": "ScText" 36 | } 37 | ], 38 | "defaultScribes": [ 39 | [ 40 | "FileSK", 41 | "logs/mainnet.log" 42 | ], 43 | [ 44 | "StdoutSK", 45 | "stdout" 46 | ] 47 | ], 48 | "rotation": { 49 | "rpLogLimitBytes": 5000000, 50 | "rpKeepFilesNum": 3, 51 | "rpMaxAgeHours": 24 52 | }, 53 | "TraceBlockFetchClient": false, 54 | "TraceBlockFetchDecisions": false, 55 | "TraceBlockFetchProtocol": false, 56 | "TraceBlockFetchProtocolSerialised": false, 57 | "TraceBlockFetchServer": false, 58 | "TraceBlockchainTime": false, 59 | "TraceChainDb": true, 60 | "TraceChainSyncClient": false, 61 | "TraceChainSyncBlockServer": false, 62 | "TraceChainSyncHeaderServer": false, 63 | "TraceChainSyncProtocol": false, 64 | "TraceDNSResolver": true, 65 | "TraceDNSSubscription": true, 66 | "TraceErrorPolicy": true, 67 | "TraceLocalErrorPolicy": true, 68 | "TraceForge": true, 69 | "TraceHandshake": false, 70 | "TraceIpSubscription": true, 71 | "TraceLocalChainSyncProtocol": false, 72 | "TraceLocalHandshake": false, 73 | "TraceLocalTxSubmissionProtocol": false, 74 | "TraceLocalTxSubmissionServer": false, 75 | "TraceMempool": true, 76 | "TraceMux": false, 77 | "TraceTxInbound": false, 78 | "TraceTxOutbound": false, 79 | "TraceTxSubmissionProtocol": false, 80 | "options": { 81 | "mapBackends": { 82 | "cardano.node.metrics": [ 83 | "EKGViewBK" 84 | ] 85 | }, 86 | "mapScribes": { 87 | "cardano.node.metrics": [ 88 | "FileSK::logs/mainnet.log" 89 | ] 90 | }, 91 | "mapSeverity": { 92 | "cardano.node.ChainDB": "Notice", 93 | "cardano.node.DnsSubscription": "Debug" 94 | } 95 | }, 96 | "EnableLogMetrics": false, 97 | "EnableLogging": true, 98 | "TestShelleyHardForkAtEpoch": 0, 99 | "TestAllegraHardForkAtEpoch": 0, 100 | "TestMaryHardForkAtEpoch": 0, 101 | "TestAlonzoHardForkAtEpoch": 0, 102 | "TestBabbageHardForkAtEpoch": 4, 103 | "TestConwayHardForkAtEpoch": 5, 104 | "EnableDevelopmentHardForkEras": true, 105 | "ExperimentalProtocolsEnabled": true 106 | } -------------------------------------------------------------------------------- /integration-test/configs/local-chang/shelley-genesis.json: -------------------------------------------------------------------------------- 1 | { 2 | "maxLovelaceSupply": 1000000000000, 3 | "securityParam": 1000000000, 4 | "slotsPerKESPeriod": 1000000000, 5 | "updateQuorum": 2, 6 | "activeSlotsCoeff": 0.5, 7 | "protocolParams": { 8 | "minUTxOValue": 1000000, 9 | "eMax": 18, 10 | "extraEntropy": { 11 | "tag": "NeutralNonce" 12 | }, 13 | "minFeeB": 155381, 14 | "tau": 0.1, 15 | "maxBlockBodySize": 65536, 16 | "minPoolCost": 0, 17 | "minFeeA": 44, 18 | "maxTxSize": 16384, 19 | "nOpt": 100, 20 | "maxBlockHeaderSize": 1100, 21 | "keyDeposit": 1000000, 22 | "protocolVersion": { 23 | "minor": 0, 24 | "major": 10 25 | }, 26 | "poolDeposit": 1000000, 27 | "a0": 0.0, 28 | "rho": 0.1, 29 | "decentralisationParam": 0.1 30 | }, 31 | "networkMagic": 42, 32 | "initialFunds": { 33 | "60d413c1745d306023e49589e658a7b7a4b4dda165ff5c97d8c8b979bf": 900000000000 34 | }, 35 | "maxKESEvolutions": 60000000, 36 | "networkId": "Testnet", 37 | "genDelegs": { 38 | "37c2ef3cfb83c1004fcc21c75f42fee8013ac994afde92c1af419d1c": { 39 | "delegate": "5bd3a54bf30412243d4616c145c79467322164b81aa577814b74a520", 40 | "vrf": "fb66920eb17f426d4f513535be0eed59859a0e83963860090bb6db571f8a5b55" 41 | } 42 | }, 43 | "slotLength": 1, 44 | "systemStart": "2021-12-21T03:17:14.803874404Z", 45 | "staking": { 46 | "pools": {}, 47 | "stake": {} 48 | }, 49 | "epochLength": 10 50 | } -------------------------------------------------------------------------------- /integration-test/configs/local-chang/shelley/kes.skey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "KesSigningKey_ed25519_kes_2^6", 3 | "description": "KES Signing Key", 4 | "cborHex": "59026051c2b5536d23bbd7ff92aa8b58a011fb57b669183b7083961ae979a7b2ad1fbcbf1ee580c9e39567b88562b370cdccd27cababc4812a2ce1a7a0c7369274cf5f18f3e4796482babf0ea8d4e97157d6221bb6448da0cf3f173bbc1b13e708e40c25559347cc225b6d916bf611bc133d265482d0c503e94493456bb607ce34fd7b51a13e8908d9d85582edbed89e0fd2a0fb34d45480cef5b277dbb46b23322ea191760cafdf5c2f3bc5307f2128c121e5f8f54fdf6ca2925c034fc11dcc933855b595493e629e717a1b2ced715dfac5bf42838928edd19c287d55c1ef04ecf31070fe52ab805cf813e752f001353ac637f8f3f76db4b8c0e12f8552335182af76683b819debaa623a730e12f2f7d9f63190c835e8211bdf86d2bf244e8ad114328621535a63fd1a1497389356220e818e5d2f530f50494401b7ee027172ca72093645465b2c83e0dcd1d9c4a81b6871849601a8706d95e3c58a4c0841fdfb214b0bb82ec1e18ba7bea9e4f3eb9a0abbb39e57a9ab96799379ca8cadeb2e1a8df84b3e0e7ca0af3d6665a12029f6cefe4d309c5b3fad5bec4ca7812d5bede426b6fff6f37da99a286cd837b327b35b645ca5bfabf0935ea87cbd29b3ce2b7b80f83f386a474c69f86f553e35069f40b04f9a6bb6a13b583c0a911126c8aed1301b4014e0ea8229d5dcce81a56836f5bb286bd28c1ee5c69fd358c16a4fdbd5b6e9b0ed1ef766dcf6c56c7a845104309c92a2013bd5a7c8354fb8a866b61b23e014a07a78ed5b69469f4121c97bce50864d8555b91e3c2d812f4760a6318750c7b71fccbc8bab1c54c0be28f60c97cc8e33cbd8da235e4ca9344c48f13d81a37459" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-chang/shelley/kes.vkey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "KesVerificationKey_ed25519_kes_2^6", 3 | "description": "KES Verification Key", 4 | "cborHex": "58206e59b21f538b5fdbe50df62f793488f8783e19d261d3fd59a700d2c41963cec2" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-chang/shelley/node.cert: -------------------------------------------------------------------------------- 1 | { 2 | "type": "NodeOperationalCertificate", 3 | "description": "", 4 | "cborHex": "828458206e59b21f538b5fdbe50df62f793488f8783e19d261d3fd59a700d2c41963cec201005840853403f4d2e63e027b26f59c45ce81c74b1dfd708dc561b5ede5204262253451b7560f1c75425d3ee08fd4d933392f7fe3f1017efb3c8ee565a5493a061a270d582091934010118a86e2628e8188413cfa3eeac1237f3f699ebe16892f41671ccf3f" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-chang/shelley/operator.counter: -------------------------------------------------------------------------------- 1 | { 2 | "type": "NodeOperationalCertificateIssueCounter", 3 | "description": "Next certificate issue number: 2", 4 | "cborHex": "8202582091934010118a86e2628e8188413cfa3eeac1237f3f699ebe16892f41671ccf3f" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-chang/shelley/operator.skey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "GenesisDelegateSigningKey_ed25519", 3 | "description": "Genesis delegate operator key", 4 | "cborHex": "5820351111fb3058c30c976b57f1b13e0e333243126768eae52133294cfe1481e943" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-chang/shelley/operator.vkey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "GenesisDelegateVerificationKey_ed25519", 3 | "description": "Genesis delegate operator key", 4 | "cborHex": "582091934010118a86e2628e8188413cfa3eeac1237f3f699ebe16892f41671ccf3f" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-chang/shelley/utxo-keys/payment.addr: -------------------------------------------------------------------------------- 1 | addr_test1vr2p8st5t5cxqglyjky7vk98k7jtfhdpvhl4e97cezuhn0cqcexl7 -------------------------------------------------------------------------------- /integration-test/configs/local-chang/shelley/utxo-keys/utxo1.skey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "GenesisUTxOSigningKey_ed25519", 3 | "description": "Genesis Initial UTxO Signing Key", 4 | "cborHex": "5820093be5cd3987d0c9fd8854ef908f7746b69e2d73320db6dc0f780d81585b84c2" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-chang/shelley/utxo-keys/utxo1.vkey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "GenesisUTxOVerificationKey_ed25519", 3 | "description": "Genesis Initial UTxO Verification Key", 4 | "cborHex": "58208be8339e9f3addfa6810d59e2f072f85e64d4c024c087e0d24f8317c6544f62f" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-chang/shelley/vrf.skey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "VrfSigningKey_PraosVRF", 3 | "description": "VRF Signing Key", 4 | "cborHex": "5840b504af084d200455b08e72f0d278cf23bd9f2acddf834755d007e87536e19d1158cc502328977455f71db641249286ce07c11de5cb1f7429db0584eca3cabb7e" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-chang/shelley/vrf.vkey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "VrfVerificationKey_PraosVRF", 3 | "description": "VRF Verification Key", 4 | "cborHex": "582058cc502328977455f71db641249286ce07c11de5cb1f7429db0584eca3cabb7e" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-chang/topology.json: -------------------------------------------------------------------------------- 1 | { 2 | "Producers": [ 3 | { 4 | "addr": "172.20.0.102", 5 | "port": 3000, 6 | "valency": 1 7 | } 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /integration-test/configs/local-vasil/byron-genesis.json: -------------------------------------------------------------------------------- 1 | { "bootStakeholders": 2 | { "b733bf8070781d30a0c8d5ca66392188f78c6604b631629cd055f402": 1 } 3 | , "heavyDelegation": 4 | { "b733bf8070781d30a0c8d5ca66392188f78c6604b631629cd055f402": 5 | { "omega": 0 6 | , "issuerPk": 7 | "ckPV1Ypq8uRkxwoDj93p7cCm4G+uB9R8SGGOKyc6KyIR8NDVVwu1FS3AwSoUjra02uiF5AlAUXUvVqZvnT8nCw==" 8 | , "delegatePk": 9 | "MYL9xuLMepgsQxRtqOu57nJw16pMWel79j0APRV1NSqH3ZUeBu+p7XaNoVCzw7yemMb4vwLiRDcMnnqHXztFVA==" 10 | , "cert": 11 | "643985a3022fedf3d9aaee8ab18d35e0cdc894beb5edb502ca47c37cce678741dd502fba0c2b8ee38513e0a75f6ee2dcc0f05d5b3c1d7ce72cc1c22a8a910909" 12 | } } 13 | , "startTime": 1640212228 14 | , "nonAvvmBalances": 15 | { "2657WMsDfac6ef4bngGRU7FmksmW8QRfAifshdj4XyDxPeVT4DbPeoiUgzRdKjYYF": 16 | "10020000000" } 17 | , "blockVersionData": 18 | { "scriptVersion": 0 19 | , "slotDuration": "1000" 20 | , "maxBlockSize": "2000000" 21 | , "maxHeaderSize": "2000000" 22 | , "maxTxSize": "4096" 23 | , "maxProposalSize": "700" 24 | , "mpcThd": "20000000000000" 25 | , "heavyDelThd": "300000000000" 26 | , "updateVoteThd": "1000000000000" 27 | , "updateProposalThd": "100000000000000" 28 | , "updateImplicit": "10000" 29 | , "softforkRule": 30 | { "initThd": "900000000000000" 31 | , "minThd": "600000000000000" 32 | , "thdDecrement": "50000000000000" 33 | } 34 | , "txFeePolicy": 35 | { "summand": "155381000000000" , "multiplier": "43946000000" } 36 | , "unlockStakeEpoch": "18446744073709551615" 37 | } 38 | , "protocolConsts": { "k": 10 , "protocolMagic": 42 } 39 | , "avvmDistr": {} 40 | } -------------------------------------------------------------------------------- /integration-test/configs/local-vasil/byron/delegate.cert: -------------------------------------------------------------------------------- 1 | { "omega": 0 2 | , "issuerPk": 3 | "ckPV1Ypq8uRkxwoDj93p7cCm4G+uB9R8SGGOKyc6KyIR8NDVVwu1FS3AwSoUjra02uiF5AlAUXUvVqZvnT8nCw==" 4 | , "delegatePk": 5 | "MYL9xuLMepgsQxRtqOu57nJw16pMWel79j0APRV1NSqH3ZUeBu+p7XaNoVCzw7yemMb4vwLiRDcMnnqHXztFVA==" 6 | , "cert": 7 | "643985a3022fedf3d9aaee8ab18d35e0cdc894beb5edb502ca47c37cce678741dd502fba0c2b8ee38513e0a75f6ee2dcc0f05d5b3c1d7ce72cc1c22a8a910909" 8 | } -------------------------------------------------------------------------------- /integration-test/configs/local-vasil/byron/delegate.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Python-Cardano/pycardano/7d63d0e1da1b0e64cd2b9d389ed4f9e2e5c076ae/integration-test/configs/local-vasil/byron/delegate.key -------------------------------------------------------------------------------- /integration-test/configs/local-vasil/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "ByronGenesisFile": "byron-genesis.json", 3 | "ShelleyGenesisFile": "shelley-genesis.json", 4 | "AlonzoGenesisFile": "alonzo-genesis.json", 5 | "ConwayGenesisFile": "conway-genesis.json", 6 | "SocketPath": "db/node.socket", 7 | "MaxConcurrencyBulkSync": 1, 8 | "MaxConcurrencyDeadline": 2, 9 | "Protocol": "Cardano", 10 | "PBftSignatureThreshold": 0.6, 11 | "RequiresNetworkMagic": "RequiresMagic", 12 | "LastKnownBlockVersion-Major": 5, 13 | "LastKnownBlockVersion-Minor": 0, 14 | "LastKnownBlockVersion-Alt": 0, 15 | "ApplicationName": "cardano-sl", 16 | "ApplicationVersion": 1, 17 | "TurnOnLogging": true, 18 | "TurnOnLogMetrics": true, 19 | "minSeverity": "Debug", 20 | "TracingVerbosity": "NormalVerbosity", 21 | "setupBackends": [ 22 | "KatipBK" 23 | ], 24 | "defaultBackends": [ 25 | "KatipBK" 26 | ], 27 | "setupScribes": [ 28 | { 29 | "scKind": "FileSK", 30 | "scName": "logs/mainnet.log", 31 | "scFormat": "ScText" 32 | }, 33 | { 34 | "scKind": "StdoutSK", 35 | "scName": "stdout", 36 | "scFormat": "ScText" 37 | } 38 | ], 39 | "defaultScribes": [ 40 | [ 41 | "FileSK", 42 | "logs/mainnet.log" 43 | ], 44 | [ 45 | "StdoutSK", 46 | "stdout" 47 | ] 48 | ], 49 | "rotation": { 50 | "rpLogLimitBytes": 5000000, 51 | "rpKeepFilesNum": 3, 52 | "rpMaxAgeHours": 24 53 | }, 54 | "TraceBlockFetchClient": false, 55 | "TraceBlockFetchDecisions": false, 56 | "TraceBlockFetchProtocol": false, 57 | "TraceBlockFetchProtocolSerialised": false, 58 | "TraceBlockFetchServer": false, 59 | "TraceBlockchainTime": false, 60 | "TraceChainDb": true, 61 | "TraceChainSyncClient": false, 62 | "TraceChainSyncBlockServer": false, 63 | "TraceChainSyncHeaderServer": false, 64 | "TraceChainSyncProtocol": false, 65 | "TraceDNSResolver": true, 66 | "TraceDNSSubscription": true, 67 | "TraceErrorPolicy": true, 68 | "TraceLocalErrorPolicy": true, 69 | "TraceForge": true, 70 | "TraceHandshake": false, 71 | "TraceIpSubscription": true, 72 | "TraceLocalChainSyncProtocol": false, 73 | "TraceLocalHandshake": false, 74 | "TraceLocalTxSubmissionProtocol": false, 75 | "TraceLocalTxSubmissionServer": false, 76 | "TraceMempool": true, 77 | "TraceMux": false, 78 | "TraceTxInbound": false, 79 | "TraceTxOutbound": false, 80 | "TraceTxSubmissionProtocol": false, 81 | "options": { 82 | "mapBackends": { 83 | "cardano.node.metrics": [ 84 | "EKGViewBK" 85 | ] 86 | }, 87 | "mapScribes": { 88 | "cardano.node.metrics": [ 89 | "FileSK::logs/mainnet.log" 90 | ] 91 | }, 92 | "mapSeverity": { 93 | "cardano.node.ChainDB": "Notice", 94 | "cardano.node.DnsSubscription": "Debug" 95 | } 96 | }, 97 | "EnableLogMetrics": false, 98 | "EnableLogging": true, 99 | "TestShelleyHardForkAtEpoch": 0, 100 | "TestAllegraHardForkAtEpoch": 0, 101 | "TestMaryHardForkAtEpoch": 0, 102 | "TestAlonzoHardForkAtEpoch": 0, 103 | "TestBabbageHardForkAtEpoch": 10, 104 | "EnableDevelopmentHardForkEras": true, 105 | "ExperimentalProtocolsEnabled": true 106 | } -------------------------------------------------------------------------------- /integration-test/configs/local-vasil/conway-genesis.json: -------------------------------------------------------------------------------- 1 | { 2 | "poolVotingThresholds": { 3 | "committeeNormal": 0.51, 4 | "committeeNoConfidence": 0.51, 5 | "hardForkInitiation": 0.51, 6 | "motionNoConfidence": 0.51, 7 | "ppSecurityGroup": 0.51 8 | }, 9 | "dRepVotingThresholds": { 10 | "motionNoConfidence": 0.51, 11 | "committeeNormal": 0.51, 12 | "committeeNoConfidence": 0.51, 13 | "updateToConstitution": 0.51, 14 | "hardForkInitiation": 0.51, 15 | "ppNetworkGroup": 0.51, 16 | "ppEconomicGroup": 0.51, 17 | "ppTechnicalGroup": 0.51, 18 | "ppGovGroup": 0.51, 19 | "treasuryWithdrawal": 0.51 20 | }, 21 | "committeeMinSize": 0, 22 | "committeeMaxTermLength": 200, 23 | "govActionLifetime": 10, 24 | "govActionDeposit": 1000000000, 25 | "dRepDeposit": 2000000, 26 | "dRepActivity": 20, 27 | "constitution": { 28 | "anchor": { 29 | "url": "", 30 | "dataHash": "0000000000000000000000000000000000000000000000000000000000000000" 31 | } 32 | }, 33 | "committee": { 34 | "members": { 35 | 36 | }, 37 | "quorum": 0 38 | } 39 | } -------------------------------------------------------------------------------- /integration-test/configs/local-vasil/shelley-genesis.json: -------------------------------------------------------------------------------- 1 | { 2 | "maxLovelaceSupply": 1000000000000, 3 | "securityParam": 1000000000, 4 | "slotsPerKESPeriod": 1000000000, 5 | "updateQuorum": 2, 6 | "activeSlotsCoeff": 0.5, 7 | "protocolParams": { 8 | "minUTxOValue": 1000000, 9 | "eMax": 18, 10 | "extraEntropy": { 11 | "tag": "NeutralNonce" 12 | }, 13 | "minFeeB": 155381, 14 | "tau": 0.1, 15 | "maxBlockBodySize": 65536, 16 | "minPoolCost": 0, 17 | "minFeeA": 44, 18 | "maxTxSize": 16384, 19 | "nOpt": 100, 20 | "maxBlockHeaderSize": 1100, 21 | "keyDeposit": 1000000, 22 | "protocolVersion": { 23 | "minor": 0, 24 | "major": 7 25 | }, 26 | "poolDeposit": 1000000, 27 | "a0": 0.0, 28 | "rho": 0.1, 29 | "decentralisationParam": 0.1 30 | }, 31 | "networkMagic": 42, 32 | "initialFunds": { 33 | "60d413c1745d306023e49589e658a7b7a4b4dda165ff5c97d8c8b979bf": 900000000000 34 | }, 35 | "maxKESEvolutions": 60000000, 36 | "networkId": "Testnet", 37 | "genDelegs": { 38 | "37c2ef3cfb83c1004fcc21c75f42fee8013ac994afde92c1af419d1c": { 39 | "delegate": "5bd3a54bf30412243d4616c145c79467322164b81aa577814b74a520", 40 | "vrf": "fb66920eb17f426d4f513535be0eed59859a0e83963860090bb6db571f8a5b55" 41 | } 42 | }, 43 | "slotLength": 1, 44 | "systemStart": "2021-12-21T03:17:14.803874404Z", 45 | "staking": { 46 | "pools": {}, 47 | "stake": {} 48 | }, 49 | "epochLength": 4 50 | } -------------------------------------------------------------------------------- /integration-test/configs/local-vasil/shelley/kes.skey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "KesSigningKey_ed25519_kes_2^6", 3 | "description": "KES Signing Key", 4 | "cborHex": "59026051c2b5536d23bbd7ff92aa8b58a011fb57b669183b7083961ae979a7b2ad1fbcbf1ee580c9e39567b88562b370cdccd27cababc4812a2ce1a7a0c7369274cf5f18f3e4796482babf0ea8d4e97157d6221bb6448da0cf3f173bbc1b13e708e40c25559347cc225b6d916bf611bc133d265482d0c503e94493456bb607ce34fd7b51a13e8908d9d85582edbed89e0fd2a0fb34d45480cef5b277dbb46b23322ea191760cafdf5c2f3bc5307f2128c121e5f8f54fdf6ca2925c034fc11dcc933855b595493e629e717a1b2ced715dfac5bf42838928edd19c287d55c1ef04ecf31070fe52ab805cf813e752f001353ac637f8f3f76db4b8c0e12f8552335182af76683b819debaa623a730e12f2f7d9f63190c835e8211bdf86d2bf244e8ad114328621535a63fd1a1497389356220e818e5d2f530f50494401b7ee027172ca72093645465b2c83e0dcd1d9c4a81b6871849601a8706d95e3c58a4c0841fdfb214b0bb82ec1e18ba7bea9e4f3eb9a0abbb39e57a9ab96799379ca8cadeb2e1a8df84b3e0e7ca0af3d6665a12029f6cefe4d309c5b3fad5bec4ca7812d5bede426b6fff6f37da99a286cd837b327b35b645ca5bfabf0935ea87cbd29b3ce2b7b80f83f386a474c69f86f553e35069f40b04f9a6bb6a13b583c0a911126c8aed1301b4014e0ea8229d5dcce81a56836f5bb286bd28c1ee5c69fd358c16a4fdbd5b6e9b0ed1ef766dcf6c56c7a845104309c92a2013bd5a7c8354fb8a866b61b23e014a07a78ed5b69469f4121c97bce50864d8555b91e3c2d812f4760a6318750c7b71fccbc8bab1c54c0be28f60c97cc8e33cbd8da235e4ca9344c48f13d81a37459" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-vasil/shelley/kes.vkey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "KesVerificationKey_ed25519_kes_2^6", 3 | "description": "KES Verification Key", 4 | "cborHex": "58206e59b21f538b5fdbe50df62f793488f8783e19d261d3fd59a700d2c41963cec2" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-vasil/shelley/node.cert: -------------------------------------------------------------------------------- 1 | { 2 | "type": "NodeOperationalCertificate", 3 | "description": "", 4 | "cborHex": "828458206e59b21f538b5fdbe50df62f793488f8783e19d261d3fd59a700d2c41963cec201005840853403f4d2e63e027b26f59c45ce81c74b1dfd708dc561b5ede5204262253451b7560f1c75425d3ee08fd4d933392f7fe3f1017efb3c8ee565a5493a061a270d582091934010118a86e2628e8188413cfa3eeac1237f3f699ebe16892f41671ccf3f" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-vasil/shelley/operator.counter: -------------------------------------------------------------------------------- 1 | { 2 | "type": "NodeOperationalCertificateIssueCounter", 3 | "description": "Next certificate issue number: 2", 4 | "cborHex": "8202582091934010118a86e2628e8188413cfa3eeac1237f3f699ebe16892f41671ccf3f" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-vasil/shelley/operator.skey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "GenesisDelegateSigningKey_ed25519", 3 | "description": "Genesis delegate operator key", 4 | "cborHex": "5820351111fb3058c30c976b57f1b13e0e333243126768eae52133294cfe1481e943" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-vasil/shelley/operator.vkey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "GenesisDelegateVerificationKey_ed25519", 3 | "description": "Genesis delegate operator key", 4 | "cborHex": "582091934010118a86e2628e8188413cfa3eeac1237f3f699ebe16892f41671ccf3f" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-vasil/shelley/utxo-keys/payment.addr: -------------------------------------------------------------------------------- 1 | addr_test1vr2p8st5t5cxqglyjky7vk98k7jtfhdpvhl4e97cezuhn0cqcexl7 -------------------------------------------------------------------------------- /integration-test/configs/local-vasil/shelley/utxo-keys/utxo1.skey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "GenesisUTxOSigningKey_ed25519", 3 | "description": "Genesis Initial UTxO Signing Key", 4 | "cborHex": "5820093be5cd3987d0c9fd8854ef908f7746b69e2d73320db6dc0f780d81585b84c2" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-vasil/shelley/utxo-keys/utxo1.vkey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "GenesisUTxOVerificationKey_ed25519", 3 | "description": "Genesis Initial UTxO Verification Key", 4 | "cborHex": "58208be8339e9f3addfa6810d59e2f072f85e64d4c024c087e0d24f8317c6544f62f" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-vasil/shelley/vrf.skey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "VrfSigningKey_PraosVRF", 3 | "description": "VRF Signing Key", 4 | "cborHex": "5840b504af084d200455b08e72f0d278cf23bd9f2acddf834755d007e87536e19d1158cc502328977455f71db641249286ce07c11de5cb1f7429db0584eca3cabb7e" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-vasil/shelley/vrf.vkey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "VrfVerificationKey_PraosVRF", 3 | "description": "VRF Verification Key", 4 | "cborHex": "582058cc502328977455f71db641249286ce07c11de5cb1f7429db0584eca3cabb7e" 5 | } 6 | -------------------------------------------------------------------------------- /integration-test/configs/local-vasil/topology.json: -------------------------------------------------------------------------------- 1 | { 2 | "Producers": [ 3 | { 4 | "addr": "172.20.0.102", 5 | "port": 3000, 6 | "valency": 1 7 | } 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /integration-test/configs/mainnet/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "AlonzoGenesisFile": "alonzo-genesis.json", 3 | "AlonzoGenesisHash": "7e94a15f55d1e82d10f09203fa1d40f8eede58fd8066542cf6566008068ed874", 4 | "ApplicationName": "cardano-sl", 5 | "ApplicationVersion": 1, 6 | "ByronGenesisFile": "byron-genesis.json", 7 | "ByronGenesisHash": "5f20df933584822601f9e3f8c024eb5eb252fe8cefb24d1317dc3d432e940ebb", 8 | "LastKnownBlockVersion-Alt": 0, 9 | "LastKnownBlockVersion-Major": 3, 10 | "LastKnownBlockVersion-Minor": 0, 11 | "MaxKnownMajorProtocolVersion": 2, 12 | "Protocol": "Cardano", 13 | "RequiresNetworkMagic": "RequiresNoMagic", 14 | "ShelleyGenesisFile": "shelley-genesis.json", 15 | "ShelleyGenesisHash": "1a3be38bcbb7911969283716ad7aa550250226b76a61fc51cc9a9a35d9276d81", 16 | "TraceAcceptPolicy": true, 17 | "TraceBlockFetchClient": false, 18 | "TraceBlockFetchDecisions": false, 19 | "TraceBlockFetchProtocol": false, 20 | "TraceBlockFetchProtocolSerialised": false, 21 | "TraceBlockFetchServer": false, 22 | "TraceChainDb": true, 23 | "TraceChainSyncBlockServer": false, 24 | "TraceChainSyncClient": false, 25 | "TraceChainSyncHeaderServer": false, 26 | "TraceChainSyncProtocol": false, 27 | "TraceConnectionManager": true, 28 | "TraceDNSResolver": true, 29 | "TraceDNSSubscription": true, 30 | "TraceDiffusionInitialization": true, 31 | "TraceErrorPolicy": true, 32 | "TraceForge": true, 33 | "TraceHandshake": false, 34 | "TraceInboundGovernor": true, 35 | "TraceIpSubscription": true, 36 | "TraceLedgerPeers": true, 37 | "TraceLocalChainSyncProtocol": false, 38 | "TraceLocalErrorPolicy": true, 39 | "TraceLocalHandshake": false, 40 | "TraceLocalRootPeers": true, 41 | "TraceLocalTxSubmissionProtocol": false, 42 | "TraceLocalTxSubmissionServer": false, 43 | "TraceMempool": true, 44 | "TraceMux": false, 45 | "TracePeerSelection": true, 46 | "TracePeerSelectionActions": true, 47 | "TracePublicRootPeers": true, 48 | "TraceServer": true, 49 | "TraceTxInbound": false, 50 | "TraceTxOutbound": false, 51 | "TraceTxSubmissionProtocol": false, 52 | "TracingVerbosity": "NormalVerbosity", 53 | "TurnOnLogMetrics": true, 54 | "TurnOnLogging": true, 55 | "defaultBackends": [ 56 | "KatipBK" 57 | ], 58 | "defaultScribes": [ 59 | [ 60 | "StdoutSK", 61 | "stdout" 62 | ] 63 | ], 64 | "hasEKG": 12788, 65 | "hasPrometheus": [ 66 | "127.0.0.1", 67 | 12798 68 | ], 69 | "minSeverity": "Info", 70 | "options": { 71 | "mapBackends": { 72 | "cardano.node.metrics": [ 73 | "EKGViewBK" 74 | ], 75 | "cardano.node.resources": [ 76 | "EKGViewBK" 77 | ] 78 | }, 79 | "mapSubtrace": { 80 | "cardano.node.metrics": { 81 | "subtrace": "Neutral" 82 | } 83 | } 84 | }, 85 | "rotation": { 86 | "rpKeepFilesNum": 10, 87 | "rpLogLimitBytes": 5000000, 88 | "rpMaxAgeHours": 24 89 | }, 90 | "setupBackends": [ 91 | "KatipBK" 92 | ], 93 | "setupScribes": [ 94 | { 95 | "scFormat": "ScText", 96 | "scKind": "StdoutSK", 97 | "scName": "stdout", 98 | "scRotation": null 99 | } 100 | ] 101 | } 102 | -------------------------------------------------------------------------------- /integration-test/configs/mainnet/shelley-genesis.json: -------------------------------------------------------------------------------- 1 | { 2 | "activeSlotsCoeff": 0.05, 3 | "protocolParams": { 4 | "protocolVersion": { 5 | "minor": 0, 6 | "major": 2 7 | }, 8 | "decentralisationParam": 1, 9 | "eMax": 18, 10 | "extraEntropy": { 11 | "tag": "NeutralNonce" 12 | }, 13 | "maxTxSize": 16384, 14 | "maxBlockBodySize": 65536, 15 | "maxBlockHeaderSize": 1100, 16 | "minFeeA": 44, 17 | "minFeeB": 155381, 18 | "minUTxOValue": 1000000, 19 | "poolDeposit": 500000000, 20 | "minPoolCost": 340000000, 21 | "keyDeposit": 2000000, 22 | "nOpt": 150, 23 | "rho": 0.003, 24 | "tau": 0.20, 25 | "a0": 0.3 26 | }, 27 | "genDelegs": { 28 | "ad5463153dc3d24b9ff133e46136028bdc1edbb897f5a7cf1b37950c": { 29 | "delegate": "d9e5c76ad5ee778960804094a389f0b546b5c2b140a62f8ec43ea54d", 30 | "vrf": "64fa87e8b29a5b7bfbd6795677e3e878c505bc4a3649485d366b50abadec92d7" 31 | }, 32 | "b9547b8a57656539a8d9bc42c008e38d9c8bd9c8adbb1e73ad529497": { 33 | "delegate": "855d6fc1e54274e331e34478eeac8d060b0b90c1f9e8a2b01167c048", 34 | "vrf": "66d5167a1f426bd1adcc8bbf4b88c280d38c148d135cb41e3f5a39f948ad7fcc" 35 | }, 36 | "60baee25cbc90047e83fd01e1e57dc0b06d3d0cb150d0ab40bbfead1": { 37 | "delegate": "7f72a1826ae3b279782ab2bc582d0d2958de65bd86b2c4f82d8ba956", 38 | "vrf": "c0546d9aa5740afd569d3c2d9c412595cd60822bb6d9a4e8ce6c43d12bd0f674" 39 | }, 40 | "f7b341c14cd58fca4195a9b278cce1ef402dc0e06deb77e543cd1757": { 41 | "delegate": "69ae12f9e45c0c9122356c8e624b1fbbed6c22a2e3b4358cf0cb5011", 42 | "vrf": "6394a632af51a32768a6f12dac3485d9c0712d0b54e3f389f355385762a478f2" 43 | }, 44 | "162f94554ac8c225383a2248c245659eda870eaa82d0ef25fc7dcd82": { 45 | "delegate": "4485708022839a7b9b8b639a939c85ec0ed6999b5b6dc651b03c43f6", 46 | "vrf": "aba81e764b71006c515986bf7b37a72fbb5554f78e6775f08e384dbd572a4b32" 47 | }, 48 | "2075a095b3c844a29c24317a94a643ab8e22d54a3a3a72a420260af6": { 49 | "delegate": "6535db26347283990a252313a7903a45e3526ec25ddba381c071b25b", 50 | "vrf": "fcaca997b8105bd860876348fc2c6e68b13607f9bbd23515cd2193b555d267af" 51 | }, 52 | "268cfc0b89e910ead22e0ade91493d8212f53f3e2164b2e4bef0819b": { 53 | "delegate": "1d4f2e1fda43070d71bb22a5522f86943c7c18aeb4fa47a362c27e23", 54 | "vrf": "63ef48bc5355f3e7973100c371d6a095251c80ceb40559f4750aa7014a6fb6db" 55 | } 56 | }, 57 | "updateQuorum": 5, 58 | "networkId": "Mainnet", 59 | "initialFunds": {}, 60 | "maxLovelaceSupply": 45000000000000000, 61 | "networkMagic": 764824073, 62 | "epochLength": 432000, 63 | "systemStart": "2017-09-23T21:44:51Z", 64 | "slotsPerKESPeriod": 129600, 65 | "slotLength": 1, 66 | "maxKESEvolutions": 62, 67 | "securityParam": 2160 68 | } 69 | -------------------------------------------------------------------------------- /integration-test/configs/mainnet/topology.json: -------------------------------------------------------------------------------- 1 | { 2 | "Producers": [ 3 | { 4 | "addr": "relays-new.cardano-mainnet.iohk.io", 5 | "port": 3001, 6 | "valency": 2 7 | } 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /integration-test/configs/testnet/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "AlonzoGenesisFile": "alonzo-genesis.json", 3 | "AlonzoGenesisHash": "7e94a15f55d1e82d10f09203fa1d40f8eede58fd8066542cf6566008068ed874", 4 | "ApplicationName": "cardano-sl", 5 | "ApplicationVersion": 0, 6 | "ByronGenesisFile": "byron-genesis.json", 7 | "ByronGenesisHash": "96fceff972c2c06bd3bb5243c39215333be6d56aaf4823073dca31afe5038471", 8 | "LastKnownBlockVersion-Alt": 0, 9 | "LastKnownBlockVersion-Major": 3, 10 | "LastKnownBlockVersion-Minor": 0, 11 | "MaxKnownMajorProtocolVersion": 2, 12 | "Protocol": "Cardano", 13 | "RequiresNetworkMagic": "RequiresMagic", 14 | "ShelleyGenesisFile": "shelley-genesis.json", 15 | "ShelleyGenesisHash": "849a1764f152e1b09c89c0dfdbcbdd38d711d1fec2db5dfa0f87cf2737a0eaf4", 16 | "TraceAcceptPolicy": true, 17 | "TraceBlockFetchClient": false, 18 | "TraceBlockFetchDecisions": false, 19 | "TraceBlockFetchProtocol": false, 20 | "TraceBlockFetchProtocolSerialised": false, 21 | "TraceBlockFetchServer": false, 22 | "TraceChainDb": true, 23 | "TraceChainSyncBlockServer": false, 24 | "TraceChainSyncClient": false, 25 | "TraceChainSyncHeaderServer": false, 26 | "TraceChainSyncProtocol": false, 27 | "TraceConnectionManager": true, 28 | "TraceDNSResolver": true, 29 | "TraceDNSSubscription": true, 30 | "TraceDiffusionInitialization": true, 31 | "TraceErrorPolicy": true, 32 | "TraceForge": true, 33 | "TraceHandshake": false, 34 | "TraceInboundGovernor": true, 35 | "TraceIpSubscription": true, 36 | "TraceLedgerPeers": true, 37 | "TraceLocalChainSyncProtocol": false, 38 | "TraceLocalErrorPolicy": true, 39 | "TraceLocalHandshake": false, 40 | "TraceLocalRootPeers": true, 41 | "TraceLocalTxSubmissionProtocol": false, 42 | "TraceLocalTxSubmissionServer": false, 43 | "TraceMempool": true, 44 | "TraceMux": false, 45 | "TracePeerSelection": true, 46 | "TracePeerSelectionActions": true, 47 | "TracePublicRootPeers": true, 48 | "TraceServer": true, 49 | "TraceTxInbound": false, 50 | "TraceTxOutbound": false, 51 | "TraceTxSubmissionProtocol": false, 52 | "TracingVerbosity": "NormalVerbosity", 53 | "TurnOnLogMetrics": true, 54 | "TurnOnLogging": true, 55 | "defaultBackends": [ 56 | "KatipBK" 57 | ], 58 | "defaultScribes": [ 59 | [ 60 | "StdoutSK", 61 | "stdout" 62 | ] 63 | ], 64 | "hasEKG": 12788, 65 | "hasPrometheus": [ 66 | "127.0.0.1", 67 | 12798 68 | ], 69 | "minSeverity": "Info", 70 | "options": { 71 | "mapBackends": { 72 | "cardano.node.metrics": [ 73 | "EKGViewBK" 74 | ], 75 | "cardano.node.resources": [ 76 | "EKGViewBK" 77 | ] 78 | }, 79 | "mapSubtrace": { 80 | "cardano.node.metrics": { 81 | "subtrace": "Neutral" 82 | } 83 | } 84 | }, 85 | "rotation": { 86 | "rpKeepFilesNum": 10, 87 | "rpLogLimitBytes": 5000000, 88 | "rpMaxAgeHours": 24 89 | }, 90 | "setupBackends": [ 91 | "KatipBK" 92 | ], 93 | "setupScribes": [ 94 | { 95 | "scFormat": "ScText", 96 | "scKind": "StdoutSK", 97 | "scName": "stdout", 98 | "scRotation": null 99 | } 100 | ] 101 | } 102 | -------------------------------------------------------------------------------- /integration-test/configs/testnet/shelley-genesis.json: -------------------------------------------------------------------------------- 1 | { 2 | "activeSlotsCoeff": 0.05, 3 | "protocolParams": { 4 | "protocolVersion": { 5 | "minor": 0, 6 | "major": 2 7 | }, 8 | "decentralisationParam": 1, 9 | "eMax": 18, 10 | "extraEntropy": { 11 | "tag": "NeutralNonce" 12 | }, 13 | "maxTxSize": 16384, 14 | "maxBlockBodySize": 65536, 15 | "maxBlockHeaderSize": 1100, 16 | "minFeeA": 44, 17 | "minFeeB": 155381, 18 | "minUTxOValue": 1000000, 19 | "poolDeposit": 500000000, 20 | "minPoolCost": 340000000, 21 | "keyDeposit": 2000000, 22 | "nOpt": 150, 23 | "rho": 0.003, 24 | "tau": 0.20, 25 | "a0": 0.3 26 | }, 27 | "genDelegs": { 28 | "2f56e87d67b8e5216582cfeb95dbdc9083110a3ef68faaa51bef3a80": { 29 | "delegate": "bd5933d3c5417f17a64c7214711a26abc3bc03e2c90dc1bb38e0c39f", 30 | "vrf": "9a0b0f537874d089cedfa9e250150405e47ea29acee87c40a223ae0a175d26f8" 31 | }, 32 | "514e81afb082fce01678809eebd90eda4f7918354ec7d0433ad16274": { 33 | "delegate": "eff1b5b26e65b791d6f236c7c0264012bd1696759d22bdb4dd0f6f56", 34 | "vrf": "e6f70fb10c7523aa76648e20d17e65fd9b2ed53960fbd20b308f223b703f2e23" 35 | }, 36 | "2fca486b4d8f1a0432f5bf18ef473ee4294c795a1a32e3132bc6b90f": { 37 | "delegate": "de665a71064706f946030505eae950583f08c316f0f58997961092b1", 38 | "vrf": "c3fde629add60e30142cd7ef3c680610975208b08aee42203a5c40ad5992e8f6" 39 | }, 40 | "4ee98623920698b77c1c7f77288cbdac5f9011ff8970b1f507567d0d": { 41 | "delegate": "bf07107c6f632de95e34af7e009d2aafa19916c7ba89b944fbedcd72", 42 | "vrf": "9d7d12e3d6b02835be3e76cfc6ae93d937035ee0e006d04a0eef9dea19754e21" 43 | }, 44 | "0d06d2547ed371fdf95fb5c4c735eecdd53e6a5bb831561bd0fcfd3d": { 45 | "delegate": "6df3e1b4b8a84c63c805076a85e5aa00924997a4eae85fddf0aee3ca", 46 | "vrf": "0774e5810fe02a014ec97ef424797172f2b8c5dcfb6e4cfc98b411c31d5096d8" 47 | }, 48 | "581e23030b6038bae716e5d64b9e053db10541b12e6b0b4eff485454": { 49 | "delegate": "b0dca078b823cde627da136200d6618c49ad712b77972a1c5e135763", 50 | "vrf": "16a4e883b72ddbd09a4f8a1170fc346ab11e4202f814faa73e9d2433ee03e7b0" 51 | }, 52 | "e5f27655371b54aed91cc916b2569060978be80056768fee2cc5ce1b": { 53 | "delegate": "b3873a254459f506e47b9a252ee7912e538b364447f31576a170db65", 54 | "vrf": "cc5c897fdf5db0017326656fe35aeb20c72b175540793f9b9b8dc9ade001bbc4" 55 | } 56 | }, 57 | "updateQuorum": 5, 58 | "networkId": "Testnet", 59 | "initialFunds": {}, 60 | "maxLovelaceSupply": 45000000000000000, 61 | "networkMagic": 1097911063, 62 | "epochLength": 432000, 63 | "systemStart": "2019-07-24T20:20:16Z", 64 | "slotsPerKESPeriod": 129600, 65 | "slotLength": 1, 66 | "maxKESEvolutions": 62, 67 | "securityParam": 2160 68 | } 69 | -------------------------------------------------------------------------------- /integration-test/configs/testnet/topology.json: -------------------------------------------------------------------------------- 1 | { 2 | "Producers": [ 3 | { 4 | "addr": "relays-new.cardano-testnet.iohkdev.io", 5 | "port": 3001, 6 | "valency": 2 7 | } 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /integration-test/docker-compose-chang.yml: -------------------------------------------------------------------------------- 1 | version: "3.5" 2 | 3 | networks: 4 | cluster: 5 | ipam: 6 | config: 7 | - subnet: 172.20.0.0/24 8 | 9 | services: 10 | 11 | cardano-node: 12 | image: ghcr.io/intersectmbo/cardano-node:${CARDANO_NODE_VERSION:-10.1.4} 13 | platform: linux/amd64 14 | entrypoint: bash 15 | environment: 16 | NETWORK: "${NETWORK:-local-alonzo}" 17 | CARDANO_NODE_SOCKET_PATH: "/ipc/node.socket" 18 | command: /code/run_node.sh 19 | 20 | networks: 21 | cluster: 22 | ipv4_address: 172.20.0.101 23 | 24 | volumes: 25 | - .:/code 26 | - /tmp:/tmp 27 | - node-db:/data/db 28 | - node-ipc:/ipc 29 | ports: 30 | - ${BFT_NODE_PORT:-3000}:3000 31 | logging: 32 | driver: "json-file" 33 | options: 34 | max-size: "200k" 35 | max-file: "10" 36 | 37 | cardano-pool: 38 | image: ghcr.io/intersectmbo/cardano-node:${CARDANO_NODE_VERSION:-10.1.4} 39 | platform: linux/amd64 40 | entrypoint: bash 41 | environment: 42 | NETWORK: "${NETWORK:-local-alonzo}" 43 | command: /code/run_pool.sh 44 | 45 | networks: 46 | cluster: 47 | ipv4_address: 172.20.0.102 48 | 49 | volumes: 50 | - .:/code 51 | - node-ipc:/ipc 52 | logging: 53 | driver: "json-file" 54 | options: 55 | max-size: "200k" 56 | max-file: "10" 57 | 58 | ogmios: 59 | image: cardanosolutions/ogmios:v6.11.2 60 | platform: linux/amd64 61 | environment: 62 | NETWORK: "${NETWORK:-local-alonzo}" 63 | 64 | command: [ 65 | "--host", "0.0.0.0", 66 | "--node-socket", "/ipc/pool.socket", 67 | "--node-config", "/code/configs/${NETWORK:-local-alonzo}/config.json", 68 | "--log-level-websocket", "Debug" 69 | ] 70 | volumes: 71 | - .:/code 72 | - node-ipc:/ipc 73 | ports: 74 | - ${OGMIOS_PORT:-1337}:1337 75 | logging: 76 | driver: "json-file" 77 | options: 78 | max-size: "200k" 79 | max-file: "10" 80 | 81 | kupo: 82 | image: cardanosolutions/kupo:v2.9.0 83 | platform: linux/amd64 84 | environment: 85 | NETWORK: "${NETWORK:-local}" 86 | 87 | command: [ 88 | "--node-socket", "/ipc/pool.socket", 89 | "--node-config", "/code/configs/${NETWORK:-local-alonzo}/config.json", 90 | "--host", "0.0.0.0", 91 | "--since", "origin", 92 | "--match", "*", 93 | "--in-memory" 94 | ] 95 | volumes: 96 | - .:/code 97 | - node-ipc:/ipc 98 | ports: 99 | - ${KUPO_PORT:-1442}:1442 100 | 101 | volumes: 102 | node-db: 103 | node-ipc: 104 | -------------------------------------------------------------------------------- /integration-test/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.5" 2 | 3 | networks: 4 | cluster: 5 | ipam: 6 | config: 7 | - subnet: 172.20.0.0/24 8 | 9 | services: 10 | 11 | cardano-node: 12 | image: ghcr.io/intersectmbo/cardano-node:${CARDANO_NODE_VERSION:-8.9.2} 13 | platform: linux/amd64 14 | entrypoint: bash 15 | environment: 16 | NETWORK: "${NETWORK:-local-alonzo}" 17 | CARDANO_NODE_SOCKET_PATH: "/ipc/node.socket" 18 | command: /code/run_node.sh 19 | 20 | networks: 21 | cluster: 22 | ipv4_address: 172.20.0.101 23 | 24 | volumes: 25 | - .:/code 26 | - /tmp:/tmp 27 | - node-db:/data/db 28 | - node-ipc:/ipc 29 | ports: 30 | - ${BFT_NODE_PORT:-3000}:3000 31 | logging: 32 | driver: "json-file" 33 | options: 34 | max-size: "200k" 35 | max-file: "10" 36 | 37 | cardano-pool: 38 | image: ghcr.io/intersectmbo/cardano-node:${CARDANO_NODE_VERSION:-8.9.2} 39 | platform: linux/amd64 40 | entrypoint: bash 41 | environment: 42 | NETWORK: "${NETWORK:-local-alonzo}" 43 | command: /code/run_pool.sh 44 | 45 | networks: 46 | cluster: 47 | ipv4_address: 172.20.0.102 48 | 49 | volumes: 50 | - .:/code 51 | - node-ipc:/ipc 52 | logging: 53 | driver: "json-file" 54 | options: 55 | max-size: "200k" 56 | max-file: "10" 57 | 58 | ogmios: 59 | image: cardanosolutions/ogmios:v6.2.0 60 | platform: linux/amd64 61 | environment: 62 | NETWORK: "${NETWORK:-local-alonzo}" 63 | 64 | command: [ 65 | "--host", "0.0.0.0", 66 | "--node-socket", "/ipc/node.socket", 67 | "--node-config", "/code/configs/${NETWORK:-local-alonzo}/config.json" 68 | ] 69 | volumes: 70 | - .:/code 71 | - node-ipc:/ipc 72 | ports: 73 | - ${OGMIOS_PORT:-1337}:1337 74 | logging: 75 | driver: "json-file" 76 | options: 77 | max-size: "200k" 78 | max-file: "10" 79 | 80 | kupo: 81 | image: cardanosolutions/kupo:v2.4.0 82 | platform: linux/amd64 83 | environment: 84 | NETWORK: "${NETWORK:-local}" 85 | 86 | command: [ 87 | "--node-socket", "/ipc/node.socket", 88 | "--node-config", "/code/configs/${NETWORK:-local-alonzo}/config.json", 89 | "--host", "0.0.0.0", 90 | "--since", "origin", 91 | "--match", "*", 92 | "--in-memory" 93 | ] 94 | volumes: 95 | - .:/code 96 | - node-ipc:/ipc 97 | ports: 98 | - ${KUPO_PORT:-1442}:1442 99 | 100 | volumes: 101 | node-db: 102 | node-ipc: 103 | -------------------------------------------------------------------------------- /integration-test/keys/extended.skey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "PaymentExtendedSigningKeyShelley_ed25519_bip32", 3 | "description": "Payment Signing Key", 4 | "cborHex": "5880e8428867ab9cc9304379a3ce0c238a592bd6d2349d2ebaf8a6ed2c6d2974a15ad59c74b6d8fa3edd032c6261a73998b7deafe983b6eeaff8b6fb3fab06bdf8019b693a62bce7a3cad1b9c02d22125767201c65db27484bb67d3cee7df7288d62c099ac0ce4a215355b149fd3114a2a7ef0438f01f8872c4487a61b469e26aae4" 5 | } -------------------------------------------------------------------------------- /integration-test/keys/pool/cold.counter: -------------------------------------------------------------------------------- 1 | { 2 | "type": "NodeOperationalCertificateIssueCounter", 3 | "description": "Next certificate issue number: 0", 4 | "cborHex": "820058202f896875fd81ee621cd8ef450c46a4e3c62a7b68ae0cc7b4372c2b02774cf759" 5 | } -------------------------------------------------------------------------------- /integration-test/keys/pool/cold.skey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "StakePoolSigningKey_ed25519", 3 | "description": "Stake Pool Operator Signing Key", 4 | "cborHex": "58201a516a8fd768f95c919917f4151a82ad62abb2080400f921da4b8808fae42dcf" 5 | } -------------------------------------------------------------------------------- /integration-test/keys/pool/cold.vkey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "StakePoolVerificationKey_ed25519", 3 | "description": "Stake Pool Operator Verification Key", 4 | "cborHex": "58202f896875fd81ee621cd8ef450c46a4e3c62a7b68ae0cc7b4372c2b02774cf759" 5 | } -------------------------------------------------------------------------------- /integration-test/keys/pool/delegation.cert: -------------------------------------------------------------------------------- 1 | { 2 | "type": "CertificateShelley", 3 | "description": "Stake Address Delegation Certificate", 4 | "cborHex": "83028200581c4828a2dadba97ca9fd0cdc99975899470c219bdc0d828cfa6ddf6d69581cc2105401f5b4e8dfcc3b04f7a2722f72a8f6c4b1c00f9b5b8f46dd5e" 5 | } -------------------------------------------------------------------------------- /integration-test/keys/pool/full.addr: -------------------------------------------------------------------------------- 1 | addr_test1qrxrqjtlfluk9axpmjj5enh0uw0cduwhz7txsqyl36m3uk2g9z3d4kaf0j5l6rxunxt43x28pssehhqds2x05mwld45sjncs0p -------------------------------------------------------------------------------- /integration-test/keys/pool/kes.skey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "KesSigningKey_ed25519_kes_2^6", 3 | "description": "KES Signing Key", 4 | "cborHex": "590260ae3a6ac34fa31150694cf978c7c7992cdc9a2f6612c6dbbab17fde0b9b6747fe77544ca65d14673aab1519b8dc3795ed045cc05cf7bae957dd953f0595b17325d98db714af3b0e77649b98080d33d0c9582294422df18cd435e25c81ab020b99b9bef7f3cc39146b52dd35177a2fa533c005e0f851939a393d4e90ba568e30669033171c4a5e4f1626a95118c3108e41ed778664ac2a36e34e4dfac8c0a9b0d675bd99fa5cd4e2d975e0661fa0ce28615b13ca128110dbc46a37e4d28baae5940fbe4496b3d8317d6d01a7ed2a692b663f0c8fef0823f423a3537135482cc3cdd8647601f5f39281079373ac4710bf38c3af728b64692bcb3d78d9ca3d607f91580f45c30a0fa5d081ef050a28988317f3e1260a55cdc4835b96d011754a2188246848a1df4fe26541e23424c7639a32c452146457270d577e235fd211205a5f890ef53011f3f30bbab61e78b9068eec18b95c72a0f5a527bcae61cfd34ae61b6be0e6ba90427b4e29df1236f969d2d60aff95d656b82577ba1131fd145809120f6e6e82ea90ed4d02fdd8eaa51a12746a9b42df785672e2ff79508544dbeb510735b068d18f3ab46c6e4a916f63b082625cceaa8c18d1cd26d73579e1b58f1f6e3102daa31fd047dbd43140f4bda388193a8a1dcab0b5b5dfb2562b9e6d0e8ae179c487f223fed1d0a50c322d679b3e44166b0167bdd33c57a823373eba958696b78066fb898ac70bb67d9ec8f10df1c6b50c4ce2dc3764971547cbabe4d9ca6e10313d25fe5355cafcc26e480d184ee29d400a9c6cbaed36e89cf8f76a0bb0af734e3922d9bc9abb640df7b2c20aa8d9e7c622b259fec177b64ea8b533ef1e" 5 | } -------------------------------------------------------------------------------- /integration-test/keys/pool/kes.vkey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "KesVerificationKey_ed25519_kes_2^6", 3 | "description": "KES Verification Key", 4 | "cborHex": "5820c73ee7d0502bdd3cbc24c76a75404727d8e85e17ca771a70c5464ba7b9702055" 5 | } -------------------------------------------------------------------------------- /integration-test/keys/pool/node.cert: -------------------------------------------------------------------------------- 1 | { 2 | "type": "NodeOperationalCertificate", 3 | "description": "", 4 | "cborHex": "82845820c73ee7d0502bdd3cbc24c76a75404727d8e85e17ca771a70c5464ba7b97020550000584077cb7194ab7ab34bb07e3a0e8405891b71c388c8c300984e41f0ae47f4555613c76d1682d3a4e85a71ba3d2b17a6401e4fc604b0c567907d8ebd7195aff4040558202f896875fd81ee621cd8ef450c46a4e3c62a7b68ae0cc7b4372c2b02774cf759" 5 | } -------------------------------------------------------------------------------- /integration-test/keys/pool/payment.addr: -------------------------------------------------------------------------------- 1 | addr_test1vrxrqjtlfluk9axpmjj5enh0uw0cduwhz7txsqyl36m3ukgm9y0gt -------------------------------------------------------------------------------- /integration-test/keys/pool/payment.skey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "PaymentSigningKeyShelley_ed25519", 3 | "description": "Payment Signing Key", 4 | "cborHex": "58204d9fc18b873d0cd70b614462418ac719d9ca12d0bfcdf7edac2a44fb385d26d8" 5 | } -------------------------------------------------------------------------------- /integration-test/keys/pool/payment.vkey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "PaymentVerificationKeyShelley_ed25519", 3 | "description": "Payment Verification Key", 4 | "cborHex": "58205797dc2cc919dfec0bb849551ebdf30d96e5cbe0f33f734a87fe826db30f7ef9" 5 | } -------------------------------------------------------------------------------- /integration-test/keys/pool/pool-registration.cert: -------------------------------------------------------------------------------- 1 | { 2 | "type": "CertificateShelley", 3 | "description": "Stake Pool Registration Certificate", 4 | "cborHex": "8a03581cc2105401f5b4e8dfcc3b04f7a2722f72a8f6c4b1c00f9b5b8f46dd5e5820d5daee7ab045f90495107b9997b677cf3b469d0f42fcf8528a80510a7d1c270b00190154d81e820001581de04828a2dadba97ca9fd0cdc99975899470c219bdc0d828cfa6ddf6d6981581c4828a2dadba97ca9fd0cdc99975899470c219bdc0d828cfa6ddf6d69818400190bb84400000000f682782768747470733a2f2f746573747374616b65706f6f6c2e636f6d2f6d657461646174612e6a736f6e5820c5c38833176e2d575bd8693e206e3af2e1088e556def86cae9f6c2fc45579f36" 5 | } -------------------------------------------------------------------------------- /integration-test/keys/pool/pool.id: -------------------------------------------------------------------------------- 1 | c2105401f5b4e8dfcc3b04f7a2722f72a8f6c4b1c00f9b5b8f46dd5e -------------------------------------------------------------------------------- /integration-test/keys/pool/pool_registration_tx.signed: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Witnessed Tx AlonzoEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "84a50081825820732bfd67e66be8e8288349fcaaa2294973ef6271cc189a239bb431275401b8e500018282583900cc30497f4ff962f4c1dca54cceefe39f86f1d7179668009f8eb71e594828a2dadba97ca9fd0cdc99975899470c219bdc0d828cfa6ddf6d691b00000068c617140082581d60d413c1745d306023e49589e658a7b7a4b4dda165ff5c97d8c8b979bf1b00000068c5f572f7021a00031c89031b00005af3107a4000048382008200581c4828a2dadba97ca9fd0cdc99975899470c219bdc0d828cfa6ddf6d698a03581cc2105401f5b4e8dfcc3b04f7a2722f72a8f6c4b1c00f9b5b8f46dd5e5820d5daee7ab045f90495107b9997b677cf3b469d0f42fcf8528a80510a7d1c270b00190154d81e820001581de04828a2dadba97ca9fd0cdc99975899470c219bdc0d828cfa6ddf6d6981581c4828a2dadba97ca9fd0cdc99975899470c219bdc0d828cfa6ddf6d69818400190bb84400000000f682782768747470733a2f2f746573747374616b65706f6f6c2e636f6d2f6d657461646174612e6a736f6e5820c5c38833176e2d575bd8693e206e3af2e1088e556def86cae9f6c2fc45579f3683028200581c4828a2dadba97ca9fd0cdc99975899470c219bdc0d828cfa6ddf6d69581cc2105401f5b4e8dfcc3b04f7a2722f72a8f6c4b1c00f9b5b8f46dd5ea100838258205edaa384c658c2bd8945ae389edac0a5bd452d0cfd5d1245e3ecd540030d1e3c5840109f3ca65a4173c986e0841f454e49805cda9f091a90e57203307fffadb0f9ed6237c81411cdf25a1122d4ffb16579cf70be41de49305529a03c62e1929e9a028258202f896875fd81ee621cd8ef450c46a4e3c62a7b68ae0cc7b4372c2b02774cf7595840fca096a9180245137d6194e7294c20c31800d397fa1ea5d731224dcf19280c0ea9c1fbab4942b11d00ac1d969fcf64ca417c270a5ae033d19f241c772cf6830e8258208be8339e9f3addfa6810d59e2f072f85e64d4c024c087e0d24f8317c6544f62f58406f9b7ea9bef5613d4dd7bc553daec40a0a2865a29885475d16558a554c565a6f2f8518bc65f6ddb1501aa9f35273956a6749c68bacee7082b6ae18bbf95d8305f5f6" 5 | } -------------------------------------------------------------------------------- /integration-test/keys/pool/stake.addr: -------------------------------------------------------------------------------- 1 | stake_test1upyz3gk6mw5he20apnwfn96cn9rscgvmmsxc9r86dh0k66gswf59n -------------------------------------------------------------------------------- /integration-test/keys/pool/stake.cert: -------------------------------------------------------------------------------- 1 | { 2 | "type": "CertificateShelley", 3 | "description": "Stake Address Registration Certificate", 4 | "cborHex": "82008200581c4828a2dadba97ca9fd0cdc99975899470c219bdc0d828cfa6ddf6d69" 5 | } -------------------------------------------------------------------------------- /integration-test/keys/pool/stake.skey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "StakeSigningKeyShelley_ed25519", 3 | "description": "Stake Signing Key", 4 | "cborHex": "5820ff3a330df8859e4e5f42a97fcaee73f6a00d0cf864f4bca902bd106d423f02c0" 5 | } -------------------------------------------------------------------------------- /integration-test/keys/pool/stake.vkey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "StakeVerificationKeyShelley_ed25519", 3 | "description": "Stake Verification Key", 4 | "cborHex": "58205edaa384c658c2bd8945ae389edac0a5bd452d0cfd5d1245e3ecd540030d1e3c" 5 | } -------------------------------------------------------------------------------- /integration-test/keys/pool/topology.json: -------------------------------------------------------------------------------- 1 | { 2 | "Producers": [ 3 | { 4 | "addr": "172.20.0.101", 5 | "port": 3000, 6 | "valency": 1 7 | } 8 | ] 9 | } -------------------------------------------------------------------------------- /integration-test/keys/pool/vrf.skey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "VrfSigningKey_PraosVRF", 3 | "description": "VRF Signing Key", 4 | "cborHex": "58407ccc63cc09619432b2f7e8958bc6da897df5802220ad5a12e85b2d744c74d08e7153171ad1b55f6fcf36e747fe30a9f061d27cf46e24b9033be11448e1631e78" 5 | } -------------------------------------------------------------------------------- /integration-test/keys/pool/vrf.vkey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "VrfVerificationKey_PraosVRF", 3 | "description": "VRF Verification Key", 4 | "cborHex": "58207153171ad1b55f6fcf36e747fe30a9f061d27cf46e24b9033be11448e1631e78" 5 | } -------------------------------------------------------------------------------- /integration-test/plutus_scripts/always_succeeds.plutus: -------------------------------------------------------------------------------- 1 | 49480100002221200101 -------------------------------------------------------------------------------- /integration-test/plutus_scripts/fortytwo.plutus: -------------------------------------------------------------------------------- 1 | 59082459082101000033232332233223232333222323332223233333333222222223233322232333322223232332232333222323332223232332233223232333332222233223322332233223322332222223232533530313330063333573466e1cd55ce9baa0054800081248c98d4c120cd5ce0260248238231bad0043333573466e1cd55cea8012400046601264646464646464646464646666ae68cdc39aab9d500a480008cccccccccc05ccd40948c8c8cccd5cd19b8735573aa004900011980e981c1aba15002302a357426ae8940088c98d4c160cd5ce02e02c82b82b09aab9e5001137540026ae854028cd4094098d5d0a804999aa8163ae502b35742a010666aa058eb940acd5d0a80399a8128209aba15006335025335505204a75a6ae854014c8c8c8cccd5cd19b8735573aa0049000119a80f9919191999ab9a3370e6aae7540092000233502733504075a6ae854008c114d5d09aba25002232635305c3357380c00ba0b60b426aae7940044dd50009aba150023232323333573466e1cd55cea80124000466a04a66a080eb4d5d0a80118229aba135744a004464c6a60b866ae7018017416c1684d55cf280089baa001357426ae8940088c98d4c160cd5ce02e02c82b82b09aab9e5001137540026ae854010cd4095d71aba15003335025335505275c40026ae854008c0dcd5d09aba2500223263530543357380b00aa0a60a426ae8940044d5d1280089aba25001135744a00226ae8940044d5d1280089aba25001135744a00226aae7940044dd50009aba150023232323333573466e1d400520062301c3039357426aae79400c8cccd5cd19b875002480108c06cc10cd5d09aab9e500423333573466e1d400d20022301b302e357426aae7940148cccd5cd19b875004480008c078dd71aba135573ca00c464c6a609e66ae7014c14013813413012c1284d55cea80089baa001357426ae8940088c98d4c120cd5ce026024823823082409931a982399ab9c49010350543500048046135573ca00226ea80048848cc00400c0088004888888888848cccccccccc00402c02802402001c01801401000c00880048848cc00400c008800448848cc00400c0084800448848cc00400c0084800448848cc00400c00848004848888c010014848888c00c014848888c008014848888c004014800448c88c008dd6000990009aa81a911999aab9f0012500e233500d30043574200460066ae880080cc8c8c8c8cccd5cd19b8735573aa006900011998039919191999ab9a3370e6aae754009200023300d303135742a00466a02605a6ae84d5d1280111931a981b99ab9c03b038036035135573ca00226ea8004d5d0a801999aa805bae500a35742a00466a01eeb8d5d09aba25002232635303333573806e06806406226ae8940044d55cf280089baa00122212333001004003002200122123300100300220011335500175ceb44488c88c008dd5800990009aa81791191999aab9f0022500923350083355031300635573aa004600a6aae794008c010d5d100181709aba10011122002122122330010040031200112232323333573466e1d400520002350083005357426aae79400c8cccd5cd19b87500248008940208c98d4c0a8cd5ce01701581481401389aab9d500113754002242446004006224400224002464646666ae68cdc39aab9d5002480008cc018c01cd5d0a8011bad357426ae8940088c98d4c090cd5ce01401281181109aab9e50011375400244246600200600440024646666ae68cdc39aab9d5001480008dd71aba135573ca004464c6a604066ae7009008407c0784dd500089119191999ab9a3370ea00290021280391999ab9a3370ea004900111a80518031aba135573ca00846666ae68cdc3a801a40004a014464c6a604666ae7009c09008808408007c4d55cea80089baa00112122230030041122200211222001120012323333573466e1d40052002200623333573466e1d400920002006232635301b33573803e03803403203026aae74dd50008910010910009000919191919191999ab9a3370ea0029006100591999ab9a3370ea0049005100691999ab9a3370ea00690041198059bae35742a00a6eb4d5d09aba2500523333573466e1d4011200623300d375c6ae85401cdd71aba135744a00e46666ae68cdc3a802a400846602460286ae854024dd71aba135744a01246666ae68cdc3a8032400446028602a6ae84d55cf280591999ab9a3370ea00e900011809980b1aba135573ca018464c6a604066ae7009008407c07807407006c0680640604d55cea80209aab9e5003135573ca00426aae7940044dd500090911111118038041109111111198030048041091111111802804091111110020911111100191091111111980100480411091111111980080480410009191919191999ab9a3370ea002900111998041bad35742a0086eb4d5d0a8019bad357426ae89400c8cccd5cd19b875002480008c028c02cd5d09aab9e5006232635301133573802a02402001e01c26aae75400c4d5d1280089aab9e5001137540024244600400644424466600200a0080064002464646666ae68cdc3a800a40044600c6eb8d5d09aab9e500323333573466e1d4009200023008375c6ae84d55cf280211931a980599ab9c00f00c00a009008135573aa00226ea80048488c00800c8488c00400c800444888c8c8cccd5cd19b8735573aa0049000119aa80598031aba150023005357426ae8940088c98d4c020cd5ce00600480380309aab9e5001137540029309000900088910919800801801089000a4903505431001123230010012233003300200200133322222253353004333573466e1c00920540060051006133573892010e77726f6e672072656465656d65720000512200212200120011 -------------------------------------------------------------------------------- /integration-test/plutus_scripts/fortytwoV2.plutus: -------------------------------------------------------------------------------- 1 | 58775875010000323232322225335323253350021001100933320015007003332001500648150ccc8005401800ccc8005401520541004132632498cd5ce2491d496e636f727265637420646174756d2e2045787065637465642034322e0000412001123750002244666ae68cdd780100089100100189100081 -------------------------------------------------------------------------------- /integration-test/plutus_scripts/helloworldV3.plutus: -------------------------------------------------------------------------------- 1 | 59011d0100003232323232323225333002323232323253330073370e900118041baa0011323232533300a3370e900018059baa005132533300e0011613253333330120011616161613253330103012003132533300e3370e900018079baa005132533300f002100114a06644646600200200644a66602a00229404c94ccc04ccdc79bae301700200414a2266006006002602e0026eb0c048c04cc04cc04cc04cc04cc04cc04cc04cc040dd50059bae301230103754602460206ea801458cdc79bae3011300f375401091010d48656c6c6f2c20576f726c64210016375c002601e00260186ea801458c034c038008c030004c024dd50008b1805180580118048009804801180380098021baa00114984d9595cd2ab9d5573caae7d5d0aba25749 -------------------------------------------------------------------------------- /integration-test/plutus_scripts/pass_certifying_and_rewarding.plutus: -------------------------------------------------------------------------------- 1 | 5901e9010000323232323232323232323232322232323232323232323232323374a90001bb1498c8c8ccccd400c01001401840084004030030488888c8c8c94ccd5cd19180d88009980c180aa8012400c2930992999ab9a32301c100133019301650034801052615333573464603820029404c00452613263357389201136e6f7420612076616c696420707572706f7365004988c00852624984004c0454004405840584c98cd5ce2481104e616d654572726f723a207e626f6f6c004984c98cd5ce2481144e616d654572726f723a2076616c696461746f72004984c98cd5ce2481124e616d654572726f723a20707572706f7365004984c98cd5ce2481104e616d654572726f723a20646174756d004984c98cd5ce2481124e616d654572726f723a20636f6e74657874004984c98cd5ce2481144e616d654572726f723a20526577617264696e67004984c98cd5ce2481154e616d654572726f723a2043657274696679696e67004980080088c010c0200048c0140040108c018c94ccd55cf800899319ab9c49010a496e6465784572726f72004984d5d1000800919000a80091aab9d3754002e1c8d55cf1baa00123253335573e002264c66ae712410a496e6465784572726f72004984d5d0800800919ba548018cd5d028009bb14988cdd2a400866ae814004dd8a4c1 -------------------------------------------------------------------------------- /integration-test/plutus_scripts/unroll.plutus: -------------------------------------------------------------------------------- 1 | 58a20100003232232323232323374a90001bb1498c8d4008400401448c8c92610013330063758a00246eb400452f580264c66ae712410c4e616d654572726f723a207a004984c98cd5ce2481144e616d654572726f723a2076616c696461746f72004984c98cd5ce24810d4e616d654572726f723a20723300498888cc8c014894ccd55cf8008a802099aba0300335742002660040046ae8800400800c8c8c0040040041 -------------------------------------------------------------------------------- /integration-test/run_node.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$NETWORK" = "local-alonzo" ] || [ "$NETWORK" = "local-vasil" ] || [ "$NETWORK" = "local-chang" ] 4 | then 5 | chmod 400 /code/tmp_configs/"$NETWORK"/shelley/*.skey 6 | chmod 400 /code/tmp_configs/"$NETWORK"/shelley/*.vkey 7 | cardano-node run \ 8 | --config /code/tmp_configs/"$NETWORK"/config.json \ 9 | --topology /code/tmp_configs/"$NETWORK"/topology.json \ 10 | --database-path /data/db --socket-path /ipc/node.socket \ 11 | --shelley-kes-key /code/tmp_configs/"$NETWORK"/shelley/kes.skey \ 12 | --shelley-vrf-key /code/tmp_configs/"$NETWORK"/shelley/vrf.skey \ 13 | --shelley-operational-certificate /code/tmp_configs/"$NETWORK"/shelley/node.cert \ 14 | --host-addr 0.0.0.0 \ 15 | --port 3000 16 | else 17 | cardano-node run \ 18 | --config /code/tmp_configs/"$NETWORK"/config.json \ 19 | --topology /code/tmp_configs/"$NETWORK"/topology.json \ 20 | --database-path /data/db --socket-path /ipc/node.socket 21 | fi -------------------------------------------------------------------------------- /integration-test/run_pool.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "$NETWORK" 4 | if [ "$NETWORK" = "local-alonzo" ] || [ "$NETWORK" = "local-vasil" ] || [ "$NETWORK" = "local-chang" ] 5 | then 6 | 7 | # Waiting for BFT node to be ready 8 | while [ ! -S /ipc/node.socket ] 9 | do 10 | sleep 0.1 11 | done 12 | 13 | sleep 5 14 | 15 | export CARDANO_NODE_SOCKET_PATH=/ipc/node.socket 16 | 17 | cardano-cli alonzo transaction submit \ 18 | --tx-file /code/keys/pool/pool_registration_tx.signed \ 19 | --testnet-magic 42 20 | 21 | mkdir -p /data/db 22 | chmod 400 /code/keys/pool/*.skey 23 | chmod 400 /code/keys/pool/*.vkey 24 | 25 | # Start pool node 26 | cardano-node run \ 27 | --config /code/tmp_configs/"$NETWORK"/config.json \ 28 | --topology /code/keys/pool/topology.json \ 29 | --database-path /data/db \ 30 | --socket-path /ipc/pool.socket \ 31 | --shelley-kes-key /code/keys/pool/kes.skey \ 32 | --shelley-vrf-key /code/keys/pool/vrf.skey \ 33 | --shelley-operational-certificate /code/keys/pool/node.cert \ 34 | --host-addr 0.0.0.0 \ 35 | --port 3000 36 | fi -------------------------------------------------------------------------------- /integration-test/run_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | ROOT=$(pwd) 7 | 8 | poetry install -C .. 9 | make ensure-pure-cbor2 -f ../Makefile 10 | #poetry run pip install ogmios 11 | 12 | ########## 13 | # Alonzo # 14 | ########## 15 | # 16 | ## Cleanup containers and volumes in case there is any running 17 | #docker-compose down --volumes --remove-orphans 18 | # 19 | ## Run alonzo integration tests 20 | #./bootstrap.sh local-alonzo 21 | # 22 | ## Launch containers 23 | #docker-compose up -d 24 | # 25 | #export PAYMENT_KEY="$ROOT"/configs/local-alonzo/shelley/utxo-keys/utxo1.skey 26 | #export EXTENDED_PAYMENT_KEY="$ROOT"/keys/extended.skey 27 | #export POOL_ID=$(cat "$ROOT"/keys/pool/pool.id) 28 | # 29 | ## Wait for stake pool to start producing blocks 30 | #sleep 10 31 | # 32 | ## Cleanup 33 | #docker-compose down --volumes --remove-orphans 34 | # 35 | ########## 36 | ## Vasil # 37 | ########## 38 | # 39 | ## Cleanup containers and volumes in case there is any running 40 | #docker-compose down --volumes --remove-orphans 41 | # 42 | ## Run integration tests 43 | #./bootstrap.sh local-vasil 44 | # 45 | ## Launch containers 46 | #docker-compose up -d 47 | # 48 | #export PAYMENT_KEY="$ROOT"/configs/local-vasil/shelley/utxo-keys/utxo1.skey 49 | #export EXTENDED_PAYMENT_KEY="$ROOT"/keys/extended.skey 50 | #export POOL_ID=$(cat "$ROOT"/keys/pool/pool.id) 51 | # 52 | ## Wait for stake pool to start producing blocks 53 | #sleep 30 54 | # 55 | #poetry run pytest -s -vv -n 4 "$ROOT"/test 56 | # 57 | ## Cleanup 58 | #docker-compose down --volumes --remove-orphans 59 | 60 | 61 | ######### 62 | # Chang # 63 | ######### 64 | 65 | # Cleanup containers and volumes in case there is any running 66 | docker compose -f docker-compose-chang.yml down --volumes --remove-orphans 67 | 68 | # Run integration tests 69 | ./bootstrap.sh local-chang 70 | 71 | # Launch containers 72 | docker compose -f docker-compose-chang.yml up -d 73 | 74 | export PAYMENT_KEY="$ROOT"/configs/local-chang/shelley/utxo-keys/utxo1.skey 75 | export EXTENDED_PAYMENT_KEY="$ROOT"/keys/extended.skey 76 | export POOL_COLD_KEY="$ROOT"/keys/pool/cold.skey 77 | export POOL_PAYMENT_KEY="$ROOT"/keys/pool/payment.skey 78 | export POOL_STAKE_KEY="$ROOT"/keys/pool/stake.skey 79 | export POOL_ID=$(cat "$ROOT"/keys/pool/pool.id) 80 | 81 | sleep 10 82 | 83 | while true; do 84 | response=$(curl -s -H 'Accept: application/json' http://localhost:1337/health) 85 | current_era=$(echo "$response" | jq -r '.currentEra') 86 | 87 | if [ "$current_era" == "conway" ]; then 88 | echo "Ogmios is ready! Current era: $current_era" 89 | break 90 | fi 91 | 92 | echo -n "." 93 | sleep 2 94 | done 95 | 96 | poetry run pytest -m "not (CardanoCLI)" -s -vv "$ROOT"/test --cov=pycardano --cov-config=../.coveragerc --cov-report=xml:../coverage.xml 97 | 98 | # Cleanup 99 | docker compose -f docker-compose-chang.yml down --volumes --remove-orphans -------------------------------------------------------------------------------- /integration-test/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Python-Cardano/pycardano/7d63d0e1da1b0e64cd2b9d389ed4f9e2e5c076ae/integration-test/test/__init__.py -------------------------------------------------------------------------------- /integration-test/test/base.py: -------------------------------------------------------------------------------- 1 | """An example that demonstrates low-level construction of a transaction.""" 2 | 3 | import os 4 | import time 5 | 6 | import ogmios as python_ogmios 7 | from retry import retry 8 | 9 | from pycardano import * 10 | 11 | TEST_RETRIES = 8 12 | 13 | 14 | @retry(tries=10, delay=4) 15 | def check_chain_context(chain_context): 16 | print(f"Current chain tip: {chain_context.last_block_slot}") 17 | 18 | 19 | class TestBase: 20 | # Define chain context 21 | NETWORK = Network.TESTNET 22 | 23 | # TODO: Bring back kupo test 24 | KUPO_URL = "http://localhost:1442" 25 | 26 | chain_context = OgmiosV6ChainContext( 27 | host="localhost", 28 | port=1337, 29 | network=Network.TESTNET, 30 | refetch_chain_tip_interval=1, 31 | ) 32 | 33 | check_chain_context(chain_context) 34 | 35 | payment_key_path = os.environ.get("PAYMENT_KEY") 36 | extended_key_path = os.environ.get("EXTENDED_PAYMENT_KEY") 37 | pool_cold_key_path = os.environ.get("POOL_COLD_KEY") 38 | pool_payment_key_path = os.environ.get("POOL_PAYMENT_KEY") 39 | pool_stake_key_path = os.environ.get("POOL_STAKE_KEY") 40 | if not payment_key_path or not extended_key_path: 41 | raise Exception( 42 | "Cannot find payment key. Please specify environment variable PAYMENT_KEY and extended_key_path" 43 | ) 44 | payment_skey = PaymentSigningKey.load(payment_key_path) 45 | payment_vkey = PaymentVerificationKey.from_signing_key(payment_skey) 46 | extended_payment_skey = PaymentExtendedSigningKey.load(extended_key_path) 47 | extended_payment_vkey = PaymentExtendedVerificationKey.from_signing_key( 48 | extended_payment_skey 49 | ) 50 | pool_cold_skey = PaymentSigningKey.load(pool_cold_key_path) 51 | pool_cold_vkey = PaymentVerificationKey.from_signing_key(pool_cold_skey) 52 | pool_payment_skey = PaymentSigningKey.load(pool_payment_key_path) 53 | pool_payment_vkey = PaymentVerificationKey.from_signing_key(pool_payment_skey) 54 | pool_stake_skey = StakeSigningKey.load(pool_stake_key_path) 55 | pool_stake_vkey = StakeVerificationKey.from_signing_key(pool_stake_skey) 56 | 57 | payment_key_pair = PaymentKeyPair.generate() 58 | stake_key_pair = StakeKeyPair.generate() 59 | 60 | @retry(tries=10, delay=3) 61 | def assert_output(self, target_address, target): 62 | utxos = self.chain_context.utxos(target_address) 63 | found = False 64 | 65 | for utxo in utxos: 66 | if isinstance(target, UTxO): 67 | if utxo == target: 68 | found = True 69 | if isinstance(target, TransactionOutput): 70 | if utxo.output == target: 71 | found = True 72 | if isinstance(target, TransactionId): 73 | if utxo.input.transaction_id == target: 74 | found = True 75 | 76 | assert found, f"Cannot find target UTxO in address: {target_address}" 77 | 78 | @retry(tries=TEST_RETRIES, delay=6, backoff=2, jitter=(1, 3)) 79 | def fund(self, source_address, source_key, target_address, amount=5000000): 80 | builder = TransactionBuilder(self.chain_context) 81 | 82 | builder.add_input_address(source_address) 83 | output = TransactionOutput(target_address, amount) 84 | builder.add_output(output) 85 | 86 | signed_tx = builder.build_and_sign([source_key], source_address) 87 | 88 | print("############### Transaction created ###############") 89 | print(signed_tx) 90 | print(signed_tx.to_cbor_hex()) 91 | print("############### Submitting transaction ###############") 92 | self.chain_context.submit_tx(signed_tx) 93 | target_utxo = UTxO(TransactionInput(signed_tx.id, 0), output) 94 | self.assert_output(target_address, target_utxo) 95 | -------------------------------------------------------------------------------- /integration-test/test/test_cardano_cli.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pathlib import Path 3 | 4 | import pytest 5 | from retry import retry 6 | 7 | from pycardano import ( 8 | CardanoCliChainContext, 9 | CardanoCliNetwork, 10 | GenesisParameters, 11 | Network, 12 | ProtocolParameters, 13 | ) 14 | from pycardano.backend.cardano_cli import DockerConfig 15 | 16 | from .base import TEST_RETRIES 17 | 18 | 19 | @pytest.mark.CardanoCLI 20 | class TestCardanoCli: 21 | network_env = os.getenv("NETWORK", "local-alonzo") 22 | host_socket = os.getenv("DOCKER_HOST", None) 23 | network_magic = os.getenv("NETWORK_MAGIC", 42) 24 | 25 | configs_dir = Path(__file__).parent.parent / "configs" 26 | 27 | chain_context = CardanoCliChainContext( 28 | binary=Path("cardano-cli"), 29 | socket=Path("/ipc/node.socket"), 30 | config_file=configs_dir / network_env / "config.json", 31 | network=CardanoCliNetwork.CUSTOM, 32 | docker_config=DockerConfig( 33 | container_name="integration-test_cardano-node_1", 34 | host_socket=Path(host_socket) if host_socket else None, 35 | ), 36 | network_magic_number=int(network_magic), 37 | ) 38 | 39 | @retry(tries=TEST_RETRIES, backoff=1.3, delay=2, jitter=(0, 10)) 40 | def test_protocol_param(self): 41 | protocol_param = self.chain_context.protocol_param 42 | 43 | assert protocol_param is not None 44 | assert isinstance(protocol_param, ProtocolParameters) 45 | assert protocol_param.coins_per_utxo_byte is not None 46 | 47 | cost_models = protocol_param.cost_models 48 | for cost_model in cost_models.items(): 49 | assert len(cost_model) > 0 50 | 51 | def test_genesis_param(self): 52 | genesis_param = self.chain_context.genesis_param 53 | 54 | assert genesis_param is not None 55 | assert isinstance(genesis_param, GenesisParameters) 56 | 57 | def test_network(self): 58 | network = self.chain_context.network 59 | 60 | assert network is not None 61 | assert isinstance(network, Network) 62 | 63 | def test_epoch(self): 64 | epoch = self.chain_context.epoch 65 | 66 | assert epoch is not None 67 | assert isinstance(epoch, int) 68 | assert epoch > 0 69 | 70 | def test_last_block_slot(self): 71 | last_block_slot = self.chain_context.last_block_slot 72 | 73 | assert isinstance(last_block_slot, int) 74 | assert last_block_slot > 0 75 | -------------------------------------------------------------------------------- /integration-test/test/test_certificate_script.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | 4 | import cbor2 5 | from retry import retry 6 | 7 | from pycardano import * 8 | 9 | from .base import TEST_RETRIES, TestBase 10 | 11 | 12 | class TestDelegation(TestBase): 13 | @retry(tries=TEST_RETRIES, backoff=1.3, delay=2, jitter=(0, 10)) 14 | def test_stake_delegation(self): 15 | with open("./plutus_scripts/pass_certifying_and_rewarding.plutus", "r") as f: 16 | script_hex = f.read() 17 | stake_script = PlutusV2Script(bytes.fromhex(script_hex)) 18 | cert_script_hash = plutus_script_hash(stake_script) 19 | address = Address( 20 | self.payment_key_pair.verification_key.hash(), 21 | cert_script_hash, 22 | self.NETWORK, 23 | ) 24 | 25 | utxos = self.chain_context.utxos(address) 26 | 27 | if not utxos: 28 | giver_address = Address(self.payment_vkey.hash(), network=self.NETWORK) 29 | 30 | builder = TransactionBuilder(self.chain_context) 31 | 32 | builder.add_input_address(giver_address) 33 | builder.add_output(TransactionOutput(address, 44000000000)) 34 | 35 | signed_tx = builder.build_and_sign([self.payment_skey], giver_address) 36 | 37 | print("############### Transaction created ###############") 38 | print(signed_tx) 39 | print(signed_tx.to_cbor_hex()) 40 | print("############### Submitting transaction ###############") 41 | self.chain_context.submit_tx(signed_tx) 42 | 43 | time.sleep(3) 44 | 45 | stake_credential = StakeCredential(cert_script_hash) 46 | stake_registration = StakeRegistration(stake_credential) 47 | pool_hash = PoolKeyHash(bytes.fromhex(os.environ.get("POOL_ID").strip())) 48 | stake_delegation = StakeDelegation(stake_credential, pool_keyhash=pool_hash) 49 | 50 | builder = TransactionBuilder(self.chain_context) 51 | 52 | builder.add_input_address(address) 53 | builder.add_output(TransactionOutput(address, 35000000)) 54 | builder.certificates = [stake_registration, stake_delegation] 55 | redeemer = Redeemer(0) 56 | builder.add_certificate_script(stake_script, redeemer=redeemer) 57 | 58 | signed_tx = builder.build_and_sign( 59 | [self.payment_key_pair.signing_key], 60 | address, 61 | ) 62 | 63 | print("############### Transaction created ###############") 64 | print(signed_tx) 65 | print(signed_tx.to_cbor_hex()) 66 | print("############### Submitting transaction ###############") 67 | self.chain_context.submit_tx(signed_tx) 68 | 69 | 70 | # time.sleep(8) 71 | # 72 | # builder = TransactionBuilder(self.chain_context) 73 | # 74 | # builder.add_input_address(address) 75 | # 76 | # stake_address = Address( 77 | # staking_part=cert_script_hash, 78 | # network=self.NETWORK, 79 | # ) 80 | # 81 | # builder.withdrawals = Withdrawals({bytes(stake_address): 0}) 82 | # 83 | # builder.add_output(TransactionOutput(address, 1000000)) 84 | # redeemer = Redeemer(0) 85 | # builder.add_withdrawal_script(stake_script, redeemer=redeemer) 86 | # 87 | # signed_tx = builder.build_and_sign( 88 | # [self.payment_key_pair.signing_key], 89 | # address, 90 | # ) 91 | # 92 | # print("############### Transaction created ###############") 93 | # print(signed_tx) 94 | # print(signed_tx.to_cbor_hex()) 95 | # print("############### Submitting transaction ###############") 96 | # self.chain_context.submit_tx(signed_tx) 97 | # 98 | -------------------------------------------------------------------------------- /integration-test/test/test_min_utxo.py: -------------------------------------------------------------------------------- 1 | import pathlib 2 | import tempfile 3 | from dataclasses import dataclass 4 | 5 | import cbor2 6 | import pytest 7 | from retry import retry 8 | 9 | from pycardano import * 10 | 11 | from .base import TEST_RETRIES, TestBase 12 | 13 | 14 | class TestMint(TestBase): 15 | @retry(tries=TEST_RETRIES, backoff=1.3, delay=2, jitter=(0, 10)) 16 | @pytest.mark.post_alonzo 17 | def test_min_utxo(self): 18 | address = Address(self.payment_vkey.hash(), network=self.NETWORK) 19 | 20 | with open("./plutus_scripts/always_succeeds.plutus", "r") as f: 21 | script_hex = f.read() 22 | anymint_script = PlutusV1Script(cbor2.loads(bytes.fromhex(script_hex))) 23 | 24 | policy_id = plutus_script_hash(anymint_script) 25 | 26 | my_nft = MultiAsset.from_primitive( 27 | { 28 | policy_id.payload: { 29 | b"MY_SCRIPT_NFT_1": 1, # Name of our NFT1 # Quantity of this NFT 30 | b"MY_SCRIPT_NFT_2": 1, # Name of our NFT2 # Quantity of this NFT 31 | } 32 | } 33 | ) 34 | 35 | metadata = { 36 | 721: { 37 | policy_id.payload.hex(): { 38 | "MY_SCRIPT_NFT_1": { 39 | "description": "This is my first NFT thanks to PyCardano", 40 | "name": "PyCardano NFT example token 1", 41 | "id": 1, 42 | "image": "ipfs://QmRhTTbUrPYEw3mJGGhQqQST9k86v1DPBiTTWJGKDJsVFw", 43 | }, 44 | "MY_SCRIPT_NFT_2": { 45 | "description": "This is my second NFT thanks to PyCardano", 46 | "name": "PyCardano NFT example token 2", 47 | "id": 2, 48 | "image": "ipfs://QmRhTTbUrPYEw3mJGGhQqQST9k86v1DPBiTTWJGKDJsVFw", 49 | }, 50 | } 51 | } 52 | } 53 | 54 | # Place metadata in AuxiliaryData, the format acceptable by a transaction. 55 | auxiliary_data = AuxiliaryData(AlonzoMetadata(metadata=Metadata(metadata))) 56 | 57 | # Create a transaction builder 58 | builder = TransactionBuilder(self.chain_context) 59 | 60 | # Add our own address as the input address 61 | builder.add_input_address(address) 62 | 63 | @dataclass 64 | class MyPlutusData(PlutusData): 65 | a: int 66 | 67 | # Add minting script with an empty datum and a minting redeemer 68 | builder.add_minting_script( 69 | anymint_script, redeemer=Redeemer(MyPlutusData(a=42)) 70 | ) 71 | 72 | # Set nft we want to mint 73 | builder.mint = my_nft 74 | 75 | # Set transaction metadata 76 | builder.auxiliary_data = auxiliary_data 77 | 78 | # Calculate the minimum amount of lovelace that need to hold the NFT we are going to mint 79 | min_val = min_lovelace( 80 | output=TransactionOutput(address, Value(0, my_nft)), 81 | context=self.chain_context, 82 | ) 83 | 84 | # Send the NFT to our own address 85 | nft_output = TransactionOutput(address, Value(min_val, my_nft)) 86 | pure_ada_output = TransactionOutput( 87 | address, 88 | min_lovelace( 89 | context=self.chain_context, output=TransactionOutput(address, 0) 90 | ), 91 | ) 92 | builder.add_output(nft_output) 93 | builder.add_output(pure_ada_output) 94 | 95 | # Build and sign transaction 96 | signed_tx = builder.build_and_sign([self.payment_skey], address) 97 | # signed_tx.transaction_witness_set.plutus_data 98 | 99 | print("############### Transaction created ###############") 100 | print(signed_tx) 101 | print(signed_tx.to_cbor_hex()) 102 | 103 | # Submit signed transaction to the network 104 | print("############### Submitting transaction ###############") 105 | self.chain_context.submit_tx(signed_tx) 106 | 107 | self.assert_output(address, nft_output) 108 | -------------------------------------------------------------------------------- /integration-test/test/test_ogmios.py: -------------------------------------------------------------------------------- 1 | from retry import retry 2 | 3 | from .base import TEST_RETRIES, TestBase 4 | 5 | 6 | class TestProtocolParam(TestBase): 7 | @retry(tries=TEST_RETRIES, backoff=1.3, delay=2, jitter=(0, 10)) 8 | def test_protocol_param_cost_models(self): 9 | protocol_param = self.chain_context.protocol_param 10 | 11 | cost_models = protocol_param.cost_models 12 | for _, cost_model in cost_models.items(): 13 | assert len(cost_model) > 0 14 | -------------------------------------------------------------------------------- /pycardano/__init__.py: -------------------------------------------------------------------------------- 1 | # flake8: noqa 2 | 3 | from .address import * 4 | from .backend import * 5 | from .certificate import * 6 | from .cip import * 7 | from .coinselection import * 8 | from .crypto import * 9 | from .exception import * 10 | from .governance import * 11 | from .hash import * 12 | from .key import * 13 | from .metadata import * 14 | from .nativescript import * 15 | from .network import * 16 | from .plutus import * 17 | from .pool_params import * 18 | from .serialization import * 19 | from .transaction import * 20 | from .txbuilder import * 21 | from .utils import * 22 | from .witness import * 23 | -------------------------------------------------------------------------------- /pycardano/backend/__init__.py: -------------------------------------------------------------------------------- 1 | # flake8: noqa 2 | 3 | from .base import * 4 | from .blockfrost import * 5 | from .cardano_cli import * 6 | from .ogmios_v5 import * 7 | from .ogmios_v6 import * 8 | -------------------------------------------------------------------------------- /pycardano/cip/__init__.py: -------------------------------------------------------------------------------- 1 | # flake8: noqa 2 | 3 | from .cip8 import * 4 | from .cip14 import * 5 | -------------------------------------------------------------------------------- /pycardano/cip/cip14.py: -------------------------------------------------------------------------------- 1 | from typing import Union 2 | 3 | from nacl.encoding import RawEncoder 4 | from nacl.hash import blake2b 5 | 6 | from pycardano.crypto.bech32 import encode 7 | from pycardano.hash import ScriptHash 8 | from pycardano.transaction import AssetName 9 | 10 | 11 | def encode_asset( 12 | policy_id: Union[ScriptHash, bytes, str], asset_name: Union[AssetName, bytes, str] 13 | ) -> str: 14 | """Implementation of CIP14 asset fingerprinting 15 | 16 | This function encodes the asset policy and name into an asset fingerprint, which is 17 | bech32 compliant. 18 | 19 | For more information: 20 | https://developers.cardano.org/docs/governance/cardano-improvement-proposals/cip-0014/ 21 | 22 | Args: 23 | policy_id: The asset policy as `ScriptHash`, `bytes`, or a hex `str` 24 | asset_name: The asset name as `AssetName`, `bytes`, or a hex `str` 25 | """ 26 | if isinstance(policy_id, str): 27 | policy_id = bytes.fromhex(policy_id) 28 | elif isinstance(policy_id, ScriptHash): 29 | policy_id = policy_id.payload 30 | 31 | if isinstance(asset_name, str): 32 | asset_name = bytes.fromhex(asset_name) 33 | elif isinstance(asset_name, AssetName): 34 | asset_name = asset_name.payload 35 | 36 | asset_hash = blake2b( 37 | policy_id + asset_name, 38 | digest_size=20, 39 | encoder=RawEncoder, 40 | ) 41 | 42 | return encode("asset", asset_hash) 43 | -------------------------------------------------------------------------------- /pycardano/crypto/__init__.py: -------------------------------------------------------------------------------- 1 | # flake8: noqa 2 | 3 | from .bip32 import * 4 | -------------------------------------------------------------------------------- /pycardano/exception.py: -------------------------------------------------------------------------------- 1 | class PyCardanoException(Exception): 2 | pass 3 | 4 | 5 | class DecodingException(PyCardanoException): 6 | pass 7 | 8 | 9 | class InvalidKeyTypeException(PyCardanoException): 10 | pass 11 | 12 | 13 | class InvalidAddressInputException(PyCardanoException): 14 | pass 15 | 16 | 17 | class InvalidDataException(PyCardanoException): 18 | pass 19 | 20 | 21 | class InvalidArgumentException(PyCardanoException): 22 | pass 23 | 24 | 25 | class InvalidOperationException(PyCardanoException): 26 | pass 27 | 28 | 29 | class SerializeException(PyCardanoException): 30 | pass 31 | 32 | 33 | class DeserializeException(PyCardanoException): 34 | pass 35 | 36 | 37 | class InvalidTransactionException(PyCardanoException): 38 | pass 39 | 40 | 41 | class TransactionBuilderException(PyCardanoException): 42 | pass 43 | 44 | 45 | class TransactionFailedException(PyCardanoException): 46 | pass 47 | 48 | 49 | class UTxOSelectionException(PyCardanoException): 50 | pass 51 | 52 | 53 | class InsufficientUTxOBalanceException(UTxOSelectionException): 54 | pass 55 | 56 | 57 | class MaxInputCountExceededException(UTxOSelectionException): 58 | pass 59 | 60 | 61 | class InputUTxODepletedException(UTxOSelectionException): 62 | pass 63 | 64 | 65 | class CardanoCliError(PyCardanoException): 66 | pass 67 | -------------------------------------------------------------------------------- /pycardano/logging.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from pprintpp import pformat 4 | 5 | __all__ = ["logger", "log_state"] 6 | 7 | # create logger 8 | logger = logging.getLogger("PyCardano") 9 | 10 | # create console handler and set level to debug 11 | ch = logging.StreamHandler() 12 | 13 | # create formatter 14 | formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") 15 | 16 | # add formatter to ch 17 | ch.setFormatter(formatter) 18 | 19 | # add ch to logger 20 | logger.addHandler(ch) 21 | 22 | 23 | def log_state(func): 24 | """Decorator to log the state of an object after its function call.""" 25 | 26 | def wrapper(obj, *args, **kwargs): 27 | try: 28 | output = func(obj, *args, **kwargs) 29 | logger.debug( 30 | f"Class: {obj.__class__}, method: {func}, state:\n {pformat(vars(obj), indent=2)}" 31 | ) 32 | return output 33 | except Exception as e: 34 | logger.warning( 35 | f"Class: {obj.__class__}, method: {func}, state:\n {pformat(vars(obj), indent=2)}" 36 | ) 37 | raise e 38 | 39 | return wrapper 40 | -------------------------------------------------------------------------------- /pycardano/network.py: -------------------------------------------------------------------------------- 1 | """Cardano network types.""" 2 | 3 | from __future__ import annotations 4 | 5 | from enum import Enum 6 | from typing import Type 7 | 8 | from pycardano.serialization import CBORSerializable, limit_primitive_type 9 | 10 | __all__ = ["Network"] 11 | 12 | 13 | class Network(CBORSerializable, Enum): 14 | """ 15 | Network ID 16 | """ 17 | 18 | TESTNET = 0 19 | MAINNET = 1 20 | 21 | def to_primitive(self) -> int: 22 | return self.value 23 | 24 | @classmethod 25 | @limit_primitive_type(int) 26 | def from_primitive(cls: Type[Network], value: int) -> Network: 27 | return cls(value) 28 | -------------------------------------------------------------------------------- /pycardano/types.py: -------------------------------------------------------------------------------- 1 | import os 2 | from functools import partial 3 | from typing import Any, Dict 4 | 5 | import typeguard 6 | 7 | # https://github.com/python/typing/issues/182#issuecomment-199532520 8 | JsonDict = Dict[str, Any] 9 | 10 | 11 | def typechecked(func=None, *args, **kwargs): 12 | if os.getenv("PYCARDANO_NO_TYPE_CHECK", "False").lower() in ("true", "1"): 13 | if func is None: 14 | return partial(typechecked, *args, **kwargs) 15 | return func 16 | return typeguard.typechecked(func, *args, **kwargs) 17 | 18 | 19 | def check_type(*args, **kwargs): 20 | if os.getenv("PYCARDANO_NO_TYPE_CHECK", "False").lower() in ("true", "1"): 21 | return None 22 | return typeguard.check_type(*args, **kwargs) 23 | -------------------------------------------------------------------------------- /pycardano/witness.py: -------------------------------------------------------------------------------- 1 | """Transaction witness.""" 2 | 3 | from __future__ import annotations 4 | 5 | from dataclasses import dataclass, field 6 | from typing import Any, List, Optional, Type, Union 7 | 8 | from pycardano.key import ExtendedVerificationKey, VerificationKey 9 | from pycardano.nativescript import NativeScript 10 | from pycardano.plutus import ( 11 | PlutusV1Script, 12 | PlutusV2Script, 13 | PlutusV3Script, 14 | RawPlutusData, 15 | Redeemers, 16 | ) 17 | from pycardano.serialization import ( 18 | ArrayCBORSerializable, 19 | MapCBORSerializable, 20 | NonEmptyOrderedSet, 21 | limit_primitive_type, 22 | list_hook, 23 | ) 24 | 25 | __all__ = ["VerificationKeyWitness", "TransactionWitnessSet"] 26 | 27 | 28 | @dataclass(repr=False) 29 | class VerificationKeyWitness(ArrayCBORSerializable): 30 | vkey: Union[VerificationKey, ExtendedVerificationKey] 31 | signature: bytes 32 | 33 | def __post_init__(self): 34 | # When vkey is in extended format, we need to convert it to non-extended, so it can match the 35 | # key hash of the input address we are trying to spend. 36 | if isinstance(self.vkey, ExtendedVerificationKey): 37 | self.vkey = self.vkey.to_non_extended() 38 | 39 | @classmethod 40 | @limit_primitive_type(list, tuple) 41 | def from_primitive( 42 | cls: Type[VerificationKeyWitness], values: Union[list, tuple] 43 | ) -> VerificationKeyWitness: 44 | return cls( 45 | vkey=VerificationKey.from_primitive(values[0]), 46 | signature=values[1], 47 | ) 48 | 49 | 50 | @dataclass(repr=False) 51 | class TransactionWitnessSet(MapCBORSerializable): 52 | vkey_witnesses: Optional[ 53 | Union[List[VerificationKeyWitness], NonEmptyOrderedSet[VerificationKeyWitness]] 54 | ] = field( 55 | default=None, 56 | metadata={ 57 | "key": 0, 58 | "optional": True, 59 | }, 60 | ) 61 | 62 | native_scripts: Optional[ 63 | Union[List[NativeScript], NonEmptyOrderedSet[NativeScript]] 64 | ] = field( 65 | default=None, 66 | metadata={ 67 | "key": 1, 68 | "optional": True, 69 | }, 70 | ) 71 | 72 | # TODO: Add bootstrap witness (byron) support 73 | bootstrap_witness: Optional[List[Any]] = field( 74 | default=None, metadata={"optional": True, "key": 2} 75 | ) 76 | 77 | plutus_v1_script: Optional[ 78 | Union[List[PlutusV1Script], NonEmptyOrderedSet[PlutusV1Script]] 79 | ] = field( 80 | default=None, 81 | metadata={ 82 | "key": 3, 83 | "optional": True, 84 | }, 85 | ) 86 | 87 | plutus_data: Optional[List[Any]] = field( 88 | default=None, 89 | metadata={"optional": True, "key": 4, "object_hook": list_hook(RawPlutusData)}, 90 | ) 91 | 92 | redeemer: Optional[Redeemers] = field( 93 | default=None, 94 | metadata={"optional": True, "key": 5}, 95 | ) 96 | 97 | plutus_v2_script: Optional[ 98 | Union[List[PlutusV2Script], NonEmptyOrderedSet[PlutusV2Script]] 99 | ] = field( 100 | default=None, 101 | metadata={ 102 | "key": 6, 103 | "optional": True, 104 | }, 105 | ) 106 | 107 | plutus_v3_script: Optional[ 108 | Union[List[PlutusV3Script], NonEmptyOrderedSet[PlutusV3Script]] 109 | ] = field( 110 | default=None, 111 | metadata={ 112 | "key": 7, 113 | "optional": True, 114 | }, 115 | ) 116 | 117 | def __post_init__(self): 118 | # Convert lists to NonEmptyOrderedSet for fields that should use NonEmptyOrderedSet 119 | if isinstance(self.vkey_witnesses, list): 120 | self.vkey_witnesses = NonEmptyOrderedSet(self.vkey_witnesses) 121 | if isinstance(self.native_scripts, list): 122 | self.native_scripts = NonEmptyOrderedSet(self.native_scripts) 123 | if isinstance(self.plutus_v1_script, list): 124 | self.plutus_v1_script = NonEmptyOrderedSet(self.plutus_v1_script) 125 | if isinstance(self.plutus_v2_script, list): 126 | self.plutus_v2_script = NonEmptyOrderedSet(self.plutus_v2_script) 127 | if isinstance(self.plutus_v3_script, list): 128 | self.plutus_v3_script = NonEmptyOrderedSet(self.plutus_v3_script) 129 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "pycardano" 3 | version = "0.14.0" 4 | classifiers = [ 5 | "Intended Audience :: Developers", 6 | "License :: OSI Approved :: MIT License", 7 | "Natural Language :: English", 8 | "Programming Language :: Python :: 3", 9 | "Programming Language :: Python :: 3.9", 10 | "Programming Language :: Python :: 3.10", 11 | "Programming Language :: Python :: 3.11", 12 | "Programming Language :: Python :: 3.12", 13 | "Programming Language :: Python :: 3.13", 14 | ] 15 | description = "A Cardano library in Python" 16 | homepage = "https://github.com/Python-Cardano/pycardano" 17 | documentation = "https://pycardano.readthedocs.io/en/latest/" 18 | keywords = ["python", "cardano", "blockchain", "crypto"] 19 | authors = ["Jerry "] 20 | readme = "README.md" 21 | repository = "https://github.com/Python-Cardano/pycardano" 22 | license = "MIT" 23 | 24 | [tool.poetry.dependencies] 25 | python = "^3.9.1" 26 | PyNaCl = "^1.5.0" 27 | cbor2 = "^5.6.5" 28 | typeguard = "^4.3.0" 29 | blockfrost-python = "0.6.0" 30 | websocket-client = "^1.4.1" 31 | cose = "0.9.dev8" 32 | pprintpp = "^0.4.0" 33 | mnemonic = "^0.21" 34 | ECPy = "^1.2.5" 35 | frozendict = "^2.3.8" 36 | frozenlist = "^1.3.3" 37 | cachetools = "^5.3.0" 38 | docker = "^7.1.0" 39 | ogmios = "^1.4.2" 40 | requests = "^2.32.3" 41 | websockets = "^13.0" 42 | 43 | [tool.poetry.group.dev.dependencies] 44 | Sphinx = "^5.0.0" 45 | sphinx-rtd-theme = "^2.0.0" 46 | pytest = "^8.2.0" 47 | pytest-cov = "^5.0.0" 48 | flake8 = "^7.0.0" 49 | isort = "^5.11.4" 50 | black = "^24.4.2" 51 | sphinx-copybutton = "^0.5.0" 52 | retry = "^0.9.2" 53 | Flask = "^2.0.3" 54 | pytest-xdist = "^3.5.0" 55 | mypy = "1.14.1" 56 | 57 | [build-system] 58 | requires = ["poetry-core>=1.0.0"] 59 | build-backend = "poetry.core.masonry.api" 60 | 61 | 62 | [tool.pytest.ini_options] 63 | addopts = "--doctest-modules --ignore=examples --ignore=integration-test --ignore=test/resources/haskell" 64 | minversion = "6.0" 65 | markers = [ 66 | "post_alonzo", 67 | "single", 68 | "CardanoCLI", 69 | "post_chang" 70 | ] 71 | 72 | 73 | [tool.isort] 74 | profile = "black" 75 | 76 | [tool.mypy] 77 | ignore_missing_imports = true 78 | disable_error_code = ["str-bytes-safe"] 79 | python_version = 3.9 80 | exclude = [ 81 | '^pycardano/crypto/bech32.py$', 82 | ] 83 | -------------------------------------------------------------------------------- /test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Python-Cardano/pycardano/7d63d0e1da1b0e64cd2b9d389ed4f9e2e5c076ae/test/__init__.py -------------------------------------------------------------------------------- /test/conftest.py: -------------------------------------------------------------------------------- 1 | from fractions import Fraction 2 | from test.pycardano.util import FixedChainContext 3 | 4 | import pytest 5 | 6 | from pycardano import ( 7 | POOL_KEY_HASH_SIZE, 8 | POOL_METADATA_HASH_SIZE, 9 | REWARD_ACCOUNT_HASH_SIZE, 10 | VERIFICATION_KEY_HASH_SIZE, 11 | VRF_KEY_HASH_SIZE, 12 | PoolKeyHash, 13 | PoolMetadataHash, 14 | RewardAccountHash, 15 | VerificationKeyHash, 16 | VrfKeyHash, 17 | ) 18 | from pycardano.pool_params import ( 19 | MultiHostName, 20 | PoolMetadata, 21 | PoolParams, 22 | SingleHostAddr, 23 | SingleHostName, 24 | ) 25 | 26 | 27 | @pytest.fixture 28 | def chain_context(): 29 | return FixedChainContext() 30 | 31 | 32 | @pytest.fixture 33 | def pool_params(): 34 | return PoolParams( 35 | operator=PoolKeyHash(b"1" * POOL_KEY_HASH_SIZE), 36 | vrf_keyhash=VrfKeyHash(b"1" * VRF_KEY_HASH_SIZE), 37 | pledge=100_000_000, 38 | cost=340_000_000, 39 | margin=Fraction(1, 50), 40 | reward_account=RewardAccountHash(b"1" * REWARD_ACCOUNT_HASH_SIZE), 41 | pool_owners=[VerificationKeyHash(b"1" * VERIFICATION_KEY_HASH_SIZE)], 42 | relays=[ 43 | SingleHostAddr(port=3001, ipv4="192.168.0.1", ipv6="::1"), 44 | SingleHostName(port=3001, dns_name="relay1.example.com"), 45 | MultiHostName(dns_name="relay1.example.com"), 46 | ], 47 | pool_metadata=PoolMetadata( 48 | url="https://meta1.example.com", 49 | pool_metadata_hash=PoolMetadataHash(b"1" * POOL_METADATA_HASH_SIZE), 50 | ), 51 | ) 52 | -------------------------------------------------------------------------------- /test/pycardano/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Python-Cardano/pycardano/7d63d0e1da1b0e64cd2b9d389ed4f9e2e5c076ae/test/pycardano/__init__.py -------------------------------------------------------------------------------- /test/pycardano/backend/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Python-Cardano/pycardano/7d63d0e1da1b0e64cd2b9d389ed4f9e2e5c076ae/test/pycardano/backend/__init__.py -------------------------------------------------------------------------------- /test/pycardano/backend/test_blockfrost.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import MagicMock, patch 2 | 3 | from blockfrost import ApiUrls 4 | 5 | from pycardano.backend.blockfrost import BlockFrostChainContext 6 | from pycardano.network import Network 7 | 8 | 9 | @patch("pycardano.backend.blockfrost.BlockFrostApi") 10 | def test_blockfrost_chain_context(mock_api): 11 | mock_api.return_value = MagicMock() 12 | chain_context = BlockFrostChainContext("project_id", base_url=ApiUrls.mainnet.value) 13 | assert chain_context.network == Network.MAINNET 14 | 15 | chain_context = BlockFrostChainContext("project_id", base_url=ApiUrls.testnet.value) 16 | assert chain_context.network == Network.TESTNET 17 | 18 | chain_context = BlockFrostChainContext("project_id", base_url=ApiUrls.preprod.value) 19 | assert chain_context.network == Network.TESTNET 20 | 21 | chain_context = BlockFrostChainContext("project_id", base_url=ApiUrls.preview.value) 22 | assert chain_context.network == Network.TESTNET 23 | -------------------------------------------------------------------------------- /test/pycardano/crypto/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Python-Cardano/pycardano/7d63d0e1da1b0e64cd2b9d389ed4f9e2e5c076ae/test/pycardano/crypto/__init__.py -------------------------------------------------------------------------------- /test/pycardano/test_cip14.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from pycardano.cip.cip14 import encode_asset 4 | from pycardano.hash import ScriptHash 5 | from pycardano.transaction import AssetName 6 | 7 | 8 | @pytest.mark.parametrize( 9 | "input_types", [(str, str), (bytes, bytes), (ScriptHash, AssetName)] 10 | ) 11 | @pytest.mark.parametrize( 12 | "asset", 13 | [ 14 | { 15 | "policy_id": "7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373", 16 | "asset_name": "", 17 | "asset_fingerprint": "asset1rjklcrnsdzqp65wjgrg55sy9723kw09mlgvlc3", 18 | }, 19 | { 20 | "policy_id": "7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc37e", 21 | "asset_name": "", 22 | "asset_fingerprint": "asset1nl0puwxmhas8fawxp8nx4e2q3wekg969n2auw3", 23 | }, 24 | { 25 | "policy_id": "1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209", 26 | "asset_name": "", 27 | "asset_fingerprint": "asset1uyuxku60yqe57nusqzjx38aan3f2wq6s93f6ea", 28 | }, 29 | { 30 | "policy_id": "7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373", 31 | "asset_name": "504154415445", 32 | "asset_fingerprint": "asset13n25uv0yaf5kus35fm2k86cqy60z58d9xmde92", 33 | }, 34 | { 35 | "policy_id": "1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209", 36 | "asset_name": "504154415445", 37 | "asset_fingerprint": "asset1hv4p5tv2a837mzqrst04d0dcptdjmluqvdx9k3", 38 | }, 39 | { 40 | "policy_id": "1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209", 41 | "asset_name": "7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373", 42 | "asset_fingerprint": "asset1aqrdypg669jgazruv5ah07nuyqe0wxjhe2el6f", 43 | }, 44 | { 45 | "policy_id": "7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373", 46 | "asset_name": "1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209", 47 | "asset_fingerprint": "asset17jd78wukhtrnmjh3fngzasxm8rck0l2r4hhyyt", 48 | }, 49 | { 50 | "policy_id": "7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373", 51 | "asset_name": "0000000000000000000000000000000000000000000000000000000000000000", 52 | "asset_fingerprint": "asset1pkpwyknlvul7az0xx8czhl60pyel45rpje4z8w", 53 | }, 54 | ], 55 | ) 56 | def test_encode_asset(asset, input_types): 57 | if isinstance(input_types[0], bytes): 58 | policy_id = bytes.fromhex(asset["policy_id"]) 59 | asset_name = bytes.fromhex(asset["asset_name"]) 60 | elif isinstance(input_types[0], str): 61 | policy_id = asset["policy_id"] 62 | asset_name = asset["asset_name"] 63 | 64 | if isinstance(input_types[0], ScriptHash): 65 | policy_id = ScriptHash(policy_id) 66 | asset_name = AssetName(asset_name) 67 | 68 | fingerprint = encode_asset( 69 | policy_id=asset["policy_id"], asset_name=asset["asset_name"] 70 | ) 71 | 72 | assert fingerprint == asset["asset_fingerprint"] 73 | -------------------------------------------------------------------------------- /test/pycardano/test_network.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from pycardano.exception import DeserializeException 4 | from pycardano.network import Network 5 | 6 | 7 | def test_from_primitive_invalid_primitive_input(): 8 | value = "a string value" 9 | with pytest.raises(DeserializeException): 10 | Network.from_primitive(value) 11 | 12 | 13 | def test_from_primitive_testnet(): 14 | testnet_value = 0 15 | network = Network.from_primitive(testnet_value) 16 | assert network.value == testnet_value 17 | 18 | 19 | def test_from_primitive_mainnet(): 20 | mainnet_value = 1 21 | network = Network.from_primitive(mainnet_value) 22 | assert network.value == mainnet_value 23 | 24 | 25 | def test_to_primitive_testnet(): 26 | network = Network(0) 27 | assert network.to_primitive() == 0 28 | 29 | 30 | def test_to_primitive_mainnet(): 31 | network = Network(1) 32 | assert network.to_primitive() == 1 33 | -------------------------------------------------------------------------------- /test/pycardano/test_types.py: -------------------------------------------------------------------------------- 1 | import typeguard 2 | 3 | from pycardano.types import check_type, typechecked 4 | 5 | 6 | def test_types(monkeypatch): 7 | monkeypatch.setenv("PYCARDANO_NO_TYPE_CHECK", "true") 8 | 9 | assert typeguard.typechecked != typechecked 10 | assert typeguard.check_type != check_type 11 | 12 | @typechecked 13 | def func1(): 14 | pass 15 | 16 | @typechecked() 17 | def func2(): 18 | pass 19 | 20 | check_type() 21 | -------------------------------------------------------------------------------- /test/resources/haskell/PlutusData/.gitignore: -------------------------------------------------------------------------------- 1 | dist-newstyle/ -------------------------------------------------------------------------------- /test/resources/haskell/PlutusData/README.md: -------------------------------------------------------------------------------- 1 | ## Plutus data CBOR generator 2 | 3 | This is a utility package that generates CBOR hex for any Plutus 4 | data, including datum and redeemer. We use this it to generate some ground truth values 5 | for some plutus tests. 6 | 7 | ### How to use 8 | 9 | 1. Install [nix](https://nixos.org/download.html) 10 | 2. Clone [plutus-apps](https://github.com/input-output-hk/plutus-apps). 11 | 3. Inside `plutus-apps`, start a nix shell with command `nix-shell`. 12 | 4. Change directory to the parent folder of this README file. 13 | 5. Modify file `src/PlutusData.hs` to create data structures you are interested in. 14 | 6. Run `cabal run PlutusData`, and the cbor of your target data structure will be written to `plutus-data.cbor`. 15 | 16 | 17 | Some part of the source code is copied from [Deploy.hs](https://github.com/input-output-hk/plutus-pioneer-program/blob/79b0816b6f84f171c8f01073e5445033869c41b7/code/week03/src/Week03/Deploy.hs) 18 | in plutus-pioneer-program. -------------------------------------------------------------------------------- /test/resources/haskell/PlutusData/hie.yaml: -------------------------------------------------------------------------------- 1 | cradle: 2 | cabal: 3 | - path: "./src" 4 | component: "lib:plutus-data" 5 | -------------------------------------------------------------------------------- /test/resources/haskell/PlutusData/plutus-data.cabal: -------------------------------------------------------------------------------- 1 | Cabal-Version: 2.4 2 | Name: PlutusData-cbor-generator 3 | Version: 0.1.0.0 4 | Build-Type: Simple 5 | License: Apache-2.0 6 | License-files: LICENSE 7 | 8 | executable PlutusData 9 | hs-source-dirs: src 10 | main-is: PlutusData.hs 11 | 12 | build-depends: aeson 13 | , base ^>=4.14.1.0 14 | , bytestring 15 | , cardano-api 16 | , containers 17 | , data-default 18 | , playground-common 19 | , plutus-contract 20 | , plutus-ledger 21 | , plutus-ledger-api 22 | , plutus-ledger-constraints 23 | , plutus-tx-plugin 24 | , plutus-tx 25 | , serialise 26 | , text 27 | default-language: Haskell2010 28 | ghc-options: -Wall -fobject-code -fno-ignore-interface-pragmas -fno-omit-interface-pragmas -fno-strictness -fno-spec-constr -fno-specialise 29 | 30 | -------------------------------------------------------------------------------- /test/resources/haskell/PlutusData/plutus-data.cbor: -------------------------------------------------------------------------------- 1 | "d87a9f581cc2ff616e11299d9094ce0a7eb5b7284b705147a822f4ffbd471f971a1b0000017e9874d2a0d905019fd8668218829f187b44313233349f040506ffa2014131024132ffffd9050280ff" -------------------------------------------------------------------------------- /test/resources/haskell/PlutusData/plutus-data.json: -------------------------------------------------------------------------------- 1 | {"constructor":1,"fields":[{"bytes":"c2ff616e11299d9094ce0a7eb5b7284b705147a822f4ffbd471f971a"},{"int":1643235300000},{"constructor":8,"fields":[{"constructor":130,"fields":[{"int":123},{"bytes":"31323334"},{"list":[{"int":4},{"int":5},{"int":6}]},{"map":[{"v":{"bytes":"31"},"k":{"int":1}},{"v":{"bytes":"32"},"k":{"int":2}}]}]}]},{"constructor":9,"fields":[]}]} -------------------------------------------------------------------------------- /test/resources/haskell/PlutusData/src/PlutusData.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DataKinds #-} 2 | {-# LANGUAGE MultiParamTypeClasses #-} 3 | {-# LANGUAGE OverloadedStrings #-} 4 | {-# LANGUAGE ScopedTypeVariables #-} 5 | {-# LANGUAGE TemplateHaskell #-} 6 | 7 | 8 | module Main where 9 | 10 | import Cardano.Api 11 | import Data.Aeson (encode) 12 | import qualified Data.ByteString.Lazy as LBS 13 | import qualified Data.ByteString.Lazy.Char8 as C 14 | import PlutusTx (Data (..)) 15 | import qualified PlutusTx 16 | import qualified PlutusTx.AssocMap as AssocMap 17 | import PlutusTx.Prelude ( BuiltinByteString, ) 18 | import Ledger ( PaymentPubKeyHash(PaymentPubKeyHash), POSIXTime ) 19 | 20 | writeCBORToPath :: PlutusTx.ToData a => FilePath -> a -> IO () 21 | writeCBORToPath file = LBS.writeFile file . encode . PlutusTx.toData 22 | 23 | printCBOR :: PlutusTx.ToData a => a -> IO () 24 | printCBOR = putStrLn . C.unpack . encode . PlutusTx.toData 25 | 26 | dataToScriptData :: Data -> ScriptData 27 | dataToScriptData (Constr n xs) = ScriptDataConstructor n $ dataToScriptData <$> xs 28 | dataToScriptData (Map xs) = ScriptDataMap [(dataToScriptData x, dataToScriptData y) | (x, y) <- xs] 29 | dataToScriptData (List xs) = ScriptDataList $ dataToScriptData <$> xs 30 | dataToScriptData (I n) = ScriptDataNumber n 31 | dataToScriptData (B bs) = ScriptDataBytes bs 32 | 33 | toJSONByteString :: PlutusTx.ToData a => a -> LBS.ByteString 34 | toJSONByteString = encode . scriptDataToJson ScriptDataJsonDetailedSchema . dataToScriptData . PlutusTx.toData 35 | 36 | printJSON :: PlutusTx.ToData a => a -> IO () 37 | printJSON = putStrLn . C.unpack . toJSONByteString 38 | 39 | writeJSON :: PlutusTx.ToData a => FilePath -> a -> IO () 40 | writeJSON file = LBS.writeFile file . toJSONByteString 41 | 42 | 43 | data Test = Test 44 | { 45 | a :: !Integer, 46 | b :: !BuiltinByteString, 47 | c :: !([Integer]), 48 | d :: !(AssocMap.Map Integer BuiltinByteString) 49 | } 50 | deriving (Show) 51 | 52 | PlutusTx.makeLift ''Test 53 | PlutusTx.makeIsDataIndexed ''Test [('Test, 130)] 54 | 55 | 56 | data BigTest = BigTest Test | LargestTest deriving (Show) 57 | 58 | PlutusTx.makeLift ''BigTest 59 | PlutusTx.makeIsDataIndexed ''BigTest [('BigTest, 8), ('LargestTest, 9)] 60 | 61 | data VestingParam = VestingParam 62 | { beneficiary :: PaymentPubKeyHash 63 | , deadline :: POSIXTime 64 | , testa :: BigTest 65 | , testb :: BigTest 66 | } deriving (Show) 67 | 68 | PlutusTx.makeLift ''VestingParam 69 | 70 | PlutusTx.makeIsDataIndexed ''VestingParam [('VestingParam, 1)] 71 | 72 | 73 | test :: Test 74 | test = Test 75 | { a = 123 76 | , b = "1234" 77 | , c = [4, 5, 6] 78 | , d = AssocMap.fromList [(1, "1"), (2, "2")] 79 | } 80 | 81 | param :: VestingParam 82 | param = VestingParam 83 | { beneficiary = Ledger.PaymentPubKeyHash "c2ff616e11299d9094ce0a7eb5b7284b705147a822f4ffbd471f971a" 84 | , deadline = 1643235300000 85 | , testa = BigTest test 86 | , testb = LargestTest 87 | } 88 | 89 | main :: IO () 90 | main = do 91 | putStrLn "Plutus data cbor:" 92 | printCBOR param 93 | writeCBORToPath "plutus-data.cbor" param 94 | 95 | putStrLn "Plutus data json:" 96 | printJSON param 97 | writeJSON "plutus-data.json" param 98 | -------------------------------------------------------------------------------- /test/resources/keys/cold.skey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "StakePoolSigningKey_ed25519", 3 | "description": "StakePoolSigningKey_ed25519", 4 | "cborHex": "582044181bd0e6be21cea5b0751b8c6d4f88a5cb2d5dfec31a271add617f7ce559a9" 5 | } 6 | -------------------------------------------------------------------------------- /test/resources/keys/cold.vkey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "StakePoolVerificationKey_ed25519", 3 | "description": "StakePoolVerificationKey_ed25519", 4 | "cborHex": "5820354ce32da92e7116f6c70e9be99a3a601d33137d0685ab5b7e2ff5b656989299" 5 | } 6 | -------------------------------------------------------------------------------- /test/resources/keys/payment.skey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "PaymentSigningKeyShelley_ed25519", 3 | "description": "Payment Signing Key", 4 | "cborHex": "58204d9fc18b873d0cd70b614462418ac719d9ca12d0bfcdf7edac2a44fb385d26d8" 5 | } -------------------------------------------------------------------------------- /test/resources/keys/payment.vkey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "PaymentVerificationKeyShelley_ed25519", 3 | "description": "Payment Verification Key", 4 | "cborHex": "58205797dc2cc919dfec0bb849551ebdf30d96e5cbe0f33f734a87fe826db30f7ef9" 5 | } -------------------------------------------------------------------------------- /test/resources/keys/staking.skey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "StakeSigningKeyShelley_ed25519", 3 | "description": "Stake Signing Key", 4 | "cborHex": "5820ff3a330df8859e4e5f42a97fcaee73f6a00d0cf864f4bca902bd106d423f02c0" 5 | } -------------------------------------------------------------------------------- /test/resources/keys/staking.vkey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "StakeVerificationKeyShelley_ed25519", 3 | "description": "Stake Verification Key", 4 | "cborHex": "58205edaa384c658c2bd8945ae389edac0a5bd452d0cfd5d1245e3ecd540030d1e3c" 5 | } --------------------------------------------------------------------------------