From 9d1b51e59d6a33302edde846efcb727070156da4 Mon Sep 17 00:00:00 2001 From: Pantos Snapshoter <> Date: Thu, 25 Apr 2024 12:16:08 +0200 Subject: [PATCH] Pushing a snapshot for 1.1.0 --- .github/CODEOWNERS | 3 + .github/ISSUE_TEMPLATE/ISSUE_REPORT.yml | 54 + .github/ISSUE_TEMPLATE/feature_report.yml | 28 + .github/actions/install-deps/action.yml | 19 + .github/pull_request_template.md | 40 + .github/workflows/ci.yaml | 75 + .github/workflows/release.yaml | 114 + .gitignore | 2 + CODE_OF_CONDUCT.md | 128 + Makefile | 26 +- pantos/common/blockchains/base.py | 25 +- .../contracts/avalanche_pantos_forwarder.abi | 1 + .../contracts/bnb_chain_pantos_forwarder.abi | 1 + .../contracts/celo_pantos_forwarder.abi | 1 + .../contracts/cronos_pantos_forwarder.abi | 1 + .../contracts/ethereum_pantos_forwarder.abi | 1 + .../contracts/ethereum_pantos_hub.abi | 2524 +++++++++-------- .../contracts/fantom_pantos_forwarder.abi | 1 + .../contracts/polygon_pantos_forwarder.abi | 1 + pantos/common/blockchains/enums.py | 1 + pantos/common/blockchains/ethereum.py | 11 +- pantos/common/blockchains/factory.py | 9 +- pantos/common/blockchains/solana.py | 6 +- pantos/common/configuration.py | 106 +- pantos/common/logging.py | 1 + pantos/common/signer.py | 30 +- setup.py | 9 +- tests/blockchains/test_base.py | 10 +- tests/blockchains/test_enums.py | 2 + tests/blockchains/test_ethereum.py | 11 +- tests/test_configuration.py | 122 + tests/test_exceptions.py | 1 + tests/test_logging.py | 2 +- tests/test_signer.py | 50 +- 34 files changed, 2082 insertions(+), 1334 deletions(-) create mode 100644 .github/CODEOWNERS create mode 100644 .github/ISSUE_TEMPLATE/ISSUE_REPORT.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_report.yml create mode 100644 .github/actions/install-deps/action.yml create mode 100644 .github/pull_request_template.md create mode 100644 .github/workflows/ci.yaml create mode 100644 .github/workflows/release.yaml create mode 100644 CODE_OF_CONDUCT.md create mode 120000 pantos/common/blockchains/contracts/avalanche_pantos_forwarder.abi create mode 120000 pantos/common/blockchains/contracts/bnb_chain_pantos_forwarder.abi create mode 120000 pantos/common/blockchains/contracts/celo_pantos_forwarder.abi create mode 120000 pantos/common/blockchains/contracts/cronos_pantos_forwarder.abi create mode 100644 pantos/common/blockchains/contracts/ethereum_pantos_forwarder.abi create mode 120000 pantos/common/blockchains/contracts/fantom_pantos_forwarder.abi create mode 120000 pantos/common/blockchains/contracts/polygon_pantos_forwarder.abi create mode 100644 tests/test_configuration.py diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..16e370c --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,3 @@ +* @markuslevonyak @danut13 +.github/workflows @pantos-io/qa +.github/CODEOWNERS @pantos-io/management diff --git a/.github/ISSUE_TEMPLATE/ISSUE_REPORT.yml b/.github/ISSUE_TEMPLATE/ISSUE_REPORT.yml new file mode 100644 index 0000000..1ab4f8e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/ISSUE_REPORT.yml @@ -0,0 +1,54 @@ +name: Bug Report +description: File a bug report +title: "[Bug]: " +labels: ["bug", "triage"] +projects: ["pantos-io/4"] +assignees: + - pantos-io/blockchain-backend +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! + - type: input + id: contact + attributes: + label: Contact Details + description: How can we get in touch with you if we need more info? + placeholder: ex. email@example.com + validations: + required: false + - type: textarea + id: what-happened + attributes: + label: What happened? + description: Also tell us, what did you expect to happen? + placeholder: Tell us what you see! + value: "A bug happened!" + validations: + required: true + - type: dropdown + id: version + attributes: + label: Network + description: Which network can the issue be reproduced on? + options: + - Local + - Testnet + default: 0 + validations: + required: true + - type: textarea + id: logs + attributes: + label: Relevant log output + description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. + render: shell + - type: checkboxes + id: terms + attributes: + label: Code of Conduct + description: By submitting this issue, you agree to follow our Code of Conduct + options: + - label: I agree to follow this project's Code of Conduct + required: true diff --git a/.github/ISSUE_TEMPLATE/feature_report.yml b/.github/ISSUE_TEMPLATE/feature_report.yml new file mode 100644 index 0000000..77a6e7e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_report.yml @@ -0,0 +1,28 @@ +name: Feature Request +description: You want a new feature to be implemented. +labels: [wishlisted] +projects: ["pantos-io/3"] +body: + - type: markdown + attributes: + value: | + Thanks for suggesting this. Please provide some details so we can have a better understanding of why you need this new feature. + + - type: textarea + id: Requirements + attributes: + label: Requirements + description: | + Please add some details of what is needed, including use cases. + placeholder: ex. "I want my tokens to be... because..." + validations: + required: true + + - type: textarea + id: Info + attributes: + label: "Notes & References" + description: | + Please add relevant notes, links other related issues/PRs, + anything to help diagnose, understand and develop the + feature you want. \ No newline at end of file diff --git a/.github/actions/install-deps/action.yml b/.github/actions/install-deps/action.yml new file mode 100644 index 0000000..7b27fa0 --- /dev/null +++ b/.github/actions/install-deps/action.yml @@ -0,0 +1,19 @@ +name: 'Install dependencies' +description: 'Install all required dependencies' +runs: + using: composite + steps: + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: '3.10' + + - name: Install dependencies + shell: bash + run: python3 -m pip install -r requirements.txt + + - uses: actions/cache@v3 + with: + # with this we are going to cache the virtual environment + path: ${{ env.pythonLocation }} + key: ${{ env.pythonLocation }}-${{ hashFiles('setup.py') }}-${{ hashFiles('dev-requirements.txt') }} \ No newline at end of file diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..75a8ffb --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,40 @@ + + +## What type of PR is this? (check all applicable) + +- [ ] Refactor +- [ ] Feature +- [ ] Bug Fix +- [ ] Optimization +- [ ] Documentation Update + +## Description + +## Related Tickets & Documents + + + +- Related Issue # +- Closes # + +## QA Instructions + +_Please replace this line with instructions on how to test your changes._ + + +## [optional] Are there any post deployment tasks we need to perform? diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..d0d48be --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,75 @@ +name: Format, Lint, and Test + +on: + push: + branches: + - main + pull_request: + +jobs: + Format: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: ./.github/actions/install-deps + + - name: Format + run: make format-check + + Lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: ./.github/actions/install-deps + + - name: Lint + run: make lint + + Sort: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: ./.github/actions/install-deps + + - name: Sort + run: make sort-check + + Bandit: + name: Bandit + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: ./.github/actions/install-deps + + - name: Bandit + run: make bandit + + StaticCodeAnalysis: + name: Static Code Analysis + runs-on: ubuntu-latest + needs: [Format, Lint, Sort, Bandit] + steps: + - uses: actions/checkout@v4 + + - uses: ./.github/actions/install-deps + + - name: StaticCodeAnalysis + run: | + make check + + UnitTest: + name: Unit Test + runs-on: ubuntu-latest + needs: [Format, Lint, Sort, Bandit] + steps: + - uses: actions/checkout@v4 + + - uses: ./.github/actions/install-deps + + - name: Unit Test + run: | + make coverage diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..976b1b5 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,114 @@ +name: Release Workflow +run-name: ${{ (github.event.release.prerelease && 'Beta') || 'Prod'}} Release for ${{ github.repository }} - ${{ github.event.release.tag_name }} +on: + release: + # Triggered on Pre-Releases and Releases + types: [released, prereleased] + +# Only allow one release at the time +concurrency: + group: deploy-${{ github.repository }}-release-${{ github.event.release.prerelease }} + +jobs: + build: + name: Build Package + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: recursive + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: 3.10 + cache: 'pip' + + - name: Install dependencies + run: | + python -m venv .venv + source .venv/bin/activate + python -m pip install -r requirements.txt + + - name: Build package + run: | + source .venv/bin/activate + pip install build + python -m build + env: + PANTOS_COMMON_VERSION: ${{ github.event.release.tag_name }} + + - name: Upload build artifact + uses: actions/upload-artifact@v4 + with: + name: common + path: dist + + add-assets: + name: Add Assets to the ${{ github.event.release.tag_name }} Release + needs: build + runs-on: ubuntu-latest + permissions: + contents: write + id-token: write + steps: + - uses: actions/download-artifact@v4 + with: + name: common + path: dist + + - name: List directory + run: | + cp dist/*.whl release/ + + - uses: sigstore/gh-action-sigstore-python@v2.1.1 + with: + inputs: release/* + + - uses: actions/upload-artifact@v4 + with: + name: signed-common + path: release/*.whl + + - name: Upload release assets + uses: svenstaro/upload-release-action@v2 + with: + file: "./release/*" + file_glob: true + overwrite: true + repo_token: ${{ secrets.GITHUB_TOKEN }} + tag: ${{ github.event.release.tag_name }} + + - uses: robinraju/release-downloader@v1.9 + name: Download tarball + with: + tag: ${{ github.event.release.tag_name }} + tarBall: true + zipBall: true + fileName: '*' + out-file-path: external-release + preRelease: ${{ github.event.release.prerelease }} + token: ${{ secrets.GITHUB_TOKEN }} + repository: ${{ github.repository }} + + - name: List directory + run: | + ls -lha external-release + # Remove all the files in external-release that are also present in release + for file in $(ls release); do + rm -f external-release/$file + done + + - uses: sigstore/gh-action-sigstore-python@v2.1.1 + with: + inputs: external-release/* + + - name: Upload signed source code + uses: ncipollo/release-action@v1 + with: + artifacts: "./external-release/*" + artifactErrorsFailBuild: true + allowUpdates: true + tag: ${{ github.event.release.tag_name }} + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 81de1c1..29be41b 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ build/ dist/ find.sh +local/ +.coverage diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..d3f435f --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,128 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +contact@pantos.io. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. \ No newline at end of file diff --git a/Makefile b/Makefile index dfa937f..3b4705f 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,11 @@ +PYTHON_FILES := pantos/common scripts tests ./*.py + .PHONY: code code: check format lint sort bandit test .PHONY: check check: - mypy pantos/common + mypy $(PYTHON_FILES) .PHONY: test test: @@ -11,24 +13,36 @@ test: .PHONY: coverage coverage: + rm -rf .coverage python3 -m pytest --cov-report term-missing --cov=pantos tests - rm .coverage .PHONY: lint lint: - flake8 pantos/common tests + flake8 $(PYTHON_FILES) .PHONY: sort sort: - isort --force-single-line-imports pantos/common tests + isort --force-single-line-imports $(PYTHON_FILES) + +.PHONY: sort-check +sort-check: + isort --force-single-line-imports $(PYTHON_FILES) --check-only .PHONY: bandit bandit: - bandit -r pantos/common tests --quiet --configfile=.bandit + bandit -r $(PYTHON_FILES) --quiet --configfile=.bandit + +.PHONY: bandit-check +bandit-check: + bandit -r $(PYTHON_FILES) --configfile=.bandit .PHONY: format format: - yapf --in-place --recursive pantos/common tests + yapf --in-place --recursive $(PYTHON_FILES) + +.PHONY: format-check +format-check: + yapf --diff --recursive $(PYTHON_FILES) .PHONY: clean clean: diff --git a/pantos/common/blockchains/base.py b/pantos/common/blockchains/base.py index 98e960b..d6d0b7a 100644 --- a/pantos/common/blockchains/base.py +++ b/pantos/common/blockchains/base.py @@ -259,7 +259,7 @@ def __getitem__(self, index: typing.Any) -> 'NodeConnections.Wrapper': def __call__( self, *args: typing.Any, **kwargs: typing.Any) -> \ - 'NodeConnections.Wrapper' | typing.Any: + typing.Union['NodeConnections.Wrapper', typing.Any]: """Forward the called method to the wrapped objects. If it sends a transaction to the blockchain node, it will be forwarded to only one of them, randomly chosen. @@ -428,8 +428,7 @@ def __init__(self, blockchain_node_urls: list[str], average_block_time: int, required_transaction_confirmations: int, transaction_network_id: typing.Optional[int], - default_private_key: typing.Optional[tuple[pathlib.Path, - str]] = None, + default_private_key: typing.Optional[tuple[str, str]] = None, celery_tasks_enabled: bool = False): """Construct a blockchain utilities instance. @@ -454,9 +453,9 @@ def __init__(self, blockchain_node_urls: list[str], different compatible blockchain networks). It is assumed to be the identifier of the main or a test network of the blockchain supported by the blockchain utilities subclass. - default_private_key : tuple of pathlib.Path and str, optional - The keystore file path and password of the default private - key to be used by the blockchain utilities (default: None). + default_private_key : tuple of str and str, optional + The keystore value and password of the default private + key to be used by the blockchain utilities. (default: None). celery_tasks_enabled : bool, optional If True, Celery tasks are enabled for enhanced functionalities (default: False). This requires a proper @@ -491,7 +490,7 @@ def __init__(self, blockchain_node_urls: list[str], self._blockchain_node_urls = blockchain_node_urls self._fallback_blockchain_node_urls = fallback_blockchain_node_urls self._default_private_key = ( - None if default_private_key is None else self.load_private_key( + None if default_private_key is None else self.decrypt_private_key( default_private_key[0], default_private_key[1])) self._default_address = (None if self._default_private_key is None else self.get_address(self._default_private_key)) @@ -690,15 +689,15 @@ def load_contract_abi(self, contract_abi: ContractAbi) -> list[typing.Any]: contract_abi=contract_abi) @abc.abstractmethod - def load_private_key(self, key_path: pathlib.Path, password: str) -> str: - """Load the private key from a password-encrypted key file. + def decrypt_private_key(self, encrypted_key: str, password: str) -> str: + """Load the private key from a password-encrypted key. Parameters ---------- - key_path : pathlib.Path - The path to the key file. + encrypted_key: str + The encrypted key. password : str - The password to decrypt the key file. + The password to decrypt the key. Returns ------- @@ -708,7 +707,7 @@ def load_private_key(self, key_path: pathlib.Path, password: str) -> str: Raises ------ BlockchainUtilitiesError - If the private key cannot be loaded from the key file. + If the private key cannot be decrypted. """ pass # pragma: no cover diff --git a/pantos/common/blockchains/contracts/avalanche_pantos_forwarder.abi b/pantos/common/blockchains/contracts/avalanche_pantos_forwarder.abi new file mode 120000 index 0000000..2d60bf7 --- /dev/null +++ b/pantos/common/blockchains/contracts/avalanche_pantos_forwarder.abi @@ -0,0 +1 @@ +ethereum_pantos_forwarder.abi \ No newline at end of file diff --git a/pantos/common/blockchains/contracts/bnb_chain_pantos_forwarder.abi b/pantos/common/blockchains/contracts/bnb_chain_pantos_forwarder.abi new file mode 120000 index 0000000..2d60bf7 --- /dev/null +++ b/pantos/common/blockchains/contracts/bnb_chain_pantos_forwarder.abi @@ -0,0 +1 @@ +ethereum_pantos_forwarder.abi \ No newline at end of file diff --git a/pantos/common/blockchains/contracts/celo_pantos_forwarder.abi b/pantos/common/blockchains/contracts/celo_pantos_forwarder.abi new file mode 120000 index 0000000..2d60bf7 --- /dev/null +++ b/pantos/common/blockchains/contracts/celo_pantos_forwarder.abi @@ -0,0 +1 @@ +ethereum_pantos_forwarder.abi \ No newline at end of file diff --git a/pantos/common/blockchains/contracts/cronos_pantos_forwarder.abi b/pantos/common/blockchains/contracts/cronos_pantos_forwarder.abi new file mode 120000 index 0000000..2d60bf7 --- /dev/null +++ b/pantos/common/blockchains/contracts/cronos_pantos_forwarder.abi @@ -0,0 +1 @@ +ethereum_pantos_forwarder.abi \ No newline at end of file diff --git a/pantos/common/blockchains/contracts/ethereum_pantos_forwarder.abi b/pantos/common/blockchains/contracts/ethereum_pantos_forwarder.abi new file mode 100644 index 0000000..9295eb7 --- /dev/null +++ b/pantos/common/blockchains/contracts/ethereum_pantos_forwarder.abi @@ -0,0 +1 @@ +[{"type":"function","name":"getMinimumValidatorNodeSignatures","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"getPantosHub","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"getPantosToken","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"getValidatorNodes","inputs":[],"outputs":[{"name":"","type":"address[]","internalType":"address[]"}],"stateMutability":"view"},{"type":"function","name":"isValidSenderNonce","inputs":[{"name":"sender","type":"address","internalType":"address"},{"name":"nonce","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"isValidValidatorNodeNonce","inputs":[{"name":"nonce","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"verifyAndForwardTransfer","inputs":[{"name":"request","type":"tuple","internalType":"struct PantosTypes.TransferRequest","components":[{"name":"sender","type":"address","internalType":"address"},{"name":"recipient","type":"address","internalType":"address"},{"name":"token","type":"address","internalType":"address"},{"name":"amount","type":"uint256","internalType":"uint256"},{"name":"serviceNode","type":"address","internalType":"address"},{"name":"fee","type":"uint256","internalType":"uint256"},{"name":"nonce","type":"uint256","internalType":"uint256"},{"name":"validUntil","type":"uint256","internalType":"uint256"}]},{"name":"signature","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"verifyAndForwardTransferFrom","inputs":[{"name":"sourceBlockchainFactor","type":"uint256","internalType":"uint256"},{"name":"destinationBlockchainFactor","type":"uint256","internalType":"uint256"},{"name":"request","type":"tuple","internalType":"struct PantosTypes.TransferFromRequest","components":[{"name":"destinationBlockchainId","type":"uint256","internalType":"uint256"},{"name":"sender","type":"address","internalType":"address"},{"name":"recipient","type":"string","internalType":"string"},{"name":"sourceToken","type":"address","internalType":"address"},{"name":"destinationToken","type":"string","internalType":"string"},{"name":"amount","type":"uint256","internalType":"uint256"},{"name":"serviceNode","type":"address","internalType":"address"},{"name":"fee","type":"uint256","internalType":"uint256"},{"name":"nonce","type":"uint256","internalType":"uint256"},{"name":"validUntil","type":"uint256","internalType":"uint256"}]},{"name":"signature","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"verifyAndForwardTransferTo","inputs":[{"name":"request","type":"tuple","internalType":"struct PantosTypes.TransferToRequest","components":[{"name":"sourceBlockchainId","type":"uint256","internalType":"uint256"},{"name":"sourceTransferId","type":"uint256","internalType":"uint256"},{"name":"sourceTransactionId","type":"string","internalType":"string"},{"name":"sender","type":"string","internalType":"string"},{"name":"recipient","type":"address","internalType":"address"},{"name":"sourceToken","type":"string","internalType":"string"},{"name":"destinationToken","type":"address","internalType":"address"},{"name":"amount","type":"uint256","internalType":"uint256"},{"name":"nonce","type":"uint256","internalType":"uint256"}]},{"name":"signerAddresses","type":"address[]","internalType":"address[]"},{"name":"signatures","type":"bytes[]","internalType":"bytes[]"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"verifyTransfer","inputs":[{"name":"request","type":"tuple","internalType":"struct PantosTypes.TransferRequest","components":[{"name":"sender","type":"address","internalType":"address"},{"name":"recipient","type":"address","internalType":"address"},{"name":"token","type":"address","internalType":"address"},{"name":"amount","type":"uint256","internalType":"uint256"},{"name":"serviceNode","type":"address","internalType":"address"},{"name":"fee","type":"uint256","internalType":"uint256"},{"name":"nonce","type":"uint256","internalType":"uint256"},{"name":"validUntil","type":"uint256","internalType":"uint256"}]},{"name":"signature","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"view"},{"type":"function","name":"verifyTransferFrom","inputs":[{"name":"request","type":"tuple","internalType":"struct PantosTypes.TransferFromRequest","components":[{"name":"destinationBlockchainId","type":"uint256","internalType":"uint256"},{"name":"sender","type":"address","internalType":"address"},{"name":"recipient","type":"string","internalType":"string"},{"name":"sourceToken","type":"address","internalType":"address"},{"name":"destinationToken","type":"string","internalType":"string"},{"name":"amount","type":"uint256","internalType":"uint256"},{"name":"serviceNode","type":"address","internalType":"address"},{"name":"fee","type":"uint256","internalType":"uint256"},{"name":"nonce","type":"uint256","internalType":"uint256"},{"name":"validUntil","type":"uint256","internalType":"uint256"}]},{"name":"signature","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"view"},{"type":"function","name":"verifyTransferTo","inputs":[{"name":"request","type":"tuple","internalType":"struct PantosTypes.TransferToRequest","components":[{"name":"sourceBlockchainId","type":"uint256","internalType":"uint256"},{"name":"sourceTransferId","type":"uint256","internalType":"uint256"},{"name":"sourceTransactionId","type":"string","internalType":"string"},{"name":"sender","type":"string","internalType":"string"},{"name":"recipient","type":"address","internalType":"address"},{"name":"sourceToken","type":"string","internalType":"string"},{"name":"destinationToken","type":"address","internalType":"address"},{"name":"amount","type":"uint256","internalType":"uint256"},{"name":"nonce","type":"uint256","internalType":"uint256"}]},{"name":"signerAddresses","type":"address[]","internalType":"address[]"},{"name":"signatures","type":"bytes[]","internalType":"bytes[]"}],"outputs":[],"stateMutability":"view"},{"type":"event","name":"MinimumValidatorNodeSignaturesUpdated","inputs":[{"name":"minimumValidatorNodeSignatures","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"PantosHubSet","inputs":[{"name":"pantosHub","type":"address","indexed":false,"internalType":"address"}],"anonymous":false},{"type":"event","name":"PantosTokenSet","inputs":[{"name":"pantosToken","type":"address","indexed":false,"internalType":"address"}],"anonymous":false},{"type":"event","name":"ValidatorNodeAdded","inputs":[{"name":"validatorNodeAddress","type":"address","indexed":false,"internalType":"address"}],"anonymous":false},{"type":"event","name":"ValidatorNodeRemoved","inputs":[{"name":"validatorNodeAddress","type":"address","indexed":false,"internalType":"address"}],"anonymous":false}] diff --git a/pantos/common/blockchains/contracts/ethereum_pantos_hub.abi b/pantos/common/blockchains/contracts/ethereum_pantos_hub.abi index 458fa91..ef53454 100644 --- a/pantos/common/blockchains/contracts/ethereum_pantos_hub.abi +++ b/pantos/common/blockchains/contracts/ethereum_pantos_hub.abi @@ -1,1370 +1,1500 @@ [ { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "blockchainId", - "type": "uint256" - } - ], - "name": "BlockchainNameUpdated", - "type": "event" + "type": "function", + "name": "cancelServiceNodeUnregistration", + "inputs": [ + { + "name": "serviceNodeAddress", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "blockchainId", - "type": "uint256" - } - ], - "name": "BlockchainRegistered", - "type": "event" + "type": "function", + "name": "decreaseServiceNodeStake", + "inputs": [ + { + "name": "serviceNodeAddress", + "type": "address", + "internalType": "address" + }, + { + "name": "stake", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "blockchainId", - "type": "uint256" - } - ], - "name": "BlockchainUnregistered", - "type": "event" + "type": "function", + "name": "decreaseTokenStake", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "stake", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "blockchainId", - "type": "uint256" - } - ], - "name": "ExternalTokenRegistered", - "type": "event" + "type": "function", + "name": "getBlockchainRecord", + "inputs": [ + { + "name": "blockchainId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct PantosTypes.BlockchainRecord", + "components": [ + { + "name": "active", + "type": "bool", + "internalType": "bool" + }, + { + "name": "name", + "type": "string", + "internalType": "string" + } + ] + } + ], + "stateMutability": "view" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "blockchainId", - "type": "uint256" - } - ], - "name": "ExternalTokenUnregistered", - "type": "event" + "type": "function", + "name": "getCurrentBlockchainId", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "minimumTrustedValidatorFeeUpdatePeriod", - "type": "uint256" - } - ], - "name": "MinimumTrustedValidatorFeeUpdatePeriodUpdated", - "type": "event" + "type": "function", + "name": "getExternalTokenRecord", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "blockchainId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct PantosTypes.ExternalTokenRecord", + "components": [ + { + "name": "active", + "type": "bool", + "internalType": "bool" + }, + { + "name": "externalToken", + "type": "string", + "internalType": "string" + } + ] + } + ], + "stateMutability": "view" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "pantosForwarder", - "type": "address" - } - ], - "name": "PantosForwarderSet", - "type": "event" + "type": "function", + "name": "getMinimumServiceNodeStake", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "pantosToken", - "type": "address" - } - ], - "name": "PantosTokenSet", - "type": "event" + "type": "function", + "name": "getMinimumTokenStake", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "pantosValidator", - "type": "address" - } - ], - "name": "PantosValidatorSet", - "type": "event" + "type": "function", + "name": "getMinimumValidatorFeeUpdatePeriod", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "serviceNode", - "type": "address" - } - ], - "name": "ServiceNodeRegistered", - "type": "event" + "type": "function", + "name": "getNumberActiveBlockchains", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "serviceNode", - "type": "address" - } - ], - "name": "ServiceNodeUnregistered", - "type": "event" + "type": "function", + "name": "getNumberBlockchains", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "serviceNode", - "type": "address" - } - ], - "name": "ServiceNodeUrlUpdated", - "type": "event" + "type": "function", + "name": "getPantosForwarder", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "token", - "type": "address" - } - ], - "name": "TokenRegistered", - "type": "event" + "type": "function", + "name": "getPantosToken", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "token", - "type": "address" - } - ], - "name": "TokenUnregistered", - "type": "event" + "type": "function", + "name": "getPrimaryValidatorNode", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "transferId", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "fee", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "serviceNode", - "type": "address" - } - ], - "name": "Transfer", - "type": "event" + "type": "function", + "name": "getServiceNodeRecord", + "inputs": [ + { + "name": "serviceNode", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct PantosTypes.ServiceNodeRecord", + "components": [ + { + "name": "active", + "type": "bool", + "internalType": "bool" + }, + { + "name": "url", + "type": "string", + "internalType": "string" + }, + { + "name": "freeStake", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "lockedStake", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "unstakingAddress", + "type": "address", + "internalType": "address" + }, + { + "name": "unregisterTime", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ], + "stateMutability": "view" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "sourceTransferId", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "destinationBlockchainId", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "recipient", - "type": "string" - }, - { - "indexed": false, - "internalType": "address", - "name": "sourceToken", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "destinationToken", - "type": "string" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "fee", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "serviceNode", - "type": "address" - } - ], - "name": "TransferFrom", - "type": "event" + "type": "function", + "name": "getServiceNodes", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address[]", + "internalType": "address[]" + } + ], + "stateMutability": "view" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "sourceBlockchainId", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "sourceTransferId", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "string", - "name": "sourceTransactionId", - "type": "string" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "destinationTransferId", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "string", - "name": "sender", - "type": "string" - }, - { - "indexed": false, - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "sourceToken", - "type": "string" - }, - { - "indexed": false, - "internalType": "address", - "name": "destinationToken", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "TransferTo", - "type": "event" + "type": "function", + "name": "getTokenRecord", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct PantosTypes.TokenRecord", + "components": [ + { + "name": "active", + "type": "bool", + "internalType": "bool" + }, + { + "name": "stake", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ], + "stateMutability": "view" }, { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "blockchainId", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "oldFactor", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newFactor", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "validFrom", - "type": "uint256" - } - ], - "name": "TrustedValidatorFeeUpdated", - "type": "event" + "type": "function", + "name": "getTokens", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address[]", + "internalType": "address[]" + } + ], + "stateMutability": "view" }, { - "inputs": [ - { - "internalType": "address", - "name": "serviceNodeAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "stake", - "type": "uint256" - } - ], - "name": "decreaseServiceNodeStake", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "type": "function", + "name": "getUnbondingPeriodServiceNodeStake", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" }, { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "stake", - "type": "uint256" - } - ], - "name": "decreaseTokenStake", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "type": "function", + "name": "getValidatorFeeRecord", + "inputs": [ + { + "name": "blockchainId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct PantosTypes.ValidatorFeeRecord", + "components": [ + { + "name": "oldFactor", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "newFactor", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "validFrom", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ], + "stateMutability": "view" }, { - "inputs": [ - { - "internalType": "uint256", - "name": "blockchainId", - "type": "uint256" - } - ], - "name": "getBlockchainRecord", - "outputs": [ - { - "components": [ - { - "internalType": "bool", - "name": "active", - "type": "bool" + "type": "function", + "name": "increaseServiceNodeStake", + "inputs": [ + { + "name": "serviceNodeAddress", + "type": "address", + "internalType": "address" }, { - "internalType": "string", - "name": "name", - "type": "string" - } - ], - "internalType": "struct PantosTypes.BlockchainRecord", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getCurrentBlockchainId", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" + "name": "stake", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" }, { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "blockchainId", - "type": "uint256" - } - ], - "name": "getExternalTokenRecord", - "outputs": [ - { - "components": [ - { - "internalType": "bool", - "name": "active", - "type": "bool" + "type": "function", + "name": "increaseTokenStake", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" }, { - "internalType": "string", - "name": "externalToken", - "type": "string" - } - ], - "internalType": "struct PantosTypes.ExternalTokenRecord", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getMinimumServiceNodeStake", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getMinimumTokenStake", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getMinimumTrustedValidatorFeeUpdatePeriod", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getNumberActiveBlockchains", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getNumberBlockchains", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getPantosForwarder", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getPantosToken", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" + "name": "stake", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" }, { - "inputs": [], - "name": "getPantosValidator", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" + "type": "function", + "name": "isServiceNodeInTheUnbondingPeriod", + "inputs": [ + { + "name": "serviceNodeAddress", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" }, { - "inputs": [ - { - "internalType": "address", - "name": "serviceNode", - "type": "address" - } - ], - "name": "getServiceNodeRecord", - "outputs": [ - { - "components": [ - { - "internalType": "bool", - "name": "active", - "type": "bool" - }, + "type": "function", + "name": "isValidSenderNonce", + "inputs": [ { - "internalType": "string", - "name": "url", - "type": "string" + "name": "sender", + "type": "address", + "internalType": "address" }, { - "internalType": "uint256", - "name": "freeStake", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "lockedStake", - "type": "uint256" - }, + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ { - "internalType": "address", - "name": "unstakingAddress", - "type": "address" - } - ], - "internalType": "struct PantosTypes.ServiceNodeRecord", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getServiceNodes", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]" - } - ], - "stateMutability": "view", - "type": "function" + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" }, { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - } - ], - "name": "getTokenRecord", - "outputs": [ - { - "components": [ - { - "internalType": "bool", - "name": "active", - "type": "bool" - }, + "type": "function", + "name": "isValidValidatorNodeNonce", + "inputs": [ { - "internalType": "uint256", - "name": "stake", - "type": "uint256" - } - ], - "internalType": "struct PantosTypes.TokenRecord", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getTokens", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]" - } - ], - "stateMutability": "view", - "type": "function" + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" }, { - "inputs": [ - { - "internalType": "uint256", - "name": "blockchainId", - "type": "uint256" - } - ], - "name": "getTrustedValidatorFeeRecord", - "outputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "oldFactor", - "type": "uint256" + "type": "function", + "name": "registerExternalToken", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" }, { - "internalType": "uint256", - "name": "newFactor", - "type": "uint256" + "name": "blockchainId", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "uint256", - "name": "validFrom", - "type": "uint256" - } - ], - "internalType": "struct PantosTypes.TrustedValidatorFeeRecord", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "serviceNodeAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "stake", - "type": "uint256" - } - ], - "name": "increaseServiceNodeStake", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "stake", - "type": "uint256" - } - ], - "name": "increaseTokenStake", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - } - ], - "name": "isValidPantosValidatorNonce", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - } - ], - "name": "isValidSenderNonce", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "blockchainId", - "type": "uint256" - }, - { - "internalType": "string", - "name": "externalToken", - "type": "string" - } - ], - "name": "registerExternalToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "serviceNodeAddress", - "type": "address" - }, - { - "internalType": "string", - "name": "url", - "type": "string" - }, - { - "internalType": "uint256", - "name": "stake", - "type": "uint256" - }, - { - "internalType": "address", - "name": "unstakingAddress", - "type": "address" - } - ], - "name": "registerServiceNode", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "stake", - "type": "uint256" - } - ], - "name": "registerToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "externalToken", + "type": "string", + "internalType": "string" + } + ], + "outputs": [], + "stateMutability": "nonpayable" }, { - "inputs": [ - { - "components": [ + "type": "function", + "name": "registerServiceNode", + "inputs": [ { - "internalType": "address", - "name": "sender", - "type": "address" + "name": "serviceNodeAddress", + "type": "address", + "internalType": "address" }, { - "internalType": "address", - "name": "recipient", - "type": "address" + "name": "url", + "type": "string", + "internalType": "string" }, { - "internalType": "address", - "name": "token", - "type": "address" + "name": "stake", + "type": "uint256", + "internalType": "uint256" }, { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, + "name": "unstakingAddress", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "registerToken", + "inputs": [ { - "internalType": "address", - "name": "serviceNode", - "type": "address" + "name": "token", + "type": "address", + "internalType": "address" }, { - "internalType": "uint256", - "name": "fee", - "type": "uint256" + "name": "stake", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transfer", + "inputs": [ + { + "name": "request", + "type": "tuple", + "internalType": "struct PantosTypes.TransferRequest", + "components": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "serviceNode", + "type": "address", + "internalType": "address" + }, + { + "name": "fee", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "validUntil", + "type": "uint256", + "internalType": "uint256" + } + ] }, { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, + "name": "signature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ { - "internalType": "uint256", - "name": "validUntil", - "type": "uint256" - } - ], - "internalType": "struct PantosTypes.TransferRequest", - "name": "request", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" }, { - "inputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "destinationBlockchainId", - "type": "uint256" + "type": "function", + "name": "transferFrom", + "inputs": [ + { + "name": "request", + "type": "tuple", + "internalType": "struct PantosTypes.TransferFromRequest", + "components": [ + { + "name": "destinationBlockchainId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "recipient", + "type": "string", + "internalType": "string" + }, + { + "name": "sourceToken", + "type": "address", + "internalType": "address" + }, + { + "name": "destinationToken", + "type": "string", + "internalType": "string" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "serviceNode", + "type": "address", + "internalType": "address" + }, + { + "name": "fee", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "validUntil", + "type": "uint256", + "internalType": "uint256" + } + ] }, { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "string", - "name": "recipient", - "type": "string" - }, + "name": "signature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ { - "internalType": "address", - "name": "sourceToken", - "type": "address" + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferTo", + "inputs": [ + { + "name": "request", + "type": "tuple", + "internalType": "struct PantosTypes.TransferToRequest", + "components": [ + { + "name": "sourceBlockchainId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "sourceTransferId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "sourceTransactionId", + "type": "string", + "internalType": "string" + }, + { + "name": "sender", + "type": "string", + "internalType": "string" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "sourceToken", + "type": "string", + "internalType": "string" + }, + { + "name": "destinationToken", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + } + ] }, { - "internalType": "string", - "name": "destinationToken", - "type": "string" + "name": "signerAddresses", + "type": "address[]", + "internalType": "address[]" }, { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, + "name": "signatures", + "type": "bytes[]", + "internalType": "bytes[]" + } + ], + "outputs": [ { - "internalType": "address", - "name": "serviceNode", - "type": "address" - }, + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "unregisterExternalToken", + "inputs": [ { - "internalType": "uint256", - "name": "fee", - "type": "uint256" + "name": "token", + "type": "address", + "internalType": "address" }, { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, + "name": "blockchainId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "unregisterServiceNode", + "inputs": [ { - "internalType": "uint256", - "name": "validUntil", - "type": "uint256" - } - ], - "internalType": "struct PantosTypes.TransferFromRequest", - "name": "request", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" + "name": "serviceNodeAddress", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" }, { - "inputs": [ - { - "components": [ + "type": "function", + "name": "unregisterToken", + "inputs": [ { - "internalType": "uint256", - "name": "sourceBlockchainId", - "type": "uint256" - }, + "name": "token", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "updateServiceNodeUrl", + "inputs": [ { - "internalType": "uint256", - "name": "sourceTransferId", - "type": "uint256" + "name": "url", + "type": "string", + "internalType": "string" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "verifyTransfer", + "inputs": [ + { + "name": "request", + "type": "tuple", + "internalType": "struct PantosTypes.TransferRequest", + "components": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "serviceNode", + "type": "address", + "internalType": "address" + }, + { + "name": "fee", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "validUntil", + "type": "uint256", + "internalType": "uint256" + } + ] }, { - "internalType": "string", - "name": "sourceTransactionId", - "type": "string" + "name": "signature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "view" + }, + { + "type": "function", + "name": "verifyTransferFrom", + "inputs": [ + { + "name": "request", + "type": "tuple", + "internalType": "struct PantosTypes.TransferFromRequest", + "components": [ + { + "name": "destinationBlockchainId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "recipient", + "type": "string", + "internalType": "string" + }, + { + "name": "sourceToken", + "type": "address", + "internalType": "address" + }, + { + "name": "destinationToken", + "type": "string", + "internalType": "string" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "serviceNode", + "type": "address", + "internalType": "address" + }, + { + "name": "fee", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "validUntil", + "type": "uint256", + "internalType": "uint256" + } + ] }, { - "internalType": "string", - "name": "sender", - "type": "string" + "name": "signature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "view" + }, + { + "type": "function", + "name": "verifyTransferTo", + "inputs": [ + { + "name": "request", + "type": "tuple", + "internalType": "struct PantosTypes.TransferToRequest", + "components": [ + { + "name": "sourceBlockchainId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "sourceTransferId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "sourceTransactionId", + "type": "string", + "internalType": "string" + }, + { + "name": "sender", + "type": "string", + "internalType": "string" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "sourceToken", + "type": "string", + "internalType": "string" + }, + { + "name": "destinationToken", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + } + ] }, { - "internalType": "address", - "name": "recipient", - "type": "address" + "name": "signerAddresses", + "type": "address[]", + "internalType": "address[]" }, { - "internalType": "string", - "name": "sourceToken", - "type": "string" - }, + "name": "signatures", + "type": "bytes[]", + "internalType": "bytes[]" + } + ], + "outputs": [], + "stateMutability": "view" + }, + { + "type": "function", + "name": "withdrawServiceNodeStake", + "inputs": [ { - "internalType": "address", - "name": "destinationToken", - "type": "address" + "name": "serviceNodeAddress", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "BlockchainNameUpdated", + "inputs": [ + { + "name": "blockchainId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "BlockchainRegistered", + "inputs": [ + { + "name": "blockchainId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "BlockchainUnregistered", + "inputs": [ + { + "name": "blockchainId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ExternalTokenRegistered", + "inputs": [ + { + "name": "token", + "type": "address", + "indexed": false, + "internalType": "address" }, { - "internalType": "uint256", - "name": "amount", - "type": "uint256" + "name": "blockchainId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ExternalTokenUnregistered", + "inputs": [ + { + "name": "token", + "type": "address", + "indexed": false, + "internalType": "address" }, { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - } - ], - "internalType": "struct PantosTypes.TransferToRequest", - "name": "request", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "name": "transferTo", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" + "name": "blockchainId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false }, { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "blockchainId", - "type": "uint256" - } - ], - "name": "unregisterExternalToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "type": "event", + "name": "MinimumServiceNodeStakeUpdated", + "inputs": [ + { + "name": "minimumServiceNodeStake", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "MinimumTokenStakeUpdated", + "inputs": [ + { + "name": "minimumTokenStake", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "MinimumValidatorFeeUpdatePeriodUpdated", + "inputs": [ + { + "name": "minimumValidatorFeeUpdatePeriod", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PantosForwarderSet", + "inputs": [ + { + "name": "pantosForwarder", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PantosTokenSet", + "inputs": [ + { + "name": "pantosToken", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PrimaryValidatorNodeUpdated", + "inputs": [ + { + "name": "primaryValidatorNodeAddress", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ServiceNodeRegistered", + "inputs": [ + { + "name": "serviceNode", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ServiceNodeUnregistered", + "inputs": [ + { + "name": "serviceNode", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false }, { - "inputs": [ - { - "internalType": "address", - "name": "serviceNodeAddress", - "type": "address" - } - ], - "name": "unregisterServiceNode", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "type": "event", + "name": "ServiceNodeUrlUpdated", + "inputs": [ + { + "name": "serviceNode", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false }, { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - } - ], - "name": "unregisterToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "type": "event", + "name": "TokenRegistered", + "inputs": [ + { + "name": "token", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false }, { - "inputs": [ - { - "internalType": "string", - "name": "url", - "type": "string" - } - ], - "name": "updateServiceNodeUrl", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "type": "event", + "name": "TokenUnregistered", + "inputs": [ + { + "name": "token", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false }, { - "inputs": [ - { - "components": [ + "type": "event", + "name": "Transfer", + "inputs": [ + { + "name": "transferId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, { - "internalType": "address", - "name": "sender", - "type": "address" + "name": "sender", + "type": "address", + "indexed": false, + "internalType": "address" }, { - "internalType": "address", - "name": "recipient", - "type": "address" + "name": "recipient", + "type": "address", + "indexed": false, + "internalType": "address" }, { - "internalType": "address", - "name": "token", - "type": "address" + "name": "token", + "type": "address", + "indexed": false, + "internalType": "address" }, { - "internalType": "uint256", - "name": "amount", - "type": "uint256" + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" }, { - "internalType": "address", - "name": "serviceNode", - "type": "address" + "name": "fee", + "type": "uint256", + "indexed": false, + "internalType": "uint256" }, { - "internalType": "uint256", - "name": "fee", - "type": "uint256" + "name": "serviceNode", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "TransferFrom", + "inputs": [ + { + "name": "sourceTransferId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" }, { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" + "name": "destinationBlockchainId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" }, { - "internalType": "uint256", - "name": "validUntil", - "type": "uint256" - } - ], - "internalType": "struct PantosTypes.TransferRequest", - "name": "request", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "name": "verifyTransfer", - "outputs": [], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ + "name": "sender", + "type": "address", + "indexed": false, + "internalType": "address" + }, { - "internalType": "uint256", - "name": "destinationBlockchainId", - "type": "uint256" + "name": "recipient", + "type": "string", + "indexed": false, + "internalType": "string" }, { - "internalType": "address", - "name": "sender", - "type": "address" + "name": "sourceToken", + "type": "address", + "indexed": false, + "internalType": "address" }, { - "internalType": "string", - "name": "recipient", - "type": "string" + "name": "destinationToken", + "type": "string", + "indexed": false, + "internalType": "string" }, { - "internalType": "address", - "name": "sourceToken", - "type": "address" + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" }, { - "internalType": "string", - "name": "destinationToken", - "type": "string" + "name": "fee", + "type": "uint256", + "indexed": false, + "internalType": "uint256" }, { - "internalType": "uint256", - "name": "amount", - "type": "uint256" + "name": "serviceNode", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "TransferTo", + "inputs": [ + { + "name": "sourceBlockchainId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" }, { - "internalType": "address", - "name": "serviceNode", - "type": "address" + "name": "sourceTransferId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" }, { - "internalType": "uint256", - "name": "fee", - "type": "uint256" + "name": "sourceTransactionId", + "type": "string", + "indexed": false, + "internalType": "string" }, { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" + "name": "destinationTransferId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" }, { - "internalType": "uint256", - "name": "validUntil", - "type": "uint256" - } - ], - "internalType": "struct PantosTypes.TransferFromRequest", - "name": "request", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "name": "verifyTransferFrom", - "outputs": [], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ + "name": "sender", + "type": "string", + "indexed": false, + "internalType": "string" + }, { - "internalType": "uint256", - "name": "sourceBlockchainId", - "type": "uint256" + "name": "recipient", + "type": "address", + "indexed": false, + "internalType": "address" }, { - "internalType": "uint256", - "name": "sourceTransferId", - "type": "uint256" + "name": "sourceToken", + "type": "string", + "indexed": false, + "internalType": "string" }, { - "internalType": "string", - "name": "sourceTransactionId", - "type": "string" + "name": "destinationToken", + "type": "address", + "indexed": false, + "internalType": "address" }, { - "internalType": "string", - "name": "sender", - "type": "string" + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" }, { - "internalType": "address", - "name": "recipient", - "type": "address" + "name": "nonce", + "type": "uint256", + "indexed": false, + "internalType": "uint256" }, { - "internalType": "string", - "name": "sourceToken", - "type": "string" + "name": "signerAddresses", + "type": "address[]", + "indexed": false, + "internalType": "address[]" + }, + { + "name": "signatures", + "type": "bytes[]", + "indexed": false, + "internalType": "bytes[]" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "UnbondingPeriodServiceNodeStakeUpdated", + "inputs": [ + { + "name": "unbondingPeriodServiceNodeStake", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ValidatorFeeUpdated", + "inputs": [ + { + "name": "blockchainId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" }, { - "internalType": "address", - "name": "destinationToken", - "type": "address" + "name": "oldFactor", + "type": "uint256", + "indexed": false, + "internalType": "uint256" }, { - "internalType": "uint256", - "name": "amount", - "type": "uint256" + "name": "newFactor", + "type": "uint256", + "indexed": false, + "internalType": "uint256" }, { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - } - ], - "internalType": "struct PantosTypes.TransferToRequest", - "name": "request", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "name": "verifyTransferTo", - "outputs": [], - "stateMutability": "view", - "type": "function" + "name": "validFrom", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false } - ] \ No newline at end of file +] \ No newline at end of file diff --git a/pantos/common/blockchains/contracts/fantom_pantos_forwarder.abi b/pantos/common/blockchains/contracts/fantom_pantos_forwarder.abi new file mode 120000 index 0000000..2d60bf7 --- /dev/null +++ b/pantos/common/blockchains/contracts/fantom_pantos_forwarder.abi @@ -0,0 +1 @@ +ethereum_pantos_forwarder.abi \ No newline at end of file diff --git a/pantos/common/blockchains/contracts/polygon_pantos_forwarder.abi b/pantos/common/blockchains/contracts/polygon_pantos_forwarder.abi new file mode 120000 index 0000000..2d60bf7 --- /dev/null +++ b/pantos/common/blockchains/contracts/polygon_pantos_forwarder.abi @@ -0,0 +1 @@ +ethereum_pantos_forwarder.abi \ No newline at end of file diff --git a/pantos/common/blockchains/enums.py b/pantos/common/blockchains/enums.py index 8cc9dfe..ef62617 100644 --- a/pantos/common/blockchains/enums.py +++ b/pantos/common/blockchains/enums.py @@ -55,6 +55,7 @@ class ContractAbi(enum.Enum): STANDARD_TOKEN = 0 PANTOS_TOKEN = 1 PANTOS_HUB = 2 + PANTOS_FORWARDER = 3 def get_file_name(self, blockchain: Blockchain) -> str: """Get the name of the contract ABI file. diff --git a/pantos/common/blockchains/ethereum.py b/pantos/common/blockchains/ethereum.py index c9ab7ac..448a55d 100644 --- a/pantos/common/blockchains/ethereum.py +++ b/pantos/common/blockchains/ethereum.py @@ -2,7 +2,6 @@ """ import logging -import pathlib import typing import urllib.parse @@ -50,8 +49,7 @@ def __init__(self, blockchain_node_urls: list[str], average_block_time: int, required_transaction_confirmations: int, transaction_network_id: typing.Optional[int], - default_private_key: typing.Optional[tuple[pathlib.Path, - str]] = None, + default_private_key: typing.Optional[tuple[str, str]] = None, celery_tasks_enabled: bool = False): # Docstring inherited if transaction_network_id is None: @@ -222,15 +220,12 @@ def _get_transaction_method_names(self) -> list[str]: # Docstring inherited return _TRANSACTION_METHOD_NAMES - def load_private_key(self, key_path: pathlib.Path, password: str) -> str: + def decrypt_private_key(self, encrypted_key: str, password: str) -> str: # Docstring inherited try: - with key_path.open() as key_file: - encrypted_key = key_file.read() private_key = web3.Account.decrypt(encrypted_key, password).hex() except Exception: - raise self._create_error( - 'cannot load the private key "{}"'.format(key_path)) + raise self._create_error('cannot load the private key') # Return the private key hex string without the leading 0x assert private_key.startswith('0x') return private_key[2:] diff --git a/pantos/common/blockchains/factory.py b/pantos/common/blockchains/factory.py index 5827f07..9ae8eae 100644 --- a/pantos/common/blockchains/factory.py +++ b/pantos/common/blockchains/factory.py @@ -1,7 +1,6 @@ """Factory for Pantos blockchain utilities. """ -import pathlib import typing from pantos.common.blockchains.base import BlockchainUtilities @@ -20,7 +19,7 @@ def initialize_blockchain_utilities( fallback_blockchain_node_urls: list[str], average_block_time: int, required_transaction_confirmations: int, transaction_network_id: typing.Optional[int], - default_private_key: typing.Optional[tuple[pathlib.Path, str]] = None, + default_private_key: typing.Optional[tuple[str, str]] = None, celery_tasks_enabled: bool = False) -> None: """Initialize the utilities for the specified blockchain. @@ -47,9 +46,9 @@ def initialize_blockchain_utilities( compatible blockchain networks). It is assumed to be the identifier of the main or a test network of the specified blockchain. - default_private_key : tuple of pathlib.Path and str, optional - The keystore file path and password of the default private key - to be used by the blockchain utilities (default: None). + default_private_key : tuple of str and str, optional + The keystore value and password of the default private + key to be used by the blockchain utilities. (default: None). celery_tasks_enabled : bool, optional If True, Celery tasks are enabled for enhanced functionalities (default: False). This requires a proper Celery environment to diff --git a/pantos/common/blockchains/solana.py b/pantos/common/blockchains/solana.py index aa6c57d..7c67251 100644 --- a/pantos/common/blockchains/solana.py +++ b/pantos/common/blockchains/solana.py @@ -1,7 +1,6 @@ """Module for Solana-specific utilities and errors. """ -import pathlib import typing from pantos.common.blockchains.base import BlockchainUtilities @@ -27,8 +26,7 @@ def __init__(self, blockchain_node_urls: list[str], average_block_time: int, required_transaction_confirmations: int, transaction_network_id: typing.Optional[int], - default_private_key: typing.Optional[tuple[pathlib.Path, - str]] = None, + default_private_key: typing.Optional[tuple[str, str]] = None, celery_tasks_enabled: bool = False): # Docstring inherited super().__init__(blockchain_node_urls, fallback_blockchain_node_urls, @@ -71,7 +69,7 @@ def _get_transaction_method_names(self) -> list[str]: # Docstring inherited raise NotImplementedError # pragma: no cover - def load_private_key(self, key_path: pathlib.Path, password: str) -> str: + def decrypt_private_key(self, encrypted_key: str, password: str) -> str: # Docstring inherited raise NotImplementedError # pragma: no cover diff --git a/pantos/common/configuration.py b/pantos/common/configuration.py index 79844a9..d8f23fa 100644 --- a/pantos/common/configuration.py +++ b/pantos/common/configuration.py @@ -1,17 +1,53 @@ """Module for loading and parsing a configuration file. """ +import errno import importlib.resources import logging +import os import pathlib import cerberus # type: ignore +import dotenv +import pyaml_env # type: ignore import yaml from pantos.common.exceptions import BaseError _logger = logging.getLogger(__name__) +# Ordered by priority +_CONFIGURATION_PATHS = [ + pathlib.Path.cwd(), + pathlib.Path.home(), + pathlib.Path.home() / '.config', + pathlib.Path('/etc/pantos'), + pathlib.Path('/etc') +] + +if os.environ.get('PANTOS_CONFIG'): + _logger.info('loading configuration from environment variable ' + 'PANTOS_CONFIG') + _CONFIGURATION_PATHS.insert(0, pathlib.Path(os.environ['PANTOS_CONFIG'])) + + +class _CustomValidator(cerberus.Validator): + def _validate_one_not_present(self, other: str, field: str, value: str): + if (bool(value)) == (bool(self.document.get(other))): + self._error(field, "only one field can be present: " + other) + + def _normalize_coerce_load_if_file(self, value: str): + path = pathlib.Path(value) + try: + # This method may trigger an exception if the path is not valid + if path.is_file(): + with open(path, 'r') as file: + return file.read() + except OSError as error: + if error.errno != errno.ENAMETOOLONG: + raise error + return value + class ConfigError(BaseError): """Exception class for all configuration errors. @@ -80,26 +116,12 @@ def __find_file(self, file_path=None): '{}'.format(file_path)) return path # Find the configuration file at common locations - # Current working directory - path = pathlib.Path.cwd() / self.default_file_name - if path.is_file(): - return path - # Home directory - path = pathlib.Path.home() / self.default_file_name - if path.is_file(): - return path - # Hidden file in home directory - path = pathlib.Path.home() / '.{}'.format(self.default_file_name) - if path.is_file(): - return path - # Subdirectory .config in home directory - path = pathlib.Path.home() / '.config' / self.default_file_name - if path.is_file(): - return path - # Configuration directory /etc - path = pathlib.Path('/etc') / self.default_file_name - if path.is_file(): - return path + for path in _CONFIGURATION_PATHS: + config_path = path + if config_path.is_dir(): + config_path = config_path / self.default_file_name + if config_path.is_file(): + return config_path # Package resource if importlib.resources.is_resource('pantos', self.default_file_name): with importlib.resources.path('pantos', @@ -113,20 +135,34 @@ def __parse_file(self, path): """ assert isinstance(path, pathlib.Path) - with path.open() as config_file: - # Parse the YAML code in the configuration file - try: - return yaml.safe_load(config_file) - except yaml.YAMLError as error: - if hasattr(error, 'problem_mark'): - line = error.problem_mark.line + 1 - column = error.problem_mark.column + 1 - raise ConfigError('YAML code in configuration file ' - 'invalid at line {} and ' - 'column {}'.format(line, column)) - else: - raise ConfigError('YAML code in configuration file ' - 'invalid') + # List of potential .env file paths + env_files = [ + pathlib.Path(path.as_posix() + '.env'), + pathlib.Path(path.with_suffix('.env').as_posix()) + ] + + # Iterate over the potential .env file paths + for env_file in env_files: + if env_file.is_file(): + try: + dotenv.load_dotenv(env_file) + _logger.info(f'loaded .env from file {env_file}') + break + except Exception: + raise ConfigError(f'unable to load .env file {env_file}') + # Parse the YAML code in the configuration file + try: + return pyaml_env.parse_config(path.as_posix(), default_value='') + except yaml.YAMLError as error: + if hasattr(error, 'problem_mark'): + line = error.problem_mark.line + 1 + column = error.problem_mark.column + 1 + raise ConfigError('YAML code in configuration file ' + 'invalid at line {} and ' + 'column {}'.format(line, column)) + else: + raise ConfigError('YAML code in configuration file ' + 'invalid') def __validate(self, config_dict, validation_schema): """TODO @@ -136,7 +172,7 @@ def __validate(self, config_dict, validation_schema): assert isinstance(validation_schema, dict) # Create the validator and validate the validation schema try: - validator = cerberus.Validator(validation_schema) + validator = _CustomValidator(validation_schema) except cerberus.schema.SchemaError as error: raise ConfigError('validation schema invalid: {}'.format(error)) # Validate the configuration diff --git a/pantos/common/logging.py b/pantos/common/logging.py index bd2eae1..1503a98 100644 --- a/pantos/common/logging.py +++ b/pantos/common/logging.py @@ -117,6 +117,7 @@ def json_record(self, message: str, extra: typing.Dict[str | int, The dictionary of the record. """ + extra['levelname'] = record.levelname if 'time' not in extra: extra['time'] = datetime.datetime.utcnow() diff --git a/pantos/common/signer.py b/pantos/common/signer.py index 1124de6..32c62f1 100644 --- a/pantos/common/signer.py +++ b/pantos/common/signer.py @@ -1,5 +1,4 @@ import getpass -import pathlib import typing import Crypto.PublicKey.ECC @@ -28,19 +27,19 @@ def __init__(self, message: str, name: str = 'signer error', class _Signer: - def __init__(self, pem_path: str, pem_password: str): + def __init__(self, pem_value: str, pem_password: str): """ Constructor of Signer class. Parameters ---------- - pem_path : str - Path to the PEM file containing the private key. + pem_value : str + Value of the encrypted private key. pem_password : str Password to unlock the PEM file. """ - self.__signer = self._load_signer(pem_path, pem_password) + self.__signer = self._load_signer(pem_value, pem_password) def sign_message(self, message: str) -> str: """Sign a message. @@ -127,15 +126,15 @@ def build_message(self, separator: str = '', *message_parts: return message[:-1] def _load_signer( - self, pem_path: str, + self, pem_value: str, pem_password: str) -> Crypto.Signature.eddsa.EdDSASigScheme: """Load the EdDSA signer object from a password-encrypted pem file. The key must be on the curve Ed25519 or Ed448. Parameters ---------- - pem_path : str - Path to the PEM file containing the private key. + pem_value : str + Value of the encrypted private key. pem_password : str Password to unlock the PEM file. @@ -151,15 +150,12 @@ def _load_signer( """ try: - private_key_path = pathlib.Path(pem_path) - if not private_key_path.is_file(): - raise SignerError( - f'private key "{private_key_path}" is not a file') if pem_password is None: pem_password = getpass.getpass( 'Password for decrypting the pem file') + private_key = Crypto.PublicKey.ECC.import_key( - open(private_key_path).read(), passphrase=pem_password) + pem_value, passphrase=pem_password) return Crypto.Signature.eddsa.new(private_key, 'rfc8032') # type: ignore except SignerError: @@ -171,13 +167,13 @@ def _load_signer( _signer: typing.Optional[_Signer] = None -def get_signer(pem_path: str, pem_password: str) -> _Signer: +def get_signer(pem_value: str, pem_password: str) -> _Signer: """Get a _Signer object. Parameters ---------- - pem_path : str - Path to the PEM file containing the private key. + pem_value : str + Value of the encrypted private key. pem_password : str Password to unlock the PEM file. @@ -194,5 +190,5 @@ def get_signer(pem_path: str, pem_password: str) -> _Signer: """ global _signer if not _signer: - _signer = _Signer(pem_path, pem_password) + _signer = _Signer(pem_value, pem_password) return _signer diff --git a/setup.py b/setup.py index 73a978e..66ce205 100644 --- a/setup.py +++ b/setup.py @@ -1,14 +1,15 @@ import os -import setuptools +import setuptools # type: ignore setuptools.setup( - name='pantos-common', version=os.getenv('PANTOS_COMMON_VERSION'), + name='pantos-common', version=os.getenv('PANTOS_COMMON_VERSION', '0.0.0'), description='Common code for the Pantos off-chain components', packages=setuptools.find_packages(), package_data={'pantos.common.blockchains.contracts': ['*.abi']}, install_requires=[ 'celery==5.3.1', 'Cerberus==1.3.4', 'Flask-RESTful==0.3.10', - 'JSON-log-formatter==0.5.2', 'PyYAML==6.0', 'requests==2.31.0', - 'web3==6.5.0' + 'JSON-log-formatter==0.5.2', 'PyYAML==6.0.1', 'requests==2.31.0', + 'web3==6.5.0', 'pyaml-env==1.2.1', 'python-dotenv==1.0.1', + 'hexbytes==0.3.1' ]) diff --git a/tests/blockchains/test_base.py b/tests/blockchains/test_base.py index d87f0a0..d6bf8a7 100644 --- a/tests/blockchains/test_base.py +++ b/tests/blockchains/test_base.py @@ -61,26 +61,26 @@ def blockchain_utilities(blockchain_node_urls, fallback_blockchain_node_urls, blockchain_node_urls, fallback_blockchain_node_urls, average_block_time, required_transaction_confirmations, transaction_network_id, - default_private_key=(account.keystore_path, account.keystore_password), + default_private_key=(account.keystore, account.keystore_password), celery_tasks_enabled=True) @pytest.mark.parametrize('celery_tasks_enabled', [True, False]) -@unittest.mock.patch.object(BlockchainUtilities, 'load_private_key') +@unittest.mock.patch.object(BlockchainUtilities, 'decrypt_private_key') @unittest.mock.patch.object(BlockchainUtilities, 'get_address') @unittest.mock.patch.object(BlockchainUtilities, '__abstractmethods__', set()) -def test_init_correct(mock_get_address, mock_load_private_key, +def test_init_correct(mock_get_address, mock_decrypt_private_key, celery_tasks_enabled, blockchain_node_urls, fallback_blockchain_node_urls, average_block_time, required_transaction_confirmations, transaction_network_id, account): mock_get_address.return_value = account.address - mock_load_private_key.return_value = account.private_key + mock_decrypt_private_key.return_value = account.private_key blockchain_utilities = BlockchainUtilities( blockchain_node_urls, fallback_blockchain_node_urls, average_block_time, required_transaction_confirmations, transaction_network_id, - default_private_key=(account.keystore_path, account.keystore_password), + default_private_key=(account.keystore, account.keystore_password), celery_tasks_enabled=celery_tasks_enabled) assert blockchain_utilities.average_block_time == average_block_time assert (blockchain_utilities.required_transaction_confirmations == diff --git a/tests/blockchains/test_enums.py b/tests/blockchains/test_enums.py index 91ff2e6..647f6b8 100644 --- a/tests/blockchains/test_enums.py +++ b/tests/blockchains/test_enums.py @@ -30,6 +30,8 @@ def test_blockchain_from_name_error(): [(ContractAbi.PANTOS_HUB, Blockchain.ETHEREUM, 'ethereum_pantos_hub.abi'), (ContractAbi.STANDARD_TOKEN, Blockchain.BNB_CHAIN, 'bnb_chain_standard_token.abi'), + (ContractAbi.PANTOS_FORWARDER, Blockchain.CELO, + 'celo_pantos_forwarder.abi'), (ContractAbi.PANTOS_TOKEN, Blockchain.AVALANCHE, 'avalanche_pantos_token.abi')]) def test_contract_abi_get_file_name_correct(contract_abi, blockchain, diff --git a/tests/blockchains/test_ethereum.py b/tests/blockchains/test_ethereum.py index fbf8208..c9a0901 100644 --- a/tests/blockchains/test_ethereum.py +++ b/tests/blockchains/test_ethereum.py @@ -48,7 +48,7 @@ def ethereum_utilities(mock_create_node_connections, blockchain_node_urls, blockchain_node_urls, fallback_blockchain_node_urls, average_block_time, required_transaction_confirmations, transaction_network_id, - default_private_key=(account.keystore_path, account.keystore_password), + default_private_key=(account.keystore, account.keystore_password), celery_tasks_enabled=True) mock_create_node_connections.return_value = node_connections ethereum_utilities.create_node_connections = mock_create_node_connections @@ -219,10 +219,11 @@ def test_is_equal_address(ethereum_utilities): address.lower()) is True -def test_load_private_key(ethereum_utilities, account): - private_key = ethereum_utilities.load_private_key( - account.keystore_path, account.keystore_password) - assert private_key == account.private_key +def test_decrypt_private_encrypted_key(ethereum_utilities, account): + with open(account.keystore_path, 'r') as file: + private_key = ethereum_utilities.decrypt_private_key( + file.read(), account.keystore_password) + assert private_key == account.private_key def test_get_blockchain_correct(ethereum_utilities): diff --git a/tests/test_configuration.py b/tests/test_configuration.py new file mode 100644 index 0000000..bdb22d5 --- /dev/null +++ b/tests/test_configuration.py @@ -0,0 +1,122 @@ +import pathlib +from unittest.mock import mock_open +from unittest.mock import patch + +import pytest + +from pantos.common.configuration import Config +from pantos.common.configuration import ConfigError + + +def test_validate_one_not_present(): + # Test with valid data + validation_schema = { + 'private_key_path': { + 'type': 'string', + 'required': True, + 'one_not_present': 'private_key_value' + }, + 'private_key_value': { + 'type': 'string', + 'required': True, + 'one_not_present': 'private_key_path' + } + } + config_dict = {'private_key_path': 'path', 'private_key_value': ''} + config = Config('') + result = config._Config__validate(config_dict, validation_schema) + assert result is not None + + # Test with invalid data + config_dict = {'private_key_path': '', 'private_key_value': ''} + with pytest.raises(ConfigError): + config._Config__validate(config_dict, validation_schema) + + +@patch('pathlib.Path.is_file') +@patch('builtins.open', new_callable=mock_open, read_data="loaded") +def test_validate_load_if_file(mock_open, mock_is_file): + # Test with valid data + validation_schema = { + 'private_key_path': { + 'type': 'string', + 'coerce': 'load_if_file' + }, + } + config_dict = {'private_key_path': 'not a path'} + config = Config('') + + mock_is_file.return_value = True + result = config._Config__validate(config_dict, validation_schema) + assert result == {'private_key_path': 'loaded'} + + # Test with invalid data + mock_is_file.return_value = False + result = config._Config__validate(config_dict, validation_schema) + assert result == {'private_key_path': 'not a path'} + + +def test_validate_load_if_long_string_not_file(): + validation_schema = { + 'private_key_path': { + 'type': 'string', + 'coerce': 'load_if_file' + }, + } + config_dict = {'private_key_path': '{ a }' * 100000} + config = Config('') + + result = config._Config__validate(config_dict, validation_schema) + assert result == {'private_key_path': '{ a }' * 100000} + + +@patch('pathlib.Path.is_file') +def test_validate_load_os_error_escalates(mock_is_file): + validation_schema = { + 'private_key_path': { + 'type': 'string', + 'coerce': 'load_if_file' + }, + } + config_dict = {'private_key_path': '/tmp/invalid'} # nosec + config = Config('') + mock_is_file.return_value = True + + with pytest.raises(ConfigError): + config._Config__validate(config_dict, validation_schema) + + +@patch('pathlib.Path.is_file') +@patch('dotenv.load_dotenv') +@patch('pyaml_env.parse_config') +@patch('builtins.open', new_callable=mock_open, read_data="data") +def test_parse_file(mock_open, mock_parse_config, mock_load_dotenv, + mock_is_file): + mock_is_file.return_value = True + mock_load_dotenv.return_value = True + mock_parse_config.return_value = {'key': 'value'} + + config = Config('config.yaml') + result = config._Config__parse_file( + pathlib.Path('config.yaml')) # Accessing private function + + assert result == {'key': 'value'} + + mock_load_dotenv.assert_called_once() + mock_parse_config.assert_called_once() + + +@patch('pathlib.Path.is_file') +@patch('dotenv.load_dotenv') +@patch('pyaml_env.parse_config') +@patch('builtins.open', new_callable=mock_open, read_data="data") +def test_parse_file_error(mock_open, mock_parse_config, mock_load_dotenv, + mock_is_file): + mock_is_file.return_value = True + mock_load_dotenv.side_effect = Exception() + mock_parse_config.return_value = {'key': 'value'} + + config = Config('config.yaml') + with pytest.raises(ConfigError): + config._Config__parse_file( + pathlib.Path('config.yaml')) # Accessing private function diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index 4a2e835..ae5af13 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -30,6 +30,7 @@ class _Superclass(ErrorCreator[_SuperclassError]): class _Subclass(_Superclass): + @classmethod def get_error_class(cls): return _SubclassError diff --git a/tests/test_logging.py b/tests/test_logging.py index 5070f63..042c5be 100644 --- a/tests/test_logging.py +++ b/tests/test_logging.py @@ -7,7 +7,7 @@ import tempfile import unittest.mock -import json_log_formatter +import json_log_formatter # type: ignore import pytest from pantos.common.blockchains.enums import Blockchain diff --git a/tests/test_signer.py b/tests/test_signer.py index 6fc47d9..2d3c73e 100644 --- a/tests/test_signer.py +++ b/tests/test_signer.py @@ -8,35 +8,32 @@ from pantos.common.signer import get_signer -@patch('pantos.common.signer.pathlib.Path', side_effect=Exception) -def test_signer_init_unable_to_load_key(mocked_pathlib): +def test_signer_init_unable_to_load_key(): with pytest.raises(SignerError): get_signer('', '') @patch('pantos.common.signer.Crypto') -@patch('pantos.common.signer.open') @patch('pantos.common.signer.getpass') -@patch('pantos.common.signer.pathlib.Path') -def test_signer_load_signer_correct(mocked_path, mocked_getpass, mocked_open, - mocked_crypto): +def test_signer_load_signer_correct_path(mocked_getpass, mocked_crypto): get_signer('', None) - mocked_path.assert_called_once_with('') - mocked_path().is_file.assert_called_once_with() mocked_getpass.getpass.assert_called_once_with( 'Password for decrypting the pem file') - mocked_open.assert_called_once_with(mocked_path()) mocked_crypto.PublicKey.ECC.import_key.assert_called_once_with( - mocked_open().read(), passphrase=mocked_getpass.getpass()) + '', passphrase=mocked_getpass.getpass()) + + +@patch('pantos.common.signer.Crypto') +def test_signer_load_signer_correct_value(mocked_crypto): + get_signer('test', 'mocked_password') + + assert mocked_crypto.Signature.eddsa.new.called_once() @patch('pantos.common.signer.Crypto') -@patch('pantos.common.signer.open') @patch('pantos.common.signer.getpass') -@patch('pantos.common.signer.pathlib.Path') -def test_signer_sign_message_correct(mocked_path, mocked_getpass, mocked_open, - mocked_crypto): +def test_signer_sign_message_correct(mocked_getpass, mocked_crypto): signer = get_signer('', None) signer.sign_message('') @@ -45,11 +42,8 @@ def test_signer_sign_message_correct(mocked_path, mocked_getpass, mocked_open, @patch('pantos.common.signer.Crypto') -@patch('pantos.common.signer.open') @patch('pantos.common.signer.getpass') -@patch('pantos.common.signer.pathlib.Path') -def test_signer_sign_message_error(mocked_path, mocked_getpass, mocked_open, - mocked_crypto): +def test_signer_sign_message_error(mocked_getpass, mocked_crypto): signer = get_signer('', None) message = MagicMock() message.encode.side_effect = Exception @@ -59,11 +53,8 @@ def test_signer_sign_message_error(mocked_path, mocked_getpass, mocked_open, @patch('pantos.common.signer.Crypto') -@patch('pantos.common.signer.open') @patch('pantos.common.signer.getpass') -@patch('pantos.common.signer.pathlib.Path') -def test_signer_verify_message_correct(mocked_path, mocked_getpass, - mocked_open, mocked_crypto): +def test_signer_verify_message_correct(mocked_getpass, mocked_crypto): signer = get_signer('', None) result = signer.verify_message('message', '') @@ -72,11 +63,8 @@ def test_signer_verify_message_correct(mocked_path, mocked_getpass, @patch('pantos.common.signer.Crypto') -@patch('pantos.common.signer.open') @patch('pantos.common.signer.getpass') -@patch('pantos.common.signer.pathlib.Path') -def test_signer_verify_message_false(mocked_path, mocked_getpass, mocked_open, - mocked_crypto): +def test_signer_verify_message_false(mocked_getpass, mocked_crypto): signer = get_signer('', None) result = signer.verify_message('message', 'signature') @@ -85,11 +73,8 @@ def test_signer_verify_message_false(mocked_path, mocked_getpass, mocked_open, @patch('pantos.common.signer.Crypto') -@patch('pantos.common.signer.open') @patch('pantos.common.signer.getpass') -@patch('pantos.common.signer.pathlib.Path') -def test_signer_verify_message_raises_exception(mocked_path, mocked_getpass, - mocked_open, mocked_crypto): +def test_signer_verify_message_raises_exception(mocked_getpass, mocked_crypto): signer = get_signer('', None) message = MagicMock() @@ -100,11 +85,8 @@ def test_signer_verify_message_raises_exception(mocked_path, mocked_getpass, @patch('pantos.common.signer.Crypto') -@patch('pantos.common.signer.open') @patch('pantos.common.signer.getpass') -@patch('pantos.common.signer.pathlib.Path') -def test_build_message(mocked_path, mocked_getpass, mocked_open, - mocked_crypto): +def test_build_message(mocked_getpass, mocked_crypto): signer = get_signer('', None) message = signer.build_message('-', 0, 0, [Blockchain.ETHEREUM])